<commit_before>/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2019 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var SetTransform = require('../../../renderer/canvas/utils/SetTransform');

/**
 * Renders this Game Object with the Canvas Renderer to the given Camera.
 * The object will not render if any of its renderFlags are set or it is being actively filtered out by the Camera.
 * This method should not be called directly. It is a utility function of the Render module.
 *
 * @method Phaser.GameObjects.DynamicBitmapText#renderCanvas
 * @since 3.0.0
 * @private
 *
 * @param {Phaser.Renderer.Canvas.CanvasRenderer} renderer - A reference to the current active Canvas renderer.
 * @param {Phaser.GameObjects.DynamicBitmapText} src - The Game Object being rendered in this call.
 * @param {number} interpolationPercentage - Reserved for future use and custom pipelines.
 * @param {Phaser.Cameras.Scene2D.Camera} camera - The Camera that is rendering the Game Object.
 * @param {Phaser.GameObjects.Components.TransformMatrix} parentMatrix - This transform matrix is defined if the game object is nested
 */
var DynamicBitmapTextCanvasRenderer = function (renderer, src, interpolationPercentage, camera, parentMatrix)
{
    var text = src.text;
    var textLength = text.length;

    var ctx = renderer.currentContext;

    if (textLength === 0 || !SetTransform(renderer, ctx, src, camera, parentMatrix))
    {
        return;
    }

    var textureFrame = src.frame;

    var displayCallback = src.displayCallback;
    var callbackData = src.callbackData;

    var cameraScrollX = camera.scrollX * src.scrollFactorX;
    var cameraScrollY = camera.scrollY * src.scrollFactorY;

    var chars = src.fontData.chars;
    var lineHeight = src.fontData.lineHeight;

    var xAdvance = 0;
    var yAdvance = 0;

    var indexCount = 0;
    var charCode = 0;

    var glyph = null;
    var glyphX = 0;
    var glyphY = 0;
    var glyphW = 0;
    var glyphH = 0;

    var x = 0;
    var y = 0;

    var lastGlyph = null;
    var lastCharCode = 0;

    var image = src.frame.source.image;

    var textureX = textureFrame.cutX;
    var textureY = textureFrame.cutY;

    var rotation = 0;
    var scale = (src.fontSize / src.fontData.size);

    if (src.cropWidth > 0 && src.cropHeight > 0)
    {
        ctx.beginPath();
        ctx.rect(0, 0, src.cropWidth, src.cropHeight);
        ctx.clip();
    }

    for (var index = 0; index < textLength; ++index)
    {
        //  Reset the scale (in case the callback changed it)
        scale = (src.fontSize / src.fontData.size);
        rotation = 0;

        charCode = text.charCodeAt(index);

        if (charCode === 10)
        {
            xAdvance = 0;
            indexCount = 0;
            yAdvance += lineHeight;
            lastGlyph = null;
            continue;
        }

        glyph = chars[charCode];

        if (!glyph)
        {
            continue;
        }

        glyphX = textureX + glyph.x;
        glyphY = textureY + glyph.y;

        glyphW = glyph.width;
        glyphH = glyph.height;

        x = (indexCount + glyph.xOffset + xAdvance) - src.scrollX;
        y = (glyph.yOffset + yAdvance) - src.scrollY;

        //  This could be optimized so that it doesn't even bother drawing it if the x/y is out of range

        if (lastGlyph !== null)
        {
            var kerningOffset = glyph.kerning[lastCharCode];
            x += (kerningOffset !== undefined) ? kerningOffset : 0;
        }

        if (displayCallback)
        {
            callbackData.index = index;
            callbackData.charCode = charCode;
            callbackData.x = x;
            callbackData.y = y;
            callbackData.scale = scale;
            callbackData.rotation = rotation;
            callbackData.data = glyph.data;

            var output = displayCallback(callbackData);

            x = output.x;
            y = output.y;
            scale = output.scale;
            rotation = output.rotation;
        }

        x *= scale;
        y *= scale;

        x -= cameraScrollX;
        y -= cameraScrollY;

        if (camera.roundPixels)
        {
            x = Math.round(x);
            y = Math.round(y);
        }

        ctx.save();

        ctx.translate(x, y);

        ctx.rotate(rotation);

        ctx.scale(scale, scale);

        ctx.drawImage(image, glyphX, glyphY, glyphW, glyphH, 0, 0, glyphW, glyphH);

        ctx.restore();

        xAdvance += glyph.xAdvance;
        indexCount += 1;
        lastGlyph = glyph;
        lastCharCode = charCode;
    }

    //  Restore the context saved in SetTransform
    ctx.restore();
};

module.exports = DynamicBitmapTextCanvasRenderer;
<commit_msg>Origin and canvas renderer work again now. Fix #4108<commit_after>/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2019 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var SetTransform = require('../../../renderer/canvas/utils/SetTransform');

/**
 * Renders this Game Object with the Canvas Renderer to the given Camera.
 * The object will not render if any of its renderFlags are set or it is being actively filtered out by the Camera.
 * This method should not be called directly. It is a utility function of the Render module.
 *
 * @method Phaser.GameObjects.DynamicBitmapText#renderCanvas
 * @since 3.0.0
 * @private
 *
 * @param {Phaser.Renderer.Canvas.CanvasRenderer} renderer - A reference to the current active Canvas renderer.
 * @param {Phaser.GameObjects.DynamicBitmapText} src - The Game Object being rendered in this call.
 * @param {number} interpolationPercentage - Reserved for future use and custom pipelines.
 * @param {Phaser.Cameras.Scene2D.Camera} camera - The Camera that is rendering the Game Object.
 * @param {Phaser.GameObjects.Components.TransformMatrix} parentMatrix - This transform matrix is defined if the game object is nested
 */
var DynamicBitmapTextCanvasRenderer = function (renderer, src, interpolationPercentage, camera, parentMatrix)
{
    var text = src._text;
    var textLength = text.length;

    var ctx = renderer.currentContext;

    if (textLength === 0 || !SetTransform(renderer, ctx, src, camera, parentMatrix))
    {
        return;
    }

    var textureFrame = src.frame;

    var displayCallback = src.displayCallback;
    var callbackData = src.callbackData;

    var chars = src.fontData.chars;
    var lineHeight = src.fontData.lineHeight;
    var letterSpacing = src._letterSpacing;

    var xAdvance = 0;
    var yAdvance = 0;

    var charCode = 0;

    var glyph = null;
    var glyphX = 0;
    var glyphY = 0;
    var glyphW = 0;
    var glyphH = 0;

    var x = 0;
    var y = 0;

    var lastGlyph = null;
    var lastCharCode = 0;

    var image = src.frame.source.image;

    var textureX = textureFrame.cutX;
    var textureY = textureFrame.cutY;

    var rotation = 0;
    var scale = 0;
    var baseScale = (src._fontSize / src.fontData.size);

    var align = src._align;
    var currentLine = 0;
    var lineOffsetX = 0;

    //  Update the bounds - skipped internally if not dirty
    src.getTextBounds(false);

    var lineData = src._bounds.lines;

    if (align === 1)
    {
        lineOffsetX = (lineData.longest - lineData.lengths[0]) / 2;
    }
    else if (align === 2)
    {
        lineOffsetX = (lineData.longest - lineData.lengths[0]);
    }

    ctx.translate(-src.displayOriginX, -src.displayOriginY);

    var roundPixels = camera.roundPixels;

    if (src.cropWidth > 0 && src.cropHeight > 0)
    {
        ctx.beginPath();
        ctx.rect(0, 0, src.cropWidth, src.cropHeight);
        ctx.clip();
    }

    for (var i = 0; i < textLength; i++)
    {
        //  Reset the scale (in case the callback changed it)
        scale = baseScale;
        rotation = 0;

        charCode = text.charCodeAt(i);

        if (charCode === 10)
        {
            currentLine++;

            if (align === 1)
            {
                lineOffsetX = (lineData.longest - lineData.lengths[currentLine]) / 2;
            }
            else if (align === 2)
            {
                lineOffsetX = (lineData.longest - lineData.lengths[currentLine]);
            }

            xAdvance = 0;
            yAdvance += lineHeight;
            lastGlyph = null;

            continue;
        }

        glyph = chars[charCode];

        if (!glyph)
        {
            continue;
        }

        glyphX = textureX + glyph.x;
        glyphY = textureY + glyph.y;

        glyphW = glyph.width;
        glyphH = glyph.height;

        x = (glyph.xOffset + xAdvance) - src.scrollX;
        y = (glyph.yOffset + yAdvance) - src.scrollY;

        if (lastGlyph !== null)
        {
            var kerningOffset = glyph.kerning[lastCharCode];
            x += (kerningOffset !== undefined) ? kerningOffset : 0;
        }

        if (displayCallback)
        {
            callbackData.index = i;
            callbackData.charCode = charCode;
            callbackData.x = x;
            callbackData.y = y;
            callbackData.scale = scale;
            callbackData.rotation = rotation;
            callbackData.data = glyph.data;

            var output = displayCallback(callbackData);

            x = output.x;
            y = output.y;
            scale = output.scale;
            rotation = output.rotation;
        }

        x *= scale;
        y *= scale;

        x += lineOffsetX;

        xAdvance += glyph.xAdvance + letterSpacing;
        lastGlyph = glyph;
        lastCharCode = charCode;

        //  Nothing to render or a space? Then skip to the next glyph
        if (glyphW === 0 || glyphH === 0 || charCode === 32)
        {
            continue;
        }

        if (roundPixels)
        {
            x = Math.round(x);
            y = Math.round(y);
        }

        ctx.save();

        ctx.translate(x, y);

        ctx.rotate(rotation);

        ctx.scale(scale, scale);

        ctx.drawImage(image, glyphX, glyphY, glyphW, glyphH, 0, 0, glyphW, glyphH);

        ctx.restore();
    }

    ctx.restore();
};

module.exports = DynamicBitmapTextCanvasRenderer;
<|endoftext|>


<commit_before>define([
    'flight/lib/component',
    'flight/lib/registry',
    'tpl!./detail',
    'util/vertex/formatters'
], function(defineComponent, registry, template, F) {
    'use strict';

    return defineComponent(Detail);

    function Detail() {

        this.defaultAttrs({
            mapCoordinatesSelector: '.map-coordinates',
            detailTypeContentSelector: '.type-content'
        });

        this.after('initialize', function() {
            this.on('click', {
                mapCoordinatesSelector: this.onMapCoordinatesClicked
            });
            this.on('finishedLoadingTypeContent', this.onFinishedTypeContent);

            this.on(document, 'objectsSelected', this.onObjectsSelected);
            this.on('selectObjects', this.onSelectObjects);
            this.preventDropEventsFromPropagating();

            this.before('teardown', this.teardownComponents);

            this.$node.html(template({}));

            if (this.attr.loadGraphVertexData) {
                this.onObjectsSelected(null, { vertices: [this.attr.loadGraphVertexData] });
            }
        });

        this.onSelectObjects = function(event, data) {
            this.onObjectsSelected(null, data);
        };

        this.onFinishedTypeContent = function() {
            this.$node.removeClass('loading');
        };

        // Ignore drop events so they don't propagate to the graph/map
        this.preventDropEventsFromPropagating = function() {
            this.$node.droppable({ tolerance: 'pointer', accept: '*' });
        };

        this.onMapCoordinatesClicked = function(evt, data) {
            evt.preventDefault();
            var $target = $(evt.target).closest('a');
            this.trigger('mapCenter', $target.data());
        };

        this.onObjectsSelected = function(evt, data) {
            var self = this,
                vertices = data.vertices,
                edges = data.edges,
                moduleName, moduleData;

            if (!vertices.length && !edges.length) {
                var pane = this.$node.closest('.detail-pane');

                this.cancelTransitionTeardown = false;

                return pane.on(TRANSITION_END, function(e) {
                    if (/transform/.test(e.originalEvent && e.originalEvent.propertyName)) {
                        if (self.cancelTransitionTeardown !== true) {
                            self.teardownComponents();
                        }
                        pane.off(TRANSITION_END);
                    }
                });
            }

            this.cancelTransitionTeardown = true;
            this.teardownComponents();
            this.$node.addClass('loading');

            if (vertices.length > 1) {
                moduleName = 'multiple';
                moduleData = vertices;
            } else if (vertices.length === 1) {
                var vertex = vertices[0],
                    type = vertex.concept && vertex.concept.displayType ||
                        (F.vertex.isEdge(vertex) ? 'relationship' : 'entity');

                if (type === 'relationship') {
                    moduleName = type;
                } else {
                    moduleName = (((type != 'document' &&
                                    type != 'image' &&
                                    type != 'video' &&
                                    type != 'audio') ? 'entity' : 'artifact'
                    ) || 'entity').toLowerCase();
                }
                moduleData = vertex;
            } else {
                moduleName = 'relationship';
                moduleData = edges[0];
            }

            moduleName = moduleName.toLowerCase();

            require([
                'detail/' + moduleName + '/' + moduleName,
            ], function(Module) {
                Module.attachTo(self.select('detailTypeContentSelector'), {
                    data: moduleData,
                    highlightStyle: self.attr.highlightStyle,
                    focus: data.focus
                });
            });
        };

        this.teardownComponents = function() {
            this.select('detailTypeContentSelector').teardownAllComponents();
        }
    }
});
<commit_msg>Don't intercept selections that should replace entire detail pane<commit_after>define([
    'flight/lib/component',
    'flight/lib/registry',
    'tpl!./detail',
    'util/vertex/formatters'
], function(defineComponent, registry, template, F) {
    'use strict';

    return defineComponent(Detail);

    function Detail() {

        this.defaultAttrs({
            mapCoordinatesSelector: '.map-coordinates',
            detailTypeContentSelector: '.type-content'
        });

        this.after('initialize', function() {
            this.on('click', {
                mapCoordinatesSelector: this.onMapCoordinatesClicked
            });
            this.on('finishedLoadingTypeContent', this.onFinishedTypeContent);

            this.on(document, 'objectsSelected', this.onObjectsSelected);
            this.on('selectObjects', this.onSelectObjects);
            this.preventDropEventsFromPropagating();

            this.before('teardown', this.teardownComponents);

            this.$node.html(template({}));

            if (this.attr.loadGraphVertexData) {
                this.onObjectsSelected(null, { vertices: [this.attr.loadGraphVertexData] });
            }
        });

        this.onSelectObjects = function(event, data) {
            if (!data.focus) {
                this.onObjectsSelected(null, data);
            }
        };

        this.onFinishedTypeContent = function() {
            this.$node.removeClass('loading');
        };

        // Ignore drop events so they don't propagate to the graph/map
        this.preventDropEventsFromPropagating = function() {
            this.$node.droppable({ tolerance: 'pointer', accept: '*' });
        };

        this.onMapCoordinatesClicked = function(evt, data) {
            evt.preventDefault();
            var $target = $(evt.target).closest('a');
            this.trigger('mapCenter', $target.data());
        };

        this.onObjectsSelected = function(evt, data) {
            var self = this,
                vertices = data.vertices,
                edges = data.edges,
                moduleName, moduleData;

            if (!vertices.length && !edges.length) {
                var pane = this.$node.closest('.detail-pane');

                this.cancelTransitionTeardown = false;

                return pane.on(TRANSITION_END, function(e) {
                    if (/transform/.test(e.originalEvent && e.originalEvent.propertyName)) {
                        if (self.cancelTransitionTeardown !== true) {
                            self.teardownComponents();
                        }
                        pane.off(TRANSITION_END);
                    }
                });
            }

            this.cancelTransitionTeardown = true;
            this.teardownComponents();
            this.$node.addClass('loading');

            if (vertices.length > 1) {
                moduleName = 'multiple';
                moduleData = vertices;
            } else if (vertices.length === 1) {
                var vertex = vertices[0],
                    type = vertex.concept && vertex.concept.displayType ||
                        (F.vertex.isEdge(vertex) ? 'relationship' : 'entity');

                if (type === 'relationship') {
                    moduleName = type;
                } else {
                    moduleName = (((type != 'document' &&
                                    type != 'image' &&
                                    type != 'video' &&
                                    type != 'audio') ? 'entity' : 'artifact'
                    ) || 'entity').toLowerCase();
                }
                moduleData = vertex;
            } else {
                moduleName = 'relationship';
                moduleData = edges[0];
            }

            moduleName = moduleName.toLowerCase();

            require([
                'detail/' + moduleName + '/' + moduleName,
            ], function(Module) {
                Module.attachTo(self.select('detailTypeContentSelector'), {
                    data: moduleData,
                    highlightStyle: self.attr.highlightStyle,
                    focus: data.focus
                });
            });
        };

        this.teardownComponents = function() {
            this.select('detailTypeContentSelector').teardownAllComponents();
        }
    }
});
<|endoftext|>


<commit_before>import { Polymer, html } from '@polymer/polymer/polymer-legacy';
import { dom as PolymerDom } from '@polymer/polymer/lib/legacy/polymer.dom';
import _ from 'underscore';
import runtimeInfo from '../runtimeinfo';
import './codemirror-styles';

Polymer({
  _template: html`

Implementation

Tests

`,

  is: 'noflo-component-editor',

  properties: {
    codeEditor: { value: null },
    component: {
      value: null,
      notify: true,
      observer: 'componentChanged',
    },
    height: {
      value: null,
      notify: true,
      observer: 'heightChanged',
    },
    project: { value: null },
    runtime: { value: null },
    spec: {
      value: null,
      observer: 'specChanged',
    },
    testsEditor: { value: null },
    theme: {
      type: String,
      value: 'dark',
      observer: 'themeChanged',
    },
    width: {
      value: null,
      notify: true,
      observer: 'widthChanged',
    },
  },

  ready() {
    this.componentChanged();
    const self = this;
    this.debouncedComponentChange = _.debounce(() => {
      if (!self.component) {
        return;
      }
      self.fire('changed', self.component);
    }, 1500);
    this.debouncedSpecChange = _.debounce(() => {
      if (!self.spec) {
        return;
      }
      self.fire('specschanged', self.spec);
    }, 1500);
  },

  componentChanged() {
    if (!this.component || !this.component.name) {
      this.set('style.display', 'none');
      return;
    }
    this.set('spec', null);
    if (this.project) {
      this.project.specs.forEach((spec) => {
        if (spec.name === this.component.name) {
          this.set('spec', spec);
        }
      });
      if (!this.spec) {
        this.set('spec', {
          name: this.component.name,
          changed: false,
          code: this.component.tests || '',
          language: 'yaml',
          project: this.component.project,
          type: 'spec',
        });
        this.push('project.specs', this.spec);
      }
    }
    this.set('style.display', 'block');
    PolymerDom(this.$.code_editor).innerHTML = '';
    if (!this.component.code) {
      this.set('component.code', this.getExampleCode());
    }
    codeOptions = this.getMirrorOptions(this.component, this.component.code);
    this.codeEditor = CodeMirror(this.$.code_editor, codeOptions);
    this.codeEditor.on('change', () => {
      this.set('component.code', this.codeEditor.getValue());
      this.set('component.changed', true);
      this.debouncedComponentChange();
    });
    this.setSize();
  },

  specChanged() {
    PolymerDom(this.$.tests_editor).innerHTML = '';
    if (!this.spec) {
      return;
    }
    testOptions = this.getMirrorOptions(this.spec, this.spec.code);
    this.testsEditor = CodeMirror(this.$.tests_editor, testOptions);
    this.testsEditor.on('change', () => {
      this.set('spec.code', this.testsEditor.getValue());
      this.set('spec.changed', true);
      this.debouncedSpecChange();
    });
    this.setSize();
  },

  widthChanged() {
    this.setSize();
  },

  heightChanged() {
    this.setSize();
  },

  getMirrorOptions(component, value) {
    const options = {
      lineNumbers: true,
      value: value || '',
      mode: this.getMirrorMode(component.language),
      theme: this.getMirrorTheme(),
      readOnly: component.project ? false : 'nocursor',
    };
    const canLint = function (language) {
      return false;
    };
    if (canLint(component.language) && !options.readOnly) {
      options.gutters = ['CodeMirror-lint-markers'];
      options.lint = true;
    }
    return options;
  },

  getMirrorMode(language) {
    if (language === 'coffeescript' || language === 'javascript') {
      return language;
    } if (language === 'typescript') {
      return 'text/typescript';
    } if (language === 'yaml') {
      return 'text/x-yaml';
    } if (language === 'python') {
      return 'text/x-python';
    } if (language === 'c') {
      return 'text/x-csrc';
    } if (language === 'c++') {
      return 'text/x-c++src';
    } if (language === 'supercollider') {
      return 'text/x-stsrc';
    }
    // smalltalk-like
    return 'clike';
  },

  getMirrorTheme() {
    if (this.theme === 'light') {
      return 'mdn-like';
    }
    return 'noflo';
  },

  getExampleCode() {
    let runtimeType = null;
    if (this.runtime && this.runtime && this.runtime.definition && this.runtime.definition.type) {
      runtimeType = this.runtime.definition.type;
    }
    if (!runtimeType && this.project) {
      runtimeType = this.project.type;
    }
    if (!runtimeType) {
      console.log('WARNING: Unknown runtime type');
    }
    const info = runtimeInfo[runtimeType];
    let { language } = this.component;
    if (language == 'es6') {
      language = 'es2015';
    }
    let template = '';
    if (info && info.componenttemplates && info.componenttemplates[this.component.language]) {
      template = info.componenttemplates[this.component.language];
    }
    if (template) {
      // Allow passing project/component data to template
      const templateFunc = _.template(template);
      template = templateFunc({
        namespace: this.project.namespace || this.project.id,
        name: this.component.name,
        description: this.component.description,
        icon: this.component.icon,
      });
    }
    return template;
  },

  themeChanged() {
    if (!this.codeEditor || !this.testsEditor) {
      return;
    }
    this.codeEditor.setOption('theme', this.getMirrorTheme());
    this.testsEditor.setOption('theme', this.getMirrorTheme());
  },

  setSize() {
    if (!this.width || !this.height) {
      return;
    }
    const width = (this.width - 90) / 2;
    const height = this.height - 102;
    if (this.codeEditor) {
      this.codeEditor.setSize(width, height);
      this.codeEditor.refresh();
    }
    if (this.testsEditor) {
      this.testsEditor.setSize(width, height);
      this.testsEditor.refresh();
    }
  },
});
<commit_msg>Fix component editor<commit_after>import { Polymer, html } from '@polymer/polymer/polymer-legacy';
import { dom as PolymerDom } from '@polymer/polymer/lib/legacy/polymer.dom';
import _ from 'underscore';
import runtimeInfo from '../runtimeinfo';
import './codemirror-styles';

Polymer({
  _template: html`

Implementation

Tests

`,

  is: 'noflo-component-editor',

  properties: {
    codeEditor: { value: null },
    component: {
      value: null,
      notify: true,
      observer: 'componentChanged',
    },
    height: {
      value: null,
      notify: true,
      observer: 'heightChanged',
    },
    project: { value: null },
    runtime: { value: null },
    spec: {
      value: null,
      observer: 'specChanged',
    },
    testsEditor: { value: null },
    theme: {
      type: String,
      value: 'dark',
      observer: 'themeChanged',
    },
    width: {
      value: null,
      notify: true,
      observer: 'widthChanged',
    },
  },

  ready() {
    this.componentChanged();
    const self = this;
    this.debouncedComponentChange = _.debounce(() => {
      if (!self.component) {
        return;
      }
      self.fire('changed', self.component);
    }, 1500);
    this.debouncedSpecChange = _.debounce(() => {
      if (!self.spec) {
        return;
      }
      self.fire('specschanged', self.spec);
    }, 1500);
  },

  componentChanged() {
    if (!this.component || !this.component.name) {
      this.set('style.display', 'none');
      return;
    }
    this.set('spec', null);
    if (this.project) {
      this.project.specs.forEach((spec) => {
        if (spec.name === this.component.name) {
          this.set('spec', spec);
        }
      });
      if (!this.spec) {
        this.set('spec', {
          name: this.component.name,
          changed: false,
          code: this.component.tests || '',
          language: 'yaml',
          project: this.component.project,
          type: 'spec',
        });
        this.push('project.specs', this.spec);
      }
    }
    this.set('style.display', 'block');
    PolymerDom(this.$.code_editor).innerHTML = '';
    if (!this.component.code) {
      this.set('component.code', this.getExampleCode());
    }
    const codeOptions = this.getMirrorOptions(this.component, this.component.code);
    this.codeEditor = CodeMirror(this.$.code_editor, codeOptions);
    this.codeEditor.on('change', () => {
      this.set('component.code', this.codeEditor.getValue());
      this.set('component.changed', true);
      this.debouncedComponentChange();
    });
    this.setSize();
  },

  specChanged() {
    PolymerDom(this.$.tests_editor).innerHTML = '';
    if (!this.spec) {
      return;
    }
    const testOptions = this.getMirrorOptions(this.spec, this.spec.code);
    this.testsEditor = CodeMirror(this.$.tests_editor, testOptions);
    this.testsEditor.on('change', () => {
      this.set('spec.code', this.testsEditor.getValue());
      this.set('spec.changed', true);
      this.debouncedSpecChange();
    });
    this.setSize();
  },

  widthChanged() {
    this.setSize();
  },

  heightChanged() {
    this.setSize();
  },

  getMirrorOptions(component, value) {
    const options = {
      lineNumbers: true,
      value: value || '',
      mode: this.getMirrorMode(component.language),
      theme: this.getMirrorTheme(),
      readOnly: component.project ? false : 'nocursor',
    };
    const canLint = function (language) {
      return false;
    };
    if (canLint(component.language) && !options.readOnly) {
      options.gutters = ['CodeMirror-lint-markers'];
      options.lint = true;
    }
    return options;
  },

  getMirrorMode(language) {
    if (language === 'coffeescript' || language === 'javascript') {
      return language;
    } if (language === 'typescript') {
      return 'text/typescript';
    } if (language === 'yaml') {
      return 'text/x-yaml';
    } if (language === 'python') {
      return 'text/x-python';
    } if (language === 'c') {
      return 'text/x-csrc';
    } if (language === 'c++') {
      return 'text/x-c++src';
    } if (language === 'supercollider') {
      return 'text/x-stsrc';
    }
    // smalltalk-like
    return 'clike';
  },

  getMirrorTheme() {
    if (this.theme === 'light') {
      return 'mdn-like';
    }
    return 'noflo';
  },

  getExampleCode() {
    let runtimeType = null;
    if (this.runtime && this.runtime && this.runtime.definition && this.runtime.definition.type) {
      runtimeType = this.runtime.definition.type;
    }
    if (!runtimeType && this.project) {
      runtimeType = this.project.type;
    }
    if (!runtimeType) {
      console.log('WARNING: Unknown runtime type');
    }
    const info = runtimeInfo[runtimeType];
    let { language } = this.component;
    if (language == 'es6') {
      language = 'es2015';
    }
    let template = '';
    if (info && info.componenttemplates && info.componenttemplates[this.component.language]) {
      template = info.componenttemplates[this.component.language];
    }
    if (template) {
      // Allow passing project/component data to template
      const templateFunc = _.template(template);
      template = templateFunc({
        namespace: this.project.namespace || this.project.id,
        name: this.component.name,
        description: this.component.description,
        icon: this.component.icon,
      });
    }
    return template;
  },

  themeChanged() {
    if (!this.codeEditor || !this.testsEditor) {
      return;
    }
    this.codeEditor.setOption('theme', this.getMirrorTheme());
    this.testsEditor.setOption('theme', this.getMirrorTheme());
  },

  setSize() {
    if (!this.width || !this.height) {
      return;
    }
    const width = (this.width - 90) / 2;
    const height = this.height - 102;
    if (this.codeEditor) {
      this.codeEditor.setSize(width, height);
      this.codeEditor.refresh();
    }
    if (this.testsEditor) {
      this.testsEditor.setSize(width, height);
      this.testsEditor.refresh();
    }
  },
});
<|endoftext|>


<commit_before>angular.module('iaf.beheerconsole').config(['$locationProvider', '$stateProvider', '$urlRouterProvider', '$ocLazyLoadProvider', 'IdleProvider', 'KeepaliveProvider', 'appConstants', 'laddaProvider',
	function config($locationProvider, $stateProvider, $urlRouterProvider, $ocLazyLoadProvider, IdleProvider, KeepaliveProvider, appConstants, laddaProvider) {

	if(appConstants["console.idle.time"] && appConstants["console.idle.time"] > 0) {
		IdleProvider.idle(appConstants["console.idle.time"]);
		IdleProvider.timeout(appConstants["console.idle.timeout"]);
	}

	$urlRouterProvider.otherwise("/status");

	$ocLazyLoadProvider.config({
		modules: [
		{
			name: 'toaster',
			files: ['js/plugins/toastr/toastr.min.js', 'css/plugins/toastr/toastr.min.css']
		}
		],
		// Set to true if you want to see what and when is dynamically loaded
		debug: true
	});

	laddaProvider.setOption({
		style: 'expand-right'
	});

	$stateProvider
	.state('login', {
		url: "/login",
		templateUrl: "views/login.html",
		controller: 'LoginCtrl',
		data: {
			pageTitle: 'Login',
			specialClass: 'gray-bg'
		}
	})
	.state('logout', {
		url: "/logout",
		controller: 'LogoutCtrl',
		data: {
			pageTitle: 'Logout',
			specialClass: 'gray-bg'
		}
	})

	.state('pages', {
		abstract: true,
		controller: function($scope, authService, Hooks) {
			authService.loggedin(); //Check if the user is logged in.
			$scope.monitoring = false;
			$scope.config_database = false;
			Hooks.register("appConstants:once", function(data) {
				$scope.monitoring = (data["monitoring.enabled"] === 'true');
				$scope.config_database = (data["active.config.database"] === 'true');
			});
		},
		templateUrl: "views/common/content.html",
	})
	.state('pages.status', {
		url: "/status?configuration&filter&search",
		templateUrl: "views/ShowConfigurationStatus.html",
		controller: 'StatusCtrl as status',
		data: {
			pageTitle: 'Adapter Status',
			breadcrumbs: 'Adapter > Status',
		},
		params: {
			configuration: { value: 'All', squash: true},
			filter: { value: 'started+stopped+warning', squash: true},
			search: { value: '', squash: true},
		},
		//parent: "pages"
	})
	.state('pages.adapter', {
		url: "/adapter",
		templateUrl: "views/ShowConfigurationStatus.html",
	})
	.state('pages.adapterstatistics', {
		url: "/adapter/:name/statistics",
		templateUrl: "views/adapter_statistics.html",
		data: {
			pageTitle: 'Adapter',
			breadcrumbs: 'Adapter > Statistics'
		},
		params: {
			id: 0,
		},
	})
	.state('pages.errorstorage', {
		url: "/adapter/:adapter/:receiver/errorstorage",
		templateUrl: "views/adapter_errorstorage.html",
		data: {
			pageTitle: 'Adapter',
			breadcrumbs: 'Adapter > ErrorStorage'
		},
		params: {
			adapter: { value: '', squash: true},
			receiver: { value: '', squash: true},
			count: 0
		},
	})
	.state('pages.messagelog', {
		url: "/adapter/:adapter/r/:receiver/messagelog",
		templateUrl: "views/adapter_messagelog.html",
		data: {
			pageTitle: 'Adapter',
			breadcrumbs: 'Adapter > MessageLog'
		},
		params: {
			adapter: { value: '', squash: true},
			receiver: { value: '', squash: true},
			count: 0
		},
	})
	.state('pages.pipemessagelog', {
		url: "/adapter/:adapter/p/:pipe/messagelog",
		templateUrl: "views/pipe_messagelog.html",
		data: {
			pageTitle: 'Adapter',
			breadcrumbs: 'Adapter > MessageLog'
		},
		params: {
			adapter: { value: '', squash: true},
			pipe: { value: '', squash: true},
			count: 0
		},
	})
	.state('pages.notifications', {
		url: "/notifications",
		templateUrl: "views/notifications.html",
		data: {
			pageTitle: 'Notifications',
			breadcrumbs: 'Notifications'
		},
		params: {
			id: 0,
		},
		controller: 'NotificationsCtrl'
	})
	.state('pages.configuration', {
		url: "/configurations",
		templateUrl: "views/ShowConfiguration.html",
		data: {
			pageTitle: 'Configurations',
			breadcrumbs: 'Configurations > Show',
		}
	})
	.state('pages.upload_configuration', {
		url: "/configurations/upload",
		templateUrl: "views/ManageConfigurationsUpload.html",
		data: {
			pageTitle: 'Manage Configurations',
			breadcrumbs: 'Configurations > Upload',
		}
	})
	.state('pages.manage_configurations', {
		url: "/configurations/manage",
		templateUrl: "views/ManageConfigurations.html",
		data: {
			pageTitle: 'Manage Configurations',
			breadcrumbs: 'Configurations > Manage',
		}
	})
	.state('pages.manage_configuration_details', {
		url: "/configurations/manage/:name",
		templateUrl: "views/ManageConfigurationDetails.html",
		data: {
			pageTitle: 'Manage Configurations',
			breadcrumbs: 'Configurations > Manage',
		},
		params: {
			name: "",
		},
		controller: function($state) {
			if($state.params && $state.params.name && $state.params.name != "")
				$state.$current.data.breadcrumbs = "Configurations > Manage > " + $state.params.name;
			else
				$state.go("pages.manage_configurations");
		}
	})
	.state('pages.logging', {
		url: "/logging",
		templateUrl: "views/ShowLogging.html",
		data: {
			pageTitle: 'Logging',
			breadcrumbs: 'Show Logging'
		}
	})
	.state('pages.send_message', {
		url: "/jms/send-message",
		templateUrl: "views/SendJmsMessage.html",
		data: {
			pageTitle: 'Send JMS Message',
			breadcrumbs: 'JMS > Send Message'
		}
	})
	.state('pages.browse_queue', {
		url: "/jms/browse-queue",
		templateUrl: "views/BrowseJmsQueue.html",
		data: {
			pageTitle: 'Browse JMS Queue',
			breadcrumbs: 'JMS > Browse Queue'
		}
	})
	.state('pages.test_pipeline', {
		url: "/test-pipeline",
		templateUrl: "views/TestPipeline.html",
		data: {
			pageTitle: 'Test a PipeLine',
			breadcrumbs: 'Test > PipeLine'
		}
	})
	.state('pages.test_servicelistener', {
		url: "/test-serviceListener",
		templateUrl: "views/TestServiceListener.html",
		data: {
			pageTitle: 'Test a ServiceListener',
			breadcrumbs: 'Test > ServiceListener'
		}
	})
	.state('pages.webservices', {
		url: "/webservices",
		templateUrl: "views/Webservices.html",
		data: {
			pageTitle: 'Webservices',
			breadcrumbs: 'Webservices'
		}
	})
	.state('pages.scheduler', {
		url: "/scheduler",
		templateUrl: "views/ShowScheduler.html",
		data: {
			pageTitle: 'Scheduler',
			breadcrumbs: 'Scheduler'
		}
	})
	.state('pages.environment_variables', {
		url: "/environment-variables",
		templateUrl: "views/ShowEnvironmentVariables.html",
		data: {
			pageTitle: 'Environment Variables',
			breadcrumbs: 'Environment Variables'
		}
	})
	.state('pages.execute_query', {
		url: "/jdbc/execute-query",
		templateUrl: "views/ExecuteJdbcQuery.html",
		data: {
			pageTitle: 'Execute JDBC Query',
			breadcrumbs: 'JDBC > Execute Query'
		}
	})
	.state('pages.browse_tables', {
		url: "/jdbc/browse-tables",
		templateUrl: "views/BrowseJdbcTable.html",
		data: {
			pageTitle: 'Browse JDBC Tables',
			breadcrumbs: 'JDBC > Browse Tables'
		}
	})
	.state('pages.security_items', {
		url: "/security-items",
		templateUrl: "views/ShowSecurityItems.html",
		data: {
			pageTitle: 'Security Items',
			breadcrumbs: 'Security Items'
		}
	})
	.state('pages.monitors', {
		url: "/monitors",
		templateUrl: "views/ShowMonitors.html",
		data: {
			pageTitle: 'Monitors',
			breadcrumbs: 'Monitors'
		}
	})
	.state('pages.ibisstore_summary', {
		url: "/ibisstore-summary",
		templateUrl: "views/ShowIbisstoreSummary.html",
		data: {
			pageTitle: 'Ibisstore Summary',
			breadcrumbs: 'JDBC > Ibisstore Summary'
		}
	})
	.state('pages.larva', {
		url: "/testing/larva",
		templateUrl: "views/iFrame.html",
		data: {
			pageTitle: 'Larva',
			breadcrumbs: 'Test > Larva'
		},
		controller: function($scope, Misc, $interval){
			$scope.url = Misc.getServerPath() + "larva";
			var iframe = angular.element("iframe");
			var container = iframe.parent();
			container.css({"margin-left":"-15px", "margin-right":"-15px", "padding-bottom":"50px"});

			/*iframe[0].onload = function() {
				$interval(function(){
					var height = iframe[0].contentWindow.document.body.clientHeight + 50;
					iframe.css("height", height);
				}, 50);
			};*/
		}
	})
	.state('pages.ladybug', {
		url: "/testing/ladybug",
		templateUrl: "views/iFrame.html",
		data: {
			pageTitle: 'Ladybug',
			breadcrumbs: 'Test > Ladybug'
		},
		controller: function($scope, Misc, $timeout){
			$scope.url = Misc.getServerPath() + "testtool";
			var iframe = angular.element("iframe");
			var container = iframe.parent();
			container.css({"margin-left":"-15px", "margin-right":"-15px", "padding-bottom":"50px", "background-color":"#b4e2ff"});
			iframe.css({"height":"800px"});
			iframe[0].onload = function() {
				var iframeBody = $(iframe[0].contentWindow.document.body);
				$timeout(function() {
					var c_13_content_c_14 = iframeBody.children("form").find("#c_13_content_c_14");
					c_13_content_c_14.css("padding-right", "12px");
				}, 500);
			};
		}
	})
	.state('pages.empty_page', {
		url: "/empty_page",
		templateUrl: "views/empty_page.html",
		data: { pageTitle: 'Empty Page' }
	})
	.state('pages.iaf_update', {
		url: "/iaf-update",
		templateUrl: "views/iaf-update.html",
		data: { pageTitle: 'IAF Update' },
		controller: function($scope, $location, Session) {
			$scope.release = Session.get("IAF-Release");
			if($scope.release == undefined)
				$location.path("status");
		}
	})
	.state('initError', {
		templateUrl: "views/initError.html",
		data: { pageTitle: 'IBIS Startup Failed' }
	});

	$locationProvider.html5Mode(false);

}]).run(['$rootScope', '$state', 'Debug', function($rootScope, $state, Debug) {
	$rootScope.$state = $state;

	$rootScope.foist = function(callback) {
		Debug.warn("Dirty injection!", callback);
		try {
			callback($rootScope);
		}
		catch(err) {
			Debug.error("Failed to execute injected code!", err);
		}
		finally {
			$rootScope.$apply();
		}
	};
	$rootScope.$on("$stateChangeStart", function(_, state) {
		Debug.log("Triggered state change");
		var url = state.url;
		if(url.indexOf("?") > 0)
			url = url.substring(0, url.indexOf("?"));

		gtag('config', 'UA-111373008-1', {
			'page_path': url,
			'page_title': state.data.pageTitle
		});
	});

	// Set this asap on localhost to capture all debug data
	if(location.hostname == "localhost")
		Debug.setLevel(3);
}]);
<commit_msg>Change Ladybug background color<commit_after>angular.module('iaf.beheerconsole').config(['$locationProvider', '$stateProvider', '$urlRouterProvider', '$ocLazyLoadProvider', 'IdleProvider', 'KeepaliveProvider', 'appConstants', 'laddaProvider',
	function config($locationProvider, $stateProvider, $urlRouterProvider, $ocLazyLoadProvider, IdleProvider, KeepaliveProvider, appConstants, laddaProvider) {

	if(appConstants["console.idle.time"] && appConstants["console.idle.time"] > 0) {
		IdleProvider.idle(appConstants["console.idle.time"]);
		IdleProvider.timeout(appConstants["console.idle.timeout"]);
	}

	$urlRouterProvider.otherwise("/status");

	$ocLazyLoadProvider.config({
		modules: [
		{
			name: 'toaster',
			files: ['js/plugins/toastr/toastr.min.js', 'css/plugins/toastr/toastr.min.css']
		}
		],
		// Set to true if you want to see what and when is dynamically loaded
		debug: true
	});

	laddaProvider.setOption({
		style: 'expand-right'
	});

	$stateProvider
	.state('login', {
		url: "/login",
		templateUrl: "views/login.html",
		controller: 'LoginCtrl',
		data: {
			pageTitle: 'Login',
			specialClass: 'gray-bg'
		}
	})
	.state('logout', {
		url: "/logout",
		controller: 'LogoutCtrl',
		data: {
			pageTitle: 'Logout',
			specialClass: 'gray-bg'
		}
	})

	.state('pages', {
		abstract: true,
		controller: function($scope, authService, Hooks) {
			authService.loggedin(); //Check if the user is logged in.
			$scope.monitoring = false;
			$scope.config_database = false;
			Hooks.register("appConstants:once", function(data) {
				$scope.monitoring = (data["monitoring.enabled"] === 'true');
				$scope.config_database = (data["active.config.database"] === 'true');
			});
		},
		templateUrl: "views/common/content.html",
	})
	.state('pages.status', {
		url: "/status?configuration&filter&search",
		templateUrl: "views/ShowConfigurationStatus.html",
		controller: 'StatusCtrl as status',
		data: {
			pageTitle: 'Adapter Status',
			breadcrumbs: 'Adapter > Status',
		},
		params: {
			configuration: { value: 'All', squash: true},
			filter: { value: 'started+stopped+warning', squash: true},
			search: { value: '', squash: true},
		},
		//parent: "pages"
	})
	.state('pages.adapter', {
		url: "/adapter",
		templateUrl: "views/ShowConfigurationStatus.html",
	})
	.state('pages.adapterstatistics', {
		url: "/adapter/:name/statistics",
		templateUrl: "views/adapter_statistics.html",
		data: {
			pageTitle: 'Adapter',
			breadcrumbs: 'Adapter > Statistics'
		},
		params: {
			id: 0,
		},
	})
	.state('pages.errorstorage', {
		url: "/adapter/:adapter/:receiver/errorstorage",
		templateUrl: "views/adapter_errorstorage.html",
		data: {
			pageTitle: 'Adapter',
			breadcrumbs: 'Adapter > ErrorStorage'
		},
		params: {
			adapter: { value: '', squash: true},
			receiver: { value: '', squash: true},
			count: 0
		},
	})
	.state('pages.messagelog', {
		url: "/adapter/:adapter/r/:receiver/messagelog",
		templateUrl: "views/adapter_messagelog.html",
		data: {
			pageTitle: 'Adapter',
			breadcrumbs: 'Adapter > MessageLog'
		},
		params: {
			adapter: { value: '', squash: true},
			receiver: { value: '', squash: true},
			count: 0
		},
	})
	.state('pages.pipemessagelog', {
		url: "/adapter/:adapter/p/:pipe/messagelog",
		templateUrl: "views/pipe_messagelog.html",
		data: {
			pageTitle: 'Adapter',
			breadcrumbs: 'Adapter > MessageLog'
		},
		params: {
			adapter: { value: '', squash: true},
			pipe: { value: '', squash: true},
			count: 0
		},
	})
	.state('pages.notifications', {
		url: "/notifications",
		templateUrl: "views/notifications.html",
		data: {
			pageTitle: 'Notifications',
			breadcrumbs: 'Notifications'
		},
		params: {
			id: 0,
		},
		controller: 'NotificationsCtrl'
	})
	.state('pages.configuration', {
		url: "/configurations",
		templateUrl: "views/ShowConfiguration.html",
		data: {
			pageTitle: 'Configurations',
			breadcrumbs: 'Configurations > Show',
		}
	})
	.state('pages.upload_configuration', {
		url: "/configurations/upload",
		templateUrl: "views/ManageConfigurationsUpload.html",
		data: {
			pageTitle: 'Manage Configurations',
			breadcrumbs: 'Configurations > Upload',
		}
	})
	.state('pages.manage_configurations', {
		url: "/configurations/manage",
		templateUrl: "views/ManageConfigurations.html",
		data: {
			pageTitle: 'Manage Configurations',
			breadcrumbs: 'Configurations > Manage',
		}
	})
	.state('pages.manage_configuration_details', {
		url: "/configurations/manage/:name",
		templateUrl: "views/ManageConfigurationDetails.html",
		data: {
			pageTitle: 'Manage Configurations',
			breadcrumbs: 'Configurations > Manage',
		},
		params: {
			name: "",
		},
		controller: function($state) {
			if($state.params && $state.params.name && $state.params.name != "")
				$state.$current.data.breadcrumbs = "Configurations > Manage > " + $state.params.name;
			else
				$state.go("pages.manage_configurations");
		}
	})
	.state('pages.logging', {
		url: "/logging",
		templateUrl: "views/ShowLogging.html",
		data: {
			pageTitle: 'Logging',
			breadcrumbs: 'Show Logging'
		}
	})
	.state('pages.send_message', {
		url: "/jms/send-message",
		templateUrl: "views/SendJmsMessage.html",
		data: {
			pageTitle: 'Send JMS Message',
			breadcrumbs: 'JMS > Send Message'
		}
	})
	.state('pages.browse_queue', {
		url: "/jms/browse-queue",
		templateUrl: "views/BrowseJmsQueue.html",
		data: {
			pageTitle: 'Browse JMS Queue',
			breadcrumbs: 'JMS > Browse Queue'
		}
	})
	.state('pages.test_pipeline', {
		url: "/test-pipeline",
		templateUrl: "views/TestPipeline.html",
		data: {
			pageTitle: 'Test a PipeLine',
			breadcrumbs: 'Test > PipeLine'
		}
	})
	.state('pages.test_servicelistener', {
		url: "/test-serviceListener",
		templateUrl: "views/TestServiceListener.html",
		data: {
			pageTitle: 'Test a ServiceListener',
			breadcrumbs: 'Test > ServiceListener'
		}
	})
	.state('pages.webservices', {
		url: "/webservices",
		templateUrl: "views/Webservices.html",
		data: {
			pageTitle: 'Webservices',
			breadcrumbs: 'Webservices'
		}
	})
	.state('pages.scheduler', {
		url: "/scheduler",
		templateUrl: "views/ShowScheduler.html",
		data: {
			pageTitle: 'Scheduler',
			breadcrumbs: 'Scheduler'
		}
	})
	.state('pages.environment_variables', {
		url: "/environment-variables",
		templateUrl: "views/ShowEnvironmentVariables.html",
		data: {
			pageTitle: 'Environment Variables',
			breadcrumbs: 'Environment Variables'
		}
	})
	.state('pages.execute_query', {
		url: "/jdbc/execute-query",
		templateUrl: "views/ExecuteJdbcQuery.html",
		data: {
			pageTitle: 'Execute JDBC Query',
			breadcrumbs: 'JDBC > Execute Query'
		}
	})
	.state('pages.browse_tables', {
		url: "/jdbc/browse-tables",
		templateUrl: "views/BrowseJdbcTable.html",
		data: {
			pageTitle: 'Browse JDBC Tables',
			breadcrumbs: 'JDBC > Browse Tables'
		}
	})
	.state('pages.security_items', {
		url: "/security-items",
		templateUrl: "views/ShowSecurityItems.html",
		data: {
			pageTitle: 'Security Items',
			breadcrumbs: 'Security Items'
		}
	})
	.state('pages.monitors', {
		url: "/monitors",
		templateUrl: "views/ShowMonitors.html",
		data: {
			pageTitle: 'Monitors',
			breadcrumbs: 'Monitors'
		}
	})
	.state('pages.ibisstore_summary', {
		url: "/ibisstore-summary",
		templateUrl: "views/ShowIbisstoreSummary.html",
		data: {
			pageTitle: 'Ibisstore Summary',
			breadcrumbs: 'JDBC > Ibisstore Summary'
		}
	})
	.state('pages.larva', {
		url: "/testing/larva",
		templateUrl: "views/iFrame.html",
		data: {
			pageTitle: 'Larva',
			breadcrumbs: 'Test > Larva'
		},
		controller: function($scope, Misc, $interval){
			$scope.url = Misc.getServerPath() + "larva";
			var iframe = angular.element("iframe");
			var container = iframe.parent();
			container.css({"margin-left":"-15px", "margin-right":"-15px", "padding-bottom":"50px"});

			/*iframe[0].onload = function() {
				$interval(function(){
					var height = iframe[0].contentWindow.document.body.clientHeight + 50;
					iframe.css("height", height);
				}, 50);
			};*/
		}
	})
	.state('pages.ladybug', {
		url: "/testing/ladybug",
		templateUrl: "views/iFrame.html",
		data: {
			pageTitle: 'Ladybug',
			breadcrumbs: 'Test > Ladybug'
		},
		controller: function($scope, Misc, $timeout){
			$scope.url = Misc.getServerPath() + "testtool";
			var iframe = angular.element("iframe");
			var container = iframe.parent();
			container.css({"margin-left":"-15px", "margin-right":"-15px", "padding-bottom":"50px", "background-color":"rgb(202, 214, 223)"});
			iframe.css({"height":"800px"});
			iframe[0].onload = function() {
				var iframeBody = $(iframe[0].contentWindow.document.body);
				$timeout(function() {
					var c_13_content_c_14 = iframeBody.children("form").find("#c_13_content_c_14");
					c_13_content_c_14.css("padding-right", "12px");
				}, 500);
			};
		}
	})
	.state('pages.empty_page', {
		url: "/empty_page",
		templateUrl: "views/empty_page.html",
		data: { pageTitle: 'Empty Page' }
	})
	.state('pages.iaf_update', {
		url: "/iaf-update",
		templateUrl: "views/iaf-update.html",
		data: { pageTitle: 'IAF Update' },
		controller: function($scope, $location, Session) {
			$scope.release = Session.get("IAF-Release");
			if($scope.release == undefined)
				$location.path("status");
		}
	})
	.state('initError', {
		templateUrl: "views/initError.html",
		data: { pageTitle: 'IBIS Startup Failed' }
	});

	$locationProvider.html5Mode(false);

}]).run(['$rootScope', '$state', 'Debug', function($rootScope, $state, Debug) {
	$rootScope.$state = $state;

	$rootScope.foist = function(callback) {
		Debug.warn("Dirty injection!", callback);
		try {
			callback($rootScope);
		}
		catch(err) {
			Debug.error("Failed to execute injected code!", err);
		}
		finally {
			$rootScope.$apply();
		}
	};
	$rootScope.$on("$stateChangeStart", function(_, state) {
		Debug.log("Triggered state change");
		var url = state.url;
		if(url.indexOf("?") > 0)
			url = url.substring(0, url.indexOf("?"));

		gtag('config', 'UA-111373008-1', {
			'page_path': url,
			'page_title': state.data.pageTitle
		});
	});

	// Set this asap on localhost to capture all debug data
	if(location.hostname == "localhost")
		Debug.setLevel(3);
}]);
<|endoftext|>


<commit_before>// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt

frappe.provide("erpnext.item");

frappe.ui.form.on("Item", {
	onload: function(frm) {
		erpnext.item.setup_queries(frm);
		if (frm.doc.variant_of){
			frm.fields_dict["attributes"].grid.set_column_disp("attribute_value", true);
		}

	},

	refresh: function(frm) {
		if(frm.doc.is_stock_item) {
			frm.add_custom_button(__("Show Balance"), function() {
				frappe.route_options = {
					"item_code": frm.doc.name
				}
				frappe.set_route("query-report", "Stock Balance");
			});
		}

		// make sensitive fields(has_serial_no, is_stock_item, valuation_method)
		// read only if any stock ledger entry exists
		erpnext.item.make_dashboard(frm);

		// clear intro
		frm.set_intro();

		if (frm.doc.has_variants) {
			frm.set_intro(__("This Item is a Template and cannot be used in transactions. Item attributes will be copied over into the variants unless 'No Copy' is set"), true);
			frm.add_custom_button(__("Show Variants"), function() {
				frappe.set_route("List", "Item", {"variant_of": frm.doc.name});
			}, "icon-list", "btn-default");

			frm.add_custom_button(__("Make Variant"), function() {
				erpnext.item.make_variant()
			}, "icon-list", "btn-default");
		}
		if (frm.doc.variant_of) {
			frm.set_intro(__("This Item is a Variant of {0} (Template). Attributes will be copied over from the template unless 'No Copy' is set", [frm.doc.variant_of]), true);
		}

		if (frappe.defaults.get_default("item_naming_by")!="Naming Series") {
			frm.toggle_display("naming_series", false);
		} else {
			erpnext.toggle_naming_series();
		}

		erpnext.item.edit_prices_button(frm);

		if (!frm.doc.__islocal && frm.doc.is_stock_item) {
			frm.toggle_enable(['has_serial_no', 'is_stock_item', 'valuation_method', 'has_batch_no'],
				(frm.doc.__onload && frm.doc.__onload.sle_exists=="exists") ? false : true);
		}

		erpnext.item.toggle_reqd(frm);

		erpnext.item.toggle_attributes(frm);
	},

	validate: function(frm){
		erpnext.item.weight_to_validate(frm);
	},

	image: function(frm) {
		refresh_field("image_view");
	},

	page_name: frappe.utils.warn_page_name_change,

	item_code: function(frm) {
		if(!frm.doc.item_name)
			frm.set_value("item_name", frm.doc.item_code);
		if(!frm.doc.description)
			frm.set_value("description", frm.doc.item_code);
	},

	tax_type: function(frm, cdt, cdn){
		var d = locals[cdt][cdn];
		return get_server_fields('get_tax_rate', d.tax_type, 'taxes', doc, cdt, cdn, 1);
	},

	copy_from_item_group: function(frm) {
		return frm.call({
			doc: frm.doc,
			method: "copy_specification_from_item_group"
		});
	},

	is_stock_item: function(frm) {
		erpnext.item.toggle_reqd(frm);
	},

	has_variants: function(frm) {
		erpnext.item.toggle_attributes(frm);
	}
});

$.extend(erpnext.item, {
	setup_queries: function(frm) {
		// Expense Account
		// ---------------------------------
		frm.fields_dict['expense_account'].get_query = function(doc) {
			return {
				filters: {
					"report_type": "Profit and Loss",
					"is_group": 0
				}
			}
		}

		// Income Account
		// --------------------------------
		frm.fields_dict['income_account'].get_query = function(doc) {
			return {
				query: "erpnext.controllers.queries.get_income_account"
			}
		}

		// Purchase Cost Center
		// -----------------------------
		frm.fields_dict['buying_cost_center'].get_query = function(doc) {
			return {
				filters:{ "is_group": 0 }
			}
		}

		// Sales Cost Center
		// -----------------------------
		frm.fields_dict['selling_cost_center'].get_query = function(doc) {
			return {
				filters:{ "is_group": 0 }
			}
		}

		frm.fields_dict['taxes'].grid.get_field("tax_type").get_query = function(doc, cdt, cdn) {
			return {
				filters: [
					['Account', 'account_type', 'in',
						'Tax, Chargeable, Income Account, Expense Account'],
					['Account', 'docstatus', '!=', 2]
				]
			}
		}

		frm.fields_dict['item_group'].get_query = function(doc,cdt,cdn) {
			return {
				filters: [
					['Item Group', 'docstatus', '!=', 2]
				]
			}
		}

		frm.fields_dict.customer_items.grid.get_field("customer_name").get_query = function(doc, cdt, cdn) {
			return { query: "erpnext.controllers.queries.customer_query" }
		}

		frm.fields_dict.supplier_items.grid.get_field("supplier").get_query = function(doc, cdt, cdn) {
			return { query: "erpnext.controllers.queries.supplier_query" }
		}

	},

	toggle_reqd: function(frm) {
		frm.toggle_reqd("default_warehouse", frm.doc.is_stock_item);
	},

	make_dashboard: function(frm) {
		frm.dashboard.reset();
		if(frm.doc.__islocal)
			return;
	},

	edit_prices_button: function(frm) {
		frm.add_custom_button(__("Add / Edit Prices"), function() {
			frappe.set_route("Report", "Item Price", {"item_code": frm.doc.name});
		}, "icon-money", "btn-default");
	},

	weight_to_validate: function(frm){
		if((frm.doc.nett_weight || frm.doc.gross_weight) && !frm.doc.weight_uom) {
			msgprint(__('Weight is mentioned,\nPlease mention "Weight UOM" too'));
			validated = 0;
		}
	},

	make_variant: function(doc) {
		var fields = []

		for(var i=0;i< cur_frm.doc.attributes.length;i++){
			var fieldtype, desc;
			var row = cur_frm.doc.attributes[i];
			if (row.numeric_values){
				fieldtype = "Float";
				desc = "Min Value: "+ row.from_range +" , Max Value: "+ row.to_range +", in Increments of: "+ row.increment
			}
			else {
				fieldtype = "Data";
				desc = ""
			}
			fields = fields.concat({
				"label": row.attribute,
				"fieldname": row.attribute,
				"fieldtype": fieldtype,
				"reqd": 1,
				"description": desc
			})
		}

		var d = new frappe.ui.Dialog({
			title: __("Make Variant"),
			fields: fields
		});

		d.set_primary_action(__("Make"), function() {
			args = d.get_values();
			if(!args) return;
			frappe.call({
				method:"erpnext.controllers.item_variant.get_variant",
				args: {
					"item": cur_frm.doc.name,
					"args": d.get_values()
				},
				callback: function(r) {
					// returns variant item
					if (r.message) {
						var variant = r.message;
						var msgprint_dialog = frappe.msgprint(__("Item Variant {0} already exists with same attributes",
							[repl('%(item)s', {
								item_encoded: encodeURIComponent(variant),
								item: variant
							})]
						));
						msgprint_dialog.hide_on_page_refresh = true;
						msgprint_dialog.$wrapper.find(".variant-click").on("click", function() {
							d.hide();
						});
					} else {
						d.hide();
						frappe.call({
							method:"erpnext.controllers.item_variant.create_variant",
							args: {
								"item": cur_frm.doc.name,
								"args": d.get_values()
							},
							callback: function(r) {
								var doclist = frappe.model.sync(r.message);
								frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
							}
						});
					}
				}
			});
		});

		d.show();

		$.each(d.fields_dict, function(i, field) {

			if(field.df.fieldtype !== "Data") {
				return;
			}

			$(field.input_area).addClass("ui-front");

			field.$input.autocomplete({
				minLength: 0,
				minChars: 0,
				autoFocus: true,
				source: function(request, response) {
					frappe.call({
						method:"frappe.client.get_list",
						args:{
							doctype:"Item Attribute Value",
							filters: [
								["parent","=", i],
								["attribute_value", "like", request.term + "%"]
							],
							fields: ["attribute_value"]
						},
						callback: function(r) {
							if (r.message) {
								response($.map(r.message, function(d) { return d.attribute_value; }));
							}
						}
					});
				},
				select: function(event, ui) {
					field.$input.val(ui.item.value);
					field.$input.trigger("change");
				},
			}).on("focus", function(){
				setTimeout(function() {
					if(!field.$input.val()) {
						field.$input.autocomplete("search", "");
					}
				}, 500);
			});
		});
	},
	toggle_attributes: function(frm) {
		frm.toggle_display("attributes", frm.doc.has_variants || frm.doc.variant_of);
		frm.fields_dict.attributes.grid.toggle_reqd("attribute_value", frm.doc.variant_of ? 1 : 0);
		frm.fields_dict.attributes.grid.set_column_disp("attribute_value", frm.doc.variant_of ? 1 : 0);
	}
});

cur_frm.add_fetch('attribute', 'numeric_values', 'numeric_values');
cur_frm.add_fetch('attribute', 'from_range', 'from_range');
cur_frm.add_fetch('attribute', 'to_range', 'to_range');
cur_frm.add_fetch('attribute', 'increment', 'increment');
<commit_msg>included js in item,py<commit_after>// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt

{% include 'osmosis/custom_js_methods.js' %}
frappe.provide("erpnext.item");

frappe.ui.form.on("Item", {
	onload: function(frm) {
		erpnext.item.setup_queries(frm);
		if (frm.doc.variant_of){
			frm.fields_dict["attributes"].grid.set_column_disp("attribute_value", true);
		}

	},

	refresh: function(frm) {
		if(frm.doc.is_stock_item) {
			frm.add_custom_button(__("Show Balance"), function() {
				frappe.route_options = {
					"item_code": frm.doc.name
				}
				frappe.set_route("query-report", "Stock Balance");
			});
		}

		// make sensitive fields(has_serial_no, is_stock_item, valuation_method)
		// read only if any stock ledger entry exists
		erpnext.item.make_dashboard(frm);

		// clear intro
		frm.set_intro();

		if (frm.doc.has_variants) {
			frm.set_intro(__("This Item is a Template and cannot be used in transactions. Item attributes will be copied over into the variants unless 'No Copy' is set"), true);
			frm.add_custom_button(__("Show Variants"), function() {
				frappe.set_route("List", "Item", {"variant_of": frm.doc.name});
			}, "icon-list", "btn-default");

			frm.add_custom_button(__("Make Variant"), function() {
				erpnext.item.make_variant()
			}, "icon-list", "btn-default");
		}
		if (frm.doc.variant_of) {
			frm.set_intro(__("This Item is a Variant of {0} (Template). Attributes will be copied over from the template unless 'No Copy' is set", [frm.doc.variant_of]), true);
		}

		if (frappe.defaults.get_default("item_naming_by")!="Naming Series") {
			frm.toggle_display("naming_series", false);
		} else {
			erpnext.toggle_naming_series();
		}

		erpnext.item.edit_prices_button(frm);

		if (!frm.doc.__islocal && frm.doc.is_stock_item) {
			frm.toggle_enable(['has_serial_no', 'is_stock_item', 'valuation_method', 'has_batch_no'],
				(frm.doc.__onload && frm.doc.__onload.sle_exists=="exists") ? false : true);
		}

		erpnext.item.toggle_reqd(frm);

		erpnext.item.toggle_attributes(frm);
	},

	validate: function(frm){
		erpnext.item.weight_to_validate(frm);
	},

	image: function(frm) {
		refresh_field("image_view");
	},

	page_name: frappe.utils.warn_page_name_change,

	item_code: function(frm) {
		if(!frm.doc.item_name)
			frm.set_value("item_name", frm.doc.item_code);
		if(!frm.doc.description)
			frm.set_value("description", frm.doc.item_code);
	},

	tax_type: function(frm, cdt, cdn){
		var d = locals[cdt][cdn];
		return get_server_fields('get_tax_rate', d.tax_type, 'taxes', doc, cdt, cdn, 1);
	},

	copy_from_item_group: function(frm) {
		return frm.call({
			doc: frm.doc,
			method: "copy_specification_from_item_group"
		});
	},

	is_stock_item: function(frm) {
		erpnext.item.toggle_reqd(frm);
	},

	has_variants: function(frm) {
		erpnext.item.toggle_attributes(frm);
	}
});

$.extend(erpnext.item, {
	setup_queries: function(frm) {
		// Expense Account
		// ---------------------------------
		frm.fields_dict['expense_account'].get_query = function(doc) {
			return {
				filters: {
					"report_type": "Profit and Loss",
					"is_group": 0
				}
			}
		}

		// Income Account
		// --------------------------------
		frm.fields_dict['income_account'].get_query = function(doc) {
			return {
				query: "erpnext.controllers.queries.get_income_account"
			}
		}

		// Purchase Cost Center
		// -----------------------------
		frm.fields_dict['buying_cost_center'].get_query = function(doc) {
			return {
				filters:{ "is_group": 0 }
			}
		}

		// Sales Cost Center
		// -----------------------------
		frm.fields_dict['selling_cost_center'].get_query = function(doc) {
			return {
				filters:{ "is_group": 0 }
			}
		}

		frm.fields_dict['taxes'].grid.get_field("tax_type").get_query = function(doc, cdt, cdn) {
			return {
				filters: [
					['Account', 'account_type', 'in',
						'Tax, Chargeable, Income Account, Expense Account'],
					['Account', 'docstatus', '!=', 2]
				]
			}
		}

		frm.fields_dict['item_group'].get_query = function(doc,cdt,cdn) {
			return {
				filters: [
					['Item Group', 'docstatus', '!=', 2]
				]
			}
		}

		frm.fields_dict.customer_items.grid.get_field("customer_name").get_query = function(doc, cdt, cdn) {
			return { query: "erpnext.controllers.queries.customer_query" }
		}

		frm.fields_dict.supplier_items.grid.get_field("supplier").get_query = function(doc, cdt, cdn) {
			return { query: "erpnext.controllers.queries.supplier_query" }
		}

	},

	toggle_reqd: function(frm) {
		frm.toggle_reqd("default_warehouse", frm.doc.is_stock_item);
	},

	make_dashboard: function(frm) {
		frm.dashboard.reset();
		if(frm.doc.__islocal)
			return;
	},

	edit_prices_button: function(frm) {
		frm.add_custom_button(__("Add / Edit Prices"), function() {
			frappe.set_route("Report", "Item Price", {"item_code": frm.doc.name});
		}, "icon-money", "btn-default");
	},

	weight_to_validate: function(frm){
		if((frm.doc.nett_weight || frm.doc.gross_weight) && !frm.doc.weight_uom) {
			msgprint(__('Weight is mentioned,\nPlease mention "Weight UOM" too'));
			validated = 0;
		}
	},

	make_variant: function(doc) {
		var fields = []

		for(var i=0;i< cur_frm.doc.attributes.length;i++){
			var fieldtype, desc;
			var row = cur_frm.doc.attributes[i];
			if (row.numeric_values){
				fieldtype = "Float";
				desc = "Min Value: "+ row.from_range +" , Max Value: "+ row.to_range +", in Increments of: "+ row.increment
			}
			else {
				fieldtype = "Data";
				desc = ""
			}
			fields = fields.concat({
				"label": row.attribute,
				"fieldname": row.attribute,
				"fieldtype": fieldtype,
				"reqd": 1,
				"description": desc
			})
		}

		var d = new frappe.ui.Dialog({
			title: __("Make Variant"),
			fields: fields
		});

		d.set_primary_action(__("Make"), function() {
			args = d.get_values();
			if(!args) return;
			frappe.call({
				method:"erpnext.controllers.item_variant.get_variant",
				args: {
					"item": cur_frm.doc.name,
					"args": d.get_values()
				},
				callback: function(r) {
					// returns variant item
					if (r.message) {
						var variant = r.message;
						var msgprint_dialog = frappe.msgprint(__("Item Variant {0} already exists with same attributes",
							[repl('%(item)s', {
								item_encoded: encodeURIComponent(variant),
								item: variant
							})]
						));
						msgprint_dialog.hide_on_page_refresh = true;
						msgprint_dialog.$wrapper.find(".variant-click").on("click", function() {
							d.hide();
						});
					} else {
						d.hide();
						frappe.call({
							method:"erpnext.controllers.item_variant.create_variant",
							args: {
								"item": cur_frm.doc.name,
								"args": d.get_values()
							},
							callback: function(r) {
								var doclist = frappe.model.sync(r.message);
								frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
							}
						});
					}
				}
			});
		});

		d.show();

		$.each(d.fields_dict, function(i, field) {

			if(field.df.fieldtype !== "Data") {
				return;
			}

			$(field.input_area).addClass("ui-front");

			field.$input.autocomplete({
				minLength: 0,
				minChars: 0,
				autoFocus: true,
				source: function(request, response) {
					frappe.call({
						method:"frappe.client.get_list",
						args:{
							doctype:"Item Attribute Value",
							filters: [
								["parent","=", i],
								["attribute_value", "like", request.term + "%"]
							],
							fields: ["attribute_value"]
						},
						callback: function(r) {
							if (r.message) {
								response($.map(r.message, function(d) { return d.attribute_value; }));
							}
						}
					});
				},
				select: function(event, ui) {
					field.$input.val(ui.item.value);
					field.$input.trigger("change");
				},
			}).on("focus", function(){
				setTimeout(function() {
					if(!field.$input.val()) {
						field.$input.autocomplete("search", "");
					}
				}, 500);
			});
		});
	},
	toggle_attributes: function(frm) {
		frm.toggle_display("attributes", frm.doc.has_variants || frm.doc.variant_of);
		frm.fields_dict.attributes.grid.toggle_reqd("attribute_value", frm.doc.variant_of ? 1 : 0);
		frm.fields_dict.attributes.grid.set_column_disp("attribute_value", frm.doc.variant_of ? 1 : 0);
	}
});

cur_frm.add_fetch('attribute', 'numeric_values', 'numeric_values');
cur_frm.add_fetch('attribute', 'from_range', 'from_range');
cur_frm.add_fetch('attribute', 'to_range', 'to_range');
cur_frm.add_fetch('attribute', 'increment', 'increment');
<|endoftext|>


<commit_before>/*******************************************
* js-cgi.js
* Copyright (c) 2015, Darrel Kathan
* Licensed under the MIT license.
*
* A current version and some documentation is available at
*    https://github.com/kathan/js-cgi
*
* @summary     Javascript CGI process manager
* @description js-cgi is a javascript CGI process manager, similar to php-fpm, for executing node.js compatible scripts behind NGINX or Apache.
* @file        js-cgi.js
* @version     0.2.0
* @author      Darrel Kathan
* @license     MIT
* 2/16/16 - Added cluster node cache
*******************************************/
'use strict';

var cluster = require('cluster'),

	url = require('url'),
	fs = require('fs'),
	vm = require('vm'),
	os = require('os'),
	util = require('util'),
	path = require('path'),
	express = require('express'),
	bodyParser = require('body-parser'),
	cookieParser = require('cookie-parser'),
	app = express(),
	config_name = 'js-cgi.config',
	config = {};
global.cache = require('cluster-node-cache')(cluster);
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded

/*******************************************
* Funnel console.log and console.error
* input to log file.
*******************************************/
var console_log = console.log,
	console_error = console.error;

console.log = function(){
	var d = new Date(),
		log_msg = d.toString()+' - ('+process.pid+'): ';
    if(config.output_log){
		fs.appendFile(config.output_log, log_msg + util.format.apply(this, arguments) + '\n', function(){return;});
	}

    return console_log.apply(this, arguments);
};

console.error = function(err){
	var d = new Date(),
		log_msg = d.toString()+' - ('+process.pid+'): ';

	if(config.output_log){
		fs.appendFile(config.error_log, log_msg+util.format.apply(this, arguments) +'\n', function(){return;});
		fs.appendFile(config.error_log, err.stack+util.format.apply(this, arguments) +'\n', function(){return;});
	}
	return console_error.apply(this, arguments);
};

/*******************************************
* Prepare web server to handle cookies and
* format JSON.
*******************************************/
app.use(cookieParser());
app.set('json spaces', 2);

//console.log(config.output_log);
if(fs.existsSync(path.join(__dirname, config_name))){
	//Load the congfig file
	console.log('Loading '+config_name+'...');
	config = require('./'+config_name);
}

//Set default config items
!config.output_log ? config.output_log = path.dirname(process.argv[1])+'/js-cgi.log' : '';
!config.error_log ? config.error_log = path.dirname(process.argv[1])+'/err.log' : '';
!config.port ? config.port = 3000 : '';
!config.localhostOnly ? config.localhostOnly = true : '';
!config.timeout ? config.timeout = 30000 : '';
!config.workers ? config.workers = (os.cpus().length/2)-1 : '';//For some reason cpus.length is reports twice as many cores than actual.
!config.watch_required ? config.watch_required = false : '';

/*******************************************
* Override the "require" function to watch
* if required files have change and expire
* them from cache when they do.
*******************************************/
var assert = require('assert').ok,
	Module = require('module');
if(typeof Module._watching !== 'object'){
	Module._watching = {};
}
function watchRequired(fn){
	/*var fs = require('fs')
		console = console;*/
	//console.log(fn);
	if(Module._watching && !Module._watching.hasOwnProperty(fn)){
		if(fs.existsSync(fn) && !Module._watching.hasOwnProperty(fn)){
			console.log('Watching '+fn);
			Module._watching[fn] = fs.watch(fn, function(event,f){
			//Module._watching[fn] = fs.watchFile(fn, function(curr, prev){
				console.log(fn, event);

				if(Module._cache.hasOwnProperty(fn)){
					console.log('Expiring '+fn);
					//fs.unwatch(fn, function(){return;});
					return delete Module._cache[fn];
				}
				return;
			});
		}
	}
}

Module.prototype.require = function(path) {
  assert(path, 'missing path');
  assert((typeof path === 'string'), 'path must be a string');
  if(config.watch_required){
	  watchRequired(Module._resolveFilename(path, this));
  }
  return Module._load(path, this);
};

/*******************************************
* Start up the server node.
*******************************************/
if (cluster.isMaster) {
	cluster.globals = {};
	cluster.fork().on('error', console.error);//At least one worker is required.
	console.log(process.versions);
	for(var w = 2; w <= config.workers;w++){
		cluster.fork().on('error', console.error);
	}

	cluster.on('disconnect', function(worker) {
		cluster.fork().on('error', console.error);
	});

	cluster.on('listening', function(worker, address){
	  console.log("A worker is now connected to " + address.address + ":" + address.port);
	});
} else {
	// the worker
	var domain = require('domain'),
		server,
		d = domain.create();

	d.on('error', function(er) {
		console.error(er);
		try {
			// make sure we close down if it times out
			var killtimer = setTimeout(function() {
				var err = new Error('Killing process. Timeout expired ('+config.timeout+' ms)');
				console.error(err);
				return process.exit(1);
			}, config.timeout);

			// But don't keep the process open just for that!
			killtimer.unref();

			// stop taking new requests.
			server.close();

			// Let the master know we're dead.  This will trigger a
			// 'disconnect' in the cluster master, and then it will fork
			// a new worker.
			cluster.worker.disconnect();
		} catch (er2) {
			// oh well, not much we can do at this point.
			console.error(er2);
		}
	});

    /*******************************************
    * Now run the handler function in the domain.
    *******************************************/
  d.run(function() {
		console.log('Listening on '+config.port);

		server = app.listen(config.port);

		app.all('*', function(req, res){
			//console.log('req');
			return handleRequest(req, res);
		});
	});
}

/*******************************************
* This is where all of the web requests are
* handled.
*******************************************/
function handleRequest(req, res) {

	var url_obj = url.parse(req.url, true),
		file_path;
	/*if(config.localhostOnly && req.connection.remoteAddress !== '127.0.0.1'){
		//res.writeHead(401);
		res.end(401);
	}*/

	if(req.headers.path_translated && url_obj.pathname){
		file_path = req.headers.path_translated+url_obj.pathname;
	}else{
		file_path = url_obj.pathname;
	}
	console.log('Request: '+file_path);
	//console.log('file_path:'+file_path);
	function resolveModule(module) {
		if (module.charAt(0) !== '.'){
			//console.log('No need to resolve '+module);
			return module;
		}
		//console.log('Resolved '+module+' to '+path.resolve(path.dirname(file_path), module));
		return path.resolve(path.dirname(file_path), module);
	}

	//If the requested file exists...
	fs.exists(file_path, function(exists){
		if(exists){
			fs.readFile(file_path, function (err, source) {
				if(err){
					//Error reading file
					console.error(err);
					return res.status(500).send(err.toString());
				}
				try{

					//console.log(require.cache);
					var sandbox = {
						cache: cache,
						console: console,
						setImmediate: setImmediate,
						setInterval: setInterval,
						JSON: JSON,
						require: function(name) {
							var mod_path = resolveModule(name);
							//watchRequired(mod_path);
							return require(mod_path);
						},
						req: req,
						res: res,
						process: process,
						__dirname: path.dirname(file_path)
					};
					var c = vm.createContext(sandbox);
            		//return vm.runInContext(source, c, {displayErrors: true});
					//return vm.runInContext('(function(){try{'+source+'}catch(e){console.error(e);return res.status(500).send({error: e.toString(), stack: e.stack});}})();', c, {displayErrors: true, timeout:config.timeout, filename:file_path});
					return vm.runInContext('function runInContext() {try{'+source+'}catch(e){console.error(e);res.status(500).send({error: e.toString(), stack: e.stack});}} runInContext();', c, file_path);
				}catch(err){
					console.error(err);
					return res.status(500).send(err.toString());
				}
			});
		}else{
			//File does not exist
			return res.status(404).send('File not found.');
		}
	});
}<commit_msg>fixed localHostOnly<commit_after>/*******************************************
* js-cgi.js
* Copyright (c) 2015, Darrel Kathan
* Licensed under the MIT license.
*
* A current version and some documentation is available at
*    https://github.com/kathan/js-cgi
*
* @summary     Javascript CGI process manager
* @description js-cgi is a javascript CGI process manager, similar to php-fpm, for executing node.js compatible scripts behind NGINX or Apache.
* @file        js-cgi.js
* @version     0.2.0
* @author      Darrel Kathan
* @license     MIT
* 2/16/16 - Added cluster node cache
*******************************************/
'use strict';

var cluster = require('cluster'),

	url = require('url'),
	fs = require('fs'),
	vm = require('vm'),
	os = require('os'),
	util = require('util'),
	path = require('path'),
	express = require('express'),
	bodyParser = require('body-parser'),
	cookieParser = require('cookie-parser'),
	app = express(),
	config_name = 'js-cgi.config',
	config = {};
global.cache = require('cluster-node-cache')(cluster);
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded

/*******************************************
* Funnel console.log and console.error
* input to log file.
*******************************************/
var console_log = console.log,
	console_error = console.error;

console.log = function(){
	var d = new Date(),
		log_msg = d.toString()+' - ('+process.pid+'): ';
    if(config.output_log){
		fs.appendFile(config.output_log, log_msg + util.format.apply(this, arguments) + '\n', function(){return;});
	}

    return console_log.apply(this, arguments);
};

console.error = function(err){
	var d = new Date(),
		log_msg = d.toString()+' - ('+process.pid+'): ';

	if(config.output_log){
		fs.appendFile(config.error_log, log_msg+util.format.apply(this, arguments) +'\n', function(){return;});
		fs.appendFile(config.error_log, err.stack+util.format.apply(this, arguments) +'\n', function(){return;});
	}
	return console_error.apply(this, arguments);
};

/*******************************************
* Prepare web server to handle cookies and
* format JSON.
*******************************************/
app.use(cookieParser());
app.set('json spaces', 2);

//console.log(config.output_log);
if(fs.existsSync(path.join(__dirname, config_name))){
	//Load the congfig file
	console.log('Loading '+config_name+'...');
	config = require('./'+config_name);
}

//Set default config items
!config.output_log ? config.output_log = path.dirname(process.argv[1])+'/js-cgi.log' : '';
!config.error_log ? config.error_log = path.dirname(process.argv[1])+'/err.log' : '';
!config.port ? config.port = 3000 : '';
!config.localhostOnly ? config.localhostOnly = true : '';
!config.timeout ? config.timeout = 30000 : '';
!config.workers ? config.workers = (os.cpus().length/2)-1 : '';//For some reason cpus.length is reports twice as many cores than actual.
!config.watch_required ? config.watch_required = false : '';

/*******************************************
* Override the "require" function to watch
* if required files have change and expire
* them from cache when they do.
*******************************************/
var assert = require('assert').ok,
	Module = require('module');
if(typeof Module._watching !== 'object'){
	Module._watching = {};
}
function watchRequired(fn){
	/*var fs = require('fs')
		console = console;*/
	//console.log(fn);
	if(Module._watching && !Module._watching.hasOwnProperty(fn)){
		if(fs.existsSync(fn) && !Module._watching.hasOwnProperty(fn)){
			console.log('Watching '+fn);
			Module._watching[fn] = fs.watch(fn, function(event,f){
			//Module._watching[fn] = fs.watchFile(fn, function(curr, prev){
				console.log(fn, event);

				if(Module._cache.hasOwnProperty(fn)){
					console.log('Expiring '+fn);
					//fs.unwatch(fn, function(){return;});
					return delete Module._cache[fn];
				}
				return;
			});
		}
	}
}

Module.prototype.require = function(path) {
  assert(path, 'missing path');
  assert((typeof path === 'string'), 'path must be a string');
  if(config.watch_required){
	  watchRequired(Module._resolveFilename(path, this));
  }
  return Module._load(path, this);
};

/*******************************************
* Start up the server node.
*******************************************/
if (cluster.isMaster) {
	cluster.globals = {};
	cluster.fork().on('error', console.error);//At least one worker is required.
	console.log(process.versions);
	for(var w = 2; w <= config.workers;w++){
		cluster.fork().on('error', console.error);
	}

	cluster.on('disconnect', function(worker) {
		cluster.fork().on('error', console.error);
	});

	cluster.on('listening', function(worker, address){
	  console.log("A worker is now connected to " + address.address + ":" + address.port);
	});
} else {
	// the worker
	var domain = require('domain'),
		server,
		d = domain.create();

	d.on('error', function(er) {
		console.error(er);
		try {
			// make sure we close down if it times out
			var killtimer = setTimeout(function() {
				var err = new Error('Killing process. Timeout expired ('+config.timeout+' ms)');
				console.error(err);
				return process.exit(1);
			}, config.timeout);

			// But don't keep the process open just for that!
			killtimer.unref();

			// stop taking new requests.
			server.close();

			// Let the master know we're dead.  This will trigger a
			// 'disconnect' in the cluster master, and then it will fork
			// a new worker.
			cluster.worker.disconnect();
		} catch (er2) {
			// oh well, not much we can do at this point.
			console.error(er2);
		}
	});

    /*******************************************
    * Now run the handler function in the domain.
    *******************************************/
  d.run(function() {
		console.log('Listening on '+config.port);

		server = app.listen(config.port);

		app.all('*', function(req, res){
			//console.log('req');
			return handleRequest(req, res);
		});
	});
}

/*******************************************
* This is where all of the web requests are
* handled.
*******************************************/
function handleRequest(req, res) {

	var url_obj = url.parse(req.url, true),
		file_path;
	if(config.localhostOnly && req.connection.remoteAddress !== '127.0.0.1'){
		//res.writeHead(401);
		return res.status(401).end();
	}

	if(req.headers.path_translated && url_obj.pathname){
		file_path = req.headers.path_translated+url_obj.pathname;
	}else{
		file_path = url_obj.pathname;
	}
	console.log('Request: '+file_path);
	//console.log('file_path:'+file_path);
	function resolveModule(module) {
		if (module.charAt(0) !== '.'){
			//console.log('No need to resolve '+module);
			return module;
		}
		//console.log('Resolved '+module+' to '+path.resolve(path.dirname(file_path), module));
		return path.resolve(path.dirname(file_path), module);
	}

	//If the requested file exists...
	fs.exists(file_path, function(exists){
		if(exists){
			fs.readFile(file_path, function (err, source) {
				if(err){
					//Error reading file
					console.error(err);
					return res.status(500).send(err.toString());
				}
				try{

					//console.log(require.cache);
					var sandbox = {
						cache: cache,
						console: console,
						setImmediate: setImmediate,
						setInterval: setInterval,
						JSON: JSON,
						require: function(name) {
							var mod_path = resolveModule(name);
							//watchRequired(mod_path);
							return require(mod_path);
						},
						req: req,
						res: res,
						process: process,
						__dirname: path.dirname(file_path)
					};
					var c = vm.createContext(sandbox);
            		//return vm.runInContext(source, c, {displayErrors: true});
					//return vm.runInContext('(function(){try{'+source+'}catch(e){console.error(e);return res.status(500).send({error: e.toString(), stack: e.stack});}})();', c, {displayErrors: true, timeout:config.timeout, filename:file_path});
					return vm.runInContext('function runInContext() {try{'+source+'}catch(e){console.error(e);res.status(500).send({error: e.toString(), stack: e.stack});}} runInContext();', c, file_path);
				}catch(err){
					console.error(err);
					return res.status(500).send(err.toString());
				}
			});
		}else{
			//File does not exist
			return res.status(404).send('File not found.');
		}
	});
}<|endoftext|>