repo_editor.vue 8.52 KB
Newer Older
Phil Hughes's avatar
Phil Hughes committed
1
<script>
Tim Zallmann's avatar
Tim Zallmann committed
2
import { mapState, mapGetters, mapActions } from 'vuex';
3
import { viewerInformationForPath } from '~/vue_shared/components/content_viewer/lib/viewer_utils';
Phil Hughes's avatar
Phil Hughes committed
4
import flash from '~/flash';
Tim Zallmann's avatar
Tim Zallmann committed
5
import ContentViewer from '~/vue_shared/components/content_viewer/content_viewer.vue';
6
import DiffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue';
7 8 9 10 11 12
import {
  activityBarViews,
  viewerTypes,
  FILE_VIEW_MODE_EDITOR,
  FILE_VIEW_MODE_PREVIEW,
} from '../constants';
Phil Hughes's avatar
Phil Hughes committed
13
import Editor from '../lib/editor';
14
import ExternalLink from './external_link.vue';
15
import FileTemplatesBar from './file_templates/bar.vue';
16
import { __ } from '~/locale';
Phil Hughes's avatar
Phil Hughes committed
17 18

export default {
Tim Zallmann's avatar
Tim Zallmann committed
19 20
  components: {
    ContentViewer,
21
    DiffViewer,
22
    ExternalLink,
23
    FileTemplatesBar,
Tim Zallmann's avatar
Tim Zallmann committed
24
  },
Phil Hughes's avatar
Phil Hughes committed
25 26 27 28 29 30 31
  props: {
    file: {
      type: Object,
      required: true,
    },
  },
  computed: {
32 33 34
    ...mapState('rightPane', {
      rightPaneIsOpen: 'isOpen',
    }),
35 36 37 38 39 40
    ...mapState([
      'rightPanelCollapsed',
      'viewer',
      'panelResizing',
      'currentActivityView',
      'renderWhitespaceInCode',
41
      'editorTheme',
42
    ]),
43 44 45
    ...mapGetters([
      'currentMergeRequest',
      'getStagedFile',
46
      'isEditModeActive',
47
      'isCommitModeActive',
Phil Hughes's avatar
Phil Hughes committed
48
      'isReviewModeActive',
49
    ]),
50
    ...mapGetters('fileTemplates', ['showFileTemplatesBar']),
Phil Hughes's avatar
Phil Hughes committed
51
    shouldHideEditor() {
52
      return this.file && this.file.binary;
Phil Hughes's avatar
Phil Hughes committed
53
    },
54 55
    showContentViewer() {
      return (
56
        (this.shouldHideEditor || this.isPreviewViewMode) &&
57 58 59 60 61 62
        (this.viewer !== viewerTypes.mr || !this.file.mrChange)
      );
    },
    showDiffViewer() {
      return this.shouldHideEditor && this.file.mrChange && this.viewer === viewerTypes.mr;
    },
63
    isEditorViewMode() {
64
      return this.file.viewMode === FILE_VIEW_MODE_EDITOR;
65 66
    },
    isPreviewViewMode() {
67
      return this.file.viewMode === FILE_VIEW_MODE_PREVIEW;
68
    },
Tim Zallmann's avatar
Tim Zallmann committed
69 70
    editTabCSS() {
      return {
71
        active: this.isEditorViewMode,
Tim Zallmann's avatar
Tim Zallmann committed
72 73 74 75
      };
    },
    previewTabCSS() {
      return {
76
        active: this.isPreviewViewMode,
Tim Zallmann's avatar
Tim Zallmann committed
77 78
      };
    },
79 80 81 82
    fileType() {
      const info = viewerInformationForPath(this.file.path);
      return (info && info.id) || '';
    },
83 84 85
    showEditor() {
      return !this.shouldHideEditor && this.isEditorViewMode;
    },
86 87 88
    editorOptions() {
      return {
        renderWhitespace: this.renderWhitespaceInCode ? 'all' : 'none',
89
        theme: this.editorTheme,
90 91
      };
    },
Phil Hughes's avatar
Phil Hughes committed
92 93
  },
  watch: {
94 95 96 97 98
    file(newVal, oldVal) {
      if (oldVal.pending) {
        this.removePendingTab(oldVal);
      }

99
      // Compare key to allow for files opened in review mode to be cached differently
100
      if (oldVal.key !== this.file.key) {
101
        this.initEditor();
102 103 104 105

        if (this.currentActivityView !== activityBarViews.edit) {
          this.setFileViewMode({
            file: this.file,
106
            viewMode: FILE_VIEW_MODE_EDITOR,
107 108 109 110 111 112 113 114
          });
        }
      }
    },
    currentActivityView() {
      if (this.currentActivityView !== activityBarViews.edit) {
        this.setFileViewMode({
          file: this.file,
115
          viewMode: FILE_VIEW_MODE_EDITOR,
116
        });
Phil Hughes's avatar
Phil Hughes committed
117 118 119
      }
    },
    rightPanelCollapsed() {
120
      this.refreshEditorDimensions();
Phil Hughes's avatar
Phil Hughes committed
121 122
    },
    viewer() {
123 124 125
      if (!this.file.pending) {
        this.createEditorInstance();
      }
Phil Hughes's avatar
Phil Hughes committed
126
    },
127 128
    panelResizing() {
      if (!this.panelResizing) {
129
        this.refreshEditorDimensions();
130 131
      }
    },
132
    rightPaneIsOpen() {
133 134 135 136 137 138 139
      this.refreshEditorDimensions();
    },
    showEditor(val) {
      if (val) {
        // We need to wait for the editor to actually be rendered.
        this.$nextTick(() => this.refreshEditorDimensions());
      }
140
    },
Phil Hughes's avatar
Phil Hughes committed
141 142 143 144 145
  },
  beforeDestroy() {
    this.editor.dispose();
  },
  mounted() {
146
    if (!this.editor) {
147
      this.editor = Editor.create(this.editorOptions);
Phil Hughes's avatar
Phil Hughes committed
148
    }
149
    this.initEditor();
Phil Hughes's avatar
Phil Hughes committed
150 151 152
  },
  methods: {
    ...mapActions([
153
      'getFileData',
Phil Hughes's avatar
Phil Hughes committed
154 155 156 157
      'getRawFileData',
      'changeFileContent',
      'setFileLanguage',
      'setEditorPosition',
Tim Zallmann's avatar
Tim Zallmann committed
158
      'setFileViewMode',
Phil Hughes's avatar
Phil Hughes committed
159 160
      'setFileEOL',
      'updateViewer',
161
      'removePendingTab',
162
      'triggerFilesChange',
Phil Hughes's avatar
Phil Hughes committed
163
    ]),
164
    initEditor() {
165 166 167
      if (this.shouldHideEditor && (this.file.content || this.file.raw)) {
        return;
      }
Phil Hughes's avatar
Phil Hughes committed
168 169 170

      this.editor.clearEditor();

171
      this.fetchFileData()
Phil Hughes's avatar
Phil Hughes committed
172 173 174
        .then(() => {
          this.createEditorInstance();
        })
175
        .catch(err => {
176 177 178 179 180 181 182 183
          flash(
            __('Error setting up editor. Please try again.'),
            'alert',
            document,
            null,
            false,
            true,
          );
Phil Hughes's avatar
Phil Hughes committed
184 185 186
          throw err;
        });
    },
187 188 189 190 191 192 193 194 195 196 197 198 199 200
    fetchFileData() {
      if (this.file.tempFile) {
        return Promise.resolve();
      }

      return this.getFileData({
        path: this.file.path,
        makeFileActive: false,
      }).then(() =>
        this.getRawFileData({
          path: this.file.path,
        }),
      );
    },
Phil Hughes's avatar
Phil Hughes committed
201 202 203 204
    createEditorInstance() {
      this.editor.dispose();

      this.$nextTick(() => {
205
        if (this.viewer === viewerTypes.edit) {
Phil Hughes's avatar
Phil Hughes committed
206 207
          this.editor.createInstance(this.$refs.editor);
        } else {
208
          this.editor.createDiffInstance(this.$refs.editor, !this.isReviewModeActive);
Phil Hughes's avatar
Phil Hughes committed
209 210 211 212 213 214 215 216
        }

        this.setupEditor();
      });
    },
    setupEditor() {
      if (!this.file || !this.editor.instance) return;

217 218 219 220 221 222
      const head = this.getStagedFile(this.file.path);

      this.model = this.editor.createModel(
        this.file,
        this.file.staged && this.file.key.indexOf('unstaged-') === 0 ? head : null,
      );
Phil Hughes's avatar
Phil Hughes committed
223

224
      if (this.viewer === viewerTypes.mr && this.file.mrChange) {
Tim Zallmann's avatar
Tim Zallmann committed
225 226 227 228
        this.editor.attachMergeRequestModel(this.model);
      } else {
        this.editor.attachModel(this.model);
      }
Phil Hughes's avatar
Phil Hughes committed
229

230
      this.model.onChange(model => {
Phil Hughes's avatar
Phil Hughes committed
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
        const { file } = model;

        if (file.active) {
          this.changeFileContent({
            path: file.path,
            content: model.getModel().getValue(),
          });
        }
      });

      // Handle Cursor Position
      this.editor.onPositionChange((instance, e) => {
        this.setEditorPosition({
          editorRow: e.position.lineNumber,
          editorColumn: e.position.column,
        });
      });

      this.editor.setPosition({
        lineNumber: this.file.editorRow,
        column: this.file.editorColumn,
      });

      // Handle File Language
      this.setFileLanguage({
        fileLanguage: this.model.language,
      });

      // Get File eol
      this.setFileEOL({
        eol: this.model.eol,
      });
    },
264 265 266 267 268
    refreshEditorDimensions() {
      if (this.showEditor) {
        this.editor.updateDimensions();
      }
    },
Phil Hughes's avatar
Phil Hughes committed
269
  },
270
  viewerTypes,
271 272
  FILE_VIEW_MODE_EDITOR,
  FILE_VIEW_MODE_PREVIEW,
Phil Hughes's avatar
Phil Hughes committed
273 274 275 276
};
</script>

<template>
Mike Greiling's avatar
Mike Greiling committed
277
  <div id="ide" class="blob-viewer-container blob-editor-container">
278
    <div class="ide-mode-tabs clearfix">
279
      <ul v-if="!shouldHideEditor && isEditModeActive" class="nav-links float-left border-bottom-0">
Tim Zallmann's avatar
Tim Zallmann committed
280 281 282 283
        <li :class="editTabCSS">
          <a
            href="javascript:void(0);"
            role="button"
284
            @click.prevent="setFileViewMode({ file, viewMode: $options.FILE_VIEW_MODE_EDITOR })"
Mike Greiling's avatar
Mike Greiling committed
285
          >
286 287
            <template v-if="viewer === $options.viewerTypes.edit">{{ __('Edit') }}</template>
            <template v-else>{{ __('Review') }}</template>
Tim Zallmann's avatar
Tim Zallmann committed
288 289
          </a>
        </li>
Mike Greiling's avatar
Mike Greiling committed
290
        <li v-if="file.previewMode" :class="previewTabCSS">
Tim Zallmann's avatar
Tim Zallmann committed
291 292 293
          <a
            href="javascript:void(0);"
            role="button"
294
            @click.prevent="setFileViewMode({ file, viewMode: $options.FILE_VIEW_MODE_PREVIEW })"
295
            >{{ file.previewMode.previewTitle }}</a
Mike Greiling's avatar
Mike Greiling committed
296
          >
Tim Zallmann's avatar
Tim Zallmann committed
297 298
        </li>
      </ul>
Mike Greiling's avatar
Mike Greiling committed
299
      <external-link :file="file" />
Phil Hughes's avatar
Phil Hughes committed
300
    </div>
Mike Greiling's avatar
Mike Greiling committed
301
    <file-templates-bar v-if="showFileTemplatesBar(file.name)" />
Phil Hughes's avatar
Phil Hughes committed
302
    <div
303
      v-show="showEditor"
Phil Hughes's avatar
Phil Hughes committed
304
      ref="editor"
305 306
      :class="{
        'is-readonly': isCommitModeActive,
307
        'is-deleted': file.deleted,
Mike Greiling's avatar
Mike Greiling committed
308
        'is-added': file.tempFile,
309
      }"
310
      class="multi-file-editor-holder"
311
      @focusout="triggerFilesChange"
Mike Greiling's avatar
Mike Greiling committed
312
    ></div>
Tim Zallmann's avatar
Tim Zallmann committed
313
    <content-viewer
314
      v-if="showContentViewer"
Tim Zallmann's avatar
Tim Zallmann committed
315
      :content="file.content || file.raw"
316
      :path="file.rawPath || file.path"
317
      :file-path="file.path"
318
      :file-size="file.size"
Mike Greiling's avatar
Mike Greiling committed
319
      :project-path="file.projectId"
320
      :type="fileType"
Mike Greiling's avatar
Mike Greiling committed
321
    />
322 323 324 325 326 327 328
    <diff-viewer
      v-if="showDiffViewer"
      :diff-mode="file.mrChange.diffMode"
      :new-path="file.mrChange.new_path"
      :new-sha="currentMergeRequest.sha"
      :old-path="file.mrChange.old_path"
      :old-sha="currentMergeRequest.baseCommitSha"
Mike Greiling's avatar
Mike Greiling committed
329 330
      :project-path="file.projectId"
    />
Phil Hughes's avatar
Phil Hughes committed
331 332
  </div>
</template>