First of all, thank you very much for looking into this. I'd love to have a
lot of minds sit down and think up a good standards or "mostly-standards"
way of doing this. Please take all of my comments below in the sense of
"let's work out a good solution" and not "my solution is better." I don't
think that. I think my solution, abusing input elements and inserting
invalid markup to fake out MS Word, is a terrible way of doing it. But this
is a very difficult problem and I'm afraid the proposed solution only works
in some cases.
First, though, congratulations on making a simple test page that "works" on
all 4 browsers I primarily test on: Chrome, Firefox, IE8, and Opera. I
sometimes test on Safari as well, but not this time. Mostly it just acts
like Chrome anyway.
Your test page renders fine in each browser (with some 1px issues which I
can ignore) and the ability to only select and copy the main text works as
advertised, as it should, because it's all in a <td> by itself. I can also,
if I try to, select the entire text WITH line numbers, which is pretty
awesome. The only thing that doesn't seem to work, is that the text is for
some reason pasted into MS Word unformatted from Opera and Firefox. And only
Chrome pastes the background color. One of my primary goals of this feature
was to be able to generate HTML with dynamic folding and line numbers
enabled, and copy-paste just the formatted text into my email client at work
(Lotus Notes...ugh). So, the formatted text is important to me.
> The output is placed in a <table>, and the line numbers are in a
> separate <td>. Consequently, it is possible to select the output code
> without grabbing line numbers.
>
Did you just hand-code this, or did you actually get a modified script to
generate it? Modifying the script to do this will take a lot of work,
because it currently processes entire lines, one at a time. I suppose it
could maintain multiple lists, one for each column, rather than one big list
for the entire line text, but it will be a big change to do so. Right now
each line in the buffer gets (for the most part, anyway) one line of HTML
(one giant unwieldy line sometimes, but one line nonetheless).
This brings up the other main problem with the table method. Dynamic folding
relies on looking up a single element by ID in a javascript event, and then
modifying the class of that on the fly to show/hide the element. This single
element must therefore span parts of the foldcolumn, the entire line number,
and the entire line text. Doing this would not be possible in the table
layout.
Perhaps, we can look it up by class instead of by ID. Or prepend a prefix
like LineText_ and LineNr_ and FoldC_ to the ID for each section. That is
certainly something to think about. It may be tricky but I think having
individual columns might be the best way to go forward.
The other difficulty, however, is in the fact that wrapping may be turned
on. I can not think of a good way to get text wrapping to work in the table
so that the line numbers continue to align with the beginning of their
respective line. It might be possible to simply declare that unselectable
areas only work for non-wrapping text, but that would mean 2 completely
separate output methods. I would like to avoid that if possible.
> Although not essential in this set-up, it is possible to
> make the line numbers unselectable just using CSS. I have enclosed a
> cross-browser CSS solution for the unselectable line number area.
> Disabling selectability might not work for every browser but this is
> not crucial as it is possible to select the data content separately
> anyway.
I agree it is not needed to have the content unselectable, as long as the
different content areas can be selected independently.
Your CSS solution relies on the user-select property, which was
provisionally in CSS3 for a long time (appearing in this document, for
instance: http://www.w3.org/TR/2000/WD-css3-userint-20000216 ), but was then
removed and is no longer in the spec that I have been able to find (
http://www.w3.org/TR/2012/WD-css3-ui-20120117/ is the latest version of the
aforementioned document and it has no mention of user-select). The last time
I checked it, at least two major browsers (I forget which) did not support
it, and I don't think they will be in the future since it isn't in the spec.
Perhaps they will surprise me though.
As stated, however, the primary goal is making the region uncopyable. I
don't care too much about selectability.
> Internet Explorer versions <10 require a different approach: the tag
> containing the line number needs to be given the "unselectable"
> attribute. (This is not inherited and therefore cannot be added at
> parent level!)
>
> I also changed the cursor to pointer.
Are you saying IE10 supports user-select? Perhaps I am being proven wrong
about that after all... Anyway, I want to avoid non-standard markup where
possible, and "unselectable" is certainly that.
> I made a point of keeping the CSS classes that reflext the vim colour
> scheme (lnr, Identifier,...) separate from the generic CSS that
> determines the page structure. This way one can easily paste in
> additional syntax highlighting tags into an existing stylesheet.
>
Good call. Next on the list is external stylesheets, for which there's
another patch out on vim_dev somewhere I think.
> I applied the lnr highlighting to the containing
> block rather
> than every individual line so that the whole line number column has the
> lnr background and it avoids gaps between rows.
>
If we can address dynamic folding and line wrapping, I agree this is the way
to go. I learned more than I cared to know about the line-height and default
(differing by element) font sizes for the different browsers, and none of it
ended up working anyway to fix the gaps, so I had to cheat with a 1px
border. Placing it in a real table column with its own background is much
cleaner.
>
> The output validates with the exception of the IE "unselectable"
> attribute.
>
> PS: I don't have a Windows machine, so can't test this with IE.
>
It works fine on IE8, except for not copying the background color; I
normally paste formatted text on a white background anyway, so that's kind
of a don't-care. I assume it works on other IEs as well.
The other idea I had, is abandoning the idea of getting it working on IE8,
and using inline SVG to create an image that had the line number text. I'm
not sure whether this will work or not, but I suspect it might, since it's
an image. I did not try it at first because at the time Opera did not
support inline SVG, and IE8 doesn't. Also I couldn't get the width to be
correct for browsers without the 'ch' unit, but now I've got some javascript
figured out to handle that (since Webkit and Gecko do weird things to the
width of input elements). I know absolutely nothing about SVG, if you or
someone else knows SVG and can put together a working test page which copies
regular text but not SVG text, that would be awesome. If I understand inline
SVG, IE8 and other browsers which don't support it would fall back to
showing the text.
Meant to post this, too:
Also, I'd like to optionally make the fold text and diff filler uncopyable. But only if the chosen method readily supports it. The main problem is line numbers and fold column, I can live without fold text and diff filler.
Yes, that's one of the problems the design must be able to solve. I'm not sure that putting the lines in an <ol> and using the list index as the line number as in your example will work in combination with folding, and it will take some doing for conversions starting in the middle of the file. Plus this will only make the line numbers uncopyable, when I also want the fold column.
>
> Just to confirm briefly: folding can be nested, hence the column is of
> dynamic width?
>
Yes, folding can be nested, and the width in the generated HTML depends on the greater of the max foldlevel in the document, and the 'foldcolumn' setting in Vim. In Vim in is just the 'foldcolumn' setting.
> Is the line number column of dynamic width depending on number of total
> lines?
>
Yes. With a minimum width (in characters) equal to the 'numberwidth' option in Vim.
Thanks for looking into this some more. If you come up with an alternative do let me know, but as soon as I get a chance to run some tests and look over the results, I'll have a release candidate based on the <input> method. To make the page render faster I modified it to not use one <input> per character, but to size a single <input> according to the number of characters, with the 'ch' unit if supported or a fallback to calculate the size with javascript.
I'll put that out no later than this weekend. Did you have a problem with the functionality of the <input> method? I mentioned I don't like it because it feels like such a hack, but I've yet to see a viable alternative.
By the way, I tried inline SVG as an alternative, but even though it's an "image", all the browsers supporting it allow selecting it as text, so that's not a solution. Interestingly, SVG pulled in from an external file in an <object> tag is NOT selectable. But I don't want to generate dozens of files for a single page with :TOhtml; part of the idea is for it to generate a self-contained easily share-able file.
I sometimes want to copy line numbers, for those who may have access to the source file to be able to easily get their bearings.
> Do you ever want to copy characters from the fold column?
No, I cannot think of a time this might be useful.
> Is the fold column always to the left of the line numbers?
>
> Is this correct ? :
>
> [fold col] [line nos] code [fold text]
>
Mostly. The fold text will appear INSTEAD OF the code, when present.
>
> >I'll put that out no later than this weekend. Did you have a problem
> >with the functionality of the <input> method?
>
> no - seems to work fine and is the most browser compatible
>
OK, that's good.
> >I mentioned I don't like
> >it because it feels like such a hack, but I've yet to see a viable
> >alternative.
>
> Do you want to support IE6+7?
>
I want to support IE7. I will make every effort not to break IE6 for existing features, but it is too hard to develop/test new features on IE6; I'll respond to bug reports, but won't actively test on IE6, which now has less than 1% usage share ( http://www.w3schools.com/browsers/browsers_explorer.asp ).