<commit_before>'use strict';

module.exports = function () {
    this.World = require('../support/world.js').World;

    this.When(/^я введу в поле типа дата "([^"]*)" значение "([^"]*)"$/, function (pickerText, date) {
        var selector = this.selectors.XPATH.DatePicker.caption(pickerText);
        var xpath = this.by.xpath(selector);
        var that = this;

        date = this.helpers.parseDate(date).split('.');

        return this.currentView.findElement(xpath)
            .then(function (label) {
                return label.getAttribute('for');
            })
            .then(function (id) {
                return that.currentView.findElement(that.by.id(id));
            })
            .then(function (input) {
                return input.sendKeys(that.selectAll, that.keys.BACK_SPACE, date);
            });
    });

    this.When(/^значение в поле типа дата "([^"]*)" равно "([^"]*)"$/, function (pickerText, date) {
        var selector = this.selectors.XPATH.DatePicker.caption(pickerText);
        var xpath = this.by.xpath(selector);
        var that = this;

        date = this.helpers.parseDate(date);

        return this.currentView.findElement(xpath)
            .then(function (label) {
                return label.getAttribute('for');
            })
            .then(function (id) {
                return that.currentView.findElement(that.by.id(id));
            })
            .then(function (input) {
                return input.getAttribute('value');
            })
            .then(function (value) {
                that.assert.equal(value, date);
            });
    });

    this.When(/^я очищу поле типа дата "([^"]*)"$/, function (datePickerLabel) {
        var selector = this.selectors.XPATH.DatePicker.caption(datePickerLabel);
        var xpath = this.by.xpath(selector);
        var that = this;

        return this.currentView.findElement(xpath)
            .then(function (label) {
                return label.getAttribute('for');
            })
            .then(function (id) {
                return that.currentView.findElement(that.by.id(id));
            })
            .then(function (input) {
                return input.sendKeys(that.selectAll, that.keys.BACK_SPACE);
            });
    });
};<commit_msg>UI-2673 Добавить возможность обращаться к полю типа дата по индексу<commit_after>'use strict';

module.exports = function() {
    this.World = require('../support/world.js').World;

    this.When(/^я введу в поле типа дата "([^"]*)" значение "([^"]*)"$/, function(pickerText, date) {
        var picker = this.helpers.parseElement(pickerText);

        var selector = this.selectors.XPATH.DatePicker.caption(picker.name);
        var xpath = this.by.xpath(selector);
        var that = this;

        date = this.helpers.parseDate(date).split('.');

        return this.currentView.findElements(xpath)
            .then(function(labels) {
                if (labels.length <= picker.index) {
                    throw new Error('Элемент не найден');
                }
                return labels[picker.index].getAttribute('for');
            })
            .then(function(id) {
                return that.currentView.findElement(that.by.id(id));
            })
            .then(function(input) {
                return input.sendKeys(that.selectAll, that.keys.BACK_SPACE, date);
            });
    });

    this.When(/^значение в поле типа дата "([^"]*)" равно "([^"]*)"$/, function(pickerText, date) {
        var picker = this.helpers.parseElement(pickerText);

        var selector = this.selectors.XPATH.DatePicker.caption(picker.name);
        var xpath = this.by.xpath(selector);
        var that = this;

        date = this.helpers.parseDate(date);

        return this.currentView.findElement(xpath)
            .then(function(labels) {
                if (labels.length <= picker.index) {
                    throw new Error('Элемент не найден');
                }
                return labels[picker.index].getAttribute('for');
            })
            .then(function(id) {
                return that.currentView.findElement(that.by.id(id));
            })
            .then(function(input) {
                return input.getAttribute('value');
            })
            .then(function(value) {
                that.assert.equal(value, date);
            });
    });

    this.When(/^я очищу поле типа дата "([^"]*)"$/, function(datePickerLabel) {
        var picker = this.helpers.parseElement(pickerText);

        var selector = this.selectors.XPATH.DatePicker.caption(picker.name);
        var xpath = this.by.xpath(selector);
        var that = this;

        return this.currentView.findElement(xpath)
            .then(function(labels) {
                if (labels.length <= picker.index) {
                    throw new Error('Элемент не найден');
                }
                return labels[picker.index].getAttribute('for');
            })
            .then(function(id) {
                return that.currentView.findElement(that.by.id(id));
            })
            .then(function(input) {
                return input.sendKeys(that.selectAll, that.keys.BACK_SPACE);
            });
    });
};<|endoftext|>


<commit_before>/* Copyright (c) 2012-2013 The TagSpaces Authors. All rights reserved.
 * Use of this source code is governed by a AGPL3 license that
 * can be found in the LICENSE file. */
define(function(require, exports, module) {
"use strict";

console.log("Loading perspective.manager.js");

var perspectives = undefined;

var TSCORE = require("tscore");

var initViews = function () {
	perspectives = [];

	$("#viewSwitcher").empty();
	$("#viewToolbars").empty();
	$("#viewContainers").empty();
	$("#viewFooters").empty();

	var defaultViewLoaded = false;

	// Loading perspectiveDefault as a default perspective
    require(["ext/perspectiveDefault/extension.js"], function(perspective) {
		perspectives.push(perspective);
		initViewsUI(perspective);
		perspective.init();

   		TSCORE.currentView = perspective.ID;
		perspective.load();

        // Set the default perspective to be visually active
        $("#viewSwitcher").find("button").addClass("active");

        // Make shure default perspective is loaded first
        var extensions = TSCORE.Config.getPerspectives();
        for (var i=0; i < extensions.length; i++) {
            //if(extensions[i].enabled && (extensions[i].type == "view") ) {

                // TODO Some libraries such as ace editor are not working using paths like this "file:///C:/blabal/extension.js"
                var extPath = TSCORE.Config.getExtensionPath()+"/"+extensions[i].id+"/extension.js";

                require([extPath], function(perspective) {
                    perspectives.push(perspective);
                    initViewsUI(perspective);
                    //try {
                        perspective.init();
                    //} catch(e) {
                    //  console.log("Error while executing 'init' on "+perspectives[i].ID+" - "+e);
                    //}
                });
            //}
        }

    }); // end require
}

var initViewsUI = function(perspective) {
	console.log("Init UI for "+perspective.ID);

	// Creating perspective's toolbar
    $("#viewToolbars").append($("<div>", {
        id: perspective.ID+"Toolbar",
        text: perspective.Title,
    }).hide());

	// Creating perspective's container
    $("#viewContainers").append($("<div>", {
        id: perspective.ID+"Container",
        text: perspective.Title,
        style: "width: 100%; height: 100%",
    }).hide());

    // Creating perspective's footer
    $("#viewFooters").append($("<div>", {
        id: perspective.ID+"Footer",
        text: perspective.Title,
        style: "width: 100%; height: 100%",
    }).hide());

    $("#viewSwitcher").append($("<button>", {
        "viewid": perspective.ID,
        "class":  "btn btn-link",
        "id":       perspective.ID+"Button",
        "text":     " "+perspective.Title
    }).prepend($("<i>", {
        "class":  perspective.Icon
    })))

	// Adding event listener & icon to the radio button
    $( "#"+perspective.ID+"Button" ).click(function() {
		changeView($(this).attr("viewid"));
	})
}

var getNextFile = function (filePath) {
	for (var i=0; i < perspectives.length; i++) {
		if(perspectives[i].ID == TSCORE.currentView) {
	 		try {
	 			return perspectives[i].getNextFile(filePath);
	 		} catch(e) {
	 			console.log("Error while executing 'getNextFile' on "+perspectives[i].ID+" "+e);
	 		}
 		}
	}
}

var getPrevFile = function (filePath) {
	for (var i=0; i < perspectives.length; i++) {
		if(perspectives[i].ID == TSCORE.currentView) {
	 		try {
	 			return perspectives[i].getPrevFile(filePath);
	 		} catch(e) {
	 			console.log("Error while executing 'getPrevFile' on "+perspectives[i].ID+" "+e);
	 		}
 		}
	}
}

var updateTreeData = function (treeData) {
	for (var i=0; i < perspectives.length; i++) {
 		try {
 			perspectives[i].updateTreeData(treeData);
 		} catch(e) {
 			console.log("Error while executing 'updateTreeData' on "+perspectives[i].ID+" "+e);
 		}
	}
}

var updateFileBrowserData = function(dirList) {
    console.log("Updating the file browser data...");

    TSCORE.fileList = [];
    var tags = undefined;
    var ext = undefined;
    var title = undefined;
    var fileSize = undefined;
    var fileLMDT = undefined;
    var path = undefined;
    var filename = undefined;
    for (var i=0; i < dirList.length; i++) {
        if (dirList[i].type == "file"){
            // Considering Unix HiddenEntries (. in the beginning of the filename)
            if (TSCORE.Config.getShowUnixHiddenEntries() ||
               (!TSCORE.Config.getShowUnixHiddenEntries() && (dirList[i].name.indexOf(".") != 0))) {
                 filename = dirList[i].name;
                 path = dirList[i].path;
                 tags = TSCORE.TagUtils.extractTags(path);
                 title = TSCORE.TagUtils.extractTitle(path);
				 ext = TSCORE.TagUtils.extractFileExtension(path)
                 fileSize = dirList[i].size;
                 fileLMDT = dirList[i].lmdt;

                 if(fileSize == undefined) fileSize = "";
                 if(fileLMDT == undefined) fileLMDT = "";
                 var entry = [title,ext,tags,fileSize,fileLMDT,path,filename,];
                 TSCORE.fileList.push(entry);
            }
        }
    }
    changeView(TSCORE.currentView);
}

var refreshFileListContainer = function() {
	// TODO consider search view
    TSCORE.IO.listDirectory(TSCORE.currentPath);
}

var changeView = function (viewType) {
    console.log("Change to "+viewType+" view.");
    TSCORE.showLoadingAnimation();

    //Setting the current view
    TSCORE.currentView = viewType;

    if(TSCORE.currentPath == undefined) {
        TSCORE.showAlertDialog("Please select first location from the dropdown on the left!");
    }

	for (var i=0; i < perspectives.length; i++) {
 		$( "#"+perspectives[i].ID+"Container" ).hide();
 		$( "#"+perspectives[i].ID+"Toolbar" ).hide();
 		$( "#"+perspectives[i].ID+"Footer" ).hide();
	}

	for (var i=0; i < perspectives.length; i++) {
 		if(perspectives[i].ID == viewType) {
 			// Load the selected view
	 		//try {
	 			perspectives[i].load();
	 		//} catch(e) {
	 		//	console.error("Error while executing 'load' on "+perspectives[i].ID+" "+e);
	 		//}
			$( "#"+perspectives[i].ID+"Container" ).show();
			$( "#"+perspectives[i].ID+"Toolbar" ).show();
            $( "#"+perspectives[i].ID+"Footer" ).show();
 		}
	}

    // Clear the list with the selected files
    TSCORE.PerspectiveManager.clearSelectedFiles();

	// Reset the filter by a view change
	//setFileFilter("");

//    TSCORE.hideLoadingAnimation();
}

var clearSelectedFiles = function () {
    // Clear selected files
    TSCORE.selectedFiles = [];
	for (var i=0; i < perspectives.length; i++) {
 		try {
 			perspectives[i].clearSelectedFiles();
 		} catch(e) {
 			console.log("Error while executing 'clearSelectedFiles' on "+perspectives[i].ID)
 		}
	}
}

var setFileFilter = function (filter) {
	for (var i=0; i < perspectives.length; i++) {
 		try {
 		    if(perspectives[i].ID == TSCORE.currentView){
                perspectives[i].setFileFilter(filter);
 		    }
 		} catch(e) {
 			console.log("Error while executing 'setFileFilter' on "+perspectives[i].ID)
 		}
	}
}

exports.initViews 					 = initViews
exports.getNextFile					 = getNextFile;
exports.getPrevFile 				 = getPrevFile;
exports.updateTreeData				 = updateTreeData;
exports.updateFileBrowserData		 = updateFileBrowserData;
exports.refreshFileListContainer	 = refreshFileListContainer;
exports.clearSelectedFiles			 = clearSelectedFiles;
exports.setFileFilter				 = setFileFilter;

});<commit_msg>Loading of the perspective optimized<commit_after>/* Copyright (c) 2012-2013 The TagSpaces Authors. All rights reserved.
 * Use of this source code is governed by a AGPL3 license that
 * can be found in the LICENSE file. */
define(function(require, exports, module) {
"use strict";

console.log("Loading perspective.manager.js");

var perspectives = undefined;

var TSCORE = require("tscore");

var initViews = function () {
	perspectives = [];

	$("#viewSwitcher").empty();
	$("#viewToolbars").empty();
	$("#viewContainers").empty();
	$("#viewFooters").empty();

	var defaultViewLoaded = false;

    var extensions = TSCORE.Config.getPerspectives();
    for (var i=0; i < extensions.length; i++) {

        // TODO Some libraries such as ace editor are not working using paths like this "file:///C:/blabal/extension.js"
        var extPath = TSCORE.Config.getExtensionPath()+"/"+extensions[i].id+"/extension.js";

        require([extPath], function(perspective) {
            perspectives.push(perspective);
            try {
                // Creating perspective's toolbar
                $("#viewToolbars").append($("<div>", {
                    id: perspective.ID+"Toolbar",
                    text: perspective.Title,
                }).hide());

                // Creating perspective's container
                $("#viewContainers").append($("<div>", {
                    id: perspective.ID+"Container",
                    text: perspective.Title,
                    style: "width: 100%; height: 100%",
                }).hide());

                // Creating perspective's footer
                $("#viewFooters").append($("<div>", {
                    id: perspective.ID+"Footer",
                    text: perspective.Title,
                    style: "width: 100%; height: 100%",
                }).hide());
                perspective.init();
            } catch(e) {
                console.log("Error while executing 'init' on "+perspectives[i].ID+" - "+e);
            } finally {
                if( perspectives.length == extensions.length) {
                    initViewSwitcher();
                }
            }
        });
    }
}

var initViewSwitcher = function() {
    var extensions = TSCORE.Config.getPerspectives();
    for (var i=0; i < extensions.length; i++) {
        var curPers = undefined;
        // Finding the right perspective
        perspectives.forEach(function(value) {
            if(value.ID == extensions[i].id) {
                curPers = value;
            }
        })

        $("#viewSwitcher").append($("<button>", {
            "viewid": curPers.ID,
            "class":  "btn btn-link",
            "id":       curPers.ID+"Button",
            "text":     " "+curPers.Title
        }).prepend($("<i>", {
            "class":  curPers.Icon
        })))

        // Adding event listener & icon to the radio button
        $( "#"+curPers.ID+"Button" ).click(function() {
            changeView($(this).attr("viewid"));
        })
    }

    if(perspectives.length > 0) {
        TSCORE.currentView = perspectives[0].ID;
        // Set the first perspective to be visually active
        $("#viewSwitcher").find("button").first().addClass("active");
        changeView($("#viewSwitcher").find("button").first().attr("viewid"));
    }
}

var getNextFile = function (filePath) {
	for (var i=0; i < perspectives.length; i++) {
		if(perspectives[i].ID == TSCORE.currentView) {
	 		try {
	 			return perspectives[i].getNextFile(filePath);
	 		} catch(e) {
	 			console.log("Error while executing 'getNextFile' on "+perspectives[i].ID+" "+e);
	 		}
 		}
	}
}

var getPrevFile = function (filePath) {
	for (var i=0; i < perspectives.length; i++) {
		if(perspectives[i].ID == TSCORE.currentView) {
	 		try {
	 			return perspectives[i].getPrevFile(filePath);
	 		} catch(e) {
	 			console.log("Error while executing 'getPrevFile' on "+perspectives[i].ID+" "+e);
	 		}
 		}
	}
}

var updateTreeData = function (treeData) {
	for (var i=0; i < perspectives.length; i++) {
 		try {
 			perspectives[i].updateTreeData(treeData);
 		} catch(e) {
 			console.log("Error while executing 'updateTreeData' on "+perspectives[i].ID+" "+e);
 		}
	}
}

var updateFileBrowserData = function(dirList) {
    console.log("Updating the file browser data...");

    TSCORE.fileList = [];
    var tags = undefined;
    var ext = undefined;
    var title = undefined;
    var fileSize = undefined;
    var fileLMDT = undefined;
    var path = undefined;
    var filename = undefined;
    for (var i=0; i < dirList.length; i++) {
        if (dirList[i].type == "file"){
            // Considering Unix HiddenEntries (. in the beginning of the filename)
            if (TSCORE.Config.getShowUnixHiddenEntries() ||
               (!TSCORE.Config.getShowUnixHiddenEntries() && (dirList[i].name.indexOf(".") != 0))) {
                 filename = dirList[i].name;
                 path = dirList[i].path;
                 tags = TSCORE.TagUtils.extractTags(path);
                 title = TSCORE.TagUtils.extractTitle(path);
				 ext = TSCORE.TagUtils.extractFileExtension(path)
                 fileSize = dirList[i].size;
                 fileLMDT = dirList[i].lmdt;

                 if(fileSize == undefined) fileSize = "";
                 if(fileLMDT == undefined) fileLMDT = "";
                 var entry = [title,ext,tags,fileSize,fileLMDT,path,filename,];
                 TSCORE.fileList.push(entry);
            }
        }
    }
    changeView(TSCORE.currentView);
}

var refreshFileListContainer = function() {
	// TODO consider search view
    TSCORE.IO.listDirectory(TSCORE.currentPath);
}

var changeView = function (viewType) {
    console.log("Change to "+viewType+" view.");
    TSCORE.showLoadingAnimation();

    //Setting the current view
    TSCORE.currentView = viewType;

/*    if(TSCORE.currentPath == undefined) {
        TSCORE.showAlertDialog("Please select first location from the dropdown on the left!");
    }*/

	for (var i=0; i < perspectives.length; i++) {
 		$( "#"+perspectives[i].ID+"Container" ).hide();
 		$( "#"+perspectives[i].ID+"Toolbar" ).hide();
 		$( "#"+perspectives[i].ID+"Footer" ).hide();
	}

	for (var i=0; i < perspectives.length; i++) {
 		if(perspectives[i].ID == viewType) {
 			// Load the selected view
	 		//try {
	 			perspectives[i].load();
	 		//} catch(e) {
	 		//	console.error("Error while executing 'load' on "+perspectives[i].ID+" "+e);
	 		//}
			$( "#"+perspectives[i].ID+"Container" ).show();
			$( "#"+perspectives[i].ID+"Toolbar" ).show();
            $( "#"+perspectives[i].ID+"Footer" ).show();
 		}
	}

    // Clear the list with the selected files
    TSCORE.PerspectiveManager.clearSelectedFiles();

    TSCORE.hideLoadingAnimation();
}

var clearSelectedFiles = function () {
    // Clear selected files
    TSCORE.selectedFiles = [];
	for (var i=0; i < perspectives.length; i++) {
 		try {
 			perspectives[i].clearSelectedFiles();
 		} catch(e) {
 			console.log("Error while executing 'clearSelectedFiles' on "+perspectives[i].ID)
 		}
	}
}

var setFileFilter = function (filter) {
	for (var i=0; i < perspectives.length; i++) {
 		try {
 		    if(perspectives[i].ID == TSCORE.currentView){
                perspectives[i].setFileFilter(filter);
 		    }
 		} catch(e) {
 			console.log("Error while executing 'setFileFilter' on "+perspectives[i].ID)
 		}
	}
}

exports.initViews 					 = initViews
exports.getNextFile					 = getNextFile;
exports.getPrevFile 				 = getPrevFile;
exports.updateTreeData				 = updateTreeData;
exports.updateFileBrowserData		 = updateFileBrowserData;
exports.refreshFileListContainer	 = refreshFileListContainer;
exports.clearSelectedFiles			 = clearSelectedFiles;
exports.setFileFilter				 = setFileFilter;

});<|endoftext|>


<commit_before>var $ = require('jquery');
var cdb = require('cartodb.js');
var UserSettingsView = require('../public_common/user_settings_view');
var UserTourView = require('../public_common/user_tour_view');
var UserIndustriesView = require('../public_common/user_industries_view');
var UserResourcesView = require('../public_common/user_resources_view');
var FavMapView = require('../public_dashboard/fav_map_view');
var Feed = require('./view');
var ScrollableHeader = require('../common/views/scrollable_header');

/**
 * Entry point for the user feed, bootstraps all dependency models and application.
 */
$(function() {

  cdb.init(function() {

    cdb.templates.namespace = 'cartodb/';
    cdb.config.set('url_prefix', window.base_url);
    cdb.config.set('cdn_url', window.config.cdn_url);

    var userTourView = new UserTourView({
      el: $('.js-user-tour')
    });

    var userIndustriesView = new UserIndustriesView({
      el: $('.js-user-industries')
    });

    var userResourcesView = new UserResourcesView({
      el: $('.js-user-resources')
    });

    var scrollableHeader = new ScrollableHeader({
      el: $('.js-Navmenu'),
      anchorPoint: 520
    });

    var authenticatedUser = new cdb.open.AuthenticatedUser();

    $(document.body).bind('click', function() {
      cdb.god.trigger('closeDialogs');
    });

    authenticatedUser.bind('change', function() {
      if (authenticatedUser.get('username')) {
        var user = new cdb.admin.User(authenticatedUser.attributes);
        var userSettingsView = new UserSettingsView({
          el: $('.js-user-settings'),
          model: user
        });
        userSettingsView.render();

        var userDashboardUrl = user.viewUrl().dashboard();
        $('.js-user-info .UserAvatar-img').wrap($('<a>', {
          href: userDashboardUrl
        }));

        $('.js-login').hide();
        $('.js-learn').show();
      }
    });

    var favMapView = new FavMapView(window.favMapViewAttrs);
    favMapView.render();

    var feed = new Feed({
      el: $('.js-feed'),
      authenticatedUser: authenticatedUser
    });

    feed.render();
    authenticatedUser.fetch();
  });
});
<commit_msg>Applying necessary changes to user_feed in order to render properly map previews<commit_after>var $ = require('jquery');
var cdb = require('cartodb.js');
var UserSettingsView = require('../public_common/user_settings_view');
var UserTourView = require('../public_common/user_tour_view');
var UserIndustriesView = require('../public_common/user_industries_view');
var UserResourcesView = require('../public_common/user_resources_view');
var FavMapView = require('../public_dashboard/fav_map_view');
var Feed = require('./view');
var ScrollableHeader = require('../common/views/scrollable_header');

/**
 * Entry point for the user feed, bootstraps all dependency models and application.
 */
$(function() {

  cdb.init(function() {

    cdb.templates.namespace = 'cartodb/';
    cdb.config.set(window.config);
    cdb.config.set('url_prefix', window.base_url);

    var userTourView = new UserTourView({
      el: $('.js-user-tour')
    });

    var userIndustriesView = new UserIndustriesView({
      el: $('.js-user-industries')
    });

    var userResourcesView = new UserResourcesView({
      el: $('.js-user-resources')
    });

    var scrollableHeader = new ScrollableHeader({
      el: $('.js-Navmenu'),
      anchorPoint: 520
    });

    var authenticatedUser = new cdb.open.AuthenticatedUser();

    $(document.body).bind('click', function() {
      cdb.god.trigger('closeDialogs');
    });

    authenticatedUser.bind('change', function() {
      if (authenticatedUser.get('username')) {
        var user = new cdb.admin.User(authenticatedUser.attributes);
        var userSettingsView = new UserSettingsView({
          el: $('.js-user-settings'),
          model: user
        });
        userSettingsView.render();

        var userDashboardUrl = user.viewUrl().dashboard();
        $('.js-user-info .UserAvatar-img').wrap($('<a>', {
          href: userDashboardUrl
        }));

        $('.js-login').hide();
        $('.js-learn').show();
      }
    });

    var favMapView = new FavMapView(window.favMapViewAttrs);
    favMapView.render();

    var feed = new Feed({
      el: $('.js-feed'),
      authenticatedUser: authenticatedUser
    });

    feed.render();
    authenticatedUser.fetch();
  });
});
<|endoftext|>


<commit_before>'use babel';
import invariant from 'invariant';
import type { BufferDetails, GridSize, Mode, RedrawUpdates } from './types';
import type { Nvim } from 'promised-neovim-client';
import { getBufferContents, getBuffer, getPaneAndTextEditorForBuffer } from './neovim-util';
import {shouldIgnoreOnKeydown, getVimSpecialCharInput, getVimInputFromKeyCode} from './input';
import Screen from './Screen';
import { $$textEditorBufferNumber } from './consts';
import { inferModeFromCommandLineText } from './command-line';
import CommandLineInputElement from './CommandLineInputElement';

const $$textEditorInputHandler = Symbol.for('Neovimbed/TextEditorInputHandler');

type StatusLine = {
    windowNumber: number;
    bufferNumber: number;
    windowWidth: number;
    windowHeight: number;
    cursorColumn: number;
    cursorRow: number;
    totalLineCount: number;
    lastLineLength: number;
    modified: boolean;
}

export default class LegacyVirtualWindowManager {

    gridSize: GridSize;
    client: Nvim;
    screen: Screen;
    mode: Mode = 'normal';

    queuedBufferUpdates: Object<number, Function> = {};

    lineNumberColumns: number = 6;

    statusLineNumber: number;
    commandLineNumber: number;

    pendingUpdate = {
        row: 0,
        colStart: 0,
        colEnd: 0,
    };

    constructor(client: Nvim, gridSize: GridSize) {
        this.gridSize = gridSize;
        this.statusLineNumber = gridSize.rows - 2;
        this.commandLineNumber = gridSize.rows - 1;
        this.client = client;
        this.screen = new Screen(gridSize, this.lineNumberColumns);
        this.commandLine = new CommandLineInputElement();
        this.commandLine.init();

        window.neovimbed = window.neovimbed || {};

        window.neovimbed.printCells = () => {
            console.info(this.screen.cells.map(line => line.join('')).join('\n'));
        };
        window.neovimbed.printNvimBuffer = async () => {
            const buffer = await client.getCurrentBuffer();
            const lineCount = await buffer.lineCount();
            const lines = await buffer.getLineSlice(0, lineCount, true, true);
            console.log(lines.join("\n"));
        };
    }

    /**
     * Convert a cell position to a text editor position
     */
    cellToTextEditorPosition(row, column) {
        invariant(row < this.screen.cells.length, 'row must be < than grid row count');
        const lineNumberText = this.screen.cells[row].slice(0, this.lineNumberColumns).join('');
        const lineNumber = Number(lineNumberText) - 1;
        invariant(
            !Number.isNaN(lineNumber),
            `Invalid line number parsed for row ${row}. Line was ${lineNumberText}.`);
        return [lineNumber, column - this.lineNumberColumns];
    }

    async initialise() {
        // This is used to send various bits of information that we have
        // difficulty getting otherwise. See https://github.com/neovim/neovim/issues/4763
        // for what stops us getting some of this information as needed.
        await this.client.command(
            `set statusline=%n/%{winnr()}/%{winwidth(winnr())}x%{winheight(winnr())}/%{col('.')},%{line('.')}/%L/%{len(getline(line('$')))}/%{&modified}`)
        // Regex that parses the status line we receive into each component.
        // See parseStatusLine
        this.statusLineRegex = new RegExp('([0-9]+)/([0-9]+)/([0-9]+)x([0-9]+)/([0-9]+),([0-9]+)/([0-9]+)/([0-9]+)/([0|1])')
        return this.client.command(`se nu norelativenumber numberwidth=${this.lineNumberColumns}`);
    }

    parseStatusLine(line:string) : ?StatusLine {
        const match = line.match(this.statusLineRegex);
        if (!match) return null;
        const values = match.slice(1, 10).map(Number);
        const [bufferNumber, windowNumber, windowWidth, windowHeight, cursorColumn, cursorRow, totalLineCount, lastLineLength, modified] = values;
        const statusLine = {
            windowNumber, bufferNumber, windowWidth, windowHeight, cursorColumn, cursorRow, totalLineCount, lastLineLength,
            modified: !!modified,
        };
        return statusLine;
    }

    getScreenLineText(lineNumber) {
        invariant(lineNumber < this.screen.cells.length,
                  'lineNumber must be < than number of rows in the grid');
        return this.screen.cells[lineNumber].join('');
    }

    getStatusLineText() {
        return this.getScreenLineText(this.statusLineNumber);
    }

    getCommandLineText() {
        return this.getScreenLineText(this.commandLineNumber);
    }

    /**
     * All key events get passed straight through to VIM to handle
     */
    onKeyDown(e:KeyboardEvent) : boolean {
        const specialSequence = getVimSpecialCharInput(e);
        if (shouldIgnoreOnKeydown(e)) {
            return false;
        }
        e.stopPropagation();
        e.preventDefault();
        const input = specialSequence == null ? getVimInputFromKeyCode(e) : specialSequence;
        this.client.input(input);

        return false;
    }

    /**
     * Whenever a buffer is read in neovim we force TextEditor to match it's
     * contents
     */
    async onReadBuffer(bufferDetails:BufferDetails) : Promise {
        let { path } = bufferDetails;
        if (null == path) {
            path = '';
        }
        const editor:TextEditor = await atom.workspace.open(path);
        const contents = await getBufferContents(this.client, bufferDetails.bufferNumber);
        //editor.setText(contents.join("\n"));
        // $FlowIssue
        editor[$$textEditorBufferNumber] = bufferDetails.bufferNumber;
        if (this.queuedBufferUpdates[bufferDetails.bufferNumber]) {
            this.queuedBufferUpdates[bufferDetails.bufferNumber](editor);
            delete this.queuedBufferUpdates[bufferDetails.bufferNumber];
        }
    }

    async onEnterBuffer(details:BufferDetails) : Promise {
        try {
            const { pane, editor } = getPaneAndTextEditorForBuffer(details.bufferNumber);
            pane.activateItem(editor);
        } catch (e) {
            console.warn(e.message);
        }
    }

    async onNewFileBuffer(buffer:BufferDetails) : Promise {
    }

    async onNewEmptyBuffer(buffer:BufferDetails) : Promise {
    }

    async onDeleteBuffer(buffer:BufferDetails) : Promise {
    }

    onAddTextEditor(pane: atom$Pane, editor: atom$TextEditor) : void {
        const path = editor.getPath();
        this.client.command(path ? `e ${path}` : 'enew').catch(e => {
            // E325: ATTENTION is start of string when you have a swap file
            // We only receive this message after a decision has been made
            // about what to do. We can safely ignore this one.
            if (!e.message.match(/E325: ATTENTION/)) {
                console.error(`Unexpected error opening file '${path}'`, e);
                return;
            }
        });
        // $FlowIssue
        if (!editor[$$textEditorInputHandler]) {
            // $FlowIssue
            editor[$$textEditorInputHandler] = true;
            const view = atom.views.getView(editor);
            view.addEventListener('keydown', this.onKeyDown.bind(this));
        }
    }

    onRemoveTextEditor(pane: atom$Pane, editor: atom$TextEditor, moved: boolean) : void {
        console.log('REMOVE TEXT EDITOR', pane, editor, moved);
    }

    onRemovePane(pane: atom$Pane) : void {
    }

    async onAddPane(pane: atom$Pane) {
        // console.log('add pane', pane);
    }

    async onActivePaneItem(item: mixed) {
        const bufferNumber = item[$$textEditorBufferNumber];
        if (bufferNumber != null) {
            const buffer = await getBuffer(this.client, bufferNumber);
            this.client.setCurrentBuffer(buffer);
        } else {
            console.warn('Active item changed in atom but no matching buffer found in neovim');
        }
    }

    async onDidChangeCursorPosition(editor, cursor) {
        const { newBufferPosition: { row, column } } = cursor;
        const statusLine = this.parseStatusLine(this.getStatusLineText());
        // vim is 1 based for line numbers; atom is 0 based
        const vimRow = statusLine.cursorRow - 1;
        // Column we get back on status line is 1 based, vim itself is 0 based.
        // Atom is 0 based
        const vimColumn = statusLine.cursorColumn - 1;
        if (vimRow !== row || vimColumn !== column) {
            const win = await this.client.getCurrentWindow();
            // As above - vim is 1 based for rows and 0 based for column
            win.setCursor([row + 1, column]);
        }
    }

    batch = [];

    /**
     * Batch update for processing at end of redraw call. The only reason this
     * is done is because we rely on the status line telling us which buffer
     * the update applies to so we have to wait until the status line is
     * updated (which happens after earlier lines) before we can update the
     * relevant Atom buffer.
     *
     * We can't use getCurrentBuffer() due to
     * https://github.com/neovim/neovim/issues/4763
     */
    batchUpdate() {
        let { row, colStart, colEnd } = this.pendingUpdate;
        const { cursor } = this.screen;

        this.pendingUpdate.row = cursor.row;
        this.pendingUpdate.colStart = this.pendingUpdate.colEnd = cursor.col;

        // Skip cells up to number column width so we don't output line numbers
        colStart = Math.max(this.lineNumberColumns, colStart);

        const lineNumberString = this.screen.cells[row].slice(0, this.lineNumberColumns).join('');

        // If start of number string is '~' then we have reached the end of the
        // file
        if (lineNumberString[0] === '~' || colStart >= colEnd || row >= (this.statusLineNumber)) {
            return;
        }

        const text = this.screen.cells[row].slice(colStart, colEnd).join('');
        // As the cells as just the visible rows we need to translate the cell
        // row number to the actual line number. We have line numbers enabled
        // to easily allow this - extract the line number from the cell
        // contents.
        const lineNumber = Number(lineNumberString) - 1;
        const range = [
            [lineNumber, colStart - this.lineNumberColumns],
            [lineNumber, colEnd - this.lineNumberColumns]
        ];

        this.batch.push([range, text]);
    }

    /**
     * Apply currently batched updates
     */
    flush() {
        const commandLineText = this.getCommandLineText()
        this.commandLine.setText(commandLineText);
        this.setMode(inferModeFromCommandLineText(this.mode, commandLineText));
        this.batchUpdate();
        const statusLine = this.parseStatusLine(this.getStatusLineText());
        if (!statusLine) {
            console.warn('Expected to find a status line but was unable to parse it',
                         this.getStatusLineText());
            return;
        }
        const changes = this.batch.slice();
        this.batch = [];
        const cursor = this.screen.cursor;
        let applyChanges = async (textEditor) => {
            if (cursor.row < this.statusLineNumber) {
                textEditor.setCursorBufferPosition(this.cellToTextEditorPosition(cursor.row, cursor.col));
            }
            for (const [range, text] of changes) {
                const [start, end] = range;
                const lineCount = textEditor.getLineCount();
                const endRangeLine = end[0] + 1;
                // If trying to set text outside of current TextEditor buffer
                // size first need to expand the buffer - otherwise text ends
                // up appended to the current last line in the buffer.
                if (lineCount < endRangeLine) {
                    const deficit = endRangeLine - lineCount + 1;
                    const buffer = textEditor.getBuffer();
                    textEditor.setTextInBufferRange(
                        [[lineCount + 1, 0], [lineCount + deficit, 0]],
                        Array.from({ length: deficit }, () => '').join("\n")
                    );
                }
                textEditor.setTextInBufferRange(range, text);
                const buffer = textEditor.getBuffer();
            }
            const textEditorLineCount = textEditor.getLineCount();
            // TODO: Atom has option to append new lines to files - will this
            // mess this up?
            if (statusLine.modified && textEditorLineCount > statusLine.totalLineCount) {
                // If text editor has more lines than status line indicates
                // remove everything from that point onwards
                const buffer = textEditor.getBuffer();
                buffer.deleteRows(statusLine.totalLineCount, textEditorLineCount);
                //const lastLine = statusLine.totalLineCount - 1;
                //const lastChangeRowLength = buffer.lineLengthForRow(lastLine);
                //buffer.delete([[lastLine, statusLine.lastLineLength], [lastLine, lastChangeRowLength]]);
            }
            if (textEditorLineCount < statusLine.totalLineCount) {
                //  If text editor length is now less than the neovim buffer we
                //  need to fetch the missing lines.
                //  TODO: This is naive and only works if the missing lines are
                //  to the bottom of the file - what if deletion is above? Can
                //  that happen?
                const buffer = textEditor.getBuffer();
                const neovimBuffer = await getBuffer(this.client, statusLine.bufferNumber);
                const lines = await neovimBuffer.getLineSlice(textEditorLineCount, statusLine.totalLineCount, true, true);
                textEditor.setTextInBufferRange(
                    [
                        [textEditorLineCount - 1, buffer.lineLengthForRow(textEditorLineCount - 1)],
                        [statusLine.totalLineCount, 0]
                    ], '\n'+lines.join("\n"));
            }
        };
        for (const textEditor of atom.workspace.getTextEditors()) {
            if (textEditor[$$textEditorBufferNumber] === statusLine.bufferNumber) {
                applyChanges(textEditor);
                return;
            }
        }
        // TextEditor for this buffer was not found; queue update for when
        // TextEditor is loaded.
        if (this.queuedBufferUpdates[statusLine.bufferNumber]) {
            const currentUpdate =
                this.queuedBufferUpdates[statusLine.bufferNumber];
            const combinedUpdate = textEditor => {
                currentUpdate(textEditor);
                applyChanges(textEditor);
            };
            this.queuedBufferUpdates[statusLine.bufferNumber] = combinedUpdate;
        } else {
            this.queuedBufferUpdates[statusLine.bufferNumber] = applyChanges;
        }
    }

    put(text) {
        let { cursor } = this.screen;
        if (cursor.row !== this.pendingUpdate.row) {
            this.batchUpdate();
        }

        this.screen.put(text);
        cursor = this.screen.cursor;
        this.pendingUpdate.colStart = Math.min(cursor.col - 1, this.pendingUpdate.colStart);
        this.pendingUpdate.colEnd = Math.max(cursor.col, this.pendingUpdate.colEnd);
    }

    scroll(count) {
        this.batchUpdate();
        this.screen.scroll(count);
    }

    set_scroll_region(top, bot, left, right) {
        this.screen.set_scroll_region(top, bot, left, right)
    }

    clear() {
        this.screen.clear();
    }

    eol_clear() {
        this.screen.eol_clear();
        this.batchUpdate();
        this.pendingUpdate.colEnd = this.gridSize.columns;
        this.batchUpdate();
    }

    cursor_goto(row, col) {
        this.screen.cursor_goto(row, col);
    }

    mode_change(mode:Mode) {
        this.setMode(mode);
    }

    clear_region(top, bot, left, right) {
        this.batchUpdate();
        this.screen.clear_region(top, bot, left, right);
    }

    async redraw(messages:RedrawUpdates) {
        for (const [message, ...updates] of messages) {
            if (this[message]) {
                for (const update of updates) {
                    // $FlowIssue Issues with either spread on undefined or tuples
                    this[message](...update);
                }
                if (message === 'put') {
                    const str = updates.map(update => update[0]).join('');
                    console.log('put ', str);
                } else {
                    console.log(message, ...updates);
                }
            } else {
                console.log('unhandled', message, ...updates);
            }
        }
        this.flush();
    }

    modeChangeListeners = [];

    onModeChange(listener) {
        this.modeChangeListeners.push(listener);
    }

    setMode(mode:Mode) {
        if (mode === this.mode) return;
        this.modeChangeListeners.forEach(listener => listener(this.mode, mode));
        this.mode = mode;
    }

    exit() : void {
    }

}
<commit_msg>Set TextEditor text when buffer is loaded<commit_after>'use babel';
import invariant from 'invariant';
import type { BufferDetails, GridSize, Mode, RedrawUpdates } from './types';
import type { Nvim } from 'promised-neovim-client';
import { getBufferContents, getBuffer, getPaneAndTextEditorForBuffer } from './neovim-util';
import {shouldIgnoreOnKeydown, getVimSpecialCharInput, getVimInputFromKeyCode} from './input';
import Screen from './Screen';
import { $$textEditorBufferNumber } from './consts';
import { inferModeFromCommandLineText } from './command-line';
import CommandLineInputElement from './CommandLineInputElement';

const $$textEditorInputHandler = Symbol.for('Neovimbed/TextEditorInputHandler');

type StatusLine = {
    windowNumber: number;
    bufferNumber: number;
    windowWidth: number;
    windowHeight: number;
    cursorColumn: number;
    cursorRow: number;
    totalLineCount: number;
    lastLineLength: number;
    modified: boolean;
}

export default class LegacyVirtualWindowManager {

    gridSize: GridSize;
    client: Nvim;
    screen: Screen;
    mode: Mode = 'normal';

    queuedBufferUpdates: Object<number, Function> = {};

    lineNumberColumns: number = 6;

    statusLineNumber: number;
    commandLineNumber: number;

    pendingUpdate = {
        row: 0,
        colStart: 0,
        colEnd: 0,
    };

    constructor(client: Nvim, gridSize: GridSize) {
        this.gridSize = gridSize;
        this.statusLineNumber = gridSize.rows - 2;
        this.commandLineNumber = gridSize.rows - 1;
        this.client = client;
        this.screen = new Screen(gridSize, this.lineNumberColumns);
        this.commandLine = new CommandLineInputElement();
        this.commandLine.init();

        window.neovimbed = window.neovimbed || {};

        window.neovimbed.printCells = () => {
            console.info(this.screen.cells.map(line => line.join('')).join('\n'));
        };
        window.neovimbed.printNvimBuffer = async () => {
            const buffer = await client.getCurrentBuffer();
            const lineCount = await buffer.lineCount();
            const lines = await buffer.getLineSlice(0, lineCount, true, true);
            console.log(lines.join("\n"));
        };
    }

    /**
     * Convert a cell position to a text editor position
     */
    cellToTextEditorPosition(row, column) {
        invariant(row < this.screen.cells.length, 'row must be < than grid row count');
        const lineNumberText = this.screen.cells[row].slice(0, this.lineNumberColumns).join('');
        const lineNumber = Number(lineNumberText) - 1;
        invariant(
            !Number.isNaN(lineNumber),
            `Invalid line number parsed for row ${row}. Line was ${lineNumberText}.`);
        return [lineNumber, column - this.lineNumberColumns];
    }

    async initialise() {
        // This is used to send various bits of information that we have
        // difficulty getting otherwise. See https://github.com/neovim/neovim/issues/4763
        // for what stops us getting some of this information as needed.
        await this.client.command(
            `set statusline=%n/%{winnr()}/%{winwidth(winnr())}x%{winheight(winnr())}/%{col('.')},%{line('.')}/%L/%{len(getline(line('$')))}/%{&modified}`)
        // Regex that parses the status line we receive into each component.
        // See parseStatusLine
        this.statusLineRegex = new RegExp('([0-9]+)/([0-9]+)/([0-9]+)x([0-9]+)/([0-9]+),([0-9]+)/([0-9]+)/([0-9]+)/([0|1])')
        return this.client.command(`se nu norelativenumber numberwidth=${this.lineNumberColumns}`);
    }

    parseStatusLine(line:string) : ?StatusLine {
        const match = line.match(this.statusLineRegex);
        if (!match) return null;
        const values = match.slice(1, 10).map(Number);
        const [bufferNumber, windowNumber, windowWidth, windowHeight, cursorColumn, cursorRow, totalLineCount, lastLineLength, modified] = values;
        const statusLine = {
            windowNumber, bufferNumber, windowWidth, windowHeight, cursorColumn, cursorRow, totalLineCount, lastLineLength,
            modified: !!modified,
        };
        return statusLine;
    }

    getScreenLineText(lineNumber) {
        invariant(lineNumber < this.screen.cells.length,
                  'lineNumber must be < than number of rows in the grid');
        return this.screen.cells[lineNumber].join('');
    }

    getStatusLineText() {
        return this.getScreenLineText(this.statusLineNumber);
    }

    getCommandLineText() {
        return this.getScreenLineText(this.commandLineNumber);
    }

    /**
     * All key events get passed straight through to VIM to handle
     */
    onKeyDown(e:KeyboardEvent) : boolean {
        const specialSequence = getVimSpecialCharInput(e);
        if (shouldIgnoreOnKeydown(e)) {
            return false;
        }
        e.stopPropagation();
        e.preventDefault();
        const input = specialSequence == null ? getVimInputFromKeyCode(e) : specialSequence;
        this.client.input(input);

        return false;
    }

    /**
     * Whenever a buffer is read in neovim we force TextEditor to match it's
     * contents
     */
    async onReadBuffer(bufferDetails:BufferDetails) : Promise {
        let { path } = bufferDetails;
        if (null == path) {
            path = '';
        }
        const editor:TextEditor = await atom.workspace.open(path);
        const contents = await getBufferContents(this.client, bufferDetails.bufferNumber);
        editor.setText(contents.join("\n"));
        // $FlowIssue
        editor[$$textEditorBufferNumber] = bufferDetails.bufferNumber;
        if (this.queuedBufferUpdates[bufferDetails.bufferNumber]) {
            this.queuedBufferUpdates[bufferDetails.bufferNumber](editor);
            delete this.queuedBufferUpdates[bufferDetails.bufferNumber];
        }
    }

    async onEnterBuffer(details:BufferDetails) : Promise {
        try {
            const { pane, editor } = getPaneAndTextEditorForBuffer(details.bufferNumber);
            pane.activateItem(editor);
        } catch (e) {
            console.warn(e.message);
        }
    }

    async onNewFileBuffer(buffer:BufferDetails) : Promise {
    }

    async onNewEmptyBuffer(buffer:BufferDetails) : Promise {
    }

    async onDeleteBuffer(buffer:BufferDetails) : Promise {
    }

    onAddTextEditor(pane: atom$Pane, editor: atom$TextEditor) : void {
        const path = editor.getPath();
        this.client.command(path ? `e ${path}` : 'enew').catch(e => {
            // E325: ATTENTION is start of string when you have a swap file
            // We only receive this message after a decision has been made
            // about what to do. We can safely ignore this one.
            if (!e.message.match(/E325: ATTENTION/)) {
                console.error(`Unexpected error opening file '${path}'`, e);
                return;
            }
        });
        // $FlowIssue
        if (!editor[$$textEditorInputHandler]) {
            // $FlowIssue
            editor[$$textEditorInputHandler] = true;
            const view = atom.views.getView(editor);
            view.addEventListener('keydown', this.onKeyDown.bind(this));
        }
    }

    onRemoveTextEditor(pane: atom$Pane, editor: atom$TextEditor, moved: boolean) : void {
        console.log('REMOVE TEXT EDITOR', pane, editor, moved);
    }

    onRemovePane(pane: atom$Pane) : void {
    }

    async onAddPane(pane: atom$Pane) {
        // console.log('add pane', pane);
    }

    async onActivePaneItem(item: mixed) {
        const bufferNumber = item[$$textEditorBufferNumber];
        if (bufferNumber != null) {
            const buffer = await getBuffer(this.client, bufferNumber);
            this.client.setCurrentBuffer(buffer);
        } else {
            console.warn('Active item changed in atom but no matching buffer found in neovim');
        }
    }

    async onDidChangeCursorPosition(editor, cursor) {
        const { newBufferPosition: { row, column } } = cursor;
        const statusLine = this.parseStatusLine(this.getStatusLineText());
        // vim is 1 based for line numbers; atom is 0 based
        const vimRow = statusLine.cursorRow - 1;
        // Column we get back on status line is 1 based, vim itself is 0 based.
        // Atom is 0 based
        const vimColumn = statusLine.cursorColumn - 1;
        if (vimRow !== row || vimColumn !== column) {
            const win = await this.client.getCurrentWindow();
            // As above - vim is 1 based for rows and 0 based for column
            win.setCursor([row + 1, column]);
        }
    }

    batch = [];

    /**
     * Batch update for processing at end of redraw call. The only reason this
     * is done is because we rely on the status line telling us which buffer
     * the update applies to so we have to wait until the status line is
     * updated (which happens after earlier lines) before we can update the
     * relevant Atom buffer.
     *
     * We can't use getCurrentBuffer() due to
     * https://github.com/neovim/neovim/issues/4763
     */
    batchUpdate() {
        let { row, colStart, colEnd } = this.pendingUpdate;
        const { cursor } = this.screen;

        this.pendingUpdate.row = cursor.row;
        this.pendingUpdate.colStart = this.pendingUpdate.colEnd = cursor.col;

        // Skip cells up to number column width so we don't output line numbers
        colStart = Math.max(this.lineNumberColumns, colStart);

        const lineNumberString = this.screen.cells[row].slice(0, this.lineNumberColumns).join('');

        // If start of number string is '~' then we have reached the end of the
        // file
        if (lineNumberString[0] === '~' || colStart >= colEnd || row >= (this.statusLineNumber)) {
            return;
        }

        const text = this.screen.cells[row].slice(colStart, colEnd).join('');
        // As the cells as just the visible rows we need to translate the cell
        // row number to the actual line number. We have line numbers enabled
        // to easily allow this - extract the line number from the cell
        // contents.
        const lineNumber = Number(lineNumberString) - 1;
        const range = [
            [lineNumber, colStart - this.lineNumberColumns],
            [lineNumber, colEnd - this.lineNumberColumns]
        ];

        this.batch.push([range, text]);
    }

    /**
     * Apply currently batched updates
     */
    flush() {
        const commandLineText = this.getCommandLineText()
        this.commandLine.setText(commandLineText);
        this.setMode(inferModeFromCommandLineText(this.mode, commandLineText));
        this.batchUpdate();
        const statusLine = this.parseStatusLine(this.getStatusLineText());
        if (!statusLine) {
            console.warn('Expected to find a status line but was unable to parse it',
                         this.getStatusLineText());
            return;
        }
        const changes = this.batch.slice();
        this.batch = [];
        const cursor = this.screen.cursor;
        let applyChanges = async (textEditor) => {
            if (cursor.row < this.statusLineNumber) {
                textEditor.setCursorBufferPosition(this.cellToTextEditorPosition(cursor.row, cursor.col));
            }
            for (const [range, text] of changes) {
                const [start, end] = range;
                const lineCount = textEditor.getLineCount();
                const endRangeLine = end[0] + 1;
                // If trying to set text outside of current TextEditor buffer
                // size first need to expand the buffer - otherwise text ends
                // up appended to the current last line in the buffer.
                if (lineCount < endRangeLine) {
                    const deficit = endRangeLine - lineCount + 1;
                    const buffer = textEditor.getBuffer();
                    textEditor.setTextInBufferRange(
                        [[lineCount + 1, 0], [lineCount + deficit, 0]],
                        Array.from({ length: deficit }, () => '').join("\n")
                    );
                }
                textEditor.setTextInBufferRange(range, text);
                const buffer = textEditor.getBuffer();
            }
            const textEditorLineCount = textEditor.getLineCount();
            // TODO: Atom has option to append new lines to files - will this
            // mess this up?
            if (statusLine.modified && textEditorLineCount > statusLine.totalLineCount) {
                // If text editor has more lines than status line indicates
                // remove everything from that point onwards
                const buffer = textEditor.getBuffer();
                buffer.deleteRows(statusLine.totalLineCount, textEditorLineCount);
                //const lastLine = statusLine.totalLineCount - 1;
                //const lastChangeRowLength = buffer.lineLengthForRow(lastLine);
                //buffer.delete([[lastLine, statusLine.lastLineLength], [lastLine, lastChangeRowLength]]);
            }
            if (textEditorLineCount < statusLine.totalLineCount) {
                //  If text editor length is now less than the neovim buffer we
                //  need to fetch the missing lines.
                //  TODO: This is naive and only works if the missing lines are
                //  to the bottom of the file - what if deletion is above? Can
                //  that happen?
                const buffer = textEditor.getBuffer();
                const neovimBuffer = await getBuffer(this.client, statusLine.bufferNumber);
                const lines = await neovimBuffer.getLineSlice(textEditorLineCount, statusLine.totalLineCount, true, true);
                textEditor.setTextInBufferRange(
                    [
                        [textEditorLineCount - 1, buffer.lineLengthForRow(textEditorLineCount - 1)],
                        [statusLine.totalLineCount, 0]
                    ], '\n'+lines.join("\n"));
            }
        };
        for (const textEditor of atom.workspace.getTextEditors()) {
            if (textEditor[$$textEditorBufferNumber] === statusLine.bufferNumber) {
                applyChanges(textEditor);
                return;
            }
        }
        // TextEditor for this buffer was not found; queue update for when
        // TextEditor is loaded.
        if (this.queuedBufferUpdates[statusLine.bufferNumber]) {
            const currentUpdate =
                this.queuedBufferUpdates[statusLine.bufferNumber];
            const combinedUpdate = textEditor => {
                currentUpdate(textEditor);
                applyChanges(textEditor);
            };
            this.queuedBufferUpdates[statusLine.bufferNumber] = combinedUpdate;
        } else {
            this.queuedBufferUpdates[statusLine.bufferNumber] = applyChanges;
        }
    }

    put(text) {
        let { cursor } = this.screen;
        if (cursor.row !== this.pendingUpdate.row) {
            this.batchUpdate();
        }

        this.screen.put(text);
        cursor = this.screen.cursor;
        this.pendingUpdate.colStart = Math.min(cursor.col - 1, this.pendingUpdate.colStart);
        this.pendingUpdate.colEnd = Math.max(cursor.col, this.pendingUpdate.colEnd);
    }

    scroll(count) {
        this.batchUpdate();
        this.screen.scroll(count);
    }

    set_scroll_region(top, bot, left, right) {
        this.screen.set_scroll_region(top, bot, left, right)
    }

    clear() {
        this.screen.clear();
    }

    eol_clear() {
        this.screen.eol_clear();
        this.batchUpdate();
        this.pendingUpdate.colEnd = this.gridSize.columns;
        this.batchUpdate();
    }

    cursor_goto(row, col) {
        this.screen.cursor_goto(row, col);
    }

    mode_change(mode:Mode) {
        this.setMode(mode);
    }

    clear_region(top, bot, left, right) {
        this.batchUpdate();
        this.screen.clear_region(top, bot, left, right);
    }

    async redraw(messages:RedrawUpdates) {
        for (const [message, ...updates] of messages) {
            if (this[message]) {
                for (const update of updates) {
                    // $FlowIssue Issues with either spread on undefined or tuples
                    this[message](...update);
                }
                if (message === 'put') {
                    // const str = updates.map(update => update[0]).join('');
                    // console.log('put ', str);
                } else {
                    // console.log(message, ...updates);
                }
            } else {
                // console.log('unhandled', message, ...updates);
            }
        }
        this.flush();
    }

    modeChangeListeners = [];

    onModeChange(listener) {
        this.modeChangeListeners.push(listener);
    }

    setMode(mode:Mode) {
        if (mode === this.mode) return;
        this.modeChangeListeners.forEach(listener => listener(this.mode, mode));
        this.mode = mode;
    }

    exit() : void {
    }

}
<|endoftext|>


<commit_before>;(function() {
  "use strict";

  var BaseController = require("BaseController");

  new BaseController({
    siteName: "Pandora",
    play: ".playButton",
    pause: ".pauseButton",
    playNext: ".skipButton",
    like: ".thumbUpButton > a",
    dislike: ".thumbDownButton > a",

    song: ".songTitle",
    artist: ".artistSummary",
    album: ".albumTitle"
  });
})();
<commit_msg>Change Pandora song data selectors to select current track<commit_after>;(function() {
  "use strict";

  var BaseController = require("BaseController");

  new BaseController({
    siteName: "Pandora",
    play: ".playButton",
    pause: ".pauseButton",
    playNext: ".skipButton",
    like: ".thumbUpButton > a",
    dislike: ".thumbDownButton > a",

    song: ".playerBarSong",
    artist: ".playerBarArtist",
    album: ".playerBarAlbum"
  });
})();
<|endoftext|>


<commit_before>// used to interface to Espruino emscripten...
var jsRXCallback;
var jsIdleTimeout;

// Flash memory handling
var flashMemory = new Uint8Array(FLASH_SIZE);
var maxFlashMemory = 0;
flashMemory.fill(255);

if ("undefined" != typeof window) {
  if (window.localStorage) {
    let s = localStorage.getItem("BANGLE_STORAGE");
    if (s!=null) {
      s.split(",").forEach((n,i)=>{
        flashMemory[i] = parseInt(n);
        maxFlashMemory = i;
      });
    }
  }
  window.addEventListener("unload", function() { // Save storage contents on exit
    var a = new Uint8Array(flashMemory.buffer, 0, maxFlashMemory+1);
    localStorage.setItem("BANGLE_STORAGE", a.toString()); // 1,2,3,4, etc...
  });
}
function eraseAll() {
  maxFlashMemory = 0;
  flashMemory.fill(255);
  localStorage.setItem("BANGLE_STORAGE", null);
}

// Pin handling
var hwPinValue = new Uint8Array(PIN_COUNT);
function hwSetPinValue(pin,v) { hwPinValue[pin] = v; }
function hwGetPinValue(pin) { return hwPinValue[pin]; }
function hwFlashWrite(addr,v) { flashMemory[addr] = v; if (addr>maxFlashMemory) maxFlashMemory=addr; }
function hwFlashRead(addr) { return flashMemory[addr]; }

function jsHandleIO() {
  var device;
  var l = "";
  do {
    device = Module.ccall('jshGetDeviceToTransmit', 'number', [], []);
    if (device) {
      var ch = Module.ccall('jshGetCharToTransmit', 'number', ['number'], [device]);
      if (jsRXCallback) jsRXCallback(ch);
      l += String.fromCharCode(ch);
      var ll = l.split("\n");
      if (ll.length>1) {
        console.log("EMSCRIPTEN:",ll[0]);
        l = ll[1];
      }
    }
  } while (device);
}
function jsTransmitChar(c) {
  //console.log("TX -> ",c);
  Module.ccall('jshPushIOCharEvent', 'number', ['number','number'], [DEVICE,c]);
  jsIdle();
}
function jsTransmitString(d) {
  for (var i=0;i<d.length;i++) {
    jsTransmitChar(d.charCodeAt(i));
  }
}
function jsTransmitPinEvent(pin) {
  //console.log("TX -> ",c);
  Module.ccall('jsSendPinWatchEvent', 'number', ['number'], [pin]);
  jsIdle();
}
function jsSendTouchEvent(x,y,pts,gesture) {
  //console.log(x,y,pts,gesture);
  Module.ccall('jsSendTouchEvent', 'number', ['number','number','number','number'], [x,y,pts,gesture]);
  jsIdle();
}
function jsIdle() {
  if (jsIdleTimeout) {
    clearTimeout(jsIdleTimeout);
    jsIdleTimeout = undefined;
  }
  var tries = 5;
  var msToNext = -1;
  while (tries-- && msToNext<0) {
    msToNext = Module.ccall('jsIdle', 'number', [], []);
    jsHandleIO();
  }
  if (msToNext<10) msToNext=10;
  jsIdleTimeout = setTimeout(jsIdle,msToNext);
  jsUpdateGfx();
  return msToNext;
}
function jsStopIdle() {
  if (jsIdleTimeout) {
    clearTimeout(jsIdleTimeout);
    jsIdleTimeout = undefined;
  }
}
function jsInit() {
  if ("undefined" != typeof window) {
    jsInitButtons();

    var borderColors = ['FFF', 'FF0', 'F00', '000', '00F', '0FF'];
    var borderColor = 0
    document.getElementById("border").style.color = '#' + borderColors[(borderColor + 1) % borderColors.length];
    document.getElementById("border").addEventListener('click', e => {
      borderColor = ++borderColor % borderColors.length;
      document.getElementById("gfxcanvas").style.borderColor = '#' + borderColors[borderColor];
      document.getElementById("border").style.color = '#' + borderColors[(borderColor + 1) % borderColors.length];
    });

    document.getElementById("screenshot").addEventListener('click', e => {
      document.getElementById("screenshot").href = document.getElementById("gfxcanvas").toDataURL();
      document.getElementById("screenshot").download = "screenshot.png";
    });
  }

  Module.ccall('jsInit', 'number', [], []);
  jsHandleIO();
}
function jsKill() {
  var d = document.getElementById("gfxdiv");
  if (d) d.remove();
  Module.ccall('jsKill', 'number', [], []);
}
function drawLoadingScreen() {
  var canvas = document.getElementById('gfxcanvas');
  var ctx = canvas.getContext('2d');
  ctx.font = "15px Sans";
  ctx.textAlign = "center";
  ctx.fillStyle = "black";
  ctx.fillText("Loading...", GFX_WIDTH/2, GFX_HEIGHT/2);
}
if ("undefined" != typeof window)
  drawLoadingScreen();

/* ===========================================================================
     Frame to frame comms
   ===========================================================================

HOST sends: {type:"rx",for:"emu",data:string}
            {type:"init",for:"emu"} - set up the backchannel

WE send: {type:"tx",from:"emu",data:string}

*/
if ("undefined" != typeof window) {
  var hostWindow = window.parent;
  window.addEventListener('message', function(e) {
    var event = e.data;
    console.log("EMU MESSAGE ---------------------------------------");
    console.log(JSON.stringify(event,null,2));
    console.log("-----------------------------------------------");
    if (typeof event!="object" || event.for!="emu") return;
    switch (event.type) {
      case "init": {
        console.log("HOST WINDOW CONFIGURED");
        hostWindow = e.source;
        post({type:"init"});
        jsInit();
        jsIdle();
      } break;
      case "rx": {
        var d = event.data;
        if (typeof d!="string")
          console.error("receive event expecting data string");
        jsTransmitString(d);
      } break;
      default:
        console.error("Unknown event type ",event.type);
        break;
    }
  });
  console.log("Waiting for posted {type:init} message");
}

function post(msg) {
  msg.from="emu";
  hostWindow.postMessage(msg,"*");
}

jsRXCallback = function(c) {
  post({type:"tx",data:String.fromCharCode(c)});
}

/* ===========================================================================
     Window resizing code
   =========================================================================== */

var dontTrigger = false;
var timerResize;
var WIN_WIDTH = (GFX_WIDTH+10+30);
var WIN_HEIGHT = (GFX_HEIGHT+10+4);
function resizeEnd() {
  //100ms since last resize
  dontTrigger = true;
  window.resizeBy(Math.round(byX*correctingRatio*WIN_WIDTH-window.innerWidth), Math.round(byY*correctingRatio*WIN_HEIGHT-window.innerHeight));
  var scale = correctingRatio*byX;
  if (scale < correctingRatio ) scale = correctingRatio;
  document.getElementById("gfxdiv").style.transform = "translate(-50%,-50%) scale("+scale+","+scale+")";

}
function onResize(e) {
  if ( !dontTrigger ) {
    clearTimeout(timerResize);
    timerResize = setTimeout(resizeEnd, 100);
  } else {
    dontTrigger = false;
  }

  // data collection
  if ( window.innerWidth < Math.floor(WIN_WIDTH*correctingRatio*3) || window.innerHeight < Math.floor(WIN_HEIGHT*correctingRatio*3) ) {
    if ( window.innerWidth < Math.floor(WIN_WIDTH*correctingRatio*2.5) || window.innerHeight < Math.floor(WIN_HEIGHT*correctingRatio*2.5) ) {
      byX=2;byY=2;
    } else {
      byX=3;byY=3;
    }
  } else {
    byX=3;byY=3;
  }
  if ( window.innerWidth < Math.floor(WIN_WIDTH*correctingRatio*2) || window.innerHeight < Math.floor(WIN_HEIGHT*correctingRatio*2) ) {
    if ( window.innerWidth < Math.floor(WIN_WIDTH*correctingRatio*1.5) || window.innerHeight < Math.floor(WIN_HEIGHT*correctingRatio*1.5) ) {
      byX=1;byY=1;
    } else {
      byX=2;byY=2;
    }
  }
  if ( window.innerWidth < Math.floor(WIN_WIDTH*correctingRatio) || window.innerHeight < Math.floor(WIN_HEIGHT*correctingRatio) ) {
    byX=1;byY=1;
  }
}

if ("undefined" != typeof window) {
  var correctingRatio = 1/window.devicePixelRatio;
  var byX=1,byY=1;
  window.addEventListener('resize', onResize);
  onResize();
}
<commit_msg>allow output to be captured<commit_after>// used to interface to Espruino emscripten...
var jsRXCallback;
var jsIdleTimeout;

// Flash memory handling
var flashMemory = new Uint8Array(FLASH_SIZE);
var maxFlashMemory = 0;
flashMemory.fill(255);

if ("undefined" != typeof window) {
  if (window.localStorage) {
    let s = localStorage.getItem("BANGLE_STORAGE");
    if (s!=null) {
      s.split(",").forEach((n,i)=>{
        flashMemory[i] = parseInt(n);
        maxFlashMemory = i;
      });
    }
  }
  window.addEventListener("unload", function() { // Save storage contents on exit
    var a = new Uint8Array(flashMemory.buffer, 0, maxFlashMemory+1);
    localStorage.setItem("BANGLE_STORAGE", a.toString()); // 1,2,3,4, etc...
  });
}
function eraseAll() {
  maxFlashMemory = 0;
  flashMemory.fill(255);
  localStorage.setItem("BANGLE_STORAGE", null);
}

// Pin handling
var hwPinValue = new Uint8Array(PIN_COUNT);
function hwSetPinValue(pin,v) { hwPinValue[pin] = v; }
function hwGetPinValue(pin) { return hwPinValue[pin]; }
function hwFlashWrite(addr,v) { flashMemory[addr] = v; if (addr>maxFlashMemory) maxFlashMemory=addr; }
function hwFlashRead(addr) { return flashMemory[addr]; }

function jsHandleIO() {
  var device;
  var l = "";
  do {
    device = Module.ccall('jshGetDeviceToTransmit', 'number', [], []);
    if (device) {
      var ch = Module.ccall('jshGetCharToTransmit', 'number', ['number'], [device]);
      if (jsRXCallback) jsRXCallback(ch);
      l += String.fromCharCode(ch);
      var ll = l.split("\n");
      if (ll.length>1) {
        if ("undefined" != typeof onConsoleOutput)
          onConsoleOutput(ll[0]);
        console.log("EMSCRIPTEN:",ll[0]);
        l = ll[1];
      }
    }
  } while (device);
}
function jsTransmitChar(c) {
  //console.log("TX -> ",c);
  Module.ccall('jshPushIOCharEvent', 'number', ['number','number'], [DEVICE,c]);
  jsIdle();
}
function jsTransmitString(d) {
  for (var i=0;i<d.length;i++) {
    jsTransmitChar(d.charCodeAt(i));
  }
}
function jsTransmitPinEvent(pin) {
  //console.log("TX -> ",c);
  Module.ccall('jsSendPinWatchEvent', 'number', ['number'], [pin]);
  jsIdle();
}
function jsSendTouchEvent(x,y,pts,gesture) {
  //console.log(x,y,pts,gesture);
  Module.ccall('jsSendTouchEvent', 'number', ['number','number','number','number'], [x,y,pts,gesture]);
  jsIdle();
}
function jsIdle() {
  if (jsIdleTimeout) {
    clearTimeout(jsIdleTimeout);
    jsIdleTimeout = undefined;
  }
  var tries = 5;
  var msToNext = -1;
  while (tries-- && msToNext<0) {
    msToNext = Module.ccall('jsIdle', 'number', [], []);
    jsHandleIO();
  }
  if (msToNext<10) msToNext=10;
  jsIdleTimeout = setTimeout(jsIdle,msToNext);
  jsUpdateGfx();
  return msToNext;
}
function jsStopIdle() {
  if (jsIdleTimeout) {
    clearTimeout(jsIdleTimeout);
    jsIdleTimeout = undefined;
  }
}
function jsInit() {
  if ("undefined" != typeof window) {
    jsInitButtons();

    var borderColors = ['FFF', 'FF0', 'F00', '000', '00F', '0FF'];
    var borderColor = 0
    document.getElementById("border").style.color = '#' + borderColors[(borderColor + 1) % borderColors.length];
    document.getElementById("border").addEventListener('click', e => {
      borderColor = ++borderColor % borderColors.length;
      document.getElementById("gfxcanvas").style.borderColor = '#' + borderColors[borderColor];
      document.getElementById("border").style.color = '#' + borderColors[(borderColor + 1) % borderColors.length];
    });

    document.getElementById("screenshot").addEventListener('click', e => {
      document.getElementById("screenshot").href = document.getElementById("gfxcanvas").toDataURL();
      document.getElementById("screenshot").download = "screenshot.png";
    });
  }

  Module.ccall('jsInit', 'number', [], []);
  jsHandleIO();
}
function jsKill() {
  var d = document.getElementById("gfxdiv");
  if (d) d.remove();
  Module.ccall('jsKill', 'number', [], []);
}
function drawLoadingScreen() {
  var canvas = document.getElementById('gfxcanvas');
  var ctx = canvas.getContext('2d');
  ctx.font = "15px Sans";
  ctx.textAlign = "center";
  ctx.fillStyle = "black";
  ctx.fillText("Loading...", GFX_WIDTH/2, GFX_HEIGHT/2);
}
if ("undefined" != typeof window)
  drawLoadingScreen();

/* ===========================================================================
     Frame to frame comms
   ===========================================================================

HOST sends: {type:"rx",for:"emu",data:string}
            {type:"init",for:"emu"} - set up the backchannel

WE send: {type:"tx",from:"emu",data:string}

*/
if ("undefined" != typeof window) {
  var hostWindow = window.parent;
  window.addEventListener('message', function(e) {
    var event = e.data;
    console.log("EMU MESSAGE ---------------------------------------");
    console.log(JSON.stringify(event,null,2));
    console.log("-----------------------------------------------");
    if (typeof event!="object" || event.for!="emu") return;
    switch (event.type) {
      case "init": {
        console.log("HOST WINDOW CONFIGURED");
        hostWindow = e.source;
        post({type:"init"});
        jsInit();
        jsIdle();
      } break;
      case "rx": {
        var d = event.data;
        if (typeof d!="string")
          console.error("receive event expecting data string");
        jsTransmitString(d);
      } break;
      default:
        console.error("Unknown event type ",event.type);
        break;
    }
  });
  console.log("Waiting for posted {type:init} message");
}

function post(msg) {
  msg.from="emu";
  hostWindow.postMessage(msg,"*");
}

jsRXCallback = function(c) {
  post({type:"tx",data:String.fromCharCode(c)});
}

/* ===========================================================================
     Window resizing code
   =========================================================================== */

var dontTrigger = false;
var timerResize;
var WIN_WIDTH = (GFX_WIDTH+10+30);
var WIN_HEIGHT = (GFX_HEIGHT+10+4);
function resizeEnd() {
  //100ms since last resize
  dontTrigger = true;
  window.resizeBy(Math.round(byX*correctingRatio*WIN_WIDTH-window.innerWidth), Math.round(byY*correctingRatio*WIN_HEIGHT-window.innerHeight));
  var scale = correctingRatio*byX;
  if (scale < correctingRatio ) scale = correctingRatio;
  document.getElementById("gfxdiv").style.transform = "translate(-50%,-50%) scale("+scale+","+scale+")";

}
function onResize(e) {
  if ( !dontTrigger ) {
    clearTimeout(timerResize);
    timerResize = setTimeout(resizeEnd, 100);
  } else {
    dontTrigger = false;
  }

  // data collection
  if ( window.innerWidth < Math.floor(WIN_WIDTH*correctingRatio*3) || window.innerHeight < Math.floor(WIN_HEIGHT*correctingRatio*3) ) {
    if ( window.innerWidth < Math.floor(WIN_WIDTH*correctingRatio*2.5) || window.innerHeight < Math.floor(WIN_HEIGHT*correctingRatio*2.5) ) {
      byX=2;byY=2;
    } else {
      byX=3;byY=3;
    }
  } else {
    byX=3;byY=3;
  }
  if ( window.innerWidth < Math.floor(WIN_WIDTH*correctingRatio*2) || window.innerHeight < Math.floor(WIN_HEIGHT*correctingRatio*2) ) {
    if ( window.innerWidth < Math.floor(WIN_WIDTH*correctingRatio*1.5) || window.innerHeight < Math.floor(WIN_HEIGHT*correctingRatio*1.5) ) {
      byX=1;byY=1;
    } else {
      byX=2;byY=2;
    }
  }
  if ( window.innerWidth < Math.floor(WIN_WIDTH*correctingRatio) || window.innerHeight < Math.floor(WIN_HEIGHT*correctingRatio) ) {
    byX=1;byY=1;
  }
}

if ("undefined" != typeof window) {
  var correctingRatio = 1/window.devicePixelRatio;
  var byX=1,byY=1;
  window.addEventListener('resize', onResize);
  onResize();
}
<|endoftext|>


<commit_before>"use strict";

const { src, dest, series, parallel } = require("gulp");
var concat = require("gulp-concat");
var uglify = require("gulp-uglify");
var del = require("del");
var minifyCss = require("gulp-clean-css");
var sourceMaps = require("gulp-sourcemaps");
var ts = require("gulp-typescript");
var rename = require("gulp-rename");
var file = file = require("gulp-file");
var less = require("gulp-less");
var paths = require("../paths.config.js");
var config = require("../bundle.config.js");
var tsProject = ts.createProject("tsconfig.json");

//Synchronously delete the output script file(s)
const cleanJsAndMaps = function (callBack) {
    return del
    (
        [
            paths.typescriptOutput,
            paths.appMaps
        ].concat(paths.allJavaScriptNoTests)
    );
};

// create css bundled file
const css = function (callBack) {
    return src(config.libraryStylesSrc.concat(config.customCssSrc))
        .pipe(sourceMaps.init())
        .pipe(less())
        .pipe(concat(config.cssBundle))
        .pipe(dest(config.cssDest))
        .pipe(minifyCss())
        .pipe(concat(config.cssBundleMin))
        .pipe(sourceMaps.write(config.maps))
        .pipe(dest(config.cssDest));
};

const typescript = function (callBack) {
    const tsResult = tsProject.src()
        .pipe(tsProject());

    return tsResult.js.pipe(dest(paths.source));
};

const cleanScriptBundles = function (callBack) {
    return del([
        config.script(config.libraryBundle),
        config.script(config.angularBundle),
        config.script(config.appBundle)
    ]);
};

const cleanScripts = parallel(cleanScriptBundles, cleanJsAndMaps);

// create external library bundled file
const libraryBundle = function (callBack) {
    return src(config.librarySrc)
        .pipe(sourceMaps.init())
        .pipe(concat(config.libraryBundle))
        .pipe(sourceMaps.write(config.maps))
        .pipe(dest(paths.sourceScript));
};

// create angular library bundled file
const angularBundle = function (callBack) {
    return src(config.angularSrc)
        .pipe(sourceMaps.init())
        .pipe(concat(config.angularBundle))
        .pipe(sourceMaps.write(config.maps))
        .pipe(dest(paths.sourceScript));
};

// create app bundled file
const appBundle = function (callBack) {
    return src(config.appSrc)
        .pipe(sourceMaps.init())
        .pipe(concat(config.appBundle))
        .pipe(uglify())
        .pipe(sourceMaps.write(config.maps))
        .pipe(dest(paths.sourceScript));
};

// delete style output folders
const cleanStyles = function (callBack) {
    return del([
        config.fontDest,
        config.cssDest,
        config.cssDest + "/" + config.maps
    ]);
};

// copy assets
const assets = function (callBack) {
    return src(config.assetsSrc)
        .pipe(dest(config.cssDest));
};

// copy fonts
const fonts = function (callBack) {
    return src(config.fontSrc)
        .pipe(dest(config.fontDest));
};

// copy tinyMCE fonts
const tinyMCEFonts = function (callBack) {
    return src(config.tinyMCEFontSrc);
};

const tinyMCEFixCss = function (callBack) {
    return file("content.min.css", "//Dummy file from gulp", { src: true })
        .pipe(dest(paths.sourceScript + "/skins/ui/oxide"))
        .pipe(rename("skin.min.css"))
        .pipe(dest(paths.sourceScript + "/skins/ui/oxide"))
        .pipe(rename("content.min.css"))
        .pipe(dest(paths.sourceScript + "/skins/content/default"));
};

const tinyMCEFixFonts = function (callBack) {
    return file("tinymce-small.eot", "//Dummy file from gulp", { src: true })
        .pipe(dest(paths.sourceContent + "/css/fonts"))
        .pipe(rename("tinymce-small.svg"))
        .pipe(dest(paths.sourceContent + "/css/fonts"))
        .pipe(rename("tinymce-small.ttf"))
        .pipe(dest(paths.sourceContent + "/css/fonts"))
        .pipe(rename("tinymce-small.wof"))
        .pipe(dest(paths.sourceContent + "/css/fonts"))
        .pipe(rename("tinymce-small.woff"))
        .pipe(dest(paths.sourceContent + "/css/fonts"));
};

const tinyMCEFixLang = function (callBack) {
    return file("da.js", "//Dummy file from gulp", { src: true })
        .pipe(dest(paths.sourceScript + "/langs"));
};

// bundle, minify and copy styles, fonts and assets
const styles = series(cleanStyles, parallel(css, assets, fonts), parallel(tinyMCEFonts, tinyMCEFixCss, tinyMCEFixLang, tinyMCEFixFonts));

// run bundle tasks
const scripts = series(cleanScriptBundles, parallel(appBundle, libraryBundle, angularBundle));

// bundle and deploy scripts and styles
exports.deployProd = series(typescript, parallel(scripts, styles), cleanJsAndMaps);

exports.clean = parallel(cleanStyles, cleanScripts);<commit_msg>tinymce font<commit_after>"use strict";

const { src, dest, series, parallel } = require("gulp");
var concat = require("gulp-concat");
var uglify = require("gulp-uglify");
var del = require("del");
var minifyCss = require("gulp-clean-css");
var sourceMaps = require("gulp-sourcemaps");
var ts = require("gulp-typescript");
var rename = require("gulp-rename");
var file = file = require("gulp-file");
var less = require("gulp-less");
var paths = require("../paths.config.js");
var config = require("../bundle.config.js");
var tsProject = ts.createProject("tsconfig.json");

//Synchronously delete the output script file(s)
const cleanJsAndMaps = function (callBack) {
    return del
    (
        [
            paths.typescriptOutput,
            paths.appMaps
        ].concat(paths.allJavaScriptNoTests)
    );
};

// create css bundled file
const css = function (callBack) {
    return src(config.libraryStylesSrc.concat(config.customCssSrc))
        .pipe(sourceMaps.init())
        .pipe(less())
        .pipe(concat(config.cssBundle))
        .pipe(dest(config.cssDest))
        .pipe(minifyCss())
        .pipe(concat(config.cssBundleMin))
        .pipe(sourceMaps.write(config.maps))
        .pipe(dest(config.cssDest));
};

const typescript = function (callBack) {
    const tsResult = tsProject.src()
        .pipe(tsProject());

    return tsResult.js.pipe(dest(paths.source));
};

const cleanScriptBundles = function (callBack) {
    return del([
        config.script(config.libraryBundle),
        config.script(config.angularBundle),
        config.script(config.appBundle)
    ]);
};

const cleanScripts = parallel(cleanScriptBundles, cleanJsAndMaps);

// create external library bundled file
const libraryBundle = function (callBack) {
    return src(config.librarySrc)
        .pipe(sourceMaps.init())
        .pipe(concat(config.libraryBundle))
        .pipe(sourceMaps.write(config.maps))
        .pipe(dest(paths.sourceScript));
};

// create angular library bundled file
const angularBundle = function (callBack) {
    return src(config.angularSrc)
        .pipe(sourceMaps.init())
        .pipe(concat(config.angularBundle))
        .pipe(sourceMaps.write(config.maps))
        .pipe(dest(paths.sourceScript));
};

// create app bundled file
const appBundle = function (callBack) {
    return src(config.appSrc)
        .pipe(sourceMaps.init())
        .pipe(concat(config.appBundle))
        .pipe(uglify())
        .pipe(sourceMaps.write(config.maps))
        .pipe(dest(paths.sourceScript));
};

// delete style output folders
const cleanStyles = function (callBack) {
    return del([
        config.fontDest,
        config.cssDest,
        config.cssDest + "/" + config.maps
    ]);
};

// copy assets
const assets = function (callBack) {
    return src(config.assetsSrc)
        .pipe(dest(config.cssDest));
};

// copy fonts
const fonts = function (callBack) {
    return src(config.fontSrc)
        .pipe(dest(config.fontDest));
};

// copy tinyMCE fonts
const tinyMCEFonts = function (callBack) {
    return src(config.tinyMCEFontSrc);
};

const tinyMCEFixCss = function (callBack) {
    return file("content.min.css", "//Dummy file from gulp", { src: true })
        .pipe(dest(paths.sourceScript + "/skins/ui/oxide"))
        .pipe(rename("skin.min.css"))
        .pipe(dest(paths.sourceScript + "/skins/ui/oxide"))
        .pipe(rename("content.min.css"))
        .pipe(dest(paths.sourceScript + "/skins/content/default"));
};

const tinyMCEFixFonts = function (callBack) {
    return file("tinymce-small.eot", "//Dummy file from gulp", { src: true })
        .pipe(dest(paths.sourceContent + "/css/fonts"))
        .pipe(rename("tinymce-small.svg"))
        .pipe(dest(paths.sourceContent + "/css/fonts"))
        .pipe(rename("tinymce-small.ttf"))
        .pipe(dest(paths.sourceContent + "/css/fonts"))
        .pipe(rename("tinymce-small.wof"))
        .pipe(dest(paths.sourceContent + "/css/fonts"))
        .pipe(rename("tinymce-small.woff"))
        .pipe(dest(paths.sourceContent + "/css/fonts"))
        .pipe(rename("tinymce.eot"))
        .pipe(dest(paths.sourceContent + "/css/fonts"))
        .pipe(rename("tinymce.svg"))
        .pipe(dest(paths.sourceContent + "/css/fonts"))
        .pipe(rename("tinymce.ttf"))
        .pipe(dest(paths.sourceContent + "/css/fonts"))
        .pipe(rename("tinymce.wof"))
        .pipe(dest(paths.sourceContent + "/css/fonts"))
        .pipe(rename("tinymce.woff"))
        .pipe(dest(paths.sourceContent + "/css/fonts"));
};

const tinyMCEFixLang = function (callBack) {
    return file("da.js", "//Dummy file from gulp", { src: true })
        .pipe(dest(paths.sourceScript + "/langs"));
};

// bundle, minify and copy styles, fonts and assets
const styles = series(cleanStyles, parallel(css, assets, fonts), parallel(tinyMCEFonts, tinyMCEFixCss, tinyMCEFixLang, tinyMCEFixFonts));

// run bundle tasks
const scripts = series(cleanScriptBundles, parallel(appBundle, libraryBundle, angularBundle));

// bundle and deploy scripts and styles
exports.deployProd = series(typescript, parallel(scripts, styles), cleanJsAndMaps);

exports.clean = parallel(cleanStyles, cleanScripts);<|endoftext|>


<commit_before>var util = require('util'),
    extendWithGettersAndSetters = require('../util/extendWithGettersAndSetters'),
    Json = require('./Json'),
    AssetGraph = require('../AssetGraph');

function ApplicationManifest(config) {
    Json.call(this, config);
}

util.inherits(ApplicationManifest, Json);

extendWithGettersAndSetters(ApplicationManifest.prototype, {
    contentType: 'application/manifest+json',

    supportedExtensions: ['.webmanifest'],

    findOutgoingRelationsInParseTree: function () {
        var self = this;
        var manifest = self.parseTree;
        var outgoingRelations = [];

        if (!manifest) {
            return outgoingRelations;
        }

        if (typeof manifest.start_url === 'string') {
            outgoingRelations.push(new AssetGraph.JsonUrl({
                from: self,
                to: {
                    url: manifest.start_url
                },
                hrefScope: manifest,
                hrefProperty: 'start_url'
            }));
        }

        if (Array.isArray(manifest.related_applications)) {
            manifest.related_applications.forEach(function (relatedApp) {
                if (typeof relatedApp.url === 'string') {
                    outgoingRelations.push(new AssetGraph.JsonUrl({
                        from: self,
                        to: {
                            url: relatedApp.url
                        },
                        hrefScope: relatedApp,
                        hrefProperty: 'url'
                    }));
                }
            });
        }

        if (Array.isArray(manifest.splash_screens)) {
            manifest.splash_screens.forEach(function (splashScreen) {
                if (typeof splashScreen.src === 'string') {
                    outgoingRelations.push(new AssetGraph.JsonUrl({
                        from: self,
                        to: {
                            url: splashScreen.src
                        },
                        hrefScope: splashScreen,
                        hrefProperty: 'src'
                    }));
                }
            });
        }

        if (Array.isArray(manifest.icons)) {
            manifest.icons.forEach(function (icon) {
                if (typeof icon.src === 'string') {
                    outgoingRelations.push(new AssetGraph.JsonUrl({
                        from: self,
                        to: {
                            url: icon.src
                        },
                        hrefScope: icon,
                        hrefProperty: 'src'
                    }));
                }
            });
        }

        return outgoingRelations;
    }
});

module.exports = ApplicationManifest;
<commit_msg>ApplicationManifest#findOutgoingRelationsInParseTree: Remember to call the superclass method<commit_after>var util = require('util'),
    extendWithGettersAndSetters = require('../util/extendWithGettersAndSetters'),
    Json = require('./Json'),
    Text = require('./Text'),
    AssetGraph = require('../AssetGraph');

function ApplicationManifest(config) {
    Json.call(this, config);
}

util.inherits(ApplicationManifest, Json);

extendWithGettersAndSetters(ApplicationManifest.prototype, {
    contentType: 'application/manifest+json',

    supportedExtensions: ['.webmanifest'],

    findOutgoingRelationsInParseTree: function () {
        var self = this;
        var manifest = self.parseTree;
        var outgoingRelations = Text.prototype.findOutgoingRelationsInParseTree.call(this);

        if (!manifest) {
            return outgoingRelations;
        }

        if (typeof manifest.start_url === 'string') {
            outgoingRelations.push(new AssetGraph.JsonUrl({
                from: self,
                to: {
                    url: manifest.start_url
                },
                hrefScope: manifest,
                hrefProperty: 'start_url'
            }));
        }

        if (Array.isArray(manifest.related_applications)) {
            manifest.related_applications.forEach(function (relatedApp) {
                if (typeof relatedApp.url === 'string') {
                    outgoingRelations.push(new AssetGraph.JsonUrl({
                        from: self,
                        to: {
                            url: relatedApp.url
                        },
                        hrefScope: relatedApp,
                        hrefProperty: 'url'
                    }));
                }
            });
        }

        if (Array.isArray(manifest.splash_screens)) {
            manifest.splash_screens.forEach(function (splashScreen) {
                if (typeof splashScreen.src === 'string') {
                    outgoingRelations.push(new AssetGraph.JsonUrl({
                        from: self,
                        to: {
                            url: splashScreen.src
                        },
                        hrefScope: splashScreen,
                        hrefProperty: 'src'
                    }));
                }
            });
        }

        if (Array.isArray(manifest.icons)) {
            manifest.icons.forEach(function (icon) {
                if (typeof icon.src === 'string') {
                    outgoingRelations.push(new AssetGraph.JsonUrl({
                        from: self,
                        to: {
                            url: icon.src
                        },
                        hrefScope: icon,
                        hrefProperty: 'src'
                    }));
                }
            });
        }

        return outgoingRelations;
    }
});

module.exports = ApplicationManifest;
<|endoftext|>


<commit_before>module.exports = {
  test_page: 'tests/index.html?hidepassed',
  disable_watching: true,
  launch_in_ci: [
    'Chrome'
  ],
  launch_in_dev: [
    'Chrome'
  ],
  browser_args: {
    Chrome: {
      mode: 'ci',
      args: [
        '--disable-gpu',
        '--headless',
        '--remote-debugging-port=0',
        '--window-size=1440,900'
      ]
    }
  }
};
<commit_msg>Adjust browser size to accurately check responsive constraints<commit_after>module.exports = {
  test_page: 'tests/index.html?hidepassed',
  disable_watching: true,
  launch_in_ci: [
    'Chrome'
  ],
  launch_in_dev: [
    'Chrome'
  ],
  browser_args: {
    Chrome: {
      mode: 'ci',
      args: [
        '--disable-gpu',
        '--headless',
        '--remote-debugging-port=0',
        '--window-size=1000,900'
      ]
    }
  }
};
<|endoftext|>


<commit_before><commit_msg>jshint fix<commit_after><|endoftext|>