| // Copyright (c) 2019, Compiler Explorer Authors |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are met: |
| // |
| // * Redistributions of source code must retain the above copyright notice, |
| // this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above copyright |
| // notice, this list of conditions and the following disclaimer in the |
| // documentation and/or other materials provided with the distribution. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| // POSSIBILITY OF SUCH DAMAGE. |
| |
| 'use strict'; |
| |
| var |
| $ = require('jquery'), |
| _ = require('underscore'), |
| monaco = require('monaco-editor'), |
| ga = require('analytics'), |
| History = require('./history'); |
| |
| function HistoryDiffState(model) { |
| this.model = model; |
| this.result = null; |
| } |
| |
| HistoryDiffState.prototype.update = function (result) { |
| this.result = result.sources; |
| this.refresh(); |
| |
| return true; |
| }; |
| |
| HistoryDiffState.prototype.refresh = function () { |
| var output = this.result || []; |
| var content = ''; |
| _.each(output, function (val) { |
| if (content.length > 0) { |
| content += '\n'; |
| } |
| content += '/****** ' + val.lang + ' ******/\n'; |
| content += val.source; |
| }); |
| this.model.setValue(content); |
| }; |
| |
| function HistoryWidget() { |
| this.modal = null; |
| this.diffEditor = null; |
| this.lhs = null; |
| this.rhs = null; |
| this.currentList = []; |
| } |
| |
| HistoryWidget.prototype.initializeIfNeeded = function () { |
| if (this.modal === null) { |
| this.modal = $('#history'); |
| |
| var placeholder = this.modal.find('.monaco-placeholder'); |
| this.diffEditor = monaco.editor.createDiffEditor(placeholder[0], { |
| fontFamily: 'Consolas, "Liberation Mono", Courier, monospace', |
| scrollBeyondLastLine: true, |
| readOnly: true, |
| language: 'c++', |
| minimap: { |
| enabled: true, |
| }, |
| }); |
| |
| this.lhs = new HistoryDiffState(monaco.editor.createModel('', 'c++')); |
| this.rhs = new HistoryDiffState(monaco.editor.createModel('', 'c++')); |
| this.diffEditor.setModel({ original: this.lhs.model, modified: this.rhs.model }); |
| |
| this.modal.find('.inline-diff-checkbox').click(_.bind(function (event) { |
| var inline = $(event.target).prop('checked'); |
| this.diffEditor.updateOptions({ |
| renderSideBySide: !inline, |
| }); |
| this.resizeLayout(); |
| }, this)); |
| } |
| }; |
| |
| HistoryWidget.prototype.getLanguagesFromHistoryEntry = function (entry) { |
| return _.pluck(entry.sources, 'lang'); |
| }; |
| |
| HistoryWidget.prototype.populateFromLocalStorage = function () { |
| this.currentList = History.sortedList(); |
| this.populate( |
| this.modal.find('.historiccode'), |
| _.map(this.currentList, _.bind(function (data) { |
| var dt = new Date(data.dt); |
| var languages = this.getLanguagesFromHistoryEntry(data).join(', '); |
| return { |
| dt: data.dt, |
| name: dt.toString().replace(/\s\(.*\)/, '').concat(' (' + languages + ')'), |
| load: _.bind(function () { |
| this.onLoad(data); |
| this.modal.modal('hide'); |
| }, this), |
| }; |
| }, this))); |
| }; |
| |
| HistoryWidget.prototype.hideRadiosAndSetDiff = function () { |
| var root = this.modal.find('.historiccode'); |
| var items = root.find('li:not(.template)'); |
| |
| var foundbase = false; |
| var foundcomp = false; |
| |
| items.each(_.bind(function (idx, elem) { |
| var li = $(elem); |
| var dt = li.data('dt'); |
| |
| var base = li.find('.base'); |
| var comp = li.find('.comp'); |
| |
| var baseShouldBeVisible = true; |
| var compShouldBeVisible = true; |
| |
| if (comp.prop('checked')) { |
| foundcomp = true; |
| baseShouldBeVisible = false; |
| |
| var itemRight = _.find(this.currentList, function (item) { |
| return (item.dt === dt); |
| }); |
| |
| this.rhs.update(itemRight); |
| } else if (base.prop('checked')) { |
| foundbase = true; |
| |
| var itemLeft = _.find(this.currentList, function (item) { |
| return (item.dt === dt); |
| }); |
| |
| this.lhs.update(itemLeft); |
| } |
| |
| if (foundbase && foundcomp) { |
| compShouldBeVisible = false; |
| } else if (!foundbase && !foundcomp) { |
| baseShouldBeVisible = false; |
| } |
| |
| if (compShouldBeVisible) { |
| comp.css('visibility', ''); |
| } else { |
| comp.css('visibility', 'hidden'); |
| } |
| |
| if (baseShouldBeVisible) { |
| base.css('visibility', ''); |
| } else { |
| base.css('visibility', 'hidden'); |
| } |
| }, this)); |
| }; |
| |
| HistoryWidget.prototype.populate = function (root, list) { |
| root.find('li:not(.template)').remove(); |
| var template = root.find('.template'); |
| |
| var baseMarked = false; |
| var compMarked = false; |
| |
| _.each(list, _.bind(function (elem) { |
| var li = template |
| .clone() |
| .removeClass('template') |
| .appendTo(root); |
| |
| li.data('dt', elem.dt); |
| |
| var base = li.find('.base'); |
| var comp = li.find('.comp'); |
| |
| if (!compMarked) { |
| comp.prop('checked', 'checked'); |
| compMarked = true; |
| } else if (!baseMarked) { |
| base.prop('checked', 'checked'); |
| baseMarked = true; |
| } |
| |
| base.click(_.bind(this.hideRadiosAndSetDiff, this)); |
| comp.click(_.bind(this.hideRadiosAndSetDiff, this)); |
| |
| li.find('a').text(elem.name).click(elem.load); |
| }, this)); |
| |
| this.hideRadiosAndSetDiff(); |
| }; |
| |
| HistoryWidget.prototype.resizeLayout = function () { |
| var tabcontent = this.modal.find('div.tab-content'); |
| this.diffEditor.layout({ |
| width: tabcontent.width(), |
| height: tabcontent.height() - 20, |
| }); |
| }; |
| |
| HistoryWidget.prototype.run = function (onLoad) { |
| this.initializeIfNeeded(); |
| this.populateFromLocalStorage(); |
| this.onLoad = onLoad; |
| |
| this.modal.on('shown.bs.modal', _.bind(function () { |
| this.resizeLayout(); |
| }, this)); |
| |
| this.modal.modal(); |
| |
| ga.proxy('send', { |
| hitType: 'event', |
| eventCategory: 'OpenModalPane', |
| eventAction: 'History', |
| }); |
| }; |
| |
| module.exports = { |
| HistoryWidget: HistoryWidget, |
| }; |