<commit_before>'use strict';

// UI fragments.
import './newSubmissionForm.html';
// Client-side imports.
import 'ace-builds/src-noconflict/ace.js';
import 'ace-builds/src-noconflict/theme-xcode.js';
import 'ace-builds/src-noconflict/mode-c_cpp.js';

/**
 * #### Context
 *
 * - contestId
 * - taskId
 * @todo complete section.
 *
 * #### Subscription contract
 *
 * All relevant data has already been loaded by contestPageLayout.
 * We don't need to subscribe to anything.
 *
 * Furthermore, all Tasks and TaskRevisions have been found in the DB and
 * validated.
 */
Template.newSubmissionForm.onCreated(function() {
  // Pass.
});

Template.newSubmissionForm.onRendered(function() {
  const taskId = Template.currentData().taskId.valueOf();
  /* jshint -W117 */
  Template.instance().aceEditor = ace.edit(`ace-editor-${taskId}`);
  Template.instance().aceEditor.getSession().on('change', function() {
    localStorage.setItem(`ace-editor-${taskId}`,
        Template.instance().aceEditor.getValue());
  });
  Template.instance().aceEditor.setTheme('ace/theme/xcode');
  Template.instance().aceEditor.getSession().setMode('ace/mode/c_cpp');
  Template.instance().aceEditor.setValue(`#include <iostream>
int main() {
  unsigned int a, b;
  std::cin >> a >> b;
  std::cout << a + b << std::endl;
}`);
  Template.instance().aceEditor.clearSelection();
});

Template.newSubmissionForm.helpers({
  'editorId'() {
    return this.taskId.valueOf();
  },
});

Template.newSubmissionForm.events({
  'click #submit-submission'(event) {
    // Prevent default browser form submit
    event.preventDefault();

    const contestId = this.contestId;
    const taskId = this.taskId;
    const submissionData = Template.instance().aceEditor.getValue();

    Meteor.call('submissions.insert', contestId, taskId, submissionData);
  },

  'click #reset-editor'(event) {
    Template.instance().aceEditor.setValue(`#include <iostream>
int main() {
  unsigned int a, b;
  std::cin >> a >> b;
  std::cout << a + b << std::endl;
}`);
    Template.instance().aceEditor.clearSelection();
  },

  'change #file-selector'(event) {
    const reader = new FileReader();

    // FIXME: is a closure really needed?
    reader.onload = function(editor) {
      return function(e) {
        editor.setValue(e.target.result);
        editor.clearSelection();
      };
    }(Template.instance().aceEditor);

    reader.readAsText(event.target.files[0]);
  },

  'click #file-selector'(event) {
    // FIXME: this hack is needed to have a 'change' event fire even if the same
    //        file is selected twice (e.g. you select, then click "reset", then
    //        select again) however it does not seem to work at the moment (the
    //        'click' event is fired before 'change')
    // event.target.value = null;
  },
});
<commit_msg>Make localStorage work with the editor<commit_after>'use strict';

// UI fragments.
import './newSubmissionForm.html';
// Client-side imports.
import 'ace-builds/src-noconflict/ace.js';
import 'ace-builds/src-noconflict/theme-xcode.js';
import 'ace-builds/src-noconflict/mode-c_cpp.js';

/**
 * #### Context
 *
 * - contestId
 * - taskId
 * @todo complete section.
 *
 * #### Subscription contract
 *
 * All relevant data has already been loaded by contestPageLayout.
 * We don't need to subscribe to anything.
 *
 * Furthermore, all Tasks and TaskRevisions have been found in the DB and
 * validated.
 */
Template.newSubmissionForm.onCreated(function() {
  // Pass.
});

Template.newSubmissionForm.onRendered(function() {
  const taskId = Template.currentData().taskId.valueOf();
  /* jshint -W117 */
  Template.instance().aceEditor = ace.edit(`ace-editor-${taskId}`);

  // Restore old code, or set the default one.
  if (localStorage.getItem(`ace-editor-${taskId}`)) {
    Template.instance().aceEditor.setValue(
        localStorage.getItem(`ace-editor-${taskId}`));
  } else {
    Template.instance().aceEditor.setValue(`#include <iostream>
int main() {
  unsigned int a, b;
  std::cin >> a >> b;
  std::cout << a + b << std::endl;
}`);
  }

  // Set up change event, to save the code.
  Template.instance().aceEditor.getSession().on('change', () => {
    localStorage.setItem(`ace-editor-${taskId}`,
        // FIXME: maybe we could always just use ace.edit(id) like this:
        ace.edit(`ace-editor-${taskId}`).getValue());
  });

  // Aesthetic tweaks.
  Template.instance().aceEditor.setTheme('ace/theme/xcode');
  Template.instance().aceEditor.getSession().setMode('ace/mode/c_cpp');
  Template.instance().aceEditor.clearSelection();
});

Template.newSubmissionForm.helpers({
  'editorId'() {
    return this.taskId.valueOf();
  },
});

Template.newSubmissionForm.events({
  'click #submit-submission'(event) {
    // Prevent default browser form submit
    event.preventDefault();

    const contestId = this.contestId;
    const taskId = this.taskId;
    const submissionData = Template.instance().aceEditor.getValue();

    Meteor.call('submissions.insert', contestId, taskId, submissionData);
  },

  'click #reset-editor'(event) {
    const taskId = Template.currentData().taskId.valueOf();
    localStorage.setItem(`ace-editor-${taskId}`, `#include <iostream>
int main() {
  unsigned int a, b;
  std::cin >> a >> b;
  std::cout << a + b << std::endl;
}`);

    Template.instance().aceEditor.setValue(
        localStorage.getItem(`ace-editor-${taskId}`));
    Template.instance().aceEditor.clearSelection();
  },

  'change #file-selector'(event) {
    const reader = new FileReader();

    // FIXME: is a closure really needed?
    reader.onload = function(editor) {
      return function(e) {
        editor.setValue(e.target.result);
        editor.clearSelection();
      };
    }(Template.instance().aceEditor);

    reader.readAsText(event.target.files[0]);

    // XXX: this hack is needed to have a 'change' event fire even if the same
    //      file is selected twice (e.g. you select, then click "reset", then
    //      select again)
    event.target.value = null;
  },
});

{'fraction_non_alphanumeric': 0.16187468838291508, 'fraction_numerical': 0.001329566229017783, 'mean_word_length': 3.535041446872645, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 24, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6261686', 'n_tokens_mistral': 1887, 'n_tokens_neox': 1882, 'n_words': 416}