I have the code:
img = f.read.scan(/<img/)
img = img.length
links = f.read.scan(/<a/)
links = links.length
div = f.read.scan(/<div/)
div = div.length
The program opens a link, say http://stackoverflow.com. It then prints img, links, and div. For some reason, no matter what website I choose, it returns 0 for links and div, but returns the correct number for img. Why is this?
Cause when you read file then you also move pointer. Write it that way (I also added method chains):
content = f.read
img = content.scan(/<img/).length
links = content.scan(/<a/).length
div = content.scan(/<div/).length
f.read reads the whole file on the first go, so the second and third matches get an empty string to scan for tags on, and you get zero matches. See http://www.ruby-doc.org/core-1.9.3/IO.html#method-i-read:
If length is omitted or is nil, it reads until EOF and the encoding conversion is applied. It returns a string even if EOF is met at beginning.
You might reposition the input pointer after the first read back to the beginning, but that'll only work for files, so basically read the whole data to a buffer, and then use the scanning on that. See #Hauleth's answer for an example.
Related
I am completely new to PDF creation including MigraDoc. I have gotten this far, which is really close to what I want for now. My question is that the text string (myMessage) that I pass to the "bodyParagraph" is up to 100 lines long, which causes three pages to be created, which is good. However the first page's Top margin is slightly greater than the second and third pages. I have no idea of why...
Basically, I am trying to create every page the same. Same header, footer and the body to take the same space regardless of the number of lines in the "bodyParagraph" content. If I have taken the completely wrong approach I would be open to suggestions.
Also, if there is a good tutorial to point me to that would be great. I can't really find anything but samples. I have learned everything from the samples, but sections, paragraph, etc is all new to me and I would like to get a better understanding of what I've done.
public static Document CreateWorkOrderPDF2(Document document, string filename, string WorkOrderHeader, string myMessage)
{
Section section = document.AddSection();
section.PageSetup.PageFormat = PageFormat.Letter;
section.PageSetup.StartingNumber = 1;
section.PageSetup.LeftMargin = 40;
//Sets the height of the top margin
section.PageSetup.TopMargin = 100;
section.PageSetup.RightMargin = 40;
section.PageSetup.BottomMargin = 40;
//MARGIN
HeaderFooter header = section.Headers.Primary;
header.Format.Font.Size = 16;
header.Format.Font.Color = Colors.DarkBlue;
MigraDoc.DocumentObjectModel.Shapes.Image headerImage = header.AddImage("../../Fonts/castorgate.regular.png");
headerImage.Width = "2cm";
Paragraph headerParagraph = section.AddParagraph();
headerParagraph = header.AddParagraph(WorkOrderHeader);
//BODY PARAGRAPH
Paragraph bodyParagraph = section.AddParagraph();
bodyParagraph = section.AddParagraph(myMessage);
bodyParagraph.Format.Font.Size = 10;
bodyParagraph.Format.Font.Color = Colors.DarkRed;
//paragraph.Format.Distancne = "3cm";
Paragraph renderDate = section.AddParagraph();
renderDate = section.AddParagraph("Work Order Generated: ");
renderDate.AddDateField();
return document;
}
The line Paragraph bodyParagraph = section.AddParagraph(); adds an empty paragraph. I assume that is the extra space on the first page.
Same issue with renderDate in the following code block.
Just remove the calls section.AddParagraph() to remove the empty paragraphs if you don't want them.
MigraDoc is much like Word and understanding sections, paragraphs, &c. in Word will also help you with MigraDoc. That knowledge along with the samples and IntelliSense should get you going.
You can use MigraDoc to create an RTF file, open the RTF in Word, and click the pilcrow to show formatting characters in Word.
Kendo UI 2015.2.805 Kendo UI Editor for Jacascript
I want to extend the kendo ui editor by adding a custom tool that will convert a user selected block that spans two or more paragraphs into block of single spaced text. This can be done by locating all interior p tags and converting them into br tags, taking care not to change the first or last tag.
My problem is working with the range object.
Getting the range is easy:
var range = editor.getRange();
The range object has a start and end container, and a start and end offset (within that container). I can access the text (without markup)
console.log(range.toString());
Oddly, other examples I have seen, including working examples, show that
console.log(range);
will dump the text, however that does not work in my project, I just get the word 'Range', which is the type of the object. This concerns me.
However, all I really need however is a start and end offset in the editor's markup (editor.value()) then I can locate and change the p's to br's.
I've read the telerik documentation and the referenced quirksmode site's explanation of html ranges, and while informative nothing shows how to locate the range withing the text (which seems pretty basic to me).
I suspect I'm overlooking something simple.
Given a range object how can I locate the start and end offset within the editor's content?
EDIT: After additional research it appears much more complex than I anticipated. It seems I must deal with the range and/or selection objects rather than directly with the editor content. Smarter minds than I came up with the range object for reasons I cannot fathom.
Here is what I have so far:
var range = letterEditor.editor.getRange();
var divSelection;
divSelection = range.cloneRange();
//cloning may be needless extra work...
//here manipulate the divSelection to how I want it.
//divSeletion is a range, not sure how to manipulate it
var sel = letterEditor.editor.getSelection()
sel.removeAllRanges();
sel.addRange(divSelection);
EDIT 2:
Based on Tim Down's Solution I came up with this simple test:
var html;
var sel = letterEditor.editor.getSelection();
if (sel.rangeCount) {
var container = document.createElement("div");
for (var i = 0, len = sel.rangeCount; i < len; ++i) {
container.appendChild(sel.getRangeAt(i).cloneContents());
}
html = container.innerHTML;
}
html = html.replace("</p><p>", "<br/>")
var range = letterEditor.editor.getRange();
range.deleteContents();
var div = document.createElement("div");
div.innerHTML = html;
var frag = document.createDocumentFragment(), child;
while ((child = div.firstChild)) {
frag.appendChild(child);
}
range.insertNode(frag);
The first part, getting the html selection works fine, the second part also works however the editor inserts tags around all lines so the result is incorrect; extra lines including fragments of the selection.
The editor supports a view html popup which shows the editor content as html and it allows for editing the html. If I change the targeted p tags to br's I get the desired result. (The editor does support br as a default line feed vs p, but I want p's most of the time). That I can edit the html with the html viewer tool lets me know this is possible, I just need identify the selection start and end in the editor content, then a simple textual replacement via regex on the editor value would do the trick.
Edit 3:
Poking around kendo.all.max.js I discovered that pressing shift+enter creates a br instead of a p tag for the line feed. I was going to extend it to do just that as a workaround for the single-space tool. I would still like a solution to this if anyone knows, but for now I will instruct users to shift-enter for single spaced blocks of text.
This will accomplish it. Uses Tim Down's code to get html. RegEx could probably be made more efficient. 'Trick' is using split = false in insertHtml.
var sel = letterEditor.editor.getSelection();
if (sel.rangeCount) {
var container = document.createElement("div");
for (var i = 0, len = sel.rangeCount; i < len; ++i) {
container.appendChild(sel.getRangeAt(i).cloneContents());
}
var block = container.innerHTML;
var rgx = new RegExp(/<br class="k-br">/gi);
block = block.replace(rgx, "");
rgx = new RegExp(/<\/p><p>/gi);
block = block.replace(rgx, "<br/>");
rgx = new RegExp(/<\/p>|<p>/gi);
block = block.replace(rgx, "");
letterEditor.editor.exec("insertHtml", { html: block, split: false });
}
I have a load of data in 100 .sdf files (labelled 0000.sdf to 0099.sdf), each of which contain a still image, and I'm trying to produce a .gif from these images.
The code I use to plot the figure are (in the same directory as the sdf files):
q = GetDataSDF('0000.sdf');
imagesc(q.data');
I've attempted to write a for loop that would plot the figure and then save it with the same filename as the sdf file but to no avail, using:
for a = 1:100
q=GetDataSDF('0000.sdf');
fh = imagesc(q.dist_fn.x_px.Left.data');
frm = getframe( fh );
% save as png image
saveas(fh, 'current_frame_%02d.jpg');
end
EDIT: I received the following errors when trying to run this code:
Error using hg.image/get
The name 'Units' is not an accessible property for an instance of class 'image'.
Error in getframe>Local_getRectanglesOfInterest (line 138)
if ~strcmpi(get(h, 'Units'), 'Pixels')
Error in getframe (line 56)
[offsetRect, absoluteRect, figPos, figOuterPos] = ...
Error in loop_code (line 4)
frm = getframe( fh );
How do I save these files using a for loop, and how do I then use those files to produce a movie?
The reason for the error is that you pass an image handle to getframe, but this function excpects a figure handle.
Another problem is that you always load the same file, and that you saveas will not work for gifs. (For saving figures as static images, maybe print is the better option?)
I tried to modify my own gif-writing loop so that it works with your data. I'll try to be extra explicit in the comments, since you seem to be starting out. Remember, you can always use help name_of_command to display a short Matlab help.
% Define a variable that holds the frames per second your "movie" should have
gif_fps = 24;
% Define string variable that holds the filename of your movie
video_filename = 'video.gif';
% Create figure 1, store the handle in a variable, you'll need it later
fh = figure(1);
for a = 0:99
% Prepare file name so that you loop over the data
q = GetDataSDF(['00' num2str(a,'%02d') 'sdf']);
% Plot image
imagesc(q.dist_fn.x_px.Left.data');
% Force Matlab to actually do the plot (it sometimes gets lazy in loops)
drawnow;
% Take a "screenshot" of the figure fh
frame = getframe(fh);
% Turn screenshot into image
im = frame2im(frame);
% Turn image into indexed image (the gif format needs this)
[imind,cm] = rgb2ind(im,256);
% If first loop iteration: Create the file, else append to it
if a == 0;
imwrite(imind,cm,video_filename,'gif', 'Loopcount',inf);
else
imwrite(imind,cm,video_filename,'gif','WriteMode','append','DelayTime',1/gif_fps);
end
end
One more note: When the size of the data is the same for each plot, it makes sense to only use the plot(or in this case, imagesc) command once, and in later loop iterations replace it with a set(ah,'Ydata',new_y_data) (or in this case set(ah,'CData',q.dist_fn.x_px.Left.data'), where ah is a handle of the plot axes (not the plot figure!). This is orders of magnitude faster than creating a whole new plot in each loop iteration. The downside is that the scaling (here, the color-scaling) will be the same for each plot. But in every case that I have worked on so far, that was actually desirable.
I have a GTK# TextView and I want to read the line of text under the cursor. I don't see a single method that will do that, so I think I need to combine several method calls, like Buffer.GetText, Buffer.GetIterAtOffset, Buffer.CursorPosition, but it's not obvious to me what the right combination is.
TextIter are a bit odd to use. Buffer.CursorPosition gives you the current position.
It's easy to find the end of the line:
var end = Buffer.CursorPosition;
end.ForwardToLineEnd();
To get the first character, there's not symetrical method, so you might try:
var start = Buffer.CursorPosition;
start.BackwardChars(start.LineOffset); // LineOffset gives you the iter offset on the current line.
I have a webpage which displays multiple textual entries which have no restriction on their length. They get automatically cut if they are too long to avoid going to a new line. This is the PHP function to cut them:
function cutSentence($sentence, $maxlen = 16) {
$result = trim(substr($sentence, 0, $maxlen));
$resultarr = array(
'result' => $result,
'islong' => (strlen($sentence) > $maxlen) ? true : false
);
return $resultarr;
}
As you can see in the image below, the result is fine, but there are a few exceptions. A string containing multiple Ms (I have to account for those) will go to a newline.
Right now all strings get cut after just 16 characters, which is already very low and makes them hard to read.
I'd like to know if a way exists to make sure sentences which deserve more spaces get it and those which contain wide characters end up being cut at a lower number of characters (please do not suggest using the CSS property text-overflow: ellipsis because it's not widely supported and it won't allow me to make the "..." click-able to link to the complete entry, and I need this at all costs).
Thanks in advance.
You could use a fixed width font so all characters are equal in width. Or optionally get how many pixels wide every character is and add them together and remove the additional character wont the pixel length is over a certain amount.
If the style of your application isn't too important, you could simply use a font in the monospace family such as Courier.
Do it in Javascript rather than in PHP. Use the DOM property offsetWidth to get the width of the containing element. If it exceeds some maximum width, then truncate accordingly.
Code copied from How can I mimic text-overflow: ellipsis in Firefox? :
function addOverflowEllipsis( containerElement, maxWidth )
{
var contents = containerElement.innerHTML;
var pixelWidth = containerElement.offsetWidth;
if(pixelWidth > maxWidth)
{
contents = contents + "…"; // ellipsis character, not "..." but "…"
}
while(pixelWidth > maxWidth)
{
contents = contents.substring(0,(contents.length - 2)) + "…";
containerElement.innerHTML = contents;
pixelWidth = containerElement.offsetWidth;
}
}
Since you are asking for a web page then you can use CSS text-overflow to do that.
It seems to be supported enough, and for firefox there seems to be css workarounds or jquery workarounds...
Something like this:
span.ellipsis {
white-space:nowrap;
text-overflow:ellipsis;
overflow:hidden;
width:100%;
display:block;
}
If you fill more text than it fits it will add the three dots at the end.
Just cut the text if it is really too long so you don't waste html space.
More info here:
https://developer.mozilla.org/En/CSS/Text-overflow
Adding a 'see more' link at the end is easy enough, as appending another span with fixed width, containing the link to see more. text will be truncated with ellipsis before that.