|
38 | 38 | "cpo/http-imports",
|
39 | 39 | "cpo/guess-gas",
|
40 | 40 | "cpo/cpo-builtin-modules",
|
| 41 | + "cpo/modal-prompt", |
41 | 42 | "pyret-base/js/runtime"
|
42 | 43 | ],
|
43 | 44 | provides: {},
|
44 | 45 | theModule: function(runtime, namespace, uri,
|
45 | 46 | compileLib, compileStructs, pyRepl, cpo, replUI,
|
46 | 47 | runtimeLib, loadLib, builtinModules, cpoBuiltins,
|
47 |
| - gdriveLocators, http, guessGas, cpoModules, |
| 48 | + gdriveLocators, http, guessGas, cpoModules, modalPrompt, |
48 | 49 | rtLib) {
|
49 | 50 |
|
50 | 51 |
|
|
470 | 471 |
|
471 | 472 | });
|
472 | 473 |
|
| 474 | + |
| 475 | + // Used for image definition naming (identifier: "img" + curImg) |
| 476 | + var curImg = 0; |
| 477 | + |
| 478 | + /** |
| 479 | + * Sets curImg to a value which will not clash with the code in |
| 480 | + * contents (note: this is done conservatively -- the estimation |
| 481 | + * is "dumb" in that it pays no attention to token types) |
| 482 | + */ |
| 483 | + function inferCurImg(contents) { |
| 484 | + var query = /img([0-9]+)[\s\n\r]*=/g; |
| 485 | + var maxSoFar = 0; |
| 486 | + var res; |
| 487 | + while((res = query.exec(contents)) !== null) { |
| 488 | + maxSoFar = Math.max(maxSoFar, Number(res[1])); |
| 489 | + } |
| 490 | + curImg = maxSoFar + 1; |
| 491 | + } |
| 492 | + |
| 493 | + var photoPrompt = new modalPrompt([ |
| 494 | + { |
| 495 | + message: "Import as Values", |
| 496 | + value: "values", |
| 497 | + example: 'image-url("<URL>")\nimage-url("<URL>")\n# ...' |
| 498 | + }, |
| 499 | + { |
| 500 | + message: "Import as Definitions", |
| 501 | + value: "defs", |
| 502 | + example: 'image0 = image-url("<URL>")\nimage1 = image-url("<URL>")\n# ...' |
| 503 | + }, |
| 504 | + { |
| 505 | + message: "Import as a List", |
| 506 | + value: "list", |
| 507 | + example: '[list: image-url("<URL>"),\n' |
| 508 | + + ' image-url("<URL>"),\n' |
| 509 | + + ' # ...\n ]' |
| 510 | + }]); |
| 511 | + |
| 512 | + var lastSave = 0; |
| 513 | + function handlePickerData(documents, picker, drive) { |
| 514 | + function openFile(id) { |
| 515 | + // FIXME: This causes popup blockers to get triggered... |
| 516 | + window.open('/editor#program=' + id, '_blank'); |
| 517 | + } |
| 518 | + // File loaded |
| 519 | + if (documents[0][picker.Document.TYPE] === "file") { |
| 520 | + var id = documents[0][picker.Document.ID]; |
| 521 | + // If the editor has not been modified since the last save, |
| 522 | + // load in this window |
| 523 | + if (editor.cm.getDoc().history.lastModTime === lastSave) { |
| 524 | + var p = drive.getFileById(id); |
| 525 | + showShareContainer(p); |
| 526 | + window.location.hash = "#program=" + id; |
| 527 | + setTitle(documents[0][picker.Document.NAME]); |
| 528 | + loadProgram(p); |
| 529 | + } else { |
| 530 | + openFile(id); |
| 531 | + } |
| 532 | + for (var i = 1; i < documents.length; ++i) { |
| 533 | + openFile(documents[i][picker.Document.ID]); |
| 534 | + } |
| 535 | + } |
| 536 | + // Picture loaded |
| 537 | + else if (documents[0][picker.Document.TYPE] === picker.Type.PHOTO) { |
| 538 | + |
| 539 | + photoPrompt.show(function(res) { |
| 540 | + // Name of event for CM undo history |
| 541 | + var origin = "+insertImage" + curImg; |
| 542 | + var asValues = (res === "values"); |
| 543 | + var asDefs = (res === "defs"); |
| 544 | + var asList = (res === "list"); |
| 545 | + if (!(asValues || asDefs || asList)) { |
| 546 | + // Check for garbage and log it |
| 547 | + if (res !== null) { |
| 548 | + console.warn("Unknown photoPrompt response: ", res); |
| 549 | + } |
| 550 | + return; |
| 551 | + } |
| 552 | + // http://stackoverflow.com/questions/23733455/inserting-a-new-text-at-given-cursor-position |
| 553 | + var cm = editor.cm; |
| 554 | + var doc = cm.getDoc(); |
| 555 | + function placeInEditor(str) { |
| 556 | + var cursor = doc.getCursor(); |
| 557 | + var line = doc.getLine(cursor.line); |
| 558 | + var pos = { |
| 559 | + line: cursor.line, |
| 560 | + ch: line.length |
| 561 | + }; |
| 562 | + doc.replaceRange(str, pos, undefined, origin); |
| 563 | + reindent(cursor.line); |
| 564 | + } |
| 565 | + function reindent(line) { |
| 566 | + cm.indentLine(line || doc.getCursor().line); |
| 567 | + } |
| 568 | + function emitNewline() { |
| 569 | + var cursor = doc.getCursor(); |
| 570 | + placeInEditor('\n'); |
| 571 | + // FIXME: Dunno why this happens. |
| 572 | + if (cursor.line === doc.getCursor().line) { |
| 573 | + doc.setCursor({line: cursor.line + 1, ch: 0}); |
| 574 | + } |
| 575 | + } |
| 576 | + function emitLn(s) { |
| 577 | + placeInEditor(s); |
| 578 | + emitNewline(); |
| 579 | + } |
| 580 | + function onEmptyLine() { |
| 581 | + var cursor = doc.getCursor("to"); |
| 582 | + var line = doc.getLine(cursor.line); |
| 583 | + return (/^\s*$/.test(line)); |
| 584 | + } |
| 585 | + // Make newline at cursor position if we are not on an empty line |
| 586 | + if (onEmptyLine()) { |
| 587 | + reindent(); |
| 588 | + } else { |
| 589 | + emitNewline(); |
| 590 | + } |
| 591 | + if (asList) { |
| 592 | + placeInEditor("[list:"); |
| 593 | + } |
| 594 | + documents.forEach(function(d, idx) { |
| 595 | + var pathToImg = "\"https://drive.google.com/uc?export=download&id=" |
| 596 | + + d[picker.Document.ID] + "\""; |
| 597 | + var outstr = asDefs ? ("img" + curImg + " = ") : ""; |
| 598 | + ++curImg; |
| 599 | + outstr += "image-url(" + pathToImg + ")"; |
| 600 | + var isLast = (idx === (documents.length - 1)); |
| 601 | + if (asList) { |
| 602 | + if (idx === 0) { |
| 603 | + // The space after ":" gets eaten, so we need to enter it here |
| 604 | + outstr = ' ' + outstr; |
| 605 | + } |
| 606 | + outstr += isLast ? "]" : ","; |
| 607 | + } |
| 608 | + if (isLast) { |
| 609 | + placeInEditor(outstr); |
| 610 | + } else { |
| 611 | + emitLn(outstr); |
| 612 | + } |
| 613 | + }); |
| 614 | + }); |
| 615 | + } else { |
| 616 | + flashError("Invalid file type: " + documents[0][picker.Document.TYPE]); |
| 617 | + } |
| 618 | + } |
| 619 | + var picker; |
| 620 | + picker = new FilePicker({ |
| 621 | + onLoaded: function() { |
| 622 | + $("#openFile").attr("disabled", false); |
| 623 | + picker.openOn($("#openFile")[0], "click"); |
| 624 | + }, |
| 625 | + onSelect: handlePickerData, |
| 626 | + onError: flashError, |
| 627 | + onInternalError: stickError |
| 628 | + }); |
| 629 | + |
| 630 | + |
473 | 631 | return runtime.makeModuleReturn({}, {});
|
474 | 632 | }
|
475 | 633 | })
|
0 commit comments