Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(423)

Side by Side Diff: dart/site/try/src/interaction_manager.dart

Issue 345553008: Fix issues that broke editing on browsers without Shadow DOM support. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library trydart.interaction_manager; 5 library trydart.interaction_manager;
6 6
7 import 'dart:html'; 7 import 'dart:html';
8 8
9 import 'dart:convert' show 9 import 'dart:convert' show
10 JSON; 10 JSON;
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
221 : super.internal() { 221 : super.internal() {
222 state = new InitialState(this); 222 state = new InitialState(this);
223 heartbeat = new Timer.periodic(HEARTBEAT_INTERVAL, onHeartbeat); 223 heartbeat = new Timer.periodic(HEARTBEAT_INTERVAL, onHeartbeat);
224 } 224 }
225 225
226 void onInput(Event event) => state.onInput(event); 226 void onInput(Event event) => state.onInput(event);
227 227
228 void onKeyUp(KeyboardEvent event) => state.onKeyUp(event); 228 void onKeyUp(KeyboardEvent event) => state.onKeyUp(event);
229 229
230 void onMutation(List<MutationRecord> mutations, MutationObserver observer) { 230 void onMutation(List<MutationRecord> mutations, MutationObserver observer) {
231 workAroundFirefoxBug();
231 try { 232 try {
232 try { 233 try {
233 return state.onMutation(mutations, observer); 234 return state.onMutation(mutations, observer);
234 } finally { 235 } finally {
235 // Discard any mutations during the observer, as these can lead to 236 // Discard any mutations during the observer, as these can lead to
236 // infinite loop. 237 // infinite loop.
237 observer.takeRecords(); 238 observer.takeRecords();
238 } 239 }
239 } catch (error, stackTrace) { 240 } catch (error, stackTrace) {
240 try { 241 try {
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 InteractionContext get context; 299 InteractionContext get context;
299 300
300 // TODO(ahe): Remove this. 301 // TODO(ahe): Remove this.
301 Set<AnchorElement> get oldDiagnostics { 302 Set<AnchorElement> get oldDiagnostics {
302 throw 'Use context.oldDiagnostics instead'; 303 throw 'Use context.oldDiagnostics instead';
303 } 304 }
304 305
305 void set state(InteractionState newState); 306 void set state(InteractionState newState);
306 307
307 void onStateChanged(InteractionState previous) { 308 void onStateChanged(InteractionState previous) {
308 print('State change ${previous.runtimeType} -> ${runtimeType}.');
309 } 309 }
310 310
311 void transitionToInitialState() { 311 void transitionToInitialState() {
312 state = new InitialState(context); 312 state = new InitialState(context);
313 } 313 }
314 } 314 }
315 315
316 class InitialState extends InteractionState { 316 class InitialState extends InteractionState {
317 final InteractionContext context; 317 final InteractionContext context;
318 bool requestCodeCompletion = false; 318 bool requestCodeCompletion = false;
319 319
320 InitialState(this.context); 320 InitialState(this.context);
321 321
322 void set state(InteractionState state) { 322 void set state(InteractionState state) {
323 InteractionState previous = context.state; 323 InteractionState previous = context.state;
324 if (previous != state) { 324 if (previous != state) {
325 context.state = state; 325 context.state = state;
326 state.onStateChanged(previous); 326 state.onStateChanged(previous);
327 } 327 }
328 } 328 }
329 329
330 void onInput(Event event) { 330 void onInput(Event event) {
331 state = new PendingInputState(context); 331 state = new PendingInputState(context);
332 } 332 }
333 333
334 void onKeyUp(KeyboardEvent event) { 334 void onKeyUp(KeyboardEvent event) {
335 if (computeHasModifier(event)) { 335 if (computeHasModifier(event)) {
336 print('onKeyUp (modified)');
337 onModifiedKeyUp(event); 336 onModifiedKeyUp(event);
338 } else { 337 } else {
339 print('onKeyUp (unmodified)');
340 onUnmodifiedKeyUp(event); 338 onUnmodifiedKeyUp(event);
341 } 339 }
342 } 340 }
343 341
344 void onModifiedKeyUp(KeyboardEvent event) { 342 void onModifiedKeyUp(KeyboardEvent event) {
345 } 343 }
346 344
347 void onUnmodifiedKeyUp(KeyboardEvent event) { 345 void onUnmodifiedKeyUp(KeyboardEvent event) {
348 switch (event.keyCode) { 346 switch (event.keyCode) {
349 case KeyCode.ENTER: { 347 case KeyCode.ENTER: {
(...skipping 26 matching lines...) Expand all
376 374
377 // This is a hack to get Safari (iOS) to send mutation events on 375 // This is a hack to get Safari (iOS) to send mutation events on
378 // contenteditable. 376 // contenteditable.
379 // TODO(ahe): Move to onInput? 377 // TODO(ahe): Move to onInput?
380 var newDiv = new DivElement(); 378 var newDiv = new DivElement();
381 hackDiv.replaceWith(newDiv); 379 hackDiv.replaceWith(newDiv);
382 hackDiv = newDiv; 380 hackDiv = newDiv;
383 } 381 }
384 382
385 void onMutation(List<MutationRecord> mutations, MutationObserver observer) { 383 void onMutation(List<MutationRecord> mutations, MutationObserver observer) {
386 print('onMutation');
387
388 removeCodeCompletion(); 384 removeCodeCompletion();
389 385
390 Selection selection = window.getSelection(); 386 Selection selection = window.getSelection();
391 TrySelection trySelection = new TrySelection(mainEditorPane, selection); 387 TrySelection trySelection = new TrySelection(mainEditorPane, selection);
392 388
393 Set<Node> normalizedNodes = new Set<Node>(); 389 Set<Node> normalizedNodes = new Set<Node>();
394 for (MutationRecord record in mutations) { 390 for (MutationRecord record in mutations) {
395 normalizeMutationRecord(record, trySelection, normalizedNodes); 391 normalizeMutationRecord(record, trySelection, normalizedNodes);
396 } 392 }
397 393
(...skipping 21 matching lines...) Expand all
419 for (String line in splitLines(currentText)) { 415 for (String line in splitLines(currentText)) {
420 List<Node> lineNodes = <Node>[]; 416 List<Node> lineNodes = <Node>[];
421 state = tokenizeAndHighlight( 417 state = tokenizeAndHighlight(
422 line, state, offset, trySelection, lineNodes); 418 line, state, offset, trySelection, lineNodes);
423 offset += line.length; 419 offset += line.length;
424 nodes.add(makeLine(lineNodes, state)); 420 nodes.add(makeLine(lineNodes, state));
425 } 421 }
426 422
427 node.parent.insertAllBefore(nodes, node); 423 node.parent.insertAllBefore(nodes, node);
428 node.remove(); 424 node.remove();
429 trySelection.adjust(selection); 425 if (mainEditorPane.contains(trySelection.anchorNode)) {
ahe 2014/06/27 11:23:28 This sometimes happens on Firefox. It is related t
Johnni Winther 2014/07/02 08:40:54 Put this in a comment.
ahe 2014/07/04 13:52:00 Done.
426 trySelection.adjust(selection);
427 }
430 428
431 // TODO(ahe): We know almost exactly what has changed. It could be 429 // TODO(ahe): We know almost exactly what has changed. It could be
432 // more efficient to only communicate what changed. 430 // more efficient to only communicate what changed.
433 context.currentCompilationUnit.content = getText(mainEditorPane); 431 context.currentCompilationUnit.content = getText(mainEditorPane);
434 432
435 // Discard highlighting mutations. 433 // Discard highlighting mutations.
436 observer.takeRecords(); 434 observer.takeRecords();
437 return; 435 return;
438 } 436 }
439 } 437 }
(...skipping 703 matching lines...) Expand 10 before | Expand all | Expand 10 after
1143 Text newNode = new Text('$buffer'); 1141 Text newNode = new Text('$buffer');
1144 node.replaceWith(newNode); 1142 node.replaceWith(newNode);
1145 if (selectionOffset != -1) { 1143 if (selectionOffset != -1) {
1146 selection.anchorNode = newNode; 1144 selection.anchorNode = newNode;
1147 selection.anchorOffset = selectionOffset; 1145 selection.anchorOffset = selectionOffset;
1148 } 1146 }
1149 } 1147 }
1150 if (!record.removedNodes.isEmpty) { 1148 if (!record.removedNodes.isEmpty) {
1151 normalizedNodes.add(findLine(record.target)); 1149 normalizedNodes.add(findLine(record.target));
1152 } 1150 }
1153 if (record.type == "characterData") { 1151 if (record.type == "characterData" && record.target.parent != null) {
ahe 2014/06/27 11:23:28 Firefox sends two records when the last character
Johnni Winther 2014/07/02 08:40:54 Put this in a comment.
ahe 2014/07/04 13:52:00 Done.
1154 normalizedNodes.add(findLine(record.target)); 1152 normalizedNodes.add(findLine(record.target));
1155 } 1153 }
1156 } 1154 }
1157 1155
1158 // Finds the line of [node] (a parent node with CSS class 'lineNumber'). 1156 // Finds the line of [node] (a parent node with CSS class 'lineNumber').
1159 // If no such parent exists, return mainEditorPane if it is a parent. 1157 // If no such parent exists, return mainEditorPane if it is a parent.
1160 // Otherwise return [node]. 1158 // Otherwise return [node].
1161 Node findLine(Node node) { 1159 Node findLine(Node node) {
1162 for (Node n = node; n != null; n = n.parent) { 1160 for (Node n = node; n != null; n = n.parent) {
1163 if (n is Element && n.classes.contains('lineNumber')) return n; 1161 if (n is Element && n.classes.contains('lineNumber')) return n;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1196 bool isCompilerStageMarker(String message) { 1194 bool isCompilerStageMarker(String message) {
1197 return 1195 return
1198 message.startsWith('Package root is ') || 1196 message.startsWith('Package root is ') ||
1199 message.startsWith('Compiling ') || 1197 message.startsWith('Compiling ') ||
1200 message == "Resolving..." || 1198 message == "Resolving..." ||
1201 message.startsWith('Resolved ') || 1199 message.startsWith('Resolved ') ||
1202 message == "Inferring types..." || 1200 message == "Inferring types..." ||
1203 message == "Compiling..." || 1201 message == "Compiling..." ||
1204 message.startsWith('Compiled '); 1202 message.startsWith('Compiled ');
1205 } 1203 }
1204
1205 void workAroundFirefoxBug() {
1206 Selection selection = window.getSelection();
1207 if (!isCollapsed(selection)) return;
1208 Node node = selection.anchorNode;
1209 int offset = selection.anchorOffset;
1210 if (selection.anchorNode is Element && selection.anchorOffset != 0) {
ahe 2014/06/27 11:23:28 In some cases, Firefox reports the wrong anchorOff
Johnni Winther 2014/07/02 08:40:54 Again, put this in a comment.
ahe 2014/07/04 13:52:00 Done.
1211 selection
1212 ..modify('move', 'backward', 'character')
1213 ..modify('move', 'forward', 'character');
1214 print('Worked around Firefox selection bug $node@$offset -> '
1215 '${selection.anchorNode}@${selection.anchorOffset}.');
1216 }
1217 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698