1 /*
2 * Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "jsediting.h"
27 #include "editing/htmlediting_impl.h"
28 #include "editor.h"
29
30 #include "css/cssproperties.h"
31 #include "css/cssvalues.h"
32 #include "css/css_valueimpl.h"
33 #include "xml/dom_selection.h"
34 #include "xml/dom_docimpl.h"
35 #include "dom/dom_string.h"
36
37 #include "misc/khtml_partaccessor.h"
38
39 #include <QHash>
40 #include <QString>
41
42 using khtml::TypingCommandImpl;
43 using khtml::InsertListCommandImpl;
44 //
45 #define KPAC khtml::KHTMLPartAccessor
46
47 #define DEBUG_COMMANDS
48
49 namespace DOM
50 {
51
52 class DocumentImpl;
53
54 struct CommandImp {
55 bool (*execFn)(KHTMLPart *part, bool userInterface, const DOMString &value);
56 bool (*enabledFn)(KHTMLPart *part);
57 Editor::TriState(*stateFn)(KHTMLPart *part);
58 DOMString(*valueFn)(KHTMLPart *part);
59 };
60
61 typedef QHash<QString, const CommandImp *> CommandDict;
62 static CommandDict createCommandDictionary();
63
execCommand(const CommandImp * cmd,bool userInterface,const DOMString & value)64 bool JSEditor::execCommand(const CommandImp *cmd, bool userInterface, const DOMString &value)
65 {
66 if (!cmd || !cmd->enabledFn) {
67 return false;
68 }
69 KHTMLPart *part = m_doc->part();
70 if (!part) {
71 return false;
72 }
73 m_doc->updateLayout();
74 return cmd->enabledFn(part) && cmd->execFn(part, userInterface, value);
75 }
76
queryCommandEnabled(const CommandImp * cmd)77 bool JSEditor::queryCommandEnabled(const CommandImp *cmd)
78 {
79 if (!cmd || !cmd->enabledFn) {
80 return false;
81 }
82 KHTMLPart *part = m_doc->part();
83 if (!part) {
84 return false;
85 }
86 m_doc->updateLayout();
87 return cmd->enabledFn(part);
88 }
89
queryCommandIndeterm(const CommandImp * cmd)90 bool JSEditor::queryCommandIndeterm(const CommandImp *cmd)
91 {
92 if (!cmd || !cmd->enabledFn) {
93 return false;
94 }
95 KHTMLPart *part = m_doc->part();
96 if (!part) {
97 return false;
98 }
99 m_doc->updateLayout();
100 return cmd->stateFn(part) == Editor::MixedTriState;
101 }
102
queryCommandState(const CommandImp * cmd)103 bool JSEditor::queryCommandState(const CommandImp *cmd)
104 {
105 if (!cmd || !cmd->enabledFn) {
106 return false;
107 }
108 KHTMLPart *part = m_doc->part();
109 if (!part) {
110 return false;
111 }
112 m_doc->updateLayout();
113 return cmd->stateFn(part) != Editor::FalseTriState;
114 }
115
queryCommandSupported(const CommandImp * cmd)116 bool JSEditor::queryCommandSupported(const CommandImp *cmd)
117 {
118 return cmd != nullptr;
119 }
120
queryCommandValue(const CommandImp * cmd)121 DOMString JSEditor::queryCommandValue(const CommandImp *cmd)
122 {
123 if (!cmd || !cmd->enabledFn) {
124 return DOMString();
125 }
126 KHTMLPart *part = m_doc->part();
127 if (!part) {
128 return DOMString();
129 }
130 m_doc->updateLayout();
131 return cmd->valueFn(part);
132 }
133
134 // =============================================================================================
135
136 // Private stuff
137
execStyleChange(KHTMLPart * part,int propertyID,const DOMString & propertyValue)138 static bool execStyleChange(KHTMLPart *part, int propertyID, const DOMString &propertyValue)
139 {
140 CSSStyleDeclarationImpl *style = new CSSStyleDeclarationImpl(nullptr);
141 style->setProperty(propertyID, propertyValue);
142 style->ref();
143 part->editor()->applyStyle(style);
144 style->deref();
145 return true;
146 }
147
execStyleChange(KHTMLPart * part,int propertyID,int propertyEnum)148 static bool execStyleChange(KHTMLPart *part, int propertyID, int propertyEnum)
149 {
150 CSSStyleDeclarationImpl *style = new CSSStyleDeclarationImpl(nullptr);
151 style->setProperty(propertyID, propertyEnum);
152 style->ref();
153 part->editor()->applyStyle(style);
154 style->deref();
155 return true;
156 }
157
execStyleChange(KHTMLPart * part,int propertyID,const char * propertyValue)158 static bool execStyleChange(KHTMLPart *part, int propertyID, const char *propertyValue)
159 {
160 return execStyleChange(part, propertyID, DOMString(propertyValue));
161 }
162
stateStyle(KHTMLPart * part,int propertyID,const char * desiredValue)163 static Editor::TriState stateStyle(KHTMLPart *part, int propertyID, const char *desiredValue)
164 {
165 CSSStyleDeclarationImpl *style = new CSSStyleDeclarationImpl(nullptr);
166 style->setProperty(propertyID, desiredValue);
167 style->ref();
168 Editor::TriState state = part->editor()->selectionHasStyle(style);
169 style->deref();
170 return state;
171 }
172
selectionStartHasStyle(KHTMLPart * part,int propertyID,const char * desiredValue)173 static bool selectionStartHasStyle(KHTMLPart *part, int propertyID, const char *desiredValue)
174 {
175 CSSStyleDeclarationImpl *style = new CSSStyleDeclarationImpl(nullptr);
176 style->setProperty(propertyID, desiredValue);
177 style->ref();
178 bool hasStyle = part->editor()->selectionStartHasStyle(style);
179 style->deref();
180 return hasStyle;
181 }
182
valueStyle(KHTMLPart * part,int propertyID)183 static DOMString valueStyle(KHTMLPart *part, int propertyID)
184 {
185 return part->editor()->selectionStartStylePropertyValue(propertyID);
186 }
187
188 // =============================================================================================
189 //
190 // execCommand implementations
191 //
192
execBackColor(KHTMLPart * part,bool,const DOMString & value)193 static bool execBackColor(KHTMLPart *part, bool /*userInterface*/, const DOMString &value)
194 {
195 return execStyleChange(part, CSS_PROP_BACKGROUND_COLOR, value);
196 }
197
execBold(KHTMLPart * part,bool,const DOMString &)198 static bool execBold(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
199 {
200 bool isBold = selectionStartHasStyle(part, CSS_PROP_FONT_WEIGHT, "bold");
201 return execStyleChange(part, CSS_PROP_FONT_WEIGHT, isBold ? "normal" : "bold");
202 }
203
execCopy(KHTMLPart * part,bool,const DOMString &)204 static bool execCopy(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
205 {
206 part->editor()->copy();
207 return true;
208 }
209
execCut(KHTMLPart * part,bool,const DOMString &)210 static bool execCut(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
211 {
212 part->editor()->cut();
213 return true;
214 }
215
execDelete(KHTMLPart * part,bool,const DOMString &)216 static bool execDelete(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
217 {
218 TypingCommandImpl::deleteKeyPressed0(KPAC::xmlDocImpl(part));
219 return true;
220 }
221
execFontName(KHTMLPart * part,bool,const DOMString & value)222 static bool execFontName(KHTMLPart *part, bool /*userInterface*/, const DOMString &value)
223 {
224 return execStyleChange(part, CSS_PROP_FONT_FAMILY, value);
225 }
226
execFontSize(KHTMLPart * part,bool,const DOMString & value)227 static bool execFontSize(KHTMLPart *part, bool /*userInterface*/, const DOMString &value)
228 {
229 // This should handle sizes 1-7 like <font> does. Who the heck designed this interface? (Rhetorical question)
230 bool ok;
231 int val = value.string().toInt(&ok);
232 if (ok && val >= 1 && val <= 7) {
233 int size;
234 switch (val) {
235 case 1: size = CSS_VAL_XX_SMALL; break;
236 case 2: size = CSS_VAL_SMALL; break;
237 case 3: size = CSS_VAL_MEDIUM; break;
238 case 4: size = CSS_VAL_LARGE; break;
239 case 5: size = CSS_VAL_X_LARGE; break;
240 case 6: size = CSS_VAL_XX_LARGE; break;
241 default: size = CSS_VAL__KHTML_XXX_LARGE;
242 }
243 return execStyleChange(part, CSS_PROP_FONT_SIZE, size);
244 }
245
246 return execStyleChange(part, CSS_PROP_FONT_SIZE, value);
247 }
248
execForeColor(KHTMLPart * part,bool,const DOMString & value)249 static bool execForeColor(KHTMLPart *part, bool /*userInterface*/, const DOMString &value)
250 {
251 return execStyleChange(part, CSS_PROP_COLOR, value);
252 }
253
execIndent(KHTMLPart * part,bool,const DOMString &)254 static bool execIndent(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
255 {
256 part->editor()->indent();
257 return true;
258 }
259
execInsertNewline(KHTMLPart * part,bool,const DOMString &)260 static bool execInsertNewline(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
261 {
262 TypingCommandImpl::insertNewline0(KPAC::xmlDocImpl(part));
263 return true;
264 }
265
execInsertParagraph(KHTMLPart *,bool,const DOMString &)266 static bool execInsertParagraph(KHTMLPart * /*part*/, bool /*userInterface*/, const DOMString &/*value*/)
267 {
268 // FIXME: Implement.
269 return false;
270 }
271
execInsertText(KHTMLPart * part,bool,const DOMString & value)272 static bool execInsertText(KHTMLPart *part, bool /*userInterface*/, const DOMString &value)
273 {
274 TypingCommandImpl::insertText0(KPAC::xmlDocImpl(part), value);
275 return true;
276 }
277
execInsertOrderedList(KHTMLPart * part,bool,const DOMString &)278 static bool execInsertOrderedList(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
279 {
280 InsertListCommandImpl::insertList(KPAC::xmlDocImpl(part), InsertListCommandImpl::OrderedList);
281 return true;
282 }
283
execInsertUnorderedList(KHTMLPart * part,bool,const DOMString &)284 static bool execInsertUnorderedList(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
285 {
286 InsertListCommandImpl::insertList(KPAC::xmlDocImpl(part), InsertListCommandImpl::UnorderedList);
287 return true;
288 }
289
execItalic(KHTMLPart * part,bool,const DOMString &)290 static bool execItalic(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
291 {
292 bool isItalic = selectionStartHasStyle(part, CSS_PROP_FONT_STYLE, "italic");
293 return execStyleChange(part, CSS_PROP_FONT_STYLE, isItalic ? "normal" : "italic");
294 }
295
execJustifyCenter(KHTMLPart * part,bool,const DOMString &)296 static bool execJustifyCenter(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
297 {
298 return execStyleChange(part, CSS_PROP_TEXT_ALIGN, "center");
299 }
300
execJustifyFull(KHTMLPart * part,bool,const DOMString &)301 static bool execJustifyFull(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
302 {
303 return execStyleChange(part, CSS_PROP_TEXT_ALIGN, "justify");
304 }
305
execJustifyLeft(KHTMLPart * part,bool,const DOMString &)306 static bool execJustifyLeft(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
307 {
308 return execStyleChange(part, CSS_PROP_TEXT_ALIGN, "left");
309 }
310
execJustifyRight(KHTMLPart * part,bool,const DOMString &)311 static bool execJustifyRight(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
312 {
313 return execStyleChange(part, CSS_PROP_TEXT_ALIGN, "right");
314 }
315
execOutdent(KHTMLPart * part,bool,const DOMString &)316 static bool execOutdent(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
317 {
318 part->editor()->outdent();
319 return true;
320 }
321
322 #ifndef NO_SUPPORT_PASTE
323
execPaste(KHTMLPart * part,bool,const DOMString &)324 static bool execPaste(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
325 {
326 part->editor()->paste();
327 return true;
328 }
329
330 #endif
331
execPrint(KHTMLPart * part,bool,const DOMString &)332 static bool execPrint(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
333 {
334 part->editor()->print();
335 return true;
336 }
337
execRedo(KHTMLPart * part,bool,const DOMString &)338 static bool execRedo(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
339 {
340 part->editor()->redo();
341 return true;
342 }
343
execSelectAll(KHTMLPart * part,bool,const DOMString &)344 static bool execSelectAll(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
345 {
346 part->selectAll();
347 return true;
348 }
349
execStrikeThrough(KHTMLPart * part,bool,const DOMString &)350 static bool execStrikeThrough(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
351 {
352 bool isStriked = selectionStartHasStyle(part, CSS_PROP_TEXT_DECORATION, "line-through");
353 return execStyleChange(part, CSS_PROP_TEXT_DECORATION, isStriked ? "none" : "line-through");
354 }
355
execSubscript(KHTMLPart * part,bool,const DOMString &)356 static bool execSubscript(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
357 {
358 return execStyleChange(part, CSS_PROP_VERTICAL_ALIGN, "sub");
359 }
360
execSuperscript(KHTMLPart * part,bool,const DOMString &)361 static bool execSuperscript(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
362 {
363 return execStyleChange(part, CSS_PROP_VERTICAL_ALIGN, "super");
364 }
365
execUndo(KHTMLPart * part,bool,const DOMString &)366 static bool execUndo(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
367 {
368 part->editor()->undo();
369 return true;
370 }
371
execUnderline(KHTMLPart * part,bool,const DOMString &)372 static bool execUnderline(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
373 {
374 bool isUnderline = selectionStartHasStyle(part, CSS_PROP_TEXT_DECORATION, "underline");
375 return execStyleChange(part, CSS_PROP_TEXT_DECORATION, isUnderline ? "none" : "underline");
376 }
377
execUnselect(KHTMLPart * part,bool,const DOMString &)378 static bool execUnselect(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
379 {
380 KPAC::clearSelection(part);
381 return true;
382 }
383
384 // =============================================================================================
385 //
386 // queryCommandEnabled implementations
387 //
388 // It's a bit difficult to get a clear notion of the difference between
389 // "supported" and "enabled" from reading the Microsoft documentation, but
390 // what little I could glean from that seems to make some sense.
391 // Supported = The command is supported by this object.
392 // Enabled = The command is available and enabled.
393
enabled(KHTMLPart *)394 static bool enabled(KHTMLPart * /*part*/)
395 {
396 return true;
397 }
398
enabledAnySelection(KHTMLPart * part)399 static bool enabledAnySelection(KHTMLPart *part)
400 {
401 return KPAC::caret(part).notEmpty();
402 }
403
404 #ifndef NO_SUPPORT_PASTE
405
enabledPaste(KHTMLPart * part)406 static bool enabledPaste(KHTMLPart *part)
407 {
408 return part->editor()->canPaste();
409 }
410
411 #endif
412
enabledRangeSelection(KHTMLPart * part)413 static bool enabledRangeSelection(KHTMLPart *part)
414 {
415 return KPAC::caret(part).state() == Selection::RANGE;
416 }
417
enabledRedo(KHTMLPart * part)418 static bool enabledRedo(KHTMLPart *part)
419 {
420 return part->editor()->canRedo();
421 }
422
enabledUndo(KHTMLPart * part)423 static bool enabledUndo(KHTMLPart *part)
424 {
425 return part->editor()->canUndo();
426 }
427
428 // =============================================================================================
429 //
430 // queryCommandIndeterm/State implementations
431 //
432 // It's a bit difficult to get a clear notion of what these methods are supposed
433 // to do from reading the Microsoft documentation, but my current guess is this:
434 //
435 // queryCommandState and queryCommandIndeterm work in concert to return
436 // the two bits of information that are needed to tell, for instance,
437 // if the text of a selection is bold. The answer can be "yes", "no", or
438 // "partially".
439 //
440 // If this is so, then queryCommandState should return "yes" in the case where
441 // all the text is bold and "no" for non-bold or partially-bold text.
442 // Then, queryCommandIndeterm should return "no" in the case where
443 // all the text is either all bold or not-bold and and "yes" for partially-bold text.
444
stateNone(KHTMLPart *)445 static Editor::TriState stateNone(KHTMLPart * /*part*/)
446 {
447 return Editor::FalseTriState;
448 }
449
stateBold(KHTMLPart * part)450 static Editor::TriState stateBold(KHTMLPart *part)
451 {
452 return stateStyle(part, CSS_PROP_FONT_WEIGHT, "bold");
453 }
454
stateItalic(KHTMLPart * part)455 static Editor::TriState stateItalic(KHTMLPart *part)
456 {
457 return stateStyle(part, CSS_PROP_FONT_STYLE, "italic");
458 }
459
stateStrike(KHTMLPart * part)460 static Editor::TriState stateStrike(KHTMLPart *part)
461 {
462 return stateStyle(part, CSS_PROP_TEXT_DECORATION, "line-through");
463 }
464
stateSubscript(KHTMLPart * part)465 static Editor::TriState stateSubscript(KHTMLPart *part)
466 {
467 return stateStyle(part, CSS_PROP_VERTICAL_ALIGN, "sub");
468 }
469
stateSuperscript(KHTMLPart * part)470 static Editor::TriState stateSuperscript(KHTMLPart *part)
471 {
472 return stateStyle(part, CSS_PROP_VERTICAL_ALIGN, "super");
473 }
474
stateUnderline(KHTMLPart * part)475 static Editor::TriState stateUnderline(KHTMLPart *part)
476 {
477 return stateStyle(part, CSS_PROP_TEXT_DECORATION, "underline");
478 }
479
480 // =============================================================================================
481 //
482 // queryCommandValue implementations
483 //
484
valueNull(KHTMLPart *)485 static DOMString valueNull(KHTMLPart * /*part*/)
486 {
487 return DOMString();
488 }
489
valueBackColor(KHTMLPart * part)490 static DOMString valueBackColor(KHTMLPart *part)
491 {
492 return valueStyle(part, CSS_PROP_BACKGROUND_COLOR);
493 }
494
valueFontName(KHTMLPart * part)495 static DOMString valueFontName(KHTMLPart *part)
496 {
497 return valueStyle(part, CSS_PROP_FONT_FAMILY);
498 }
499
valueFontSize(KHTMLPart * part)500 static DOMString valueFontSize(KHTMLPart *part)
501 {
502 return valueStyle(part, CSS_PROP_FONT_SIZE);
503 }
504
valueForeColor(KHTMLPart * part)505 static DOMString valueForeColor(KHTMLPart *part)
506 {
507 return valueStyle(part, CSS_PROP_COLOR);
508 }
509
510 // =============================================================================================
511
512 struct EditorCommandInfo {
513 const char *name;
514 CommandImp imp;
515 };
516
517 // NOTE: strictly keep in sync with EditorCommand in editor_command.h
518 static const EditorCommandInfo commands[] = {
519
520 { "backColor", { execBackColor, enabled, stateNone, valueBackColor } },
521 { "bold", { execBold, enabledAnySelection, stateBold, valueNull } },
522 { "copy", { execCopy, enabledRangeSelection, stateNone, valueNull } },
523 { "cut", { execCut, enabledRangeSelection, stateNone, valueNull } },
524 { "delete", { execDelete, enabledAnySelection, stateNone, valueNull } },
525 { "fontName", { execFontName, enabledAnySelection, stateNone, valueFontName } },
526 { "fontSize", { execFontSize, enabledAnySelection, stateNone, valueFontSize } },
527 { "foreColor", { execForeColor, enabledAnySelection, stateNone, valueForeColor } },
528 { "indent", { execIndent, enabledAnySelection, stateNone, valueNull } },
529 { "insertNewline", { execInsertNewline, enabledAnySelection, stateNone, valueNull } },
530 { "insertOrderedList", { execInsertOrderedList, enabledAnySelection, stateNone, valueNull } },
531 { "insertParagraph", { execInsertParagraph, enabledAnySelection, stateNone, valueNull } },
532 { "insertText", { execInsertText, enabledAnySelection, stateNone, valueNull } },
533 { "insertUnorderedList", { execInsertUnorderedList, enabledAnySelection, stateNone, valueNull } },
534 { "italic", { execItalic, enabledAnySelection, stateItalic, valueNull } },
535 { "justifyCenter", { execJustifyCenter, enabledAnySelection, stateNone, valueNull } },
536 { "justifyFull", { execJustifyFull, enabledAnySelection, stateNone, valueNull } },
537 { "justifyLeft", { execJustifyLeft, enabledAnySelection, stateNone, valueNull } },
538 { "justifyNone", { execJustifyLeft, enabledAnySelection, stateNone, valueNull } },
539 { "justifyRight", { execJustifyRight, enabledAnySelection, stateNone, valueNull } },
540 { "outdent", { execOutdent, enabledAnySelection, stateNone, valueNull } },
541 #ifndef NO_SUPPORT_PASTE
542 { "paste", { execPaste, enabledPaste, stateNone, valueNull } },
543 #else
544 { 0, { 0, 0, 0, 0 } },
545 #endif
546 { "print", { execPrint, enabled, stateNone, valueNull } },
547 { "redo", { execRedo, enabledRedo, stateNone, valueNull } },
548 { "selectAll", { execSelectAll, enabled, stateNone, valueNull } },
549 { "StrikeThrough", {execStrikeThrough, enabled, stateStrike, valueNull } },
550 { "subscript", { execSubscript, enabledAnySelection, stateSubscript, valueNull } },
551 { "superscript", { execSuperscript, enabledAnySelection, stateSuperscript, valueNull } },
552 { "underline", { execUnderline, enabledAnySelection, stateUnderline, valueNull } },
553 { "undo", { execUndo, enabledUndo, stateNone, valueNull } },
554 { "unselect", { execUnselect, enabledAnySelection, stateNone, valueNull } }
555
556 //
557 // The "unsupported" commands are listed here since they appear in the Microsoft
558 // documentation used as the basis for the list.
559 //
560
561 // 2d-position (not supported)
562 // absolutePosition (not supported)
563 // blockDirLTR (not supported)
564 // blockDirRTL (not supported)
565 // browseMode (not supported)
566 // clearAuthenticationCache (not supported)
567 // createBookmark (not supported)
568 // createLink (not supported)
569 // dirLTR (not supported)
570 // dirRTL (not supported)
571 // editMode (not supported)
572 // formatBlock (not supported)
573 // inlineDirLTR (not supported)
574 // inlineDirRTL (not supported)
575 // insertButton (not supported)
576 // insertFieldSet (not supported)
577 // insertHorizontalRule (not supported)
578 // insertIFrame (not supported)
579 // insertImage (not supported)
580 // insertInputButton (not supported)
581 // insertInputCheckbox (not supported)
582 // insertInputFileUpload (not supported)
583 // insertInputHidden (not supported)
584 // insertInputImage (not supported)
585 // insertInputPassword (not supported)
586 // insertInputRadio (not supported)
587 // insertInputReset (not supported)
588 // insertInputSubmit (not supported)
589 // insertInputText (not supported)
590 // insertMarquee (not supported)
591 // insertOrderedList (not supported)
592 // insertSelectDropDown (not supported)
593 // insertSelectListBox (not supported)
594 // insertTextArea (not supported)
595 // insertUnorderedList (not supported)
596 // liveResize (not supported)
597 // multipleSelection (not supported)
598 // open (not supported)
599 // overwrite (not supported)
600 // playImage (not supported)
601 // refresh (not supported)
602 // removeFormat (not supported)
603 // removeParaFormat (not supported)
604 // saveAs (not supported)
605 // sizeToControl (not supported)
606 // sizeToControlHeight (not supported)
607 // sizeToControlWidth (not supported)
608 // stop (not supported)
609 // stopimage (not supported)
610 // strikethrough (not supported)
611 // unbookmark (not supported)
612 // underline (not supported)
613 // unlink (not supported)
614 };
615
createCommandDictionary()616 static CommandDict createCommandDictionary()
617 {
618 const int numCommands = sizeof(commands) / sizeof(commands[0]);
619 CommandDict commandDictionary; // case-insensitive dictionary
620 for (int i = 0; i < numCommands; ++i) {
621 if (commands[i].name) {
622 commandDictionary.insert(QString(commands[i].name).toLower(), &commands[i].imp);
623 }
624 }
625 return commandDictionary;
626 }
627
commandImp(const DOMString & command)628 const CommandImp *JSEditor::commandImp(const DOMString &command)
629 {
630 static CommandDict commandDictionary = createCommandDictionary();
631 const CommandImp *result = commandDictionary.value(command.string().toLower());
632 #ifdef DEBUG_COMMANDS
633 if (!result) {
634 qCDebug(KHTML_LOG) << "[Command is not supported yet]" << command;
635 }
636 #endif
637 return result;
638 }
639
commandImp(int command)640 const CommandImp *JSEditor::commandImp(int command)
641 {
642 if (command < 0 || command >= int(sizeof commands / sizeof commands[0])) {
643 return nullptr;
644 }
645 return &commands[command].imp;
646 }
647
648 } // namespace DOM
649
650 #undef KPAC
651