Below apex code can be used to convert number (currency) into words. This code can be used in triggers,visualforce pages to convert any number/currency field value in words and stored in any text field.
How to call this class
Decimal d = 1491511.61;
NumberTOWordConvertion nwcObj = new NumberTOWordConvertion();
String numInWords = nwcObj.getNumberTOWordConvertion(d);
Output : Fourteen Lakh Ninety One Thousand Five Hundred and Eleven Rupess And Sixty One Paisa Only.
public class NumberTOWordConvertion {
// Call this method with Number to convert
public String getNumberTOWordConvertion(Decimal num) {
Decimal junkVal = num;
Decimal junkValPaisa = junkVal - Math.floor(junkVal);
junkVal = Math.floor(junkVal);
String obStr = junkVal.toPlainString();
String[] numReversed = obStr.split('');
String[] actnumber = reverse(numReversed);
String firstHalf = convertInWords(numReversed, actnumber);
Integer tmp = Math.round(junkValPaisa * 100);
junkValPaisa = (Decimal)tmp / 100; System.debug('jj :' + junkValPaisa);
String paisaStr = junkValPaisa.toPlainString();
String secondHalf;
if (paisaStr == '0') {
secondHalf = '';
} else if (paisaStr.length() != 4) {
paisaStr = paisaStr + '0';
paisaStr = paisaStr.substring(2);
String [] numReversedPaisa = paisaStr.split('');
String[] actnumberPaisa = reverse(numReversedPaisa);
secondHalf = convertInWords(numReversedPaisa, actnumberPaisa);
} else {
paisaStr = paisaStr.substring(2);
String [] numReversedPaisa = paisaStr.split('');
String[] actnumberPaisa = reverse(numReversedPaisa);
secondHalf = convertInWords(numReversedPaisa, actnumberPaisa);
}
String SumOFHalves = '';
if (secondHalf.length() > 4) {
firstHalf = firstHalf.replace('Only', 'Rupess And ');
secondHalf = secondHalf.replace('Only', 'Paisa Only');
SumOFHalves = firstHalf + secondHalf;
} else {
firstHalf = firstHalf.replace('Only', 'Rupess Only');
SumOFHalves = firstHalf;
}
// IF amount has any value
if (SumOFHalves.length() > 5) {
return SumOFHalves;
} else {
return '';
}
}
// Method reverse the number
public List<String> reverse(List<String> strToRev) {
List<String> revList = new List<String>();
for (Integer i = strToRev.size() - 1; i >= 0; i--) {
revList.add(strToRev.get(i));
}
revList.add('');
return revList;
}
public String convertInWords(String[] numRev, String[] actnum) {
List<String> iWords = new List<String> {'Zero', ' One', ' Two', ' Three', ' Four', ' Five', ' Six', ' Seven', ' Eight', ' Nine'};
List<String> ePlace = new List<String> {' Ten', ' Eleven', ' Twelve', ' Thirteen', ' Fourteen', ' Fifteen', ' Sixteen', ' Seventeen', ' Eighteen', ' Nineteen'};
List<String> tensPlace = new List<String> {'dummy', ' Ten', ' Twenty', ' Thirty', ' Forty', ' Fifty', ' Sixty', ' Seventy', ' Eighty', ' Ninety' };
Integer iWordsLength = numRev.size();
String totalWords = '';
List<String> inWords = new List<String>();
for (Integer k = 0; k < iWordsLength; k++) {
inWords.add('');
}
String finalWord = '';
Integer j = 0;
// Main For loop
for (Integer i = 0; i < iWordsLength; i++) {
if (i == 0) {
if (actnum[i] == '0' || actnum[i + 1] == '1') {
inWords[j] = '';
} else {
inWords[j] = iWords[Integer.valueof(actnum[i])];
}
inWords[j] = inWords[j] + ' Only';
} else if (i == 1) {
if (actnum[i] == '0') {
inWords[j] = '';
} else if (actnum[i] == '1') {
inWords[j] = ePlace[Integer.valueof(actnum[i - 1])];
} else {
inWords[j] = tensPlace[Integer.valueof(actnum[i])];
}
} else if (i == 2) {
if (actnum[i] == '0') {
inWords[j] = '';
} else if (actnum[i - 1] != '0' && actnum[i - 2] != '0') {
inWords[j] = iWords[Integer.valueof(actnum[i])] + ' Hundred and';
} else {
inWords[j] = iWords[Integer.valueof(actnum[i])] + ' Hundred';
}
} else if (i == 3) {
if (actnum[i] == '0' || actnum[i + 1] == '1') {
inWords[j] = '';
} else {
inWords[j] = iWords[Integer.valueof(actnum[i])];
}
if (actnum[i + 1] != '0' || Integer.valueof(actnum[i]) > 0) {
inWords[j] = inWords[j] + ' Thousand';
}
} else if (i == 4) {
if (actnum[i] == '0') {
inWords[j] = '';
} else if (actnum[i] == '1') {
inWords[j] = ePlace[Integer.valueof(actnum[i - 1])];
} else {
inWords[j] = tensPlace[Integer.valueof(actnum[i])];
}
} else if (i == 5) {
if (actnum[i] == '0' || actnum[i + 1] == '1') {
inWords[j] = '';
} else {
inWords[j] = iWords[Integer.valueof(actnum[i])];
}
if (actnum[i + 1] != '0' || Integer.valueof(actnum[i]) > 0) {
inWords[j] = inWords[j] + ' Lakh';
}
} else if (i == 6) {
if (actnum[i] == '0') {
inWords[j] = '';
} else if (actnum[i] == '1') {
inWords[j] = ePlace[Integer.valueof(actnum[i - 1])];
} else {
inWords[j] = tensPlace[Integer.valueof(actnum[i])];
}
} else if (i == 7) {
if (actnum[i] == '0' || actnum[i + 1] == '1' ) {
inWords[j] = '';
} else {
inWords[j] = iWords[Integer.valueof(actnum[i])];
}
inWords[j] = inWords[j] + ' Crore';
} else if (i == 8) {
if (actnum[i] == '0') {
inWords[j] = '';
} else if (actnum[i] == '1') {
inWords[j] = ePlace[Integer.valueof(actnum[i - 1])];
} else {
inWords[j] = tensPlace[Integer.valueof(actnum[i])];
}
}
j++;
}
// End of For loop
// Reverse the List
inWords = reverse(inWords);
for (Integer i = 0; i < inWords.size(); i++) {
finalWord += inWords[i];
}
return finalWord;
}
}
String.valueOf(num);
returns the string equivalent of the num
Related
I am trying to figure out why I get the Error in Title when adding if-Statements to my program. Without the if-statements everything works just fine. I hope someone can help me out :D Greetings
String? btmRechneranzeige(double? menge, double? prozent, String? btmittel,) {
// Add your function code here!
var m = menge;
var p = prozent;
double mengebtm = 0;
if (m != 0 && p != 0) {
mengebtm = m! * (p! / 100);
}
var result = mengebtm.toString();
String stoff = "";
if(btmittel == null){
return "...";
}
if (btmittel == "Amphetamin" && mengebtm >= 10) {
stoff = "Amphetaminbase übersteigt die nicht-geringe Menge";
} else {
if (btmittel == "Amphetamin" && mengebtm < 10) {
stoff = "Amphetaminbase übersteigt die nicht-geringe Menge nicht";
} else {return null;}
String output =
"Bei einer Menge von $result gramm handelt es sich um eine geringe Menge!";
//String result = nonono;
return output;
}
The brackets don't match up right, making paths that don't return anything. I suspect you want to change the line that says
} else {
to
} else
Although other things seem wrong as well. Like you don't even use the result of stoff
String? btmRechneranzeige1(double? menge, double? prozent, String? btmittel) {
var m = menge;
var p = prozent;
String stoff = "";
double mengebtm = 0;
if (m != 0 && p != 0) {
mengebtm = m! * (p! / 100);
}
var result = mengebtm.toString();
if (btmittel == null) {
return "...";
} else if (btmittel == "Amphetamin" && mengebtm >= 10) {
stoff = "Amphetaminbase übersteigt die nicht-geringe Menge";
} else if (btmittel == "Amphetamin" && mengebtm < 10) {
stoff = "Amphetaminbase übersteigt die nicht-geringe Menge nicht";
String output = "Bei einer Menge von $result gramm handelt es sich um eine geringe Menge!";
return output;
}
return null; // this line optional
}
You are missing a return at this if-statement "btmittel == "Amphetamin" && mengebtm >= 10"
So this would work:
String? btmRechneranzeige(double? menge, double? prozent, String? btmittel,) {
// Add your function code here!
var m = menge;
var p = prozent;
double mengebtm = 0;
if (m != 0 && p != 0) {
mengebtm = m! * (p! / 100);
}
var result = mengebtm.toString();
String stoff = "";
if(btmittel == null){
return "...";
}
if (btmittel == "Amphetamin" && mengebtm >= 10) {
stoff = "Amphetaminbase übersteigt die nicht-geringe Menge";
return "some text here..." // -> This is the added line!!
} else {
if (btmittel == "Amphetamin" && mengebtm < 10) {
stoff = "Amphetaminbase übersteigt die nicht-geringe Menge nicht";
} else {return null;}
String output =
"Bei einer Menge von $result gramm handelt es sich um eine geringe Menge!";
//String result = nonono;
return output;
}
} // You were also missing this bracket :D
When returning an instance of something make sure you add a return value (null is also a value) for each path, so every if (else) branch.
I am trying to write a date input control which accepts a date like 23/12/1997. What I would like it to do is automatically insert the / characters for the user. So as they type in 23 the listener returns 23/, so that they can then type in 12. At this point the listener again adds a / leaving the user to complete the date by typing 1997.
My TextEditingController code half works and looks like this:
final _controller = TextEditingController();
_controller.addListener(() {
String text = _controller.text;
if (text.length == 2) {
text += '/';
}
if (text.length == 5) {
text += '/';
}
_controller.value = _controller.value.copyWith(
text: text,
selection:
TextSelection(baseOffset: text.length, extentOffset: text.length),
composing: TextRange.empty,
);
print(_controller.text);
}
So it works fine until the user makes a mistake and needs to backtrack. As soon as a / is deleted it is immediately replaced stopping any further editing of the date.
In order to get it to work I need to access is the previously entered text to determine if the user is backspacing. So if text == 23/ && previous_text == 23/1 then I can remove the / from text.
I found this question textfield must only accept numbers and I think it may help me, but I am not sure how to implement an existing widget and override its methods. Of course there may be a simpler way to do this within the TextEditingController?
I have found what I needed to solve my date validation input. It is not perfect, but it is good enough for what I am trying to do. All I needed was to look at the inputFormatters method of a TextField(). This allow manipulation of the input text to put it into any number of user-defined formats. I am including a segment of my code for anyone who would like to try it out:
class _DateFormatter extends TextInputFormatter {
#override
TextEditingValue formatEditUpdate(
TextEditingValue prevText, TextEditingValue currText) {
int selectionIndex;
// Get the previous and current input strings
String pText = prevText.text;
String cText = currText.text;
// Abbreviate lengths
int cLen = cText.length;
int pLen = pText.length;
if (cLen == 1) {
// Can only be 0, 1, 2 or 3
if (int.parse(cText) > 3) {
// Remove char
cText = '';
}
} else if (cLen == 2 && pLen == 1) {
// Days cannot be greater than 31
int dd = int.parse(cText.substring(0, 2));
if (dd == 0 || dd > 31) {
// Remove char
cText = cText.substring(0, 1);
} else {
// Add a / char
cText += '/';
}
} else if (cLen == 4) {
// Can only be 0 or 1
if (int.parse(cText.substring(3, 4)) > 1) {
// Remove char
cText = cText.substring(0, 3);
}
} else if (cLen == 5 && pLen == 4) {
// Month cannot be greater than 12
int mm = int.parse(cText.substring(3, 5));
if (mm == 0 || mm > 12) {
// Remove char
cText = cText.substring(0, 4);
} else {
// Add a / char
cText += '/';
}
} else if ((cLen == 3 && pLen == 4) || (cLen == 6 && pLen == 7)) {
// Remove / char
cText = cText.substring(0, cText.length - 1);
} else if (cLen == 3 && pLen == 2) {
if (int.parse(cText.substring(2, 3)) > 1) {
// Replace char
cText = cText.substring(0, 2) + '/';
} else {
// Insert / char
cText =
cText.substring(0, pLen) + '/' + cText.substring(pLen, pLen + 1);
}
} else if (cLen == 6 && pLen == 5) {
// Can only be 1 or 2 - if so insert a / char
int y1 = int.parse(cText.substring(5, 6));
if (y1 < 1 || y1 > 2) {
// Replace char
cText = cText.substring(0, 5) + '/';
} else {
// Insert / char
cText = cText.substring(0, 5) + '/' + cText.substring(5, 6);
}
} else if (cLen == 7) {
// Can only be 1 or 2
int y1 = int.parse(cText.substring(6, 7));
if (y1 < 1 || y1 > 2) {
// Remove char
cText = cText.substring(0, 6);
}
} else if (cLen == 8) {
// Can only be 19 or 20
int y2 = int.parse(cText.substring(6, 8));
if (y2 < 19 || y2 > 20) {
// Remove char
cText = cText.substring(0, 7);
}
}
selectionIndex = cText.length;
return TextEditingValue(
text: cText,
selection: TextSelection.collapsed(offset: selectionIndex),
);
}
}
To use it simply call it from the Textfield() as shown below. I've also incorporated two built in methods as well. WhitelistingTextInputFormatter() to only allow digits and a slash(/) character to be entered and LengthLimitingTextInputFormatter() to restrict the number of characters allowed. The latter could be achieved using the maxLength parameter of TextField() but it is here by way of example. Note that there is also a BlacklistingTextInputFormatter() which does as you would expect.
WhitelistingTextInputFormatter was removed use FilteringTextInputFormatter.allow(RegExp("[0-9-]")), to replace, and If you want to change split symbol (current is "/"), Pls add it to RegExp(....).
TextField(
// maxLength: 10,
keyboardType: TextInputType.datetime,
controller: _controllerDOB,
focusNode: _focusNodeDOB,
decoration: InputDecoration(
hintText: 'DD/MM/YYYY',
counterText: '',
),
inputFormatters: [
WhitelistingTextInputFormatter(RegExp("[0-9/]")),
LengthLimitingTextInputFormatter(10),
_DateFormatter(),
],
),
You can use datepicker dialog made by flutter.
DateTime _date = DateTime.now()
onPressed: () {
showDatePicker(
context: context,
initialDate: _date,
firstDate: DateTime(2020),
lastDate: DateTime(2021),
).then((date) {
setState(() {
_date = date;
});
});
},
I find your code to be a great utility, without any dependencies. I took the liberty to do a few mods and thought of posting it back here, as I find your concept very neat and lightweight on the UI. The requirements were;
Validating the date for non-31-day months and leap years. The mods were quite straightforward.
Preventing the user entering "/" at undesirable places which will throw the algorithm off-track. The simplest solution is to make the
keyboardType: TextInputType.number, in the TextField
This works perfectly for mobile devices.
But Flutter being cross-platform, this solution may not be foolproof when it comes to a device with physical keyboard. I tried various checks and blocks but only partially succeeded; i.e, user can still input "/" in between the digits of the Day and Month. I think there is an internal delay between KB input and programmatic formatter.
Following is the modified code for _DateFormatter. I have used the /// notion to distinguish my comments. They should be read along with the original // comments.
class _DateFormatter extends TextInputFormatter {
#override
TextEditingValue formatEditUpdate(
TextEditingValue prevText, TextEditingValue currText) {
int selectionIndex;
String date;
String month;
int year;
// Get the previous and current input strings
String pText = prevText.text;
String cText = currText.text;
cText = cText.replaceAll("//", "/");
// Abbreviate lengths
int cLen = cText.length;
int pLen = pText.length;
/// ENTERING THE DATE
if (cLen == 1) {
/// User enters the first digit of the date. The first digit
// Can only be 0, 1, 2 or 3
if (int.parse(cText) > 3) {
// Remove char
cText = '';
}
} else if (cLen == 2 && pLen == 1) {
/// User has already entered a valid first digit of the date, now he
/// enters the second digit of the date; but
// Days cannot be greater than 31
int dd = int.parse(cText.substring(0, 2));
if (dd == 0 || dd > 31) {
// Remove char
cText = cText.substring(0, 1);
} else {
/// User has entered a valid date (between 1 and 31). So now,
// Add a / char
cText += '/';
}
/// ENTERING THE MONTH
} else if (cLen == 4) {
/// after entering a valid date and programmatic insertion of '/', now User has entered
/// the first digit of the Month. But, it
// Can only be 0 or 1
/// (and, not '/' either)
if (int.parse(cText.substring(3, 4)) > 1 || cText.substring(3, 4) == "/") {
// Remove char
cText = cText.substring(0, 3);
}
} else if (cLen == 5 && pLen == 4) {
int mm = int.parse(cText.substring(3, 5));
int dd = int.parse(cText.substring(0, 2));
/// User has entered the second digit of the Month, but the
// Month cannot be greater than 12
/// Also, that entry cannot be '/'
if ((mm == 0 || mm > 12|| cText.substring(3, 5) == "/") ||
/// If the date is 31, the month cannot be Apr, Jun, Sept or Nov
(dd == 31 && (mm == 02 || mm == 04 || mm == 06 || mm == 09 || mm == 11)) ||
/// If the date is greater than 29, the month cannot be Feb
/// (Leap years will be dealt with, when user enters the Year)
(dd > 29 && (mm == 02))) {
// Remove char
cText = cText.substring(0, 4);
}
else if (cText.length == 5) {
/// the Month entered is valid; so,
// Add a / char
cText += '/';
}
} else if ((cLen == 3 && pLen == 4) || (cLen == 6 && pLen == 7)) {
// Remove / char
cText = cText.substring(0, cText.length - 1);
} else if (cLen == 3 && pLen == 2) {
if (int.parse(cText.substring(2, 3)) > 1) {
// Replace char
cText = cText.substring(0, 2) + '/';
} else {
// Insert / char
cText =
cText.substring(0, pLen) + '/' + cText.substring(pLen, pLen + 1);
}
/// ENTERING THE YEAR
} else if (cLen == 6 && pLen == 5) {
// Can only be 1 or 2 - if so insert a / char
int y1 = int.parse(cText.substring(5, 6));
if (y1 < 1 || y1 > 2) {
// Replace char
/// i.e, add '/' after the 5th position
cText = cText.substring(0, 5) + '/';
} else {
// Insert / char
cText = cText.substring(0, 5) + '/' + cText.substring(5, 6);
}
} else if (cLen == 7) {
/// the first digit of year
// Can only be 1 or 2
int y1 = int.parse(cText.substring(6, 7));
if (y1 < 1 || y1 > 2) {
// Remove char
cText = cText.substring(0, 6);
}
} else if (cLen == 8) {
// Can only be 19 or 20
/// Also, there cannot be / typed by the user
String y2 = cText.substring(6, 8);
if (y2 != "19" && y2 != "20") {
// Remove char
cText = cText.substring(0, 7);
}
} else if (cLen == 9) {
/// There cannot be / typed by the user
if (cText.substring(8, 9) == "/") {
// Remove char
cText = cText.substring(0, 8);
}
} else if (cLen == 10) {
/// There cannot be / typed by the user
if (cText.substring(9, 10) == "/") {
// Remove char
cText = cText.substring(0, 9);
}
/// If the year entered is not a leap year but the date entered is February 29,
/// it will be advanced to the next valid date
date = cText.substring(0, 2);
month = cText.substring(3, 5);
year = int.parse(cText.substring(6, 10));
bool isNotLeapYear = !((year % 4 == 0) && (year % 100 != 0) ||
(year % 400 == 0));
if (isNotLeapYear && month == "02" && date == "29") {
cText = "01/03/$year";
}
}
selectionIndex = cText.length;
return TextEditingValue(
text: cText,
selection: TextSelection.collapsed(offset: selectionIndex),
);
}
} // END OF class _DateFormatter
I found one solution for this, But not an optimized solution, but it is covering almost all the scenarios,
forward slash during adding fields
remove the forward slash on clearing fields
in between editing handling... etc
class CustomDateTextFormatter extends TextInputFormatter {
#override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue, TextEditingValue newValue) {
var text = _format(newValue.text, '/', oldValue);
return newValue.copyWith(
text: text, selection: _updateCursorPosition(text, oldValue));
}
}
String _format(String value, String seperator, TextEditingValue old) {
var finalString = '';
var dd = '';
var mm = '';
var yyy = '';
var oldVal = old.text;
print('<------------------------- start---------------------------->');
print('oldVal -> $oldVal');
print('value -> $value');
var temp_oldVal = oldVal;
var temp_value = value;
if (!oldVal.contains(seperator) ||
oldVal.isEmpty ||
seperator.allMatches(oldVal).length < 2) {
oldVal += '///';
}
if (!value.contains(seperator) || _backSlashCount(value) < 2) {
value += '///';
}
var splitArrOLD = oldVal.split(seperator);
var splitArrNEW = value.split(seperator);
print('----> splitArrOLD: $splitArrOLD');
print('----> splitArrNEW: $splitArrNEW');
for (var i = 0; i < 3; i++) {
splitArrOLD[i] = splitArrOLD[i].toString().trim();
splitArrNEW[i] = splitArrNEW[i].toString().trim();
}
// block erasing
if ((splitArrOLD[0].isNotEmpty &&
splitArrOLD[2].isNotEmpty &&
splitArrOLD[1].isEmpty &&
temp_value.length < temp_oldVal.length &&
splitArrOLD[0] == splitArrNEW[0] &&
splitArrOLD[2].toString().trim() ==
splitArrNEW[1].toString().trim()) ||
(_backSlashCount(temp_oldVal) > _backSlashCount(temp_value) &&
splitArrNEW[1].length > 2) ||
(splitArrNEW[0].length > 2 && _backSlashCount(temp_oldVal) == 1) ||
(_backSlashCount(temp_oldVal) == 2 &&
_backSlashCount(temp_value) == 1 &&
splitArrNEW[0].length > splitArrOLD[0].length)) {
finalString = temp_oldVal; // making the old date as it is
print('blocked finalString : $finalString ');
} else {
if (splitArrNEW[0].length > splitArrOLD[0].length) {
if (splitArrNEW[0].length < 3) {
dd = splitArrNEW[0];
} else {
for (var i = 0; i < 2; i++) {
dd += splitArrNEW[0][i];
}
}
if (dd.length == 2 && !dd.contains(seperator)) {
dd += seperator;
}
} else if (splitArrNEW[0].length == splitArrOLD[0].length) {
print('splitArrNEW[0].length == 2');
if (oldVal.length > value.length && splitArrNEW[1].isEmpty) {
dd = splitArrNEW[0];
} else {
dd = splitArrNEW[0] + seperator;
}
} else if (splitArrNEW[0].length < splitArrOLD[0].length) {
print('splitArrNEW[0].length < splitArrOLD[0].length');
if (oldVal.length > value.length &&
splitArrNEW[1].isEmpty &&
splitArrNEW[0].isNotEmpty) {
dd = splitArrNEW[0];
} else if (temp_oldVal.length > temp_value.length &&
splitArrNEW[0].isEmpty &&
_backSlashCount(temp_value) == 2) {
dd += seperator;
} else {
if (splitArrNEW[0].isNotEmpty) {
dd = splitArrNEW[0] + seperator;
}
}
}
print('dd value --> $dd');
if (dd.isNotEmpty) {
finalString = dd;
if (dd.length == 2 &&
!dd.contains(seperator) &&
oldVal.length < value.length &&
splitArrNEW[1].isNotEmpty) {
if (seperator.allMatches(dd).isEmpty) {
finalString += seperator;
}
} else if (splitArrNEW[2].isNotEmpty &&
splitArrNEW[1].isEmpty &&
temp_oldVal.length > temp_value.length) {
if (seperator.allMatches(dd).isEmpty) {
finalString += seperator;
}
} else if (oldVal.length < value.length &&
(splitArrNEW[1].isNotEmpty || splitArrNEW[2].isNotEmpty)) {
if (seperator.allMatches(dd).isEmpty) {
finalString += seperator;
}
}
} else if (_backSlashCount(temp_oldVal) == 2 && splitArrNEW[1].isNotEmpty) {
dd += seperator;
}
print('finalString after dd=> $finalString');
if (splitArrNEW[0].length == 3 && splitArrOLD[1].isEmpty) {
mm = splitArrNEW[0][2];
}
if (splitArrNEW[1].length > splitArrOLD[1].length) {
print('splitArrNEW[1].length > splitArrOLD[1].length');
if (splitArrNEW[1].length < 3) {
mm = splitArrNEW[1];
} else {
for (var i = 0; i < 2; i++) {
mm += splitArrNEW[1][i];
}
}
if (mm.length == 2 && !mm.contains(seperator)) {
mm += seperator;
}
} else if (splitArrNEW[1].length == splitArrOLD[1].length) {
print('splitArrNEW[1].length = splitArrOLD[1].length');
if (splitArrNEW[1].isNotEmpty) {
mm = splitArrNEW[1];
}
} else if (splitArrNEW[1].length < splitArrOLD[1].length) {
print('splitArrNEW[1].length < splitArrOLD[1].length');
if (splitArrNEW[1].isNotEmpty) {
mm = splitArrNEW[1] + seperator;
}
}
print('mm value --> $mm');
if (mm.isNotEmpty) {
finalString += mm;
if (mm.length == 2 && !mm.contains(seperator)) {
if (temp_oldVal.length < temp_value.length) {
finalString += seperator;
}
}
}
print('finalString after mm=> $finalString');
if (splitArrNEW[1].length == 3 && splitArrOLD[2].isEmpty) {
yyy = splitArrNEW[1][2];
}
if (splitArrNEW[2].length > splitArrOLD[2].length) {
print('splitArrNEW[2].length > splitArrOLD[2].length');
if (splitArrNEW[2].length < 5) {
yyy = splitArrNEW[2];
} else {
for (var i = 0; i < 4; i++) {
yyy += splitArrNEW[2][i];
}
}
} else if (splitArrNEW[2].length == splitArrOLD[2].length) {
print('splitArrNEW[2].length == splitArrOLD[2].length');
if (splitArrNEW[2].isNotEmpty) {
yyy = splitArrNEW[2];
}
} else if (splitArrNEW[2].length < splitArrOLD[2].length) {
print('splitArrNEW[2].length < splitArrOLD[2].length');
yyy = splitArrNEW[2];
}
print('yyy value --> $yyy');
if (yyy.isNotEmpty) {
if (_backSlashCount(finalString) < 2) {
if (splitArrNEW[0].isEmpty && splitArrNEW[1].isEmpty) {
finalString = seperator + seperator + yyy;
} else {
finalString = finalString + seperator + yyy;
}
} else {
finalString += yyy;
}
} else {
if (_backSlashCount(finalString) > 1 && oldVal.length > value.length) {
var valueUpdate = finalString.split(seperator);
finalString = valueUpdate[0] + seperator + valueUpdate[1];
}
}
print('finalString after yyyy=> $finalString');
}
print('<------------------------- finish---------------------------->');
return finalString;
}
TextSelection _updateCursorPosition(String text, TextEditingValue oldValue) {
var endOffset = max(
oldValue.text.length - oldValue.selection.end,
0,
);
var selectionEnd = text.length - endOffset;
print('My log ---> $selectionEnd');
return TextSelection.fromPosition(TextPosition(offset: selectionEnd));
}
int _backSlashCount(String value) {
return '/'.allMatches(value).length;
}
We can Use our custom formator as in inputFormatters like below
TextField(
// maxLength: 10,
keyboardType: TextInputType.datetime,
controller: _controllerDOB,
focusNode: _focusNodeDOB,
decoration: InputDecoration(
hintText: 'DD/MM/YYYY',
counterText: '',
),
inputFormatters: [
WhitelistingTextInputFormatter(RegExp("[0-9/]")),
LengthLimitingTextInputFormatter(10),
CustomDateTextFormatter(),
],
),
try out this solution.
Here after the result is loaded and try to input the next input it just get appended with the result, but the display should be cleared for the second calculation. Any help will be appreciated.
var arr=[];
var input=0;
function numberBtn(arg){
if ( document.getElementById("currentValue").innerHTML ==="ERROR" || (document.getElementById("currentValue").innerHTML == "0"))
{
document.getElementById("currentValue").innerHTML = "";
}
input += arg;
document.getElementById("currentValue").innerHTML += arg;
}
function calculate(val){
if(input !== 0){
addToArr(input);
}
var answer = val[0];
var divideZero =0;
var i=2
switch(arr[i-1]){
case '+':
answer= Number(val[i-2]) + Number(val[i]);
break;
case '-':
answer-= val[i];
break;
case '/':
if (val[i] == 0) divideZero = 1;
else answer = answer / val[i];
break;
case'*':
//console.log(value,'before multiply');
answer = answer * val[i];
// console.log(val[i],'after multiply');
break;
case'%':
if (val[i] == 0) divideZero = 1;
else{
var q= val[i-2]/val[i];
answer= val[i-2] - (val[i] * Math.floor(q));
}
break;
case'+/-':
answer= -answer;
break;
}
if ( divideZero === 1) {
clearAll();
document.getElementById("currentValue").innerHTML = "ERROR";
}
else
{
document.getElementById("currentValue").innerHTML = answer;
input = answer;
arr = [];
}
}
function addToArr(input){
arr.push(input);
}
function clearAll() {
arr = [];
input = 0;
document.getElementById("currentValue").innerHTML = "0";
}
function operatorBtn(arg){
if (input !== 0) {
addToArr(input);
addToArr(arg);
document.getElementById("currentValue").innerHTML +=arg;
input = 0;
}
}
I have tried to get the exact position to drop the content in tinymce. But not able to find the cursor position and not able to fetch the data values takes place. Its only fetching values in previous position.
Please help me.
I have tried below code,
tinymce.activeEditor.selection.getRng() - here we can't able to find the exact position. it fetch only previoous position.
ed.on("drop", function($event) {
if($event.preventDefault) {
$event.preventDefault();
}
if($event.stopPropagation()) {
$event.stopPropagation();
}
if ($event.dataTransfer) {
var data = $event.dataTransfer.getData("Text");
var $data = angular.fromJson(data);
}
});
In drop also we cant able to find the exact position.
Please give me the solution.
This is a tricky one.
I wrote two functions. One to get the absolute cursor position in tinymce and one to set the cursor to a specified cursor position. Plus two helpfull functions to set the caret in the editor and one to get the block element in which the actual caret is to be found.
I have those functions placed inside my own custom tinymce plugin myownplugin, but you may put those functions where you like.
Here they are:
// gets the caret offset to the editor start
get_caret_offset: function()
{
var ed = this.editor;
var range = ed.selection.getRng(1);
var copied_range = range.cloneRange();
var subtract_from_index = 0;
// count returns
var index = $(ed.plugins.myownplugin.p_of(range.startContainer)).index();
var add_to_offset = 0;
// add 1 for each empty paragraph
var $children = $(ed.getBody()).children();
// some node contents need to be subtracted from the offset later on.
// free paragraphs count for example
var subtract = 0;
var rte_starts = 0;
for (var i=0; i < index; i++)
{
var child_node = $children.eq(i).get(0);
if (child_node)
{
if (child_node.nodeName == 'RTEPHTAG')
{
subtract_from_index++;
if (child_node.className == "start")
{
subtract = 0;
}
else subtract = 0;
}
if (subtract && (child_node.nodeName == 'P' || child_node.nodeName == 'OL' || child_node.nodeName == 'UL'))
{
subtract_from_index += child_node.textContent.replace(re_exspaces,'')
.replace( /\ufeff/g, '' )
.replace( /\u00ad/g, '' )
.replace( //g, '')
.replace( //g, '')
.replace( //g, '').length + 1;
}
// count bBRs
else if(child_node.nodeName == 'P' || child_node.nodeName == 'OL' || child_node.nodeName == 'UL')
{
add_to_offset += $(child_node).find('br').length;
}
}
}
// copy range to be able to calculate characters to the start of the initial range
copied_range.setStart(ed.getBody().firstChild, 0);
// caret paragraph needs to be counted too?
if(subtract)
{
if (index)
{
var endnode = $children.eq(index - 1).get(0);
if (endnode) copied_range.setEndAfter(endnode);
else copied_range.setEnd(range.endContainer, range.endOffset);
}
else return 0;
}
else copied_range.setEnd(range.endContainer, range.endOffset);
var str = copied_range.toString();
subtract_from_index += ( str.match(/[\uD800-\uDBFF]/g) || [] ).length;
var caret_offset = str
.replace(re_exspaces,'')
.replace( /\ufeff/g, '' )
.replace( /\u00ad/g, '' )
.replace( //g, '')
.replace( //g, '')
.replace( //g, '').length + index + add_to_offset + rte_starts - subtract_from_index;
// add BRs in the actual paragraph?
var p_end = ed.plugins.myownplugin.p_of(range.endContainer);
if(range.endContainer && range.endContainer.nodeName != 'BODY')
{
if (p_end){
copied_range.setStartBefore(p_end);
}
}
return caret_offset;
},
// sets the caret according to the offset
set_caret_offset: function(offset, scroll_into_view)
{
function get_count(where_str, search_str) {
var m = where_str.match(new RegExp(search_str.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "g"));
return m ? m.length:0;
}
var ed = this.editor;
// Check: enough content to set caret?
if (!offset)
ed.plugins.myownplugin.setCursor(ed, ed.getBody().firstChild, 1);
var $body = $(ed.getBody());
var content = ed.getContent({format : 'text', no_events : 1})
.replace(re_exspaces,'')
.replace( /\ufeff/g, '' )
.replace( /\u00ad/g, '' )
.replace( //g, '')
.replace( //g, '')
.replace( //g, '');
var content_length = content.length + $body.find('br').length - ( content.match(/[\uD800-\uDBFF]/g) || [] ).length;
if (content_length <= offset)
{
// set caret to the end of the editor
ed.plugins.myownplugin.setCursor(ed, ed.getBody().lastChild, 0);
}
else
{
var offset_till_now = 0;
var node = ed.getBody().firstChild;
var rng;
var counter = 0;
while (node && offset > offset_till_now)
{
var br_count = 0;
// Offset muss verringert werden, da Indesign Ps und BRs als Zeichen zählt
if (counter && (node.nodeName == "BR" || node.nodeName == "P" || node.nodeName == "OL" || node.nodeName == "UL"))
{
offset = offset - 1;
}
counter++;
if (node.nodeName == "P" || node.nodeName == "OL" || node.nodeName == "UL")
{
br_count = $(node).find('br').length;
}
var textContent = node.textContent
.replace(re_exspaces,'')
.replace( /\ufeff/g, '' )
.replace( /\u00ad/g, '' )
.replace( //g, '')
.replace( //g, '')
.replace( //g, '');
var length = textContent.length + br_count - ( textContent.match(/[\uD800-\uDBFF]/g) || [] ).length;
// textnode?
if (node && node.nodeType == 3)
{
if (offset <= offset_till_now + length)
{
rng = ed.selection.getRng(1);
rng.setStart(node, offset - offset_till_now);
rng.setEnd(node, offset - offset_till_now);
offset_till_now = offset; // fertig
}
else
{
node = node.nextSibling;
offset_till_now += length;
}
}
else
{
// caret to be inserted here ?
if (offset < offset_till_now + length)
{
// nur text nodes als Kinder?
// dann schreibe den textknoten neu und setze die Range entsprechend
// ansonsten weiter mit dem ersten Kind
if (!node.children.length)
{
var textnode = ed.getDoc().createTextNode(node.textContent);
node.innerHTML = '';
node.appendChild(textnode);
rng = ed.selection.getRng(1);
rng.setStart(textnode, offset - offset_till_now);
rng.setEnd(textnode, offset - offset_till_now);
var copied_range = rng.cloneRange();
copied_range.setStart(textnode, 0);
copied_range.setEnd(textnode, offset - offset_till_now);
var t = copied_range.toString();
var add_to_index = ( t.match(/[\uD800-\uDBFF]/g) || [] ).length;
rng.setStart(textnode, offset - offset_till_now + add_to_index);
rng.setEnd(textnode, offset - offset_till_now + add_to_index);
offset_till_now = offset; // fertig
}
node = node.firstChild;
}
// caret needs to be set after this node
else
{
if (offset == offset_till_now + length)
{
// set caret to start of node
ed.plugins.myownplugin.setCursor(ed, node, 0);
offset_till_now = offset; // fertig
}
else
{
// get following node
node = node.nextSibling;
offset_till_now += length;
}
}
}
}
}
// scrollinto view
if (scroll_into_view)
{
ed.execCommand('mceInsertContent', false, '<span class="set_caret_marker">\ufeff</span>');
setTimeout(function() {
var $marker = $(ed.getBody()).find('.set_caret_marker');
if ($marker.length)
{
$marker.get(0).scrollIntoView();
ed.selection.select($marker.get(0));
$marker.remove();
}
}, 500);
}
},
// sets the cursor position (start defines if the caret is to be placed at the start)
setCursor: function (ed, element, start)
{
// caret may appear inside lis only
if (element.nodeName == "UL" || element.nodeName == "OL")
{
$element = $(element);
element = start ? $element.find('li:first').get(0) : $element.find('li:last').get(0);
}
var doc = ed.getDoc();
var edwin = ed.getWin();
var range = ed.selection.dom.createRng();
range.selectNodeContents(element);
range.collapse(start);
var sel = ed.selection.getSel();
sel && sel.removeAllRanges();
sel && sel.addRange(range);
},
// returns the block parent element of the actual element
// stopper defines a node at which we will stop
p_of: function (node, stopper)
{
stopper = stopper ? stopper.toUpperCase() : null;
while (node)
{
if (node.nodeName == 'BODY') { return null; }
if (node.nodeName == 'P' || node.nodeName == 'UL' || node.nodeName == 'OL' || node.nodeName == stopper) { return node; }
else { node = node.parentNode; }
}
return null;
},
I hope this is usefull for some of you.
I have a page where I am displaying some text in a div and I need to highlight this text in certain parts. I have done this by surrounding the text I need to highlight with a tag and appropriate css styling.
E.g.
<div>
My text will look like this with <span class="highlight">highlighted bits</span> in it.
</div>
This works fine. However, another requirement for this page is that the user must be able to select texts, click a button, and the selected text must be highlighted too.
The problem I have is when trying to identify the range of the selected text to grab (using window.getSelection.getRangeAt(0)), this gives me the range which resets after every <span> tag in the text, not from the beginning of the text.
For those who would like to know in the future this is how I did it:
jQuery.fn.highlight = function(startOffset,endOffset,type) {
function innerHighlight(node, startOffset,endOffset) {
var calledStartOffset = parseInt(startOffset);
var startOffsetNode=getChildNodeForOffset(node,parseInt(startOffset));
var endOffsetNode=getChildNodeForOffset(node,parseInt(endOffset));
startOffset = resizeOffsetForNode(startOffsetNode,parseInt(startOffset));
if (startOffsetNode == endOffsetNode){
endOffset = resizeOffsetForNode(endOffsetNode,parseInt(endOffset));
highlightSameNode(startOffsetNode, parseInt(startOffset),parseInt(endOffset),type,calledStartOffset);
} else {
highlightDifferentNode(startOffsetNode,endOffsetNode,parseInt(startOffset),parseInt(endOffset),type,calledStartOffset);
}
}
return this.each(function() {
innerHighlight(this, startOffset,endOffset);
});
};
function resizeOffsetForNode(offsetNode,offset){
if (offsetNode.id >= 0){
offset = parseInt(offset)-parseInt(offsetNode.id);
} else if (offsetNode.previousSibling != null && offsetNode.previousSibling.id > 0){
offset = parseInt(offset)-parseInt(offsetNode.previousSibling.id)-parseInt(offsetNode.previousSibling.textContent.length);
}
return offset;
}
function getChildNodeForOffset(testNode,offset) {
if (testNode.nodeType == 1 && testNode.childNodes && !/(script|style)/i.test(testNode.tagName)) {
var offsetNode=null;
var currentNode;
for (var i = 0; i < testNode.childNodes.length; ++i) {
currentNode=testNode.childNodes[i];
if (currentNode.id >= 0 && parseInt(currentNode.id) <= parseInt(offset) && ((parseInt(currentNode.id) + parseInt(currentNode.textContent.length)) >= parseInt(offset))){
offsetNode = currentNode;
break;
} else if (currentNode.id >= 0 && parseInt(currentNode.id) > parseInt(offset)){
offsetNode = currentNode.previousSibling;
break;
}
}
if (offsetNode==null){
offsetNode = testNode.childNodes[testNode.childNodes.length-1];
}
return offsetNode;
}
}
function highlightSameNode(node, startOffset,endOffset,type,calledStartOffset) {
var skip = 0;
if (node.nodeType == 3) {
if (startOffset >= 0) {
var spannode = document.createElement('span');
spannode.className = 'entity '+ type;
spannode.id=calledStartOffset;
var middlebit = node.splitText(startOffset);
var endbit = middlebit.splitText(endOffset-startOffset);
var middleclone = middlebit.cloneNode(true);
spannode.appendChild(middleclone);
middlebit.parentNode.replaceChild(spannode, middlebit);
}
} else if (node.nodeType == 1 && node.childNodes && !/(script|style)/i.test(node.tagName)) {
var childnode = node.childNodes[0];
highlightSameNode(childnode, startOffset,endOffset,type,calledStartOffset);
}
}
function highlightDifferentNode(startnode, endnode, startOffset,endOffset,type,calledStartOffset) {
var skip = 0;
if (startnode.nodeName == "#text") {
if (startOffset >= 0) {
var spannode = document.createElement('span');
spannode.className = 'entity '+ type;
spannode.id=calledStartOffset;
var endbit = node.splitText(startOffset);
var endclone = endbit.cloneNode(true);
spannode.appendChild(endclone);
endbit.parentNode.replaceChild(spannode, endbit);
}
} else if (startnode.nodeName == "SPAN") {
if (startOffset >= 0) {
var spannode = document.createElement('span');
spannode.className = 'entity '+ type;
spannode.id=calledStartOffset;
var endTextbit = startnode.childNodes[0].splitText(startOffset);
spannode.appendChild(endTextbit);
startnode.parentNode.insertBefore(spannode, startnode.nextSibling);
}
}
var currentTestNode=startnode.nextSibling;
while (currentTestNode!=endnode){
if (currentTestNode.nodeName == "#text") {
var spannode = document.createElement('span');
spannode.className = 'entity '+ type;
spannode.id=parseInt(currentTestNode.previousSibling.id)+parseInt(currentTestNode.previousSibling.textContent.length);
var currentNodeClone=currentTestNode.cloneNode(true);
spannode.appendChild(currentNodeClone);
endbit.parentNode.replaceChild(spannode, currentTestNode);
} else if (currentTestNode.nodeName == "SPAN") {
currentTestNode.className = 'entity overlap';
}
currentTestNode=currentTestNode.nextSibling;
}
var previousNodeEnd = parseInt(endnode.previousSibling.id)+parseInt(endnode.previousSibling.textContent.length);
var spannode = document.createElement('span');
spannode.className = 'entity '+ type;
spannode.id=previousNodeEnd;
if (endnode.nodeName == "#text") {
if (endOffset >= 0) {
//end offset here is the original end offset from the beginning of the text, not node
var unwantedbit = endnode.splitText(parseInt(endOffset)-parseInt(previousNodeEnd));
var endclone = endnode.cloneNode(true);
spannode.appendChild(endclone);
endnode.parentNode.replaceChild(spannode, endnode);
}
} else if (endnode.nodeName == "SPAN") {
if (endOffset >= 0) {
var wantTextbit = endnode.childNodes[0].splitText(parseInt(endOffset)-parseInt(previousNodeEnd));
spannode.appendChild(wantTextbit);
wantTextbit.parentNode.parentNode.insertBefore(spannode, endnode);
}
}
if (startnode.textContent.length < 1){
startnode.parentNode.removeChild(startnode);
}
if (endnode.textContent.length < 1){
endnode.parentNode.removeChild(endnode);
}
}
jQuery.fn.removeHighlight = function() {
return this.find("span.entity").each(function() {
this.parentNode.firstChild.nodeName;
with (this.parentNode) {
replaceChild(this.firstChild, this);
normalize();
}
}).end();
};
function contains(a, b){
return a.contains ? a != b && a.contains(b) : !!(a.compareDocumentPosition(b) & 16);
}