Menu

[r111]: / trunk / Src / UWBHighlighter.pas  Maximize  Restore  History

Download this file

382 lines (354 with data), 14.5 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
{
* UWBHighlighter.pas
*
* Class that highlights text in web browser that match a search criteria.
*
* v0.1 of 28 Feb 2005 - Original version.
* v1.0 of 25 May 2006 - Improved and corrected comments.
* - Deleted redundant const in TWBHighlighter.Create.
* v1.1 of 07 Nov 2006 - Changed to use UCSSUtils methods to generate CSS
* attributes.
* v1.2 of 17 Feb 2007 - We now create text ranges by calling a method of
* THTMLDocHelper.
* - Changed to use colour constants from UColours for
* text search highlighting. Highlight made paler yellow.
* - Added new assertions to test that text ranges passed
* to methods are assigned.
* - Changed to use TWBHelper to wait for document to load
* and to check it contains a valid HTML document. Raises
* EBug exception if not.
* v1.3 of 14 Oct 2007 - Fixed strange bug that was raising EOleException when
* user clicks scroll bar on scrolling display then
* selects item with no scroll bar
* (IHTMLTxtRange.moveToPoint(0, 0); raised "expecting
* method or property" exception!!). Fixed by re-creating
* text range for each search word and removing call to
* moveToPoint).
* v1.4 of 25 Jan 2009 - Modified to generate HTML tags using routines from
* UHTMLUtils rather than hard wiring them.
* - Assertions now get class name from ClassName method.
* - Made private section strict.
*
*
* ***** BEGIN LICENSE BLOCK *****
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
*
* The Original Code is UWBHighlighter.pas
*
* The Initial Developer of the Original Code is Peter Johnson
* (http://www.delphidabbler.com/).
*
* Portions created by the Initial Developer are Copyright (C) 2005-2009 Peter
* Johnson. All Rights Reserved.
*
* ***** END LICENSE BLOCK *****
}
unit UWBHighlighter;
interface
uses
// Delphi
Classes, SHDocVw, MSHTML, Graphics,
// Project
USearch;
type
{
TWBHighlighter:
Highlights text in web browser's current document that matches text search
criteria. The document may be divided into named search sections, and if so
only the text in the defined sections is highlighted. For example, if we
have a document containing these HTML fragments:
<div id="one">Division one text</div>
<div id="two">Division two text</div>
<div id="three">Division three text</div>
and we want only text in division's one and three to be highlighted we would
add the IDs 'one' and 'three' to the SearchSectionIDs property. If we want
all text in the document to highlighted we ensure the SearchSectionIDs
property is emnpty.
}
TWBHighlighter = class(TObject)
strict private
fWebBrowser: TWebBrowser;
{Browser control containing document being highlighted}
fSearchSectionIDs: TStrings;
{List of IDs of HTML tags enclosing text that is to be highlighted}
fHighlightBackColor: TColor;
{Background colour of highlighted text}
fHighlightTextColor: TColor;
{Colour of highlighted text}
fHighLightStyle: string;
{Current style used to highlight text}
function IsRangeInSearchSection(const Range: IHTMLTxtRange): Boolean;
{Checks if an HTML text range is within one of the identifies sections of
the document that are to be searched. If no sections are defined then all
ranges are searched.
@param Range [in] Text range to be searched.
@return True if text range is included in a search section.
}
function HighlightWord(const Word: string;
const FindFlags: Integer): Integer;
{Searches document for a word. Any words found are highlighted only if
they fall within one of the designated search sections per the
SearchSectionIDs property.
@param Word [in] Word to be highlighted.
@param FindFlags [in] Flags that customise search.
@return Number of words highlighted.
}
procedure SetSearchSectionIDs(const Value: TStrings);
{Write accessor for SearchSectionIDs property. Copies strings from new
value to property.
@param Value [in] String list containing IDs. If nil the property is
cleared.
}
procedure SetHighlightBackColor(const Value: TColor);
{Write accessor for HighlightBackColor property. Updates highlight colour.
@param Value [in] New background colour.
}
procedure SetHighlightTextColor(const Value: TColor);
{Write accessor for HighlightTextColor property. Updates highlight colour.
@param Value [in] New text colour.
}
procedure UpdateHighlightStyle;
{Updates CSS code that defines style used for highlighted text using
values of HighlightTextColor and HighlightBackColor properties.
}
function SearchOptionsToFlags(const Options: TTextSearchOptions): Integer;
{Converts text search options into equivalent bit mask used by web browser
control to modify how search is performed.
@param Options [in] Set of text search options to convert.
@return Equivalent bit mask.
}
public
constructor Create(const WebBrowser: TWebBrowser);
{Class constructor. Sets up the object.
@param WebBrowser [in] Browser control containing document to be
highlighted.
@except EBug raised if browser control does not contain a HTML document.
}
destructor Destroy; override;
{Class destructor. Tears down object.
}
function HighlightSearchResults(
const Criteria: ITextSearchCriteria): Integer;
{Searches for and highlights all text in document within defined search
sections that matches search criteria.
@param Criteria [in] Provides information about a text search.
@return Number of words highlighted.
}
property SearchSectionIDs: TStrings
read fSearchSectionIDs write SetSearchSectionIDs;
{List of IDs of HTML tags that enclose text which is to be highlighted. If
the list is non-empty only the text enclosed by the identified tags is
highlighted. If the list is empty then found text in the whole document is
highlighted}
property HighlightBackColor: TColor
read fHighlightBackColor write SetHighlightBackColor default clYellow;
{Background colour of highlight text}
property HighlightTextColor: TColor
read fHighlightTextColor write SetHighlightTextColor default clNone;
{Colour of highlighted text}
end;
implementation
uses
// Delphi
SysUtils,
// Project
UColours, UCSSUtils, UHTMLDocHelper, UHTMLUtils, UWBHelper;
{ TWBHighlighter }
constructor TWBHighlighter.Create(const WebBrowser: TWebBrowser);
{Class constructor. Sets up the object.
@param WebBrowser [in] Browser control containing document to be
highlighted.
@except EBug raised if browser control does not contain a valid HTML
document.
}
begin
Assert(Assigned(WebBrowser), ClassName + '.Create: WebBrowser is nil');
inherited Create;
// Record reference to web browser control
fWebBrowser := WebBrowser;
// Set up properties
fSearchSectionIDs := TStringList.Create;
fHighlightBackColor := clTextSearchHighlight;
fHighlightTextColor := clTextSearchText;
UpdateHighlightStyle;
// Ensure browser has loaded document before continuing
TWBHelper.WaitForValidDocToLoad(fWebBrowser); // can raise EBug
end;
destructor TWBHighlighter.Destroy;
{Class destructor. Tears down object.
}
begin
fSearchSectionIDs.Free;
inherited;
end;
function TWBHighlighter.HighlightSearchResults(
const Criteria: ITextSearchCriteria): Integer;
{Searches for and highlights all text in document within defined search
sections that matches search criteria.
@param Criteria [in] Provides information about a text search.
@return Number of words highlighted.
}
var
Idx: Integer; // loops thru all words in text search criteria
FindFlags: Integer; // flags that control how browser searches for text
begin
// Initialise count
Result := 0;
if Assigned(Criteria) then
begin
// Convert search options into bit mask that controls text search in web
// browser control
FindFlags := SearchOptionsToFlags(Criteria.Options);
// Highlight each search word
for Idx := 0 to Pred(Criteria.Words.Count) do
Result := Result + HighlightWord(Criteria.Words[Idx], FindFlags);
end;
end;
function TWBHighlighter.HighlightWord(const Word: string;
const FindFlags: Integer): Integer;
{Searches document for a word. Any words found are highlighted only if they
fall within one of the designated search sections per the SearchSectionIDs
property.
@param Word [in] Word to be highlighted.
@param FindFlags [in] Flags that customise search.
@return Number of words highlighted.
}
var
Range: IHTMLTxtRange; // HTML range to be searched for the word
SpanAttrs: IHTMLAttributes; // attributes of generated span tag
begin
Range := THTMLDocHelper.CreateBodyTextRange(fWebBrowser.Document);
Assert(Assigned(Range), ClassName + '.HighlightWord: Range is nil');
// Set up counter of highlighted items
Result := 0;
// Find each word according to find flags
while Range.findText(Word, 1, FindFlags) do
begin
// Check that found text is in a search section
if IsRangeInSearchSection(Range) then
begin
// Apply highlight to found text by spanning it with highlight style
SpanAttrs := THTMLAttributes.Create;
SpanAttrs.Add('style', fHighLightStyle);
Range.pasteHTML(MakeCompoundTag('span', SpanAttrs, Range.htmlText));
// Count the found text item
Inc(Result);
end
else
// Ignoring this word - not in search section: skip over it
Range.move('character', 1);
end;
end;
function TWBHighlighter.IsRangeInSearchSection(
const Range: IHTMLTxtRange): Boolean;
{Checks if an HTML text range is within one of the identifies sections of the
document that are to be searched. If no sections are defined then all ranges
are searched.
@param Range [in] Text range to be searched.
@return True if text range is included in a search section.
}
var
Elem: IHTMLElement; // an HTML element in range
begin
Assert(Assigned(Range), ClassName + '.IsRangeInSearchSection: Range is nil');
// Check if we have any specified search sections to search - if none provided
// then we class whole document as a single search section
if fSearchSectionIDs.Count > 0 then
begin
// Assume failure
Result := False;
// Loop thru all HTML elements from current range up to <body> tag, looking
// for enclosing tag with one of IDs that define a search section. Returns
// true if element found
Elem := Range.parentElement;
while Assigned(Elem) and not AnsiSameText(Elem.tagName, 'body') do
begin
if fSearchSectionIDs.IndexOf(Elem.id) >= 0 then
begin
Result := True;
Break;
end;
Elem := Elem.parentElement;
end;
end
else
// There are no specified search sections => all elements are searched
Result := True;
end;
function TWBHighlighter.SearchOptionsToFlags(
const Options: TTextSearchOptions): Integer;
{Converts text search options into equivalent bit mask used by web browser
control to modify how search is performed.
@param Options [in] Set of text search options to convert.
@return Equivalent bit mask.
}
var
Option: TTextSearchOption; // loops thru all search options
const
// Map of search options to find flags
cFlags: array[TTextSearchOption] of Integer = (
FINDTEXT_MATCHCASE, FINDTEXT_WHOLEWORD
);
begin
Result := 0;
for Option := Low(TTextSearchOption) to High(TTextSearchOption) do
if Option in Options then
Result := Result or cFlags[Option];
end;
procedure TWBHighlighter.SetHighlightBackColor(const Value: TColor);
{Write accessor for HighlightBackColor property. Updates highlight colour.
@param Value [in] New background colour.
}
begin
if fHighlightBackColor <> Value then
begin
fHighlightBackColor := Value;
UpdateHighlightStyle;
end;
end;
procedure TWBHighlighter.SetHighlightTextColor(const Value: TColor);
{Write accessor for HighlightTextColor property. Updates highlight colour.
@param Value [in] New text colour.
}
begin
if fHighlightTextColor <> Value then
begin
fHighlightTextColor := Value;
UpdateHighlightStyle;
end;
end;
procedure TWBHighlighter.SetSearchSectionIDs(const Value: TStrings);
{Write accessor for SearchSectionIDs property. Copies strings from new value
to property.
@param Value [in] String list containing IDs. If nil the property is
cleared.
}
begin
if Assigned(Value) then
fSearchSectionIDs.Assign(Value)
else
fSearchSectionIDs.Clear;
end;
procedure TWBHighlighter.UpdateHighlightStyle;
{Updates CSS code that defines style used for highlighted text using values of
HighlightTextColor and HighlightBackColor properties.
}
begin
fHighlightStyle := '';
if fHighlightBackColor <> clNone then
fHighlightStyle := fHighlightStyle +
CSSBackgroundColorProp(fHighlightBackColor);
if fHighlightTextColor <> clNone then
fHighlightStyle := fHighlightStyle +
CSSColorProp(fHighlightTextColor);
end;
end.
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.