I'm creating a pdf using the MultiColumnText object within iTextSharp. The text carries over to the second page where it only fills the left column. So I have two questions:
1) Is it possible to fill in all three columns on the second page, and only take up as much vertical space as it requires?
2) Is it possible to add additional page elements after the column object ends without knocking the new elements over to a new page?
The only thing I can think of would be to "write out" your text into a ColumnText using go(true) to simulate layout and find out how tall your text really is (with no page breaks), and use that knowledge to construct columns with specific heights such that they'll be even.
This gets Really Difficult if your columns aren't all the same width.
Don't forget about the page's top & bottom margins when calculating how much room you have to work with.
Here is my solution to disperse the text equally among 3 columns on the final page.
The trick was to
1) simulate the code
2)find which column the code ended in
3)find how far down the page the text went
4)calculate the new 'bottom'
5)only apply the new 'bottom' to the final page of the non-simulated output
class Program
{
static void Main(string[] args)
{
string fileName = "columntexttest.pdf";
Document doc = new Document(PageSize.LETTER, 50, 50, 50, 50);
PdfWriter pdfWrite = PdfWriter.GetInstance(doc, new FileStream(fileName, FileMode.Create));
doc.Open();
PdfContentByte cb = pdfWrite.DirectContent;
ColumnText ct = new ColumnText(cb);
//default values
int colCount = 0;
float bottom = doc.Bottom;
int pageCount = 0;
AddText(ct);
CreateColumnText(doc, ct, ref bottom, true, ref pageCount, ref colCount); //simulation
AddText(ct);
CreateColumnText(doc, ct, ref bottom, false, ref pageCount, ref colCount); //non-simulation
doc.Add(new Paragraph("testing new paragraph"));
doc.Close();
System.Diagnostics.Process.Start(fileName);
}
private static void CreateColumnText(Document doc, ColumnText ct, ref float bottom, bool simulate, ref int pageCount, ref int colCount)
{
//reseting variables for non-simulation
int status = 0;
int currentPage = 1;
int currentColumn = 0;
float tempBottom = bottom;
float tempBottom2 = tempBottom;
if (simulate)
{
pageCount = 1;
}
//column attributes
float gutter = 15f;
float colwidth = (doc.Right - doc.Left - gutter * 2) / 3;
while (ColumnText.HasMoreText(status))
{
//calculates the bottom Y
if (simulate == false && currentPage == pageCount)
{
if (colCount == 1) //1 column on final page
{
tempBottom2 = (doc.Top - tempBottom) / 3 + 6;
bottom = doc.Top - tempBottom2;
}
else if (colCount == 2) //2 columns on final page
{
tempBottom2 = ((doc.Top - tempBottom) + doc.Top) / 3 + 6;
bottom = doc.Top - tempBottom2;
}
else if (colCount == 0) //0 colCount means 3 columns
{
tempBottom2 = ((doc.Top - tempBottom) + doc.Top * 2) / 3 + 6;
bottom = doc.Top - tempBottom2;
}
}
else
{
bottom = doc.Bottom; //default value for all pages except the last, or the value for a single page
}
if (currentColumn == 0) //writes first column
{
float[] left = {doc.Left, doc.Top, //top = 742 (true top is 792 then a 50 point margin)
doc.Left, bottom }; //bottom = 50
float[] right = {doc.Left + colwidth, doc.Top,
doc.Left + colwidth, bottom};
ct.SetColumns(left, right);
currentColumn++;
}
else if (currentColumn == 1) //writes second column
{
float[] left2 = {doc.Left+ colwidth + gutter, doc.Top,
doc.Left + colwidth + gutter, bottom};
float[] right2 = {doc.Right - colwidth - gutter, doc.Top,
doc.Right - colwidth - gutter, bottom};
ct.SetColumns(left2, right2);
currentColumn++;
}
else //writes third column
{
float[] left3 = { doc.Right - colwidth, doc.Top,
doc.Right- colwidth, bottom};
float[] right3 = { doc.Right, doc.Top,
doc.Right, bottom};
ct.SetColumns(left3, right3);
currentColumn = 0;
}
status = ct.Go(simulate); //simulate mode
if (currentColumn == 0 && status == 2) //creates new page only if text remains.
{
doc.NewPage();
currentPage += 1;
}
}
//values carry forward to non-simulation mode
pageCount = currentPage;
bottom = ct.YLine;
colCount = currentColumn;
}
private static void AddText(ColumnText ct)
{
Font font2 = new Font(Font.NORMAL, 9f);
ct.AddText(new Phrase("orem ipsum dolor sit amet, consectetuer adipiscing elit. Suspendisse blandit blandit turpis. Nam in lectus ut dolor consectetuer bibendum. Morbi neque ipsum, laoreet id; dignissim et, viverra id, mauris. Nulla mauris elit, consectetuer sit amet, accumsan eget, congue ac, libero. Vivamus suscipit. Nunc dignissim consectetuer lectus. Fusce elit nisi; commodo non, facilisis quis, hendrerit eu, dolor? Suspendisse eleifend nisi ut magna. Phasellus id lectus! Vivamus laoreet enim et dolor. Integer arcu mauris, ultricies vel, porta quis, venenatis at, libero. Donec nibh est, adipiscing et, ullamcorper vitae, placerat at, diam. Integer ac turpis vel ligula rutrum auctor! Morbi egestas erat sit amet diam. Ut ut ipsum? Aliquam non sem. Nulla risus eros, mollis quis, blandit ut; luctus eget, urna. Vestibulum vestibulum dapibus erat. Proin egestas leo a metus?\n\n", font2));
ct.AddText(new Phrase("Vivamus enim nisi, mollis in, sodales vel, convallis a, augue? Proin non enim. Nullam elementum euismod erat. Aliquam malesuada eleifend quam! Nulla facilisi. Aenean ut turpis ac est tempor malesuada. Maecenas scelerisque orci sit amet augue laoreet tempus. Duis interdum est ut eros. Fusce dictum dignissim elit. Morbi at dolor. Fusce magna. Nulla tellus turpis, mattis ut, eleifend a, adipiscing vitae, mauris. Pellentesque mattis lobortis mi.\n\n", font2));
ct.AddText(new Phrase("Nullam sit amet metus scelerisque diam hendrerit porttitor. Aenean pellentesque, lorem a consectetuer consectetuer, nunc metus hendrerit quam, mattis ultrices lorem tellus lacinia massa. Aliquam sit amet odio. Proin mauris. Integer dictum quam a quam accumsan lacinia. Pellentesque pulvinar feugiat eros. Suspendisse rhoncus. Sed consectetuer leo eu nisi. Suspendisse massa! Sed suscipit lacus sit amet elit! Aliquam sollicitudin condimentum turpis. Nunc ut augue! Maecenas eu eros. Morbi in urna consectetuer ipsum vehicula tristique.\n\n", font2));
ct.AddText(new Phrase("Donec imperdiet purus vel ligula. Vestibulum tempor, odio ut scelerisque eleifend, nulla sapien laoreet dui; vel aliquam arcu libero eu ante. Curabitur rutrum tristique mi. Sed lobortis iaculis arcu. Suspendisse mauris. Aliquam metus lacus, elementum quis, mollis non, consequat nec, tortor.\n", font2));
ct.AddText(new Phrase("Quisque id diam. Ut egestas leo a elit. Nulla in metus. Aliquam iaculis turpis non augue. Donec a nunc? Phasellus eu eros. Nam luctus. Duis eu mi. Ut mollis. Nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aenean pede. Nulla facilisi. Vestibulum mattis adipiscing nulla. Praesent orci ante, mattis in, cursus eget, posuere sed, mauris.\n\n", font2));
ct.AddText(new Phrase("Nulla facilisi. Nunc accumsan risus aliquet quam. Nam pellentesque! Aenean porttitor. Aenean congue ullamcorper velit. Phasellus suscipit placerat tellus. Vivamus diam odio, tempus quis, suscipit a, dictum eu; lectus. Sed vel nisl. Ut interdum urna eu nibh. Praesent vehicula, orci id venenatis ultrices, mauris urna mollis lacus, et blandit odio magna at enim. Pellentesque lorem felis, ultrices quis, gravida sed, pharetra vitae, quam. Mauris libero ipsum, pharetra a, faucibus aliquet, pellentesque in, mauris. Cras magna neque, interdum vel, varius nec; vulputate at, erat. Quisque vitae urna. Suspendisse potenti. Nulla luctus purus at turpis! Vestibulum vitae dui. Nullam odio.\n\n", font2));
ct.AddText(new Phrase("Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed eget mi at sem iaculis hendrerit. Nulla facilisi. Etiam sed elit. In viverra dapibus sapien. Aliquam nisi justo, ornare non, ultricies vitae, aliquam sit amet, risus! Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Phasellus risus. Vestibulum pretium augue non mi. Sed magna. In hac habitasse platea dictumst. Quisque massa. Etiam viverra diam pharetra ante. Phasellus fringilla velit ut odio! Nam nec nulla.\n\n", font2));
ct.AddText(new Phrase("Integer augue. Morbi orci. Sed quis nibh. Nullam ac magna id leo faucibus ornare. Vestibulum eget lectus sit amet nunc facilisis bibendum. Donec adipiscing convallis mi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus enim. Mauris ligula lorem, pellentesque quis, semper sed, tristique sit amet, justo. Suspendisse potenti. Proin vitae enim. Morbi et nisi sit amet sapien ve.", font2));
ct.Alignment = Element.ALIGN_JUSTIFIED;
}
}
Related
Is it possible to check if a SingleChildScrollView fits in a screen so it doesn't need scrolling?
I want to achieve different behaviours based on this information.
Thanks to everyone in advance.
I had the same issue, and found a way around this. Here's how I made it:
Theory:
You need to provide a scroll controller to your SingleChildScrollView.
The reason is that the "[...] scroll controller creates a ScrollPosition to manage the state specific to an individual Scrollable widget", and we'll use exactly that to determine if the contents of our scrollable widget fits in the screen.
The property we're interested in is maxScrollExtent. It belongs to the ScrollPosition, and indicates the "maximum in-range value for pixels" that we can scroll to.
How:
The way I used it was to check if this value is greater than zero:
If so, then the contents do not fit in the given height.
Otherwise, if it's equal to zero, then the contents of the scrollable fits the screen.
Caveats in using this approach:
The child's size is a reflex of the build, so you can't know in advance if it will be scrollable or not. But what we can do is add a post frame callback to be executed after the build. By that point, when this callback is run, the build has already occurred, so we can check if the child fits in the screen or not.
Problem is, we need a StatefulWidget to do so. In that, we can schedule a post frame callback either in the initState() override - which will run only once during the widget's lifecycle, or in didChangeDependencies() - which runs whenever the widget needs rebuilding due a dependency change. See what fits best to your purpose.
TL;DR:
Here's a sample that shows how to take advantage of maxScrollExtent. Try running it in a flutter dartpad and change the width of the preview:
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
// Here's the important widget
class MyWidget extends StatefulWidget {
#override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
final ScrollController _controller = ScrollController();
#override
void didChangeDependencies() {
super.didChangeDependencies();
WidgetsBinding.instance.addPostFrameCallback((_) {
// Checks to see the controller's [ScrollMetrics] maxScrollExtent.
// If zero, then the entire scrollable fits in the screen's viewport.
// So, triggers fadeoutController.reverse() to make scrollbar go away.
var maxScrollExtent = _controller.position.maxScrollExtent;
if (maxScrollExtent == 0) {
print('Fits entirely');
} else {
print('Needs scrolling');
}
});
}
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
controller: _controller,
child: Column(
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width,
child: Text(_text),
),
],
),
);
}
}
// very, very long lorem ipsum so that we can get to scroll if it doesn't fit.
const String _text = '''Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam semper, massa ac dignissim elementum, sapien nibh faucibus nibh, vel fermentum justo augue non est. Vestibulum at diam a orci hendrerit pellentesque vitae et tortor. Donec vel ultricies ipsum. Morbi eleifend dolor eget risus dignissim tempor. Curabitur suscipit eros turpis, id iaculis odio fringilla nec. Phasellus ullamcorper lacus nec dapibus euismod. Aenean convallis euismod pellentesque. Integer congue libero in turpis dapibus, vitae condimentum ex elementum. Nullam condimentum, turpis eget tincidunt ultrices, orci mi maximus ex, sit amet tempor nulla mi quis libero. Sed congue elementum magna, ut luctus felis congue ut. Aliquam fringilla tortor at elit tempus venenatis. Quisque porta commodo nisi, sit amet rhoncus arcu dapibus non. Nam sit amet ullamcorper dui. Quisque dui dolor, tincidunt in urna sit amet, ultricies egestas libero.
Sed at lorem magna. Sed dignissim ullamcorper convallis. Nunc ornare, urna eget sodales feugiat, sem odio eleifend felis, a blandit lorem mi sed orci. Nulla facilisi. Pellentesque sed mi scelerisque, sollicitudin nunc non, ullamcorper neque. Quisque purus magna, lacinia vel ex a, tempor viverra ante. Phasellus volutpat nulla nec aliquet sollicitudin. Morbi ultricies dapibus scelerisque. Pellentesque ut elit justo. Phasellus eget tempus massa. Curabitur id enim mollis, rutrum lorem in, aliquet diam. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Proin semper ultricies orci. Nunc tempor fermentum dolor, placerat aliquam arcu ullamcorper sed. Cras eleifend erat gravida, mattis dolor eu, mollis lorem. Donec eu aliquet mauris, a egestas tortor.
Vivamus eu lorem erat. Phasellus condimentum quam quam, semper mattis odio dapibus vitae. Nulla eleifend lectus malesuada sem feugiat elementum. Phasellus semper luctus sodales. Aenean facilisis eu purus eget ultricies. Mauris non hendrerit lectus. Donec mollis ante non viverra euismod. Nulla aliquam, quam a rutrum dictum, tortor magna sagittis diam, non pulvinar erat nibh id nibh. Aliquam rutrum, mauris sit amet eleifend convallis, orci arcu egestas purus, vel dignissim tellus quam sit amet dolor. In hac habitasse platea dictumst. Etiam justo orci, sagittis a arcu vitae, viverra fringilla nunc. Maecenas ac semper ligula. Suspendisse ultrices tellus placerat nisl euismod pharetra.
Quisque et tellus ut magna efficitur volutpat ut nec metus. Vestibulum sed turpis id justo porta sagittis vitae et ligula. Aliquam ultricies tortor nulla, laoreet efficitur dui dictum eget. Aenean at ante a odio ornare pharetra in eget metus. Fusce vulputate luctus tortor in convallis. Praesent a velit libero. Proin molestie condimentum commodo. Nullam congue massa a odio congue, a bibendum tortor vestibulum. Etiam pellentesque dapibus libero. Donec iaculis vitae ante luctus varius.
Donec eleifend, elit eget accumsan rhoncus, diam nunc luctus dui, eu accumsan arcu sapien sed urna. Vivamus non viverra tellus, eget tincidunt nisl. Suspendisse nec laoreet risus. Vestibulum sit amet est elit. Duis vestibulum maximus magna ut dignissim. Mauris suscipit fermentum sapien sit amet finibus. Morbi quis lectus tincidunt nibh malesuada auctor non at neque. Fusce in tortor dictum, ornare felis ut, fermentum justo. Nulla ullamcorper viverra bibendum. Aliquam erat volutpat. Mauris et neque in purus auctor bibendum. Proin posuere enim id egestas scelerisque. In sollicitudin velit a ex fringilla, nec vulputate arcu volutpat. Mauris euismod sapien justo, sit amet pulvinar nisl volutpat quis. Sed finibus, leo vel molestie porta, quam est placerat mauris, vitae placerat eros turpis porta lorem. Donec at tortor tortor.''';
Can't seem to wrap my head around the proper regex!
MY GOAL
add 2 spaces to each line of a selected block of text
MY CONTEXT
some markdown tools I used need 2 spaces at the end of each line to properly manage lists, etc.
if a file is edited multiple times, I do not want to end up with lines ending with 4+ spaces
a block of text can be a line, a paragraph, the whole file content as shown in the editor
I have some kind of macro in Notepad++ that does the trick but I want to do the same with Autohotkey to be editor-independant
MY EXAMPLE
----
# 2020-03-17
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu.
In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a,
MY SNIPPET SO FAR
; CTL+SHIFT+F12
^+F12::
Clipboard = ; Empty the clipboard so that ClipWait has something to detect
SendInput, ^c ; Copy selected text
ClipWait
OutputText := ""
Loop, parse, Clipboard, `n, `r
{
OutputText .= RegExReplace(A_LoopField,"m)^(.*) *$","$1 `r`n")
}
SendRaw % OutputText
return
MY PROBLEM
Between the character ignored when looping, what I am trying to match and what I try to replace the group with, I end up with far more lines and spaces than needed.
CURRENT OUTPUT
----
# 2020-03-17
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu.
In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a,
DESIRED OUTPUT
----
# 2020-03-17
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu.
In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a,
You're getting too many lines in the output because the send command is messing up due to the carriage returns, which aren't needed in there anyway. I don't really know why that is happening, and I can't be bothered to find out why since the approach isn't good anyway.
And also your indentation is getting messed up because your text editor automatically adds indentation based on the previous line.
But anyway, sending such (long) input is never a good idea.
Make use of the clipboard and just send a ctrl+v to instantly and reliably paste in the text.
Here's an example of that along another way to add the spaces at the end:
inp := "
(
----
# 2020-03-17
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu.
In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a,
)"
Loop, Parse, inp, `n, `r
OutputText .= (A_LoopField = "" ? "" : RTrim(A_LoopField) " ") "`n"
Clipboard := OutputText
SendInput, ^v
The ternary A_LoopField = "" ? "" : RTrim(A_LoopField) " " returns true if the line was empty and then the two spaces aren't added at the end.
I think that's the behavior you were doing for.
And RTrim is used to trim any trailing spaces (or tabs) off the end, so we're sure to end up with just the two we want.
And, of course, at the end of any line we add one line feed `n.
Also, your Regex approach was just fine as well at first it just seemed off to me, but well, here's another way. And I guess this would be more efficient, though you'd have to work with seriously large inputs and/or slow hardware for that to make any meaningful difference haha.
As of macOS 10.13.2, the following simple Cocoa app app causes a deadlock on the main thread (and we never see the NSAlert):
AppDelegate.swift:
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
let text = "Lorem ipsum dolor sit amet consectetur adipiscing elit, phasellus elementum lobortis quisque aptent leo a, rutrum dictum velit nostra viverra mollis. Nam pharetra feugiat sollicitudin quisque consequat suspendisse nisi blandit purus nascetur proin mi, fermentum magna felis et aenean condimentum ultrices justo vulputate etiam fusce, turpis id netus tristique porta libero hendrerit scelerisque semper fringilla placerat. Accumsan nisl felis nascetur lorem vulputate metus mauris aliquet purus, rutrum non viverra dictumst mi commodo mollis risus, sociis ullamcorper integer tincidunt donec himenaeos porta vestibulum. Senectus torquent per odio viverra mauris dui lacus nisi ligula porta pretium ornare purus amet, ad cursus suspendisse dis porttitor nec enim class nunc leo ante cras tempor. Mollis posuere cum gravida a primis et donec mauris, sagittis sit duis nulla hac penatibus imperdiet amet montes, libero mattis blandit urna orci fringilla vestibulum. Vehicula porta tempor augue fringilla fames pellentesque feugiat sagittis, quis lobortis lectus phasellus class sapien vulputate senectus, volutpat duis erat tellus fusce ultricies morbi. Id cubilia malesuada consectetur quisque tempus mattis a, vulputate aliquet elementum non laoreet penatibus auctor, hac ad neque pharetra magnis amet."
var synth: NSSpeechSynthesizer?
func applicationDidFinishLaunching(_ aNotification: Notification) {
let url = URL(fileURLWithPath: "\(NSTemporaryDirectory())/\(UUID().uuidString).aiff")
synth = NSSpeechSynthesizer()
synth?.startSpeaking(text, to: url)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2) {
self.synth?.stopSpeaking()
let alert = NSAlert()
alert.messageText = "After 'stopSpeaking'"
alert.runModal()
}
}
}
This issue didn't exist before macOS 10.13.2, as far as I can tell. There are a lot of ways I can get the speech synthesizer to deadlock; the above code is the simplest reproduction case.
I filed a Radar (36138159) (https://openradar.appspot.com/radar?id=4990843182120960) but I'm curious to know if anyone else has had any luck fixing this issue.
An added note: once I get this deadlock, I have to kill lingering com.apple.speech.speechsynthesisd processes or else anything I try to do with NSSpeechSynthesizer causes a deadlock.
How does Kentico calculate the length of inputted content in a text area on a form and how much value does it give to a line break? A line break is 2 characters according to my JavaScript calculation but seems like Kentico calculates it as being more than 2 characters.
Summary of problem:
I have a maximum length of 2500 set on a text area input on a form on my Kentico site.
I have entered some text into a this text area and with my JavaScript calculations (used to show how many characters the user has left) the character length is exactly 2500 (including line breaks and spaces) and so should therefore validate and send. However Kentico is failing my input saying that my max length has been exceeded. See below:
If I remove the line break and type some extra characters to bring my character calculation back up to 2500, the form sends without failing.
Test used that fails:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque vitae
augue ac enim molestie scelerisque a id metus. Suspendisse purus
justo, iaculis quis accumsan ut, congue vitae mauris. Nunc luctus
vulputate scelerisque. Nullam ullamcorper porta elit, sed ornare lorem
placerat dictum. Sed quis enim quis nibh convallis sagittis nec vitae
felis. Sed porttitor, nibh et volutpat posuere, neque dui sollicitudin
sapien, at scelerisque lacus elit quis enim. Donec at metus lectus.
Sed quis enim quis nibh convallis sagittis nec vitae felis. Sed
porttitor, nibh et volutpat posuere, neque dui sollicitudin sapien, at
scelerisque lacus elit quis enim. Donec at metus lectus. Lorem ipsum
dolor sit amet, consectetur adipiscing elit. Quisque vitae augue ac
enim molestie scelerisque a id metus. Suspendisse purus justo, iaculis
quis accumsan ut, congue vitae mauris. Nunc luctus vulputate
scelerisque. Nullam ullamcorper porta elit, sed ornare lorem placerat
dictum. Sed quis enim quis nibh convallis sagittis nec vitae felis.
Sed porttitor, nibh et volutpat posuere, neque dui sollicitudin
sapien, at scelerisque lacus elit quis enim. Donec at metus
lectus.Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Quisque vitae augue ac enim molestie scelerisque a id metus.
Suspendisse purus jus
to, iaculis quis accumsan ut, congue vitae mauris. Nunc luctus
vulputate scelerisque. Nullam ullamcorper porta elit, sed ornare lorem
placerat dictum. Sed quis enim quis nibh convallis sagittis nec vitae
felis. Sed porttitor, nibh et volutpat posuere, neque dui sollicitudin
sapien, at scelerisque lacus elit quis enim. Donec at metus lectus.
Sed quis enim quis nibh convallis sagittis nec vitae felis. Sed
porttitor, nibh et volutpat posuere, neque dui sollicitudin sapien, at
scelerisque lacus elit quis enim. Donec at metus lectus. Lorem ipsum
dolor sit amet, consectetur adipiscing elit. Quisque vitae augue ac
enim molestie scelerisque a id metus. Suspendisse purus justo, iaculis
quis accumsan ut, congue vitae mauris. Nunc luctus vulputate
scelerisque. Nullam ullamcorper porta elit, sed ornare lorem placerat
dictum. Sed quis enim quis nibh convallis sagittis nec vitae felis.
Sed porttitor, nibh et volutpat posuere, neque dui sollicitudin
sapien, at scelerisque lacus elit quis enim. Donec at metus
lectus.Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Quisque vitae augue ac enim molestie scelerisque a id metus.
Suspendisse purus justo, iaculis quis accumsan ut, congue vitae maur d
Test used that passes: Notice that the line break has been removed and 2 extra characters added to the end to bring it back up to 2500 characters
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque vitae
augue ac enim molestie scelerisque a id metus. Suspendisse purus
justo, iaculis quis accumsan ut, congue vitae mauris. Nunc luctus
vulputate scelerisque. Nullam ullamcorper porta elit, sed ornare lorem
placerat dictum. Sed quis enim quis nibh convallis sagittis nec vitae
felis. Sed porttitor, nibh et volutpat posuere, neque dui sollicitudin
sapien, at scelerisque lacus elit quis enim. Donec at metus lectus.
Sed quis enim quis nibh convallis sagittis nec vitae felis. Sed
porttitor, nibh et volutpat posuere, neque dui sollicitudin sapien, at
scelerisque lacus elit quis enim. Donec at metus lectus. Lorem ipsum
dolor sit amet, consectetur adipiscing elit. Quisque vitae augue ac
enim molestie scelerisque a id metus. Suspendisse purus justo, iaculis
quis accumsan ut, congue vitae mauris. Nunc luctus vulputate
scelerisque. Nullam ullamcorper porta elit, sed ornare lorem placerat
dictum. Sed quis enim quis nibh convallis sagittis nec vitae felis.
Sed porttitor, nibh et volutpat posuere, neque dui sollicitudin
sapien, at scelerisque lacus elit quis enim. Donec at metus
lectus.Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Quisque vitae augue ac enim molestie scelerisque a id metus.
Suspendisse purus justo, iaculis quis accumsan ut, congue vitae
mauris. Nunc luctus vulputate scelerisque. Nullam ullamcorper porta
elit, sed ornare lorem placerat dictum. Sed quis enim quis nibh
convallis sagittis nec vitae felis. Sed porttitor, nibh et volutpat
posuere, neque dui sollicitudin sapien, at scelerisque lacus elit quis
enim. Donec at metus lectus. Sed quis enim quis nibh convallis
sagittis nec vitae felis. Sed porttitor, nibh et volutpat posuere,
neque dui sollicitudin sapien, at scelerisque lacus elit quis enim.
Donec at metus lectus. Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Quisque vitae augue ac enim molestie scelerisque a id
metus. Suspendisse purus justo, iaculis quis accumsan ut, congue vitae
mauris. Nunc luctus vulputate scelerisque. Nullam ullamcorper porta
elit, sed ornare lorem placerat dictum. Sed quis enim quis nibh
convallis sagittis nec vitae felis. Sed porttitor, nibh et volutpat
posuere, neque dui sollicitudin sapien, at scelerisque lacus elit quis
enim. Donec at metus lectus.Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Quisque vitae augue ac enim molestie scelerisque a id
metus. Suspendisse purus justo, iaculis quis accumsan ut, congue vitae
maur dee
The problem lay in the fact that my calculation in my JavaScript gave a length of 1 to a line break whereby Kentico's calculation gives a length of 2 to a line break. So they weren't matching up. Hence my character counter said that the length of the entered text was ok but Kentico's check deemed it over the max length.
This is what I had previously:
enteredText = textareaVariableName.val();
characterCount = enteredText.length; //one line break entered returned 1
This is what I have changed it to:
enteredText = textareaVariableName.val();
enteredTextEncoded = escape(enteredText);
//next I match any line break characters - %0A - after encoding the text area text
linebreaks = enteredTextEncoded.match(/%0A/g);
(linebreaks != null) ? linebreaksLength = linebreaks.length : linebreaksLength = 0;
characterCount = enteredText.length + linebreaksLength; //one line break entered now returns 2
Is there a better way I could check for line breaks in the text, rather than to encode the text and then check for the substring %0A ?
EDIT/UPDATE: I believe the following is a better solution as opposed to what I was doing above.
var limit = 2500; //for example
enteredText = textareaVariableName.val();
numberOfLineBreaks = (enteredText.match(/\n/g)||[]).length;
left = limit - enteredText.length - numberOfLineBreaks;
if (left < 0) {
//character count over code here
} else {
//character count within limits code here
}
This is basically JavaScript problem related to browser. In Firefox or Chrome or any other WebKit based browser textareaVariableName.val().length will count only 1 character for new line (\n). Same for jQuery implementation. But in IE document.getElementById('textareaVariableName').value.length will count 2 for new line (\r\n)
In Kentico, the text is validated to the actual count of characters and therefore the validation is failing.
Quick fix for this is simple regular expression for counting the actual length:
function getTextLength(elementId){
if (elementId) {
var elem = document.getElementById(elementId);
if (elem) {
var str = elem.value;
if (str) {
str = str.replace(/(\r\n|\r|\n)/g, '\r\n');
return str.length;
}
}
}
return 0;
}
This should help you to count characters correctly independently of the browser used by the customer.
I have read so much and still no real answer. How can I get iFrames to work on the iPhone and iPad? Especially now you can't 2 finger scroll. I just want to have an iFrame scroll or something that functions like one. I feel like this should be so simple!
Here is a sample page:
http://olbrichdesigns.com/ffff/characters/test.html
Thanks!
jenny
Mobile safari supports them but generally they're not great.
Using a DIV with overflow-y: scroll would probably be better for you
<div style="overflow-y: scroll; height: 100px;">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam at laoreet augue. Pellentesque felis arcu, convallis eu luctus vitae, imperdiet ut est. Nulla rhoncus varius odio, non facilisis felis imperdiet pellentesque. Aliquam in luctus orci. Ut convallis felis sodales diam ultricies in elementum ligula ultricies. Vivamus consequat convallis mauris, sed ullamcorper ante fermentum a. Quisque at velit eu velit venenatis faucibus id vel velit. Integer eget nisi elit. Ut blandit eros lorem, sed feugiat nunc. Sed lacus nisi, placerat sit amet blandit feugiat, accumsan ut urna. Proin risus sapien, porttitor sed euismod quis, adipiscing vitae nulla. Vestibulum at ipsum vel tortor fermentum tristique. Fusce laoreet magna vitae tellus accumsan eget adipiscing velit ullamcorper. Proin tempus volutpat fringilla. Etiam eu magna sit amet mi commodo volutpat sit amet eget lacus. Nullam euismod tellus id odio tempus id tincidunt felis mollis.
</div>