<commit_before>/*
* Copyright (c) 2012-2015 S-Core Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
 * Constructor function
 * TextEditorPart implementation of EditorPart
 * This should be an ancestor of all text based editors.
 *
 * @constructor
 * @see EditorPart
 * @since: 2015.06.11
 * @author: hw.shim
 *
 * file.__elemId removed
 */

// @formatter:off
define([
    'dojo/topic',
    'external/lodash/lodash.min',
    'webida-lib/util/genetic',
    'webida-lib/util/logger/logger-client',
    'webida-lib/plugins/editors/plugin',
    'webida-lib/plugins/editors/EditorPreference',
    'webida-lib/plugins/workbench/plugin',
    'webida-lib/plugins/workbench/ui/EditorModelManager',
    'webida-lib/plugins/workbench/ui/EditorPart',
    'webida-lib/plugins/workbench/ui/Part',
    'webida-lib/plugins/workbench/ui/PartContainer',
    'webida-lib/plugins/workbench/ui/PartModel',
    'webida-lib/plugins/workbench/ui/partModelProvider',
    'webida-lib/plugins/workbench/ui/PartRegistry',
    'webida-lib/plugins/workbench/ui/Viewer',
    'webida-lib/plugins/workbench/preference-system/store', // TODO: issue #12055
    './configloader',
    './Document',
    './preferences/preference-config',
    './TextEditorContextMenu',
    './TextEditorViewer',
    'dojo/domReady!'
], function(
    topic,
    _,
    genetic,
    Logger,
    editors,
    EditorPreference,
    workbench,
    EditorModelManager,
    EditorPart,
    Part,
    PartContainer,
    PartModel,
    partModelProvider,
    PartRegistry,
    Viewer,
    store,
    configloader,
    Document,
    preferenceConfig,
    TextEditorContextMenu,
    TextEditorViewer
) {
    'use strict';
// @formatter:on

    /**
     * @typedef {Object} DataSource
     * @typedef {Object} Document
     */

    //TODO : this.viewer -> this.getViewer()
    //See File.prototype.isModified = function () {
    //TODO : this.file -> this.getFile()

    var logger = new Logger();
    //logger.off();

    var preferenceIds = ['texteditor', 'texteditor.lines', 'texteditor.key-map', 'texteditor.show-hide', 'content-assist'];

    //To support synchronizeWidgetModel
    //TODO : refactor
    var recentViewers = new Map();
    var partRegistry = workbench.getCurrentPage().getPartRegistry();
    partRegistry.on(PartRegistry.PART_UNREGISTERED, function(part) {
        if (partModelProvider.isModelUsed(part.getModel()) === false) {
            recentViewers['delete'](part.getDataSource());
        }
    });

    function TextEditorPart(container) {
        logger.info('new TextEditorPart(' + container + ')');
        EditorPart.apply(this, arguments);
        var that = this;
        var dataSource = container.getDataSource();
        var file = dataSource.getPersistence();
        this.setFile(file);
        this.fileOpenedHandle = null;
        this.fileSavedHandle = null;
        this.preferences = null;
        this.foldingStatus = null;
        this.on(Part.CONTENT_READY, function(part) {
            console.log('Part.CONTENT_READY!!');
            var viewer = part.getViewer();
            var ds = part.getDataSource();
            var recentViewer = recentViewers.get(ds);
            if (recentViewer) {
                viewer.synchronizeWidgetModel(recentViewer);
            }
            recentViewers.set(ds, viewer);
        });
    }

    genetic.inherits(TextEditorPart, EditorPart, {

        initialize: function() {
            logger.info('initialize()');
            this.initializeViewer();
            this.initializeListeners();
            this.initializePreferences();
        },

        initializeViewer: function() {
            logger.info('initializeViewer()');
            var that = this;
            var viewer = this.getViewer();
            var parent = this.getParentElement();
            viewer.clearHistory();
            viewer.markClean();
            viewer.setSize(parent.offsetWidth, parent.offsetHeight);
            viewer.setMatchBrackets(true);
            var setStatusBarText = function() {
                var workbench = require('webida-lib/plugins/workbench/plugin');
                var file = that.file;
                var viewer = that.getViewer();
                var cursor = viewer.getCursor();
                workbench.__editor = viewer;
                //TODO : refactor
                workbench.setContext([file.path], {
                    cursor: (cursor.row + 1) + ':' + (cursor.col + 1)
                });
            };
            viewer.addCursorListener(setStatusBarText);
            viewer.addFocusListener(setStatusBarText);
            viewer.addCursorListener(function(viewer) {
                TextEditorPart.pushCursorLocation(viewer.file, viewer.getCursor());
            });
            viewer.addExtraKeys({
                'Ctrl-Alt-Left': function() {
                    TextEditorPart.moveBack();
                },
                'Ctrl-Alt-Right': function() {
                    TextEditorPart.moveForth();
                }
            });
        },

        /**
         * To initialize listeners you want
         * override this
         */
        initializeListeners: function() {
            logger.info('initializeListeners()');
            var that = this;
            //TODO : remove listener
            this.on(EditorPart.AFTER_SAVE, function() {
                that.foldingStatus = that.getViewer().getFoldings();
            });
        },

        initializePreferences: function() {
            logger.info('initializePreferences()');
            var viewer = this.getViewer();
            var file = this.file;
            //preferences
            this.preferences = new EditorPreference(preferenceIds, viewer);
            //editorconfig
            this.preferences.setFields(this.getPreferences());
            if (store.getValue('webida.editor.text-editor:editorconfig') === true) {
                configloader.editorconfig(viewer, file);
            }
        },

        /**
         * To use the Preferences you want, override this method
         * and return Preferences you want use
         *
         * @returns preferenceConfig for TextEditor
         */
        getPreferences: function() {
            return preferenceConfig;
        },

        /**
         * To use the Context you want, override this method
         * and return Class you want use
         *
         * @returns TextEditorViewer
         */
        getViewerClass: function() {
            return TextEditorViewer;
        },

        /**
         * TODO : move to CodeEditorPart
         */
        getFoldingStatus: function() {
            return this.foldingStatus;
        },

        /**
         * @param {HTMLElement} parent
         * @return {Viewer}
         */
        createViewer: function(parentNode) {
            logger.info('%c createViewer(' + parentNode.tagName + ')', 'color:green');
            //TODO : remove
            this.setParentElement(parentNode);
            var that = this;

            //Viewer
            var ViewerClass = this.getViewerClass();
            var viewer = new (ViewerClass)(parentNode, this.file, function(file, viewer) {
                viewer.addChangeListener(function(viewer, change) {
                    if (viewer._changeCallback) {
                        viewer._changeCallback(file, change);
                    }
                });
            });
            this.setViewer(viewer);
            this.initialize();
            return viewer;
        },

        /**
         * @return {Document}
         */
        createModel: function() {
            logger.info('%c createModel()', 'color:green');
            this.setModelManager(new EditorModelManager(this.getDataSource(), Document));
            var model = this.getModelManager().getSynchronizedModel(function(doc) {
                //do something with doc ready if needed
            });
            //this.getModelManager().SynchroWith(SvgModel);
            this.setModel(model);
            return model;
        },

        onDestroy: function() {
            logger.info('onDestroy()');
            EditorPart.prototype.onDestroy.apply(this);
            if (this.viewer) {
                this.viewer.destroyAdapter();
                this.viewer = null;
            } else {
                logger.info('this.viewer not found');
                logger.trace();
            }
            //unset preferences
            if (this.preferences) {
                this.preferences.unsetFields();
            }
            //unsubscribe topic
            if (this.fileOpenedHandle !== null) {
                logger.info('this.fileOpenedHandle.remove()');
                this.fileOpenedHandle.remove();
            }
            if (this.fileSavedHandle !== null) {
                this.fileSavedHandle.remove();
            }
        },

        hide: function() {
            logger.info('hide()');
        },

        getValue: function() {
            if (this.viewer) {
                return this.viewer.getValue();
                //TODO : getViewer()
            } else {
                logger.info('this.viewer not found');
                logger.trace();
            }
        },

        addChangeListener: function(callback) {
            this.viewer._changeCallback = callback;
        },

        focus: function() {
            if (this.viewer) {
                this.viewer.focus();
                //TODO : getViewer()
            } else {
                logger.info('this.viewer not found');
                logger.trace();
            }
        },

        isClean: function() {
            var docMan = this.getModelManager();
            return !docMan.canSaveModel();
        },

        getContextMenuClass: function() {
            return TextEditorContextMenu;
        },

        getContextMenuItems: function(menuItems) {
            logger.info('getContextMenuItems(' + menuItems + ')');
            var contextMenu = new (this.getContextMenuClass())(menuItems, this);
            return contextMenu.getItems();
        },

        save: function(callback) {
            logger.info('save(' + typeof callback + ')');
            var that = this;
            this._beforeSave();
            //TODO Refactor : find more a way without setTimeout
            setTimeout(function() {
                EditorPart.prototype.save.call(that, callback);
            });
        },

        _beforeSave: function() {
            logger.info('_beforeSave');
            var viewer = this.getViewer();
            var doc = this.getModel();
            var text = doc.getContents();
            if ( typeof text === 'undefined') {
                return;
            }

            //logger.info('viewer.trimTrailingWhitespaces = ',
            // viewer.trimTrailingWhitespaces);
            //logger.info('viewer.insertFinalNewLine = ',
            // viewer.insertFinalNewLine);
            //logger.info('viewer.retabIndentations = ',
            // viewer.retabIndentations);

            if (viewer.trimTrailingWhitespaces && text.match(/( |\t)+$/m)) {
                text = text.replace(/( |\t)+$/mg, '');
            }

            if (viewer.insertFinalNewLine && text.match(/.$/)) {
                text = text + '\n';
            }

            if (viewer.retabIndentations) {
                function getSpaces(n) {
                    var spaces = ['', ' ', '  ', '   ', '    '];
                    if (spaces[n] === undefined) {
                        return (spaces[n] = ( n ? ' ' + getSpaces(n - 1) : ''));
                    } else {
                        return spaces[n];
                    }
                }

                var unit = viewer.options.indentUnit, re = /^(( )*)\t/m, m;
                while (( m = text.match(re))) {
                    text = text.replace(re, '$1' + getSpaces(unit - (m[0].length - 1) % unit));
                }
            }

            if (text !== doc.getContents()) {
                var cursor = viewer.getCursor();
                var scrollInfo = viewer.getScrollInfo();
                viewer.refresh(text);
                //TODO Refactor : use execCommand();
                viewer.setCursor(cursor);
                viewer.scrollToScrollInfo(scrollInfo);
            }
        }
    });

    //Static functions

    var cursorStacks = {
        back: [],
        forth: []
    };

    TextEditorPart.moveTo = function(location) {
        topic.publish('editor/open', location.filepath, {
            show: true
        }, function(file) {
            if (editors.getPart(file) === null) {
                return;
            }
            var part = editors.getPart(file);
            var viewer = part.getViewer();
            if (location.start && location.end) {
                viewer.setSelection(location.start, location.end);
            } else {
                viewer.setCursor(location.cursor);
            }

            viewer.addDeferredAction(function(viewer) {
                viewer.editor.focus();
            });
        });
    };

    TextEditorPart.moveBack = function() {
        if (cursorStacks.back.length > 1) {
            var popped = cursorStacks.back.pop();
            if (popped) {
                cursorStacks.forth.push(popped);
            }
            TextEditorPart.moveTo(cursorStacks.back[cursorStacks.back.length - 1]);
        }
    };

    TextEditorPart.moveForth = function() {
        var popped = cursorStacks.forth.pop();
        if (popped) {
            cursorStacks.back.push(popped);
            TextEditorPart.moveTo(popped);
        }
    };

    TextEditorPart.pushCursorLocation = function(file, cursor, forced) {
        logger.info('pushCursorLocation(file, ' + cursor + ', forced)');
        var filepath = ( typeof file === 'string') ? file : file.path;
        var thisLocation = {
            filepath: filepath,
            cursor: cursor,
            timestamp: new Date().getTime(),
            forced: forced
        };

        function compareLocations(cursor1, cursor2, colspan, rowspan, timespan) {
            if (cursor1.filepath === cursor2.filepath) {
                // @formatter:off
                if (((!colspan || (Math.abs(cursor1.cursor.col - cursor2.cursor.col) < colspan))
                	&& (!rowspan || (Math.abs(cursor1.cursor.row - cursor2.cursor.row) < rowspan)))
                	|| (!timespan || (Math.abs(cursor1.timestamp - cursor2.timestamp) < timespan))) {
                    return true;
                }
                // @formatter:on
                return false;
            } else {
                return false;
            }
        }

        function similarLocations(cursor1, cursor2) {
            return compareLocations(cursor1, cursor2, 5, 5, 3000);
        }

        function identicalLocations(cursor1, cursor2) {
            return compareLocations(cursor1, cursor2, 1, 1, false);
        }

        if (cursorStacks.back.length > 0) {
            var latest = cursorStacks.back.pop();
            // @formatter:off
            if (((forced || latest.forced) && !identicalLocations(thisLocation, latest))
            	|| (!similarLocations(thisLocation, latest))) {
                cursorStacks.back.push(latest);
                cursorStacks.forth = [];
            }
            // @formatter:on
        }
        cursorStacks.back.push(thisLocation);
        return thisLocation;
    };

    return TextEditorPart;
});
<commit_msg>[TASK] TextEditorPart : function definition for Strict Mode<commit_after>/*
* Copyright (c) 2012-2015 S-Core Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
 * Constructor function
 * TextEditorPart implementation of EditorPart
 * This should be an ancestor of all text based editors.
 *
 * @constructor
 * @see EditorPart
 * @since: 2015.06.11
 * @author: hw.shim
 *
 * file.__elemId removed
 */

// @formatter:off
define([
    'dojo/topic',
    'external/lodash/lodash.min',
    'webida-lib/util/genetic',
    'webida-lib/util/logger/logger-client',
    'webida-lib/plugins/editors/plugin',
    'webida-lib/plugins/editors/EditorPreference',
    'webida-lib/plugins/workbench/plugin',
    'webida-lib/plugins/workbench/ui/EditorModelManager',
    'webida-lib/plugins/workbench/ui/EditorPart',
    'webida-lib/plugins/workbench/ui/Part',
    'webida-lib/plugins/workbench/ui/PartContainer',
    'webida-lib/plugins/workbench/ui/PartModel',
    'webida-lib/plugins/workbench/ui/partModelProvider',
    'webida-lib/plugins/workbench/ui/PartRegistry',
    'webida-lib/plugins/workbench/ui/Viewer',
    'webida-lib/plugins/workbench/preference-system/store', // TODO: issue #12055
    './configloader',
    './Document',
    './preferences/preference-config',
    './TextEditorContextMenu',
    './TextEditorViewer',
    'dojo/domReady!'
], function(
    topic,
    _,
    genetic,
    Logger,
    editors,
    EditorPreference,
    workbench,
    EditorModelManager,
    EditorPart,
    Part,
    PartContainer,
    PartModel,
    partModelProvider,
    PartRegistry,
    Viewer,
    store,
    configloader,
    Document,
    preferenceConfig,
    TextEditorContextMenu,
    TextEditorViewer
) {
    'use strict';
// @formatter:on

    /**
     * @typedef {Object} DataSource
     * @typedef {Object} Document
     */

    //TODO : this.viewer -> this.getViewer()
    //See File.prototype.isModified = function () {
    //TODO : this.file -> this.getFile()

    var logger = new Logger();
    //logger.off();

    var preferenceIds = ['texteditor', 'texteditor.lines', 'texteditor.key-map', 'texteditor.show-hide', 'content-assist'];

    //To support synchronizeWidgetModel
    //TODO : refactor
    var recentViewers = new Map();
    var partRegistry = workbench.getCurrentPage().getPartRegistry();
    partRegistry.on(PartRegistry.PART_UNREGISTERED, function(part) {
        if (partModelProvider.isModelUsed(part.getModel()) === false) {
            recentViewers['delete'](part.getDataSource());
        }
    });

    function TextEditorPart(container) {
        logger.info('new TextEditorPart(' + container + ')');
        EditorPart.apply(this, arguments);
        var that = this;
        var dataSource = container.getDataSource();
        var file = dataSource.getPersistence();
        this.setFile(file);
        this.fileOpenedHandle = null;
        this.fileSavedHandle = null;
        this.preferences = null;
        this.foldingStatus = null;
        this.on(Part.CONTENT_READY, function(part) {
            console.log('Part.CONTENT_READY!!');
            var viewer = part.getViewer();
            var ds = part.getDataSource();
            var recentViewer = recentViewers.get(ds);
            if (recentViewer) {
                viewer.synchronizeWidgetModel(recentViewer);
            }
            recentViewers.set(ds, viewer);
        });
    }

    genetic.inherits(TextEditorPart, EditorPart, {

        initialize: function() {
            logger.info('initialize()');
            this.initializeViewer();
            this.initializeListeners();
            this.initializePreferences();
        },

        initializeViewer: function() {
            logger.info('initializeViewer()');
            var that = this;
            var viewer = this.getViewer();
            var parent = this.getParentElement();
            viewer.clearHistory();
            viewer.markClean();
            viewer.setSize(parent.offsetWidth, parent.offsetHeight);
            viewer.setMatchBrackets(true);
            var setStatusBarText = function() {
                var workbench = require('webida-lib/plugins/workbench/plugin');
                var file = that.file;
                var viewer = that.getViewer();
                var cursor = viewer.getCursor();
                workbench.__editor = viewer;
                //TODO : refactor
                workbench.setContext([file.path], {
                    cursor: (cursor.row + 1) + ':' + (cursor.col + 1)
                });
            };
            viewer.addCursorListener(setStatusBarText);
            viewer.addFocusListener(setStatusBarText);
            viewer.addCursorListener(function(viewer) {
                TextEditorPart.pushCursorLocation(viewer.file, viewer.getCursor());
            });
            viewer.addExtraKeys({
                'Ctrl-Alt-Left': function() {
                    TextEditorPart.moveBack();
                },
                'Ctrl-Alt-Right': function() {
                    TextEditorPart.moveForth();
                }
            });
        },

        /**
         * To initialize listeners you want
         * override this
         */
        initializeListeners: function() {
            logger.info('initializeListeners()');
            var that = this;
            //TODO : remove listener
            this.on(EditorPart.AFTER_SAVE, function() {
                that.foldingStatus = that.getViewer().getFoldings();
            });
        },

        initializePreferences: function() {
            logger.info('initializePreferences()');
            var viewer = this.getViewer();
            var file = this.file;
            //preferences
            this.preferences = new EditorPreference(preferenceIds, viewer);
            //editorconfig
            this.preferences.setFields(this.getPreferences());
            if (store.getValue('webida.editor.text-editor:editorconfig') === true) {
                configloader.editorconfig(viewer, file);
            }
        },

        /**
         * To use the Preferences you want, override this method
         * and return Preferences you want use
         *
         * @returns preferenceConfig for TextEditor
         */
        getPreferences: function() {
            return preferenceConfig;
        },

        /**
         * To use the Context you want, override this method
         * and return Class you want use
         *
         * @returns TextEditorViewer
         */
        getViewerClass: function() {
            return TextEditorViewer;
        },

        /**
         * TODO : move to CodeEditorPart
         */
        getFoldingStatus: function() {
            return this.foldingStatus;
        },

        /**
         * @param {HTMLElement} parent
         * @return {Viewer}
         */
        createViewer: function(parentNode) {
            logger.info('%c createViewer(' + parentNode.tagName + ')', 'color:green');
            //TODO : remove
            this.setParentElement(parentNode);
            var that = this;

            //Viewer
            var ViewerClass = this.getViewerClass();
            var viewer = new (ViewerClass)(parentNode, this.file, function(file, viewer) {
                viewer.addChangeListener(function(viewer, change) {
                    if (viewer._changeCallback) {
                        viewer._changeCallback(file, change);
                    }
                });
            });
            this.setViewer(viewer);
            this.initialize();
            return viewer;
        },

        /**
         * @return {Document}
         */
        createModel: function() {
            logger.info('%c createModel()', 'color:green');
            this.setModelManager(new EditorModelManager(this.getDataSource(), Document));
            var model = this.getModelManager().getSynchronizedModel(function(doc) {
                //do something with doc ready if needed
            });
            //this.getModelManager().SynchroWith(SvgModel);
            this.setModel(model);
            return model;
        },

        onDestroy: function() {
            logger.info('onDestroy()');
            EditorPart.prototype.onDestroy.apply(this);
            if (this.viewer) {
                this.viewer.destroyAdapter();
                this.viewer = null;
            } else {
                logger.info('this.viewer not found');
                logger.trace();
            }
            //unset preferences
            if (this.preferences) {
                this.preferences.unsetFields();
            }
            //unsubscribe topic
            if (this.fileOpenedHandle !== null) {
                logger.info('this.fileOpenedHandle.remove()');
                this.fileOpenedHandle.remove();
            }
            if (this.fileSavedHandle !== null) {
                this.fileSavedHandle.remove();
            }
        },

        hide: function() {
            logger.info('hide()');
        },

        getValue: function() {
            if (this.viewer) {
                return this.viewer.getValue();
                //TODO : getViewer()
            } else {
                logger.info('this.viewer not found');
                logger.trace();
            }
        },

        addChangeListener: function(callback) {
            this.viewer._changeCallback = callback;
        },

        focus: function() {
            if (this.viewer) {
                this.viewer.focus();
                //TODO : getViewer()
            } else {
                logger.info('this.viewer not found');
                logger.trace();
            }
        },

        isClean: function() {
            var docMan = this.getModelManager();
            return !docMan.canSaveModel();
        },

        getContextMenuClass: function() {
            return TextEditorContextMenu;
        },

        getContextMenuItems: function(menuItems) {
            logger.info('getContextMenuItems(' + menuItems + ')');
            var contextMenu = new (this.getContextMenuClass())(menuItems, this);
            return contextMenu.getItems();
        },

        save: function(callback) {
            logger.info('save(' + typeof callback + ')');
            var that = this;
            this._beforeSave();
            //TODO Refactor : find more a way without setTimeout
            setTimeout(function() {
                EditorPart.prototype.save.call(that, callback);
            });
        },

        _beforeSave: function() {
            logger.info('_beforeSave');
            var viewer = this.getViewer();
            var doc = this.getModel();
            var text = doc.getContents();
            if ( typeof text === 'undefined') {
                return;
            }

            //logger.info('viewer.trimTrailingWhitespaces = ',
            // viewer.trimTrailingWhitespaces);
            //logger.info('viewer.insertFinalNewLine = ',
            // viewer.insertFinalNewLine);
            //logger.info('viewer.retabIndentations = ',
            // viewer.retabIndentations);

            if (viewer.trimTrailingWhitespaces && text.match(/( |\t)+$/m)) {
                text = text.replace(/( |\t)+$/mg, '');
            }

            if (viewer.insertFinalNewLine && text.match(/.$/)) {
                text = text + '\n';
            }

            if (viewer.retabIndentations) {
                var getSpaces = function(n) {
                    var spaces = ['', ' ', '  ', '   ', '    '];
                    if (spaces[n] === undefined) {
                        return (spaces[n] = ( n ? ' ' + getSpaces(n - 1) : ''));
                    } else {
                        return spaces[n];
                    }
                };
                var unit = viewer.options.indentUnit, re = /^(( )*)\t/m, m;
                while (( m = text.match(re))) {
                    text = text.replace(re, '$1' + getSpaces(unit - (m[0].length - 1) % unit));
                }
            }

            if (text !== doc.getContents()) {
                var cursor = viewer.getCursor();
                var scrollInfo = viewer.getScrollInfo();
                viewer.refresh(text);
                //TODO Refactor : use execCommand();
                viewer.setCursor(cursor);
                viewer.scrollToScrollInfo(scrollInfo);
            }
        }
    });

    //Static functions

    var cursorStacks = {
        back: [],
        forth: []
    };

    TextEditorPart.moveTo = function(location) {
        topic.publish('editor/open', location.filepath, {
            show: true
        }, function(file) {
            if (editors.getPart(file) === null) {
                return;
            }
            var part = editors.getPart(file);
            var viewer = part.getViewer();
            if (location.start && location.end) {
                viewer.setSelection(location.start, location.end);
            } else {
                viewer.setCursor(location.cursor);
            }

            viewer.addDeferredAction(function(viewer) {
                viewer.editor.focus();
            });
        });
    };

    TextEditorPart.moveBack = function() {
        if (cursorStacks.back.length > 1) {
            var popped = cursorStacks.back.pop();
            if (popped) {
                cursorStacks.forth.push(popped);
            }
            TextEditorPart.moveTo(cursorStacks.back[cursorStacks.back.length - 1]);
        }
    };

    TextEditorPart.moveForth = function() {
        var popped = cursorStacks.forth.pop();
        if (popped) {
            cursorStacks.back.push(popped);
            TextEditorPart.moveTo(popped);
        }
    };

    TextEditorPart.pushCursorLocation = function(file, cursor, forced) {
        logger.info('pushCursorLocation(file, ' + cursor + ', forced)');
        var filepath = ( typeof file === 'string') ? file : file.path;
        var thisLocation = {
            filepath: filepath,
            cursor: cursor,
            timestamp: new Date().getTime(),
            forced: forced
        };

        function compareLocations(cursor1, cursor2, colspan, rowspan, timespan) {
            if (cursor1.filepath === cursor2.filepath) {
                // @formatter:off
                if (((!colspan || (Math.abs(cursor1.cursor.col - cursor2.cursor.col) < colspan))
                	&& (!rowspan || (Math.abs(cursor1.cursor.row - cursor2.cursor.row) < rowspan)))
                	|| (!timespan || (Math.abs(cursor1.timestamp - cursor2.timestamp) < timespan))) {
                    return true;
                }
                // @formatter:on
                return false;
            } else {
                return false;
            }
        }

        function similarLocations(cursor1, cursor2) {
            return compareLocations(cursor1, cursor2, 5, 5, 3000);
        }

        function identicalLocations(cursor1, cursor2) {
            return compareLocations(cursor1, cursor2, 1, 1, false);
        }

        if (cursorStacks.back.length > 0) {
            var latest = cursorStacks.back.pop();
            // @formatter:off
            if (((forced || latest.forced) && !identicalLocations(thisLocation, latest))
            	|| (!similarLocations(thisLocation, latest))) {
                cursorStacks.back.push(latest);
                cursorStacks.forth = [];
            }
            // @formatter:on
        }
        cursorStacks.back.push(thisLocation);
        return thisLocation;
    };

    return TextEditorPart;
});
<|endoftext|>


<commit_before>// climate control template -- start with this when an HVAC unit can be managed independently
// search for TBD to see what to change

// load the module that knows how to discover/communicate with a bulb
var samsung     = require('samsung-airconditioner')
  , util        = require('util')
  , devices     = require('./../../core/device')
  , steward     = require('./../../core/steward')
  , utility     = require('./../../core/utility')
  , climate     = require('./../device-climate')
  , sensor      = require('./../device-sensor')
  ;

// var logger = climate.logger;

// define the prototype that will be instantiated when the HVAC unit is discovered
// later, we will create a ...perform function, and a ...update function.
var Thermostat = exports.Device = function(deviceID, deviceUID, info) {
  var self = this;

  self.whatami = info.deviceType;
  self.deviceID = deviceID.toString();
  self.deviceUID = deviceUID;
  self.name = info.device.name;
  self.getName();

  self.hvac = info.hvac;
// TBD: invoked by the lower-level hvac driver whenever the hvac unit changes state. You probably
// have to set the name of the event to whatever the hvac driver emits when its state changes.
  self.hvac.on('stateChange', function(state) { self.update(self, state); });
  self.update(self, self.hvac.state);
  self.changed();

  utility.broker.subscribe('actors', function(request, taskID, actor, perform, parameter) {
    if (actor !== ('device/' + self.deviceID)) return;

    if (request === 'perform') return self.perform(self, taskID, perform, parameter);
  });
};
util.inherits(Thermostat, climate.Device);

Thermostat.prototype.setup = function (aircon) {
  var self = this;
  var logger2 = utility.logger('discovery');

  // var db = require('./../../core/database').db
  // db.on('trace', function(e) {
  //   console.log(e);
  // });

  var state = self.getState(function (err, state) {
    if (!state) {
      state = {};
    }

    if (!state.token) {
      aircon.get_token(function(err, token) {
        if (!!err) {
          self.update(self, {}, 'reset');

          return logger2.info(self.name, 'Get Token error: ' + err.message);
        }

        logger2.info(self.name, "Token found:" + token);

        state.token = token;

        self.setState(state);

        aircon.login(token, function () {
          self.update(self, {}, 'present');
          logger2.info(self.name, "Logged on");
        });
      }).on('waiting', function() {
        self.alert('Please power on the device within the next 30 seconds');
        logger2.info(self.name, 'Please power on the device within the next 30 seconds');
      });
    } else {
      aircon.login(state.token, function () {
        self.update(self, {}, 'present');
        logger2.info(self.name, "Logged on");
      });
    }
  });

};

Thermostat.prototype.update = function(self, params, status) {
  var param, updateP;

  updateP = false;
  if ((!!status) && (status !== self.status)) {
    self.status = status;
    updateP = true;
  }
  for (param in params) {
    if ((!params.hasOwnProperty(param)) || (!params[param]) || (self.info[param] === params[param])) continue;

    self.info[param] = params[param];
    updateP = true;
  }
  if (updateP) {
    self.changed();
    sensor.update(self.deviceID, params);
  }
};

Thermostat.operations = {
  set: function(self, params) {

    var performed = false;

    var attempt_perform = function(key, fn) {
      if (typeof params[key] !== 'undefined') {
        fn(params[key]);
        performed = true;
      }
    };

    attempt_perform('hvac', function(value) {
      switch (value) {
        case 'off':
          self.hvac.onoff(false);
          break;
        case 'on':
          self.hvac.onoff(true);
          break;
        case 'cool':
          self.hvac.onoff(true);
          self.hvac.mode('Cool');
          break;
        case 'heat':
          self.hvac.onoff(true);
          self.hvac.mode('Heat');
          break;
        case 'fan':
          self.hvac.onoff(true);
          self.hvac.mode('Wind');
          break;
      }
    });

    attempt_perform('fan', function(value) {
      var time;

      switch (value) {
        // Available options for convenient mode
        // var modes = ['Off', 'Quiet', 'Sleep', 'Smart', 'SoftCool', 'TurboMode', 'WindMode1', 'WindMode2', 'WindMode3']
        case 'off':
          self.hvac.set_convenient_mode('Off');
          break;
        case 'on':
          self.hvac.set_convenient_mode('Quiet');
          break;
        case 'auto':
          self.hvac.set_convenient_mode('WindMode1');
          break;

        default:
          time = parseInt(value, 10);
          if (isNaN(time)) break;
// TBD: set the fan duration. adjust time from milliseconds to whatever
          break;
      }
    });

    attempt_perform('goalTemperature', function(value) {
      var goalTemperature;

      goalTemperature = parseInt(value, 10);
      if (isNaN(goalTemperature)) {
        return;
      }

      if (goalTemperature > 30 || goalTemperature < 16) {
        return;
      }

      // TODO UI says F, the unit works in C, which is this?
      self.hvac.set_temperature(goalTemperature);
    });

    return performed;
  }
};

Thermostat.prototype.perform = function(self, taskID, perform, parameter) {
  var params;

  try { params = JSON.parse(parameter); } catch(e) { params = {}; }

  if (!!Thermostat.operations[perform]) {
    if (Thermostat.operations[perform](this, params)) {
      return steward.performed(taskID);
    }
  }

  return devices.perform(self, taskID, perform, parameter);
};

var checkParam = function(key, params, result, allowNumeric, map) {
  if (typeof params[key] !== 'undefined') {

    var defined = typeof map[params[key]] !== 'undefined';

    if (((!defined) && (!allowNumeric)) || ((!defined) && allowNumeric && isNaN(parseInt(params[key], 10)))) {
      result.invalid.push(key);
    }
  }
};

var validate_perform = function(perform, parameter) {
  var params = {}
    , result = { invalid: [], requires: [] }
    ;

  if (!!parameter) try { params = JSON.parse(parameter); } catch(ex) { result.invalid.push('parameter'); }

  if (!!Thermostat.operations[perform]) {
    if (perform === 'set') {
      if (!params) {
        result.requires.push('parameter');
        return result;
      }

      checkParam('hvac', params, result, false, { heat: 1, cool: 1, fan: 1, off: 1 });
      checkParam('fan', params, result, true, { off: 1, on: 1, auto: 1 });
      checkParam('goalTemperature', params, result, true, {});
    }
    return result;
  }

  return devices.validate_perform(perform, parameter);
};

exports.start = function() {
  var logger2 = utility.logger('discovery');

  steward.actors.device.climate.samsung = steward.actors.device.climate.samsung ||
      { $info     : { type: '/device/climate/samsung' } };

  steward.actors.device.climate.samsung.control =
      { $info     : { type       : '/device/climate/samsung/control'
                    , observe    : [ ]
                    , perform    : [ ]
                    , properties : { name            : true
                                   , lastSample      : 'timestamp'
                                   , temperature     : 'celsius'
                                   , humidity        : 'percentage'
                                   , hvac            : [ 'cool', 'heat', 'fan', 'off' ]
                                   , fan             : [ 'on', 'auto', 'milliseconds' ]
                                   , goalTemperature : 'celsius'
                                   }
                    }
        , $validate : { perform    : validate_perform }
      };
  devices.makers['/device/climate/samsung/control'] = Thermostat;

// TBD: when the hardware driver discovers a new HVAC unit, it will call us.
// TBD: or if the low-level driver needs to be polled, then create a 'scan' function and call it periodically.

  new samsung().on('discover', function(aircon) {
    // TODO This is done to avoid detecting ourselves listening for the SSDP response.
    // There should be a better way :(
    if (!aircon.options.duid) {
      return;
    }
    var info;
    info = { source     : 'samsung'
           , hvac       : aircon
           , device     : { url          : null
                          , name         : aircon.options.info["NICKNAME"]
                          , manufacturer : aircon.manufacturer || 'Samsung'
                          , model        : { name        : aircon.options.info["MODELCODE"]
                                           , description : ''
                                           }
                          , unit         : { serial      : aircon.props.duid
                                           , udn         : 'Samsung:' + aircon.props.duid
                                           }
                          }

         };

    info.url = info.device.url;
    info.deviceType = '/device/climate/samsung/control';
    info.id = info.device.unit.udn;

    devices.discover(info, function (err, deviceID) {
      if (!deviceID) {
        return;
      }

      var thermostat = devices.devices[deviceID].device;

      thermostat.setup(aircon);
    });

  }).on('error', function(err) {
    logger2.error('samsung', { diagnostic: err.message });
  }).logger = logger2;
};
<commit_msg>Avoid crash when samsung phone app starts SSDP.<commit_after>// climate control template -- start with this when an HVAC unit can be managed independently
// search for TBD to see what to change

// load the module that knows how to discover/communicate with a bulb
var samsung     = require('samsung-airconditioner')
  , util        = require('util')
  , devices     = require('./../../core/device')
  , steward     = require('./../../core/steward')
  , utility     = require('./../../core/utility')
  , climate     = require('./../device-climate')
  , sensor      = require('./../device-sensor')
  ;

// var logger = climate.logger;

// define the prototype that will be instantiated when the HVAC unit is discovered
// later, we will create a ...perform function, and a ...update function.
var Thermostat = exports.Device = function(deviceID, deviceUID, info) {
  var self = this;

  self.whatami = info.deviceType;
  self.deviceID = deviceID.toString();
  self.deviceUID = deviceUID;
  self.name = info.device.name;
  self.getName();

  self.hvac = info.hvac;
// TBD: invoked by the lower-level hvac driver whenever the hvac unit changes state. You probably
// have to set the name of the event to whatever the hvac driver emits when its state changes.
  self.hvac.on('stateChange', function(state) { self.update(self, state); });
  self.update(self, self.hvac.state);
  self.changed();

  utility.broker.subscribe('actors', function(request, taskID, actor, perform, parameter) {
    if (actor !== ('device/' + self.deviceID)) return;

    if (request === 'perform') return self.perform(self, taskID, perform, parameter);
  });
};
util.inherits(Thermostat, climate.Device);

Thermostat.prototype.setup = function (aircon) {
  var self = this;
  var logger2 = utility.logger('discovery');

  // var db = require('./../../core/database').db
  // db.on('trace', function(e) {
  //   console.log(e);
  // });

  var state = self.getState(function (err, state) {
    if (!state) {
      state = {};
    }

    if (!state.token) {
      aircon.get_token(function(err, token) {
        if (!!err) {
          self.update(self, {}, 'reset');

          return logger2.info(self.name, 'Get Token error: ' + err.message);
        }

        logger2.info(self.name, "Token found:" + token);

        state.token = token;

        self.setState(state);

        aircon.login(token, function () {
          self.update(self, {}, 'present');
          logger2.info(self.name, "Logged on");
        });
      }).on('waiting', function() {
        self.alert('Please power on the device within the next 30 seconds');
        logger2.info(self.name, 'Please power on the device within the next 30 seconds');
      });
    } else {
      aircon.login(state.token, function () {
        self.update(self, {}, 'present');
        logger2.info(self.name, "Logged on");
      });
    }
  });

};

Thermostat.prototype.update = function(self, params, status) {
  var param, updateP;

  updateP = false;
  if ((!!status) && (status !== self.status)) {
    self.status = status;
    updateP = true;
  }
  for (param in params) {
    if ((!params.hasOwnProperty(param)) || (!params[param]) || (self.info[param] === params[param])) continue;

    self.info[param] = params[param];
    updateP = true;
  }
  if (updateP) {
    self.changed();
    sensor.update(self.deviceID, params);
  }
};

Thermostat.operations = {
  set: function(self, params) {

    var performed = false;

    var attempt_perform = function(key, fn) {
      if (typeof params[key] !== 'undefined') {
        fn(params[key]);
        performed = true;
      }
    };

    attempt_perform('hvac', function(value) {
      switch (value) {
        case 'off':
          self.hvac.onoff(false);
          break;
        case 'on':
          self.hvac.onoff(true);
          break;
        case 'cool':
          self.hvac.onoff(true);
          self.hvac.mode('Cool');
          break;
        case 'heat':
          self.hvac.onoff(true);
          self.hvac.mode('Heat');
          break;
        case 'fan':
          self.hvac.onoff(true);
          self.hvac.mode('Wind');
          break;
      }
    });

    attempt_perform('fan', function(value) {
      var time;

      switch (value) {
        // Available options for convenient mode
        // var modes = ['Off', 'Quiet', 'Sleep', 'Smart', 'SoftCool', 'TurboMode', 'WindMode1', 'WindMode2', 'WindMode3']
        case 'off':
          self.hvac.set_convenient_mode('Off');
          break;
        case 'on':
          self.hvac.set_convenient_mode('Quiet');
          break;
        case 'auto':
          self.hvac.set_convenient_mode('WindMode1');
          break;

        default:
          time = parseInt(value, 10);
          if (isNaN(time)) break;
// TBD: set the fan duration. adjust time from milliseconds to whatever
          break;
      }
    });

    attempt_perform('goalTemperature', function(value) {
      var goalTemperature;

      goalTemperature = parseInt(value, 10);
      if (isNaN(goalTemperature)) {
        return;
      }

      if (goalTemperature > 30 || goalTemperature < 16) {
        return;
      }

      // TODO UI says F, the unit works in C, which is this?
      self.hvac.set_temperature(goalTemperature);
    });

    return performed;
  }
};

Thermostat.prototype.perform = function(self, taskID, perform, parameter) {
  var params;

  try { params = JSON.parse(parameter); } catch(e) { params = {}; }

  if (!!Thermostat.operations[perform]) {
    if (Thermostat.operations[perform](this, params)) {
      return steward.performed(taskID);
    }
  }

  return devices.perform(self, taskID, perform, parameter);
};

var checkParam = function(key, params, result, allowNumeric, map) {
  if (typeof params[key] !== 'undefined') {

    var defined = typeof map[params[key]] !== 'undefined';

    if (((!defined) && (!allowNumeric)) || ((!defined) && allowNumeric && isNaN(parseInt(params[key], 10)))) {
      result.invalid.push(key);
    }
  }
};

var validate_perform = function(perform, parameter) {
  var params = {}
    , result = { invalid: [], requires: [] }
    ;

  if (!!parameter) try { params = JSON.parse(parameter); } catch(ex) { result.invalid.push('parameter'); }

  if (!!Thermostat.operations[perform]) {
    if (perform === 'set') {
      if (!params) {
        result.requires.push('parameter');
        return result;
      }

      checkParam('hvac', params, result, false, { heat: 1, cool: 1, fan: 1, off: 1 });
      checkParam('fan', params, result, true, { off: 1, on: 1, auto: 1 });
      checkParam('goalTemperature', params, result, true, {});
    }
    return result;
  }

  return devices.validate_perform(perform, parameter);
};

exports.start = function() {
  var logger2 = utility.logger('discovery');

  steward.actors.device.climate.samsung = steward.actors.device.climate.samsung ||
      { $info     : { type: '/device/climate/samsung' } };

  steward.actors.device.climate.samsung.control =
      { $info     : { type       : '/device/climate/samsung/control'
                    , observe    : [ ]
                    , perform    : [ ]
                    , properties : { name            : true
                                   , lastSample      : 'timestamp'
                                   , temperature     : 'celsius'
                                   , humidity        : 'percentage'
                                   , hvac            : [ 'cool', 'heat', 'fan', 'off' ]
                                   , fan             : [ 'on', 'auto', 'milliseconds' ]
                                   , goalTemperature : 'celsius'
                                   }
                    }
        , $validate : { perform    : validate_perform }
      };
  devices.makers['/device/climate/samsung/control'] = Thermostat;

// TBD: when the hardware driver discovers a new HVAC unit, it will call us.
// TBD: or if the low-level driver needs to be polled, then create a 'scan' function and call it periodically.

  new samsung().on('discover', function(aircon) {
    // TODO This is done to avoid detecting ourselves listening for the SSDP response.
    // There should be a better way :(
    if (!aircon.options.duid) {
      return;
    }
    var info;
    info = { source     : 'samsung'
           , hvac       : aircon
           , device     : { url          : null
                          , name         : aircon.options.info["NICKNAME"]
                          , manufacturer : aircon.manufacturer || 'Samsung'
                          , model        : { name        : aircon.options.info["MODELCODE"]
                                           , description : ''
                                           }
                          , unit         : { serial      : aircon.props.duid
                                           , udn         : 'Samsung:' + aircon.props.duid
                                           }
                          }

         };

    info.url = info.device.url;
    info.deviceType = '/device/climate/samsung/control';
    info.id = info.device.unit.udn;

    devices.discover(info, function (err, deviceID) {
      if (!deviceID) {
        return;
      }

      if (!devices.devices[deviceID]) {
        return;
      }
      var thermostat = devices.devices[deviceID].device;

      thermostat.setup(aircon);
    });

  }).on('error', function(err) {
    logger2.error('samsung', { diagnostic: err.message });
  }).logger = logger2;
};
<|endoftext|>


<commit_before>const
	path = require('path');

const paths = {}

const config = {
	site: {
		name: 'Amped Admin'
	},
	url: {
		prefix: '/api'
	},
	jwt: {
		secret: 'secret',
		expires: 7200,
		issuer: 'amped-framework.com'
	},
	errors: {
		loginerror: {
			code: 1000,
			message: 'Username or password is incorrect'
		}
	},
	bcrypt: {
		saltRounds: 10
	},
	uploads: {
		thumb: {
			width: 300,
			height: 300
		},
		sourceFilePath: '/uploads/source',
		thumbFilePath: '/uploads/thumb',
		baseDir: path.join(__dirname, '../../uploads'),
		thumbDir: path.join(__dirname, '../../uploads/thumb'),
		sourceDir: path.join(__dirname, '../../uploads/source'),
		tempDir: path.join(__dirname, '../../uploads/tmp')
	}
};

config.routing = {
	noAuth: [
		'/config',
		// `${config.url.prefix}/user`,
		`${config.url.prefix}/user/login`,
		`${config.url.prefix}/user/register`,
		`${config.url.prefix}/user/resetpassword`,
		`${config.url.prefix}/user/setpassword`,
		'/auth/google',
		'/auth/google/callback',
		'/auth/facebook',
		'/auth/facebook/callback',
		'/uploads/thumb'
	],
	openRoutes : [
		'/uploads/thumb',
		'/uploads/source'
	]
},

// @TODO make this mor comprehensive with regexp
config.routing.isPublic = (url) => {
	const base = url.split('?')[0];
	const parts = url.split('/');
	return config.routing.noAuth.indexOf(base) !== -1 || config.routing.openRoutes.filter(( route ) => url.indexOf(route) === 0 ).length > 0;
}
config.errors.getError = (key) => {
	//@TODO can add i18n translations here for message
	return config[key];
};

module.exports = config;
<commit_msg>Debugging on server<commit_after>const
	path = require('path');

const paths = {}

const config = {
	site: {
		name: 'Amped Admin'
	},
	url: {
		prefix: '/api'
	},
	jwt: {
		secret: 'secret',
		expires: 7200,
		issuer: 'amped-framework.com'
	},
	errors: {
		loginerror: {
			code: 1000,
			message: 'Username or password is incorrect'
		}
	},
	bcrypt: {
		saltRounds: 10
	},
	uploads: {
		thumb: {
			width: 300,
			height: 300
		},
		sourceFilePath: '/uploads/source',
		thumbFilePath: '/uploads/thumb',
		baseDir: path.join(__dirname, '../../uploads'),
		thumbDir: path.join(__dirname, '../../uploads/thumb'),
		sourceDir: path.join(__dirname, '../../uploads/source'),
		tempDir: path.join(__dirname, '../../uploads/tmp')
	}
};

config.routing = {
	noAuth: [
		'/config',
		// `${config.url.prefix}/user`,
		`${config.url.prefix}/user/login`,
		`${config.url.prefix}/user/register`,
		`${config.url.prefix}/user/resetpassword`,
		`${config.url.prefix}/user/setpassword`,
		'/auth/google',
		'/auth/google/callback',
		'/auth/facebook',
		'/auth/facebook/callback',
		'/uploads/thumb'
	],
	openRoutes : [
		'/uploads/thumb',
		'/uploads/source'
	]
},

// @TODO make this mor comprehensive with regexp
config.routing.isPublic = (url) => {

	console.log('IS PUBLIC', url);

	const base = url.split('?')[0];
	const parts = url.split('/');
	console.log(config.routing.noAuth.indexOf(base) !== -1);
	console.log(config.routing.openRoutes.filter(( route ) => url.indexOf(route) === 0 ));
	console.log(config.routing.noAuth.indexOf(base) !== -1 || config.routing.openRoutes.filter(( route ) => url.indexOf(route) === 0 ).length > 0);

	return config.routing.noAuth.indexOf(base) !== -1 || config.routing.openRoutes.filter(( route ) => url.indexOf(route) === 0 ).length > 0;
}
config.errors.getError = (key) => {
	//@TODO can add i18n translations here for message
	return config[key];
};

module.exports = config;
<|endoftext|>


<commit_before>define(function(require, exports, module) {
    main.consumes = ["editors", "ui", "settings", "tabManager", "ace"];
    main.provides = ["immediate"];
    return main;

    function main(options, imports, register) {
        var editors  = imports.editors;
        // var settings = imports.settings;
        var tabs     = imports.tabManager;
        var ui       = imports.ui;

        var Repl     = require("plugins/c9.ide.ace.repl/repl").Repl;
        var markup   = require("text!./immediate.xml");

        var counter  = 0;

        /***** Initialization *****/

        var extensions = [];

        var handle = editors.register("immediate", "Immediate Window",
                                      Immediate, extensions);
        var emit   = handle.getEmitter();

        var replTypes = {}; //Shared across Immediate windows

        handle.on("load", function(){
            handle.addElement(
                tabs.getElement("mnuEditors").appendChild(
                    new ui.item({
                        caption : "New Immediate Window",
                        onclick : function(e){
                            tabs.open({
                                active     : true,
                                pane        : this.parentNode.pane,
                                editorType : "immediate"
                            }, function(){});
                        }
                    })
                )
            );

            // Insert some CSS
            ui.insertCss(require("text!./style.css"), options.staticPrefix, handle);
        });

        /**
         * The immediate handle, provides an API for adding
         * {@link immediate.evaluator evaluators} to the immediate panes.
         * An evaluator is a plugin that can take the expressions typed in the
         * multi-line REPL like interface and return resuls. The results can be
         * rendered as HTML and are fully interactive.
         *
         * This is the object you get when you request the immediate service
         * in your plugin.
         *
         * Example:
         *
         *     define(function(require, exports, module) {
         *         main.consumes = ["immediate", "Plugin"];
         *         main.provides = ["myplugin"];
         *         return main;
         *
         *         function main(options, imports, register) {
         *             var immediate = imports.immediate;
         *             var plugin    = new imports.Plugin("name", main.consumes);
         *
         *             plugin.on("load", function(){
         *                 var evaluator = {
         *                     name        : "Go Language",
         *                     mode        : "ace/mode/go",
         *                     message     : "",
         *                     canEvaluate : function(str) { return str.trim() ? true : false; },
         *                     evaluate    : function(expression, cell, done) {
         *
         *                         executeCommand(expression, function(result){
         *                             cell.addWidget({
         *                                 html       : "
"
         *                                     + result + "
",
         *                                 coverLine  : true,
         *                                 fixedWidth : true
         *                             });
         *
         *                             done();
         *                         });
         *
         *                     }
         *                 };
         *
         *                 immediate.addEvaluator("Go Language", "go", evaluator, plugin);
         *             });
         *         });
         *     });
         *
         *
         * @class immediate
         * @extends Plugin
         * @singleton
         */
        handle.freezePublicAPI({
            _events : [
                /**
                 * @event addEvaluator
                 * @param {Object}              e
                 * @param {String}              e.caption     The caption of the evaluator.
                 * @param {String}              e.id          The unique identifier of the evaluator.
                 * @param {immediate.evaluator} e.evaluator   The evaluator.
                 * @param {Plugin}              e.plugin      The plugin responsible for adding the evaluator.
                 */
                "addEvaluator",
                /**
                 * @event removeEvaluator
                 * @param {Object}              e
                 * @param {String}              e.caption     The caption of the evaluator.
                 * @param {String}              e.id          The unique identifier of the evaluator.
                 * @param {immediate.evaluator} e.evaluator   The evaluator.
                 * @param {Plugin}              e.plugin      The plugin responsible for adding the evaluator.
                 */
                "removeEvaluator"
            ],

            /**
             * Adds a new evaluator to all immediate panes. The user is able
             * to choose the evaluator from a dropdown in the UI of the
             * immediate pane.
             * @param {String}              caption     The caption in the dropdown.
             * @param {String}              id          The unique identifier of this evaluator.
             * @param {immediate.evaluator} evaluator   The evaluator for your runtime.
             * @param {Plugin}              plugin      The plugin responsible for adding the evaluator.
             * @fires addEvaluator
             */
            addEvaluator : function(caption, id, evaluator, plugin){
                if (replTypes[id])
                    throw new Error("An evaluator is already registered with "
                        + "the id '" + id + "'");

                replTypes[id] = {
                    caption   : caption,
                    id        : id,
                    evaluator : evaluator,
                    plugin    : plugin
                };
                emit("addEvaluator", replTypes[id]);

                plugin.addOther(function(){
                    handle.removeEvaluator(id);
                });
            },

            /**
             *
             */
            findEvaluator : function(type, callback){
                if (!type || !replTypes[type]) {
                    handle.on("addEvaluator", function wait(e){
                        if (!type || e.id == type)
                            callback(e.id, replTypes[e.id].evaluator);

                        handle.off("addEvaluator", wait);
                    });
                }
                else {
                    callback(type, replTypes[type].evaluator);
                }
            },

            /**
             *
             */
            removeEvaluator : function(id){
                emit("removeEvaluator", replTypes[id]);
                delete replTypes[id];
            }
        });

        function Immediate(){
            var Baseclass = editors.findEditor("ace");

            var deps   = main.consumes.splice(0, main.consumes.length - 1);
            var plugin = new Baseclass(true, [], deps);
            // var emit   = plugin.getEmitter();

            var ddType, btnClear, ace;

            plugin.on("draw", function(e){
                // Create UI elements
                ui.insertMarkup(e.tab, markup, plugin);

                ddType    = plugin.getElement("ddType");
                btnClear  = plugin.getElement("btnClear");

                ace = plugin.ace;

                ace.setOption("printMargin", false);
                ace.setOption("scrollPastEnd", 0);
                ace.setOption("fontSize", 11);
                ace.setOption("showFoldWidgets", false);
                ace.setOption("highlightActiveLine", false);
                ace.setOption("highlightGutterLine", false);
                ace.container.style.lineHeight = "17px";

                e.htmlNode.className += " immediate";

                ddType.on("afterchange", function(){
                    if (currentDocument)
                        currentDocument.getSession().changeType(ddType.value);
                });
                btnClear.on("click", function(){
                    plugin.clear();
                });

                for (var type in replTypes){
                    var t = replTypes[type];
                    addType(t.caption, type, t.plugin);
                }

                handle.on("addEvaluator", function(e){
                    addType(e.caption, e.id, e.plugin);
                });
            });

            /***** Method *****/

            function addType(caption, value, plugin){
                var item = ddType.appendChild(new ui.item({
                    caption : caption,
                    value   : value
                }));

                plugin.addElement(item);
            }

            // Set the tab in loading state - later this could be the output block
            // currentDocument.tab.className.add("loading");
            // settings.save();

            /***** Lifecycle *****/

            plugin.on("load", function(){
            });

            var currentDocument;
            plugin.on("documentLoad", function(e){
                var doc     = e.doc;
                var session = doc.getSession();

                doc.undoManager.on("change", function(e){
                    if (!doc.undoManager.isAtBookmark())
                        doc.undoManager.bookmark();
                });

                doc.title = "Immediate";

                if (session.repl) return;

                session.changeType = function(type){
                    handle.findEvaluator(type, function(type, evaluator){
                        session.type = type;

                        if (!session.repl) {
                            session.repl = new Repl(session.session, {
                                mode      : evaluator.mode,
                                evaluator : evaluator,
                                message   : evaluator.message
                            });

                            if (currentDocument
                              && currentDocument.getSession() == session)
                                session.repl.attach(ace);
                        }
                        else {
                            session.repl.setEvaluator(evaluator);
                            session.repl.setMode(evaluator.mode);
                        }
                    });
                };

                session.changeType(session.type || ddType.value);
            });
            plugin.on("documentActivate", function(e){
                currentDocument = e.doc;
                var session = e.doc.getSession();

                if (session.type)
                    ddType.setValue(session.type);

                if (session.repl)
                    session.repl.attach(ace);
            });
            plugin.on("documentUnload", function(e){
                var session = e.doc.getSession();
                if (session.repl)
                    session.repl.detach();
                // TODO: this breaks moving repl between splits
                // delete session.repl;
            });
            plugin.on("getState", function(e){
                // @todo at one for each value container
                e.state.type      = e.doc.getSession().type;
            });
            plugin.on("setState", function(e){
                if (e.state.type)
                    ddType.setValue(e.state.type);
            });
            plugin.on("clear", function(){
            });
            plugin.on("focus", function(){
            });
            plugin.on("enable", function(){
            });
            plugin.on("disable", function(){
            });
            plugin.on("unload", function(){
            });

            /***** Register and define API *****/

            /**
             * Immediate Pane for Cloud9 IDE
             * @extends Editor
             */
            /**
             * The type of editor. Use this to create an immediate pane using
             * {@link tabManager#openEditor} or {@link editors#createEditor}.
             * @property {"immediate"} type
             * @readonly
             */
            plugin.freezePublicAPI({

            });

            plugin.load("immediate" + counter++);

            return plugin;
        }

        register(null, {
            immediate: handle
        });
    }
});<commit_msg>resolved merge conflict<commit_after>define(function(require, exports, module) {
    main.consumes = ["editors", "ui", "settings", "tabManager", "ace"];
    main.provides = ["immediate"];
    return main;

    function main(options, imports, register) {
        var editors  = imports.editors;
        // var settings = imports.settings;
        var tabs     = imports.tabManager;
        var ui       = imports.ui;

        var Repl     = require("plugins/c9.ide.ace.repl/repl").Repl;
        var markup   = require("text!./immediate.xml");

        var counter  = 0;

        /***** Initialization *****/

        var extensions = [];

        var handle = editors.register("immediate", "Immediate Window",
                                      Immediate, extensions);
        var emit   = handle.getEmitter();

        var replTypes = {}; //Shared across Immediate windows

        handle.on("load", function(){
            handle.addElement(
                tabs.getElement("mnuEditors").appendChild(
                    new ui.item({
                        caption : "New Immediate Window",
                        onclick : function(e){
                            tabs.open({
                                active     : true,
                                pane        : this.parentNode.pane,
                                editorType : "immediate"
                            }, function(){});
                        }
                    })
                )
            );

            // Insert some CSS
            ui.insertCss(require("text!./style.css"), options.staticPrefix, handle);
        });

        function Immediate(){
            var Baseclass = editors.findEditor("ace");

            var deps   = main.consumes.splice(0, main.consumes.length - 1);
            var plugin = new Baseclass(true, [], deps);
            // var emit   = plugin.getEmitter();

            var ddType, btnClear, ace;

            plugin.on("draw", function(e){
                // Create UI elements
                ui.insertMarkup(e.tab, markup, plugin);

                ddType    = plugin.getElement("ddType");
                btnClear  = plugin.getElement("btnClear");

                ace = plugin.ace;

                ace.setOption("printMargin", false);
                ace.setOption("scrollPastEnd", 0);
                ace.setOption("fontSize", 11);
                ace.setOption("showFoldWidgets", false);
                ace.setOption("highlightActiveLine", false);
                ace.setOption("highlightGutterLine", false);
                ace.container.style.lineHeight = "17px";

                e.htmlNode.className += " immediate";

                ddType.on("afterchange", function(){
                    if (currentDocument)
                        currentDocument.getSession().changeType(ddType.value);
                });
                btnClear.on("click", function(){
                    plugin.clear();
                });

                for (var type in replTypes){
                    var t = replTypes[type];
                    addType(t.caption, type, t.plugin);
                }

                handle.on("addEvaluator", function(e){
                    addType(e.caption, e.id, e.plugin);
                });
            });

            /***** Method *****/

            function addType(caption, value, plugin){
                var item = ddType.appendChild(new ui.item({
                    caption : caption,
                    value   : value
                }));

                plugin.addElement(item);
            }

            // Set the tab in loading state - later this could be the output block
            // currentDocument.tab.className.add("loading");
            // settings.save();

            /***** Lifecycle *****/

            plugin.on("load", function(){
            });

            var currentDocument;
            plugin.on("documentLoad", function(e){
                var doc     = e.doc;
                var session = doc.getSession();

                doc.undoManager.on("change", function(e){
                    if (!doc.undoManager.isAtBookmark())
                        doc.undoManager.bookmark();
                });

                doc.title = "Immediate";

                if (session.repl) return;

                session.changeType = function(type){
                    handle.findEvaluator(type, function(type, evaluator){
                        session.type = type;

                        if (!session.repl) {
                            session.repl = new Repl(session.session, {
                                mode      : evaluator.mode,
                                evaluator : evaluator,
                                message   : evaluator.message
                            });

                            if (currentDocument
                              && currentDocument.getSession() == session)
                                session.repl.attach(ace);
                        }
                        else {
                            session.repl.setEvaluator(evaluator);
                            session.repl.setMode(evaluator.mode);
                        }
                    });
                };

                session.changeType(session.type || ddType.value);
            });
            plugin.on("documentActivate", function(e){
                currentDocument = e.doc;
                var session = e.doc.getSession();

                if (session.type)
                    ddType.setValue(session.type);

                if (session.repl)
                    session.repl.attach(ace);
            });
            plugin.on("documentUnload", function(e){
                var session = e.doc.getSession();
                if (session.repl)
                    session.repl.detach();
                // TODO: this breaks moving repl between splits
                // delete session.repl;
            });
            plugin.on("getState", function(e){
                // @todo at one for each value container
                e.state.type      = e.doc.getSession().type;
            });
            plugin.on("setState", function(e){
                if (e.state.type)
                    ddType.setValue(e.state.type);
            });
            plugin.on("clear", function(){
            });
            plugin.on("focus", function(){
            });
            plugin.on("enable", function(){
            });
            plugin.on("disable", function(){
            });
            plugin.on("unload", function(){
            });

            /***** Register and define API *****/

            /**
             * Immediate Pane for Cloud9 IDE
             * @extends Editor
             */
            /**
             * The type of editor. Use this to create an immediate pane using
             * {@link tabManager#openEditor} or {@link editors#createEditor}.
             * @property {"immediate"} type
             * @readonly
             */
            plugin.freezePublicAPI({

            });

            plugin.load("immediate" + counter++);

            return plugin;
        }

        /**
         * Evaluates expressions from the {@link immediate immediate pane} REPL.
         *
         * This documentation doesn't describe an implementation, instead these
         * docs provide you a guide on how to write your own evaluator.
         *
         * The following example shows a simple evaluator that evaluates
         * javascript in an iframe:
         *
         *     var evaluator = {
         *         mode        : "ace/mode/javascript",
         *         message     : "",
         *         canEvaluate : function(str) { return str.trim() ? true : false; },
         *         evaluate    : function(expression, cell, done) {
         *
         *             var win = iframe.contentWindow;
         *             win.eval("try{window.result = " + expression
         *                 + "}catch(e){window.result = e}");
         *
         *             var result = JSON.serialize(win.result);
         *             cell.addWidget({
         *                 html       : "
" + result + "
",
         *                 coverLine  : true,
         *                 fixedWidth : true
         *             });
         *             cell.setWaiting(false);
         *
         *         }
         *     };
         *
         * @class immediate.evaluator
         * @extends Object
         * @singleton
         */
        /**
         * The language mode that is used to provide syntax highlighting. Any
         * ace mode is supported (e.g. "ace/mode/javascript", "ace/mode/html", etc).
         * @property {String} mode
         */
        /**
         * A message displayed at the top of the REPL. Leave this empty to not
         * show a message.
         * @property {String} message
         */
        /**
         * Determines whether the expression is valid and can be executed.
         * @method canEvaluate
         * @param {String} expression  The expression to inspect.
         * @return {Boolean}
         */
        /**
         * Evaluates an expression. Both synchronous and asynchronous evaluators
         * are supported.
         *
         * Example of a sync evaluator:
         *
         *     var evaluator = {
         *         mode        : "ace/mode/javascript",
         *         message     : "",
         *         canEvaluate : function(str) { return str.trim() ? true : false; },
         *         evaluate    : function(expression, cell, done) {
         *
         *             var win = iframe.contentWindow;
         *             win.eval("try{window.result = " + expression
         *                 + "}catch(e){window.result = e}");
         *
         *             var result = JSON.serialize(win.result);
         *             cell.addWidget({
         *                 html       : "
" + result + "
",
         *                 coverLine  : true,
         *                 fixedWidth : true
         *             });
         *             cell.setWaiting(false);
         *
         *         }
         *     };
         *
         * Example of an async evaluator:
         *
         *     var evaluator = {
         *         mode        : "ace/mode/text",
         *         message     : "",
         *         canEvaluate : function(str) { return str.trim() ? true : false; },
         *         evaluate    : function(expression, cell, done) {
         *
         *             executeCommand(expression, function(err, result){
         *                 if (err)
         *                     done("Error: " + err);
         *                 else {
         *                     cell.addWidget({
         *                         html       : "
"
         *                             + result + "
",
         *                         coverLine  : true,
         *                         fixedWidth : true
         *                     });
         *
         *                     done();
         *                 }
         *             });
         *
         *         }
         *     };
         *
         * @method evaluate
         * @param {String}          expression     The expression to evaluate.
         * @param {immediate.cell}  cell           The cell (each REPL section is a cell) that the expression was typed in.
         * @param {Function}        done           Call this function when the evaluation is async and the execution is completed.
         * @param {String}          [done.message] The message to print below the cell in plain text.
         */
        /**
         * A cell in the immediate REPL. Each section where a user can write
         * an (multi-line) epxression in is called a cell. A cell can have one
         * or more 'widgets' that display HTML or plain text, which are usually
         * the result of executing the expression.
         * @class immediate.Cell
         */
        /**
         * The immediate handle, provides an API for adding
         * {@link immediate.evaluator evaluators} to the immediate panes.
         * An evaluator is a plugin that can take the expressions from the
         * multi-line REPL and return resuls. The results can be
         * rendered as HTML and are fully interactive.
         *
         * This is the object you get when you request the immediate service
         * in your plugin.
         *
         * Example:
         *
         *     define(function(require, exports, module) {
         *         main.consumes = ["immediate", "Plugin"];
         *         main.provides = ["myplugin"];
         *         return main;
         *
         *         function main(options, imports, register) {
         *             var immediate = imports.immediate;
         *             var plugin    = new imports.Plugin("Your Name", main.consumes);
         *
         *             plugin.on("load", function(){
         *                 var evaluator = {
         *                     mode        : "ace/mode/go",
         *                     message     : "",
         *                     canEvaluate : function(str) { return str.trim() ? true : false; },
         *                     evaluate    : function(expression, cell, done) {
         *
         *                         executeCommand(expression, function(result){
         *                             cell.addWidget({
         *                                 html       : "
"
         *                                     + result + "
",
         *                                 coverLine  : true,
         *                                 fixedWidth : true
         *                             });
         *
         *                             done();
         *                         });
         *
         *                     }
         *                 };
         *
         *                 immediate.addEvaluator("Go Language", "go", evaluator, plugin);
         *             });
         *         });
         *     });
         *
         *
         * @class immediate
         * @extends Plugin
         * @singleton
         */
        handle.freezePublicAPI({
            _events : [
                /**
                 * Fires when an evaluator is added.
                 * @event addEvaluator
                 * @param {Object}              e
                 * @param {String}              e.caption     The caption of the evaluator.
                 * @param {String}              e.id          The unique identifier of the evaluator.
                 * @param {immediate.evaluator} e.evaluator   The evaluator.
                 * @param {Plugin}              e.plugin      The plugin responsible for adding the evaluator.
                 */
                "addEvaluator",
                /**
                 * Fires when an evaluator is removed.
                 * @event removeEvaluator
                 * @param {Object}              e
                 * @param {String}              e.caption     The caption of the evaluator.
                 * @param {String}              e.id          The unique identifier of the evaluator.
                 * @param {immediate.evaluator} e.evaluator   The evaluator.
                 * @param {Plugin}              e.plugin      The plugin responsible for adding the evaluator.
                 */
                "removeEvaluator"
            ],

            /**
             * Adds a new evaluator to all immediate panes. The user is able
             * to choose the evaluator from a dropdown in the UI of the
             * immediate pane.
             * @param {String}              caption     The caption in the dropdown.
             * @param {String}              id          The unique identifier of this evaluator.
             * @param {immediate.evaluator} evaluator   The evaluator for your runtime.
             * @param {Plugin}              plugin      The plugin responsible for adding the evaluator.
             * @fires addEvaluator
             */
            addEvaluator : function(caption, id, evaluator, plugin){
                if (replTypes[id])
                    throw new Error("An evaluator is already registered with "
                        + "the id '" + id + "'");

                replTypes[id] = {
                    caption   : caption,
                    id        : id,
                    evaluator : evaluator,
                    plugin    : plugin
                };
                emit("addEvaluator", replTypes[id]);

                plugin.addOther(function(){
                    handle.removeEvaluator(id);
                });
            },

            /**
             * Retrieves an evaluator based on it's id. When the evaluator is
             * not yet registered, the callback will be returned when the
             * evaluator is registered.
             * @param {String}              id                  The id of the evaluator to retrieve.
             * @param {Function}            callback            Called when the evaluator is available.
             * @param {Error}               callback.id         The id of the requested evaluator.
             * @param {immediate.evaluator} callback.evaluator  The evaluator requested.
             */
            findEvaluator : function(id, callback){
                if (!id || !replTypes[id]) {
                    handle.on("addEvaluator", function wait(e){
                        if (!id || e.id == id)
                            callback(e.id, replTypes[e.id].evaluator);

                        handle.off("addEvaluator", wait);
                    });
                }
                else {
                    callback(id, replTypes[id].evaluator);
                }
            },

            /**
             * Removes an evaluator from all immediate panes.
             * @param {String} id  The unique identifier of the evaluator to remove.
             */
            removeEvaluator : function(id){
                emit("removeEvaluator", replTypes[id]);
                delete replTypes[id];
            }
        });

        register(null, {
            immediate: handle
        });
    }
});<|endoftext|>


<commit_before>// @flow
import React, { Component } from 'react';
import type { Children } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { Modal } from '../components';
import Layout from '../containers/Layout';
// ======================================================
// Actions
// ======================================================
import * as ApplicationActions from '../actions/applicationActions';
// ======================================================
// Selectors
// ======================================================
import MasterappSelector from '../selectors/masterapp';
// ======================================================
// APIs
// ======================================================

const mapStateToProps = state => ({
  location: state.router.location,
  baseURL: MasterappSelector.getBaseURL(state.masterapp),
  modal: state.modal,
});

const actions = {
  ...ApplicationActions,
};

const mapDispatchToProps = dispatch => bindActionCreators(actions, dispatch);

class App extends Component {
  props: {
    children: Children,
    baseURL: string,
    location: Object,
    backToHome: Function,
    initApplication: Function
  };

  componentWillMount = () => {
    const { initApplication } = this.props;
    initApplication();
  };

  render() {
    const { backToHome, baseURL, location, insetCoin, modal } = this.props;
    console.log('App@render', this.props, location.pathname);
    return (

        <Layout.Header backToHome={backToHome} baseURL={baseURL} />
        {this.props.children}
        <Layout.Footer />
        {process.env.NODE_ENV !== 'production' && (

                 insetCoin(1)}>1B

                 insetCoin(5)}>5B

                 insetCoin(10)}>10B

                 insetCoin(20)}>20B

                 insetCoin(50)}>50B

                 insetCoin(100)}>100B

        )}

    );
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(App);
<commit_msg>Add UI 500, 1000 Baht<commit_after>// @flow
import React, { Component } from 'react';
import type { Children } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { Modal } from '../components';
import Layout from '../containers/Layout';
// ======================================================
// Actions
// ======================================================
import * as ApplicationActions from '../actions/applicationActions';
// ======================================================
// Selectors
// ======================================================
import MasterappSelector from '../selectors/masterapp';
// ======================================================
// APIs
// ======================================================

const mapStateToProps = state => ({
  location: state.router.location,
  baseURL: MasterappSelector.getBaseURL(state.masterapp),
  modal: state.modal,
});

const actions = {
  ...ApplicationActions,
};

const mapDispatchToProps = dispatch => bindActionCreators(actions, dispatch);

class App extends Component {
  props: {
    children: Children,
    baseURL: string,
    location: Object,
    backToHome: Function,
    initApplication: Function
  };

  componentWillMount = () => {
    const { initApplication } = this.props;
    initApplication();
  };

  render() {
    const { backToHome, baseURL, location, insetCoin, modal } = this.props;
    console.log('App@render', this.props, location.pathname);
    return (

        <Layout.Header backToHome={backToHome} baseURL={baseURL} />
        {this.props.children}
        <Layout.Footer />
        {process.env.NODE_ENV !== 'production' && (

                 insetCoin(1)}>1B

                 insetCoin(5)}>5B

                 insetCoin(10)}>10B

                 insetCoin(20)}>20B

                 insetCoin(50)}>50B

                 insetCoin(100)}>100B

                 insetCoin(500)}>500B

                 insetCoin(1000)}>1000B

        )}

    );
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(App);
<|endoftext|>


<commit_before>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
// @ts-check
(function () {
	const id = document.location.search.match(/\bid=([\w-]+)/)[1];

	const hostMessaging = new class HostMessaging {
		constructor() {
			this.handlers = new Map();
			window.addEventListener('message', (e) => {
				if (e.data && (e.data.command === 'onmessage' || e.data.command === 'do-update-state')) {
					// Came from inner iframe
					this.postMessage(e.data.command, e.data.data);
					return;
				}

				const channel = e.data.channel;
				const handler = this.handlers.get(channel);
				if (handler) {
					handler(e, e.data.args);
				} else {
					console.log('no handler for ', e);
				}
			});
		}

		postMessage(channel, data) {
			window.parent.postMessage({ target: id, channel, data }, '*');
		}

		onMessage(channel, handler) {
			this.handlers.set(channel, handler);
		}
	}();

	const workerReady = new Promise(async (resolveWorkerReady) => {
		if (!navigator.serviceWorker) {
			resolveWorkerReady();
		}

		const expectedWorkerVersion = 1;

		navigator.serviceWorker.register('service-worker.js').then(async registration => {
			await navigator.serviceWorker.ready;

			const versionHandler = (event) => {
				if (event.data.channel !== 'version') {
					return;
				}

				navigator.serviceWorker.removeEventListener('message', versionHandler);
				if (event.data.version === expectedWorkerVersion) {
					return resolveWorkerReady();
				} else {
					// If we have the wrong version, try once to unregister and re-register
					return registration.unregister()
						.then(() => navigator.serviceWorker.register('service-worker.js'))
						.then(() => navigator.serviceWorker.ready)
						.finally(resolveWorkerReady);
				}
			};
			navigator.serviceWorker.addEventListener('message', versionHandler);
			registration.active.postMessage({ channel: 'version' });
		});

		const forwardFromHostToWorker = (channel) => {
			hostMessaging.onMessage(channel, event => {
				navigator.serviceWorker.ready.then(registration => {
					registration.active.postMessage({ channel: channel, data: event.data.args });
				});
			});
		};
		forwardFromHostToWorker('did-load-resource');
		forwardFromHostToWorker('did-load-localhost');

		navigator.serviceWorker.addEventListener('message', event => {
			if (['load-resource', 'load-localhost'].includes(event.data.channel)) {
				hostMessaging.postMessage(event.data.channel, event.data);
			}
		});
	});
	var createWebviewManager;
	createWebviewManager({
		postMessage: hostMessaging.postMessage.bind(hostMessaging),
		onMessage: hostMessaging.onMessage.bind(hostMessaging),
		ready: workerReady,
	});
}());<commit_msg>Use update instead of manually tring to re-register<commit_after>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
// @ts-check
(function () {
	const id = document.location.search.match(/\bid=([\w-]+)/)[1];

	const hostMessaging = new class HostMessaging {
		constructor() {
			this.handlers = new Map();
			window.addEventListener('message', (e) => {
				if (e.data && (e.data.command === 'onmessage' || e.data.command === 'do-update-state')) {
					// Came from inner iframe
					this.postMessage(e.data.command, e.data.data);
					return;
				}

				const channel = e.data.channel;
				const handler = this.handlers.get(channel);
				if (handler) {
					handler(e, e.data.args);
				} else {
					console.log('no handler for ', e);
				}
			});
		}

		postMessage(channel, data) {
			window.parent.postMessage({ target: id, channel, data }, '*');
		}

		onMessage(channel, handler) {
			this.handlers.set(channel, handler);
		}
	}();

	const workerReady = new Promise(async (resolveWorkerReady) => {
		if (!navigator.serviceWorker) {
			resolveWorkerReady();
		}

		const expectedWorkerVersion = 1;

		navigator.serviceWorker.register('service-worker.js').then(async registration => {
			await navigator.serviceWorker.ready;

			const versionHandler = (event) => {
				if (event.data.channel !== 'version') {
					return;
				}

				navigator.serviceWorker.removeEventListener('message', versionHandler);
				if (event.data.version === expectedWorkerVersion) {
					return resolveWorkerReady();
				} else {
					// If we have the wrong version, try once to unregister and re-register
					return registration.update()
						.then(() => navigator.serviceWorker.ready)
						.finally(resolveWorkerReady);
				}
			};
			navigator.serviceWorker.addEventListener('message', versionHandler);
			registration.active.postMessage({ channel: 'version' });
		});

		const forwardFromHostToWorker = (channel) => {
			hostMessaging.onMessage(channel, event => {
				navigator.serviceWorker.ready.then(registration => {
					registration.active.postMessage({ channel: channel, data: event.data.args });
				});
			});
		};
		forwardFromHostToWorker('did-load-resource');
		forwardFromHostToWorker('did-load-localhost');

		navigator.serviceWorker.addEventListener('message', event => {
			if (['load-resource', 'load-localhost'].includes(event.data.channel)) {
				hostMessaging.postMessage(event.data.channel, event.data);
			}
		});
	});
	var createWebviewManager;
	createWebviewManager({
		postMessage: hostMessaging.postMessage.bind(hostMessaging),
		onMessage: hostMessaging.onMessage.bind(hostMessaging),
		ready: workerReady,
	});
}());<|endoftext|>