<commit_before>(function () {

window.ProjectSettings = {};

/**
*  returns a random name from this list to use as a confirmation string
*/
function randomScientist() {
    var scientists = [
    'Anning',
    'Banneker',
    'Cannon',
    'Carver',
    'Chappelle',
    'Curie',
    'Divine',
    'Emeagwali',
    'Fahlberg',
    'Forssmann',
    'Franklin',
    'Herschel',
    'Hodgkin',
    'Hopper',
    'Horowitz',
    'Jemison',
    'Julian',
    'Kovalevsky',
    'Lamarr',
    'Lavoisier',
    'Lovelace',
    'Massie',
    'McClintock',
    'Meitner',
    'Mitchell',
    'Morgan',
    'Nosek',
    'Odum',
    'Pasteur',
    'Pauling',
    'Payne',
    'Pearce',
    'Pollack',
    'Rillieux',
    'Sanger',
    'Somerville',
    'Tesla',
    'Tyson',
    'Turing',
    ];

    return scientists[Math.floor(Math.random() * scientists.length)];
}

/**
    * Pulls a random name from the scientist list to use as confirmation string
*  Ignores case and whitespace
*/
ProjectSettings.getConfirmationCode = function(nodeType) {
    var key = randomScientist();
    function successHandler(response) {
        // Redirect to either the parent project or the dashboard
        window.location.href = response.url;
    }

    $.ajax({
        url: nodeApiUrl + 'get_contributors/?limit=10',
        type: "get",
        dataType: "json",
        success: function(result) {
            contributorsHTML = result['contributors']
            more = result['more']

            contriblist = ''
            $.each(contributorsHTML, function(i, b){
                contriblist += "
" + b.fullname + "
"
            });

            console.log(contriblist)

            bootbox.prompt(
                'Are you sure you want to delete this ' + nodeType + '?' +
                '

It will be permanently deleted for every contributor:
' +
                '
' + contriblist +'
' +
                '
' +
                ((more > 0) ? 'and ' + more + ' more...
' : '') +
                '
' +
                'If you want to continue, type ' + key + ' and click OK.

',
                function(result) {
                    if (result != null) {
                        result = result.toLowerCase();
                    }
                    if ($.trim(result) === key.toLowerCase()) {
                        var request = $.ajax({
                            type: 'DELETE',
                            dataType: 'json',
                            url: nodeApiUrl
                        });
                        request.done(successHandler);
                        request.fail($.osf.handleJSONError);
                    } else if (result != null) {
                        bootbox.alert({
                            title: 'Incorrect confirmation',
                            message: 'The confirmation string you provided was incorrect. Please try again.'
                        });
                    }
                }
            );
        }
    })
};

$(document).ready(function() {

    // TODO: Knockout-ify me
    $('#commentSettings').on('submit', function() {
        var $commentMsg = $('#configureCommentingMessage');

        var $this = $(this);
        var commentLevel = $this.find('input[name="commentLevel"]:checked').val();

        $.osf.postJSON(
            nodeApiUrl + 'settings/comments/',
            {commentLevel: commentLevel}
        ).done(function() {
            $commentMsg.addClass('text-success');
            $commentMsg.text('Successfully updated settings.');
            window.location.reload();
        }).fail(function() {
            bootbox.alert('Could not set commenting configuration. Please try again.');
        });

        return false;

    });

    // Set up submission for addon selection form
    $('#selectAddonsForm').on('submit', function() {

        var formData = {};
        $('#selectAddonsForm').find('input').each(function(idx, elm) {
            var $elm = $(elm);
            formData[$elm.attr('name')] = $elm.is(':checked');
        });
        var msgElm = $(this).find('.addon-settings-message');
        $.ajax({
            url: nodeApiUrl + 'settings/addons/',
            data: JSON.stringify(formData),
            type: 'POST',
            contentType: 'application/json',
            dataType: 'json',
            success: function() {
                msgElm.text('Settings updated').fadeIn();
                window.location.reload();
            }
        });

        return false;

    });

    // Show capabilities modal on selecting an addon; unselect if user
    // rejects terms
    $('.addon-select').on('change', function() {
        var that = this,
            $that = $(that);
        if ($that.is(':checked')) {
            var name = $that.attr('name');
            var capabilities = $('#capabilities-' + name).html();
            if (capabilities) {
                bootbox.confirm(
                    capabilities,
                    function(result) {
                        if (!result) {
                            $(that).attr('checked', false);
                        }
                    }
                );
            }
        }
    });

});

}());
<commit_msg>Deletion confirmation wording change<commit_after>(function () {

window.ProjectSettings = {};

/**
*  returns a random name from this list to use as a confirmation string
*/
function randomScientist() {
    var scientists = [
    'Anning',
    'Banneker',
    'Cannon',
    'Carver',
    'Chappelle',
    'Curie',
    'Divine',
    'Emeagwali',
    'Fahlberg',
    'Forssmann',
    'Franklin',
    'Herschel',
    'Hodgkin',
    'Hopper',
    'Horowitz',
    'Jemison',
    'Julian',
    'Kovalevsky',
    'Lamarr',
    'Lavoisier',
    'Lovelace',
    'Massie',
    'McClintock',
    'Meitner',
    'Mitchell',
    'Morgan',
    'Nosek',
    'Odum',
    'Pasteur',
    'Pauling',
    'Payne',
    'Pearce',
    'Pollack',
    'Rillieux',
    'Sanger',
    'Somerville',
    'Tesla',
    'Tyson',
    'Turing',
    ];

    return scientists[Math.floor(Math.random() * scientists.length)];
}

/**
    * Pulls a random name from the scientist list to use as confirmation string
*  Ignores case and whitespace
*/
ProjectSettings.getConfirmationCode = function(nodeType) {
    var key = randomScientist();
    function successHandler(response) {
        // Redirect to either the parent project or the dashboard
        window.location.href = response.url;
    }

    $.ajax({
        url: nodeApiUrl + 'get_contributors/?limit=5',
        type: "get",
        dataType: "json",
        success: function(result) {
            contributorsHTML = result['contributors']
            more = result['more']

            contriblist = ''
            $.each(contributorsHTML, function(i, b){
                contriblist += "
" + b.fullname + "
"
            });

            console.log(contriblist)

            bootbox.prompt(
                'Are you sure you want to delete this ' + nodeType + '?' +
                '

It will no longer be available to other contributors on the project including:
' +
                '
' + contriblist +'
' +
                '
' +
                ((more > 0) ? 'and ' + more + ' others...
' : '') +
                '
' +
                'If you want to continue, type ' + key + ' and click OK.

',
                function(result) {
                    if (result != null) {
                        result = result.toLowerCase();
                    }
                    if ($.trim(result) === key.toLowerCase()) {
                        var request = $.ajax({
                            type: 'DELETE',
                            dataType: 'json',
                            url: nodeApiUrl
                        });
                        request.done(successHandler);
                        request.fail($.osf.handleJSONError);
                    } else if (result != null) {
                        bootbox.alert({
                            title: 'Incorrect confirmation',
                            message: 'The confirmation string you provided was incorrect. Please try again.'
                        });
                    }
                }
            );
        }
    })
};

$(document).ready(function() {

    // TODO: Knockout-ify me
    $('#commentSettings').on('submit', function() {
        var $commentMsg = $('#configureCommentingMessage');

        var $this = $(this);
        var commentLevel = $this.find('input[name="commentLevel"]:checked').val();

        $.osf.postJSON(
            nodeApiUrl + 'settings/comments/',
            {commentLevel: commentLevel}
        ).done(function() {
            $commentMsg.addClass('text-success');
            $commentMsg.text('Successfully updated settings.');
            window.location.reload();
        }).fail(function() {
            bootbox.alert('Could not set commenting configuration. Please try again.');
        });

        return false;

    });

    // Set up submission for addon selection form
    $('#selectAddonsForm').on('submit', function() {

        var formData = {};
        $('#selectAddonsForm').find('input').each(function(idx, elm) {
            var $elm = $(elm);
            formData[$elm.attr('name')] = $elm.is(':checked');
        });
        var msgElm = $(this).find('.addon-settings-message');
        $.ajax({
            url: nodeApiUrl + 'settings/addons/',
            data: JSON.stringify(formData),
            type: 'POST',
            contentType: 'application/json',
            dataType: 'json',
            success: function() {
                msgElm.text('Settings updated').fadeIn();
                window.location.reload();
            }
        });

        return false;

    });

    // Show capabilities modal on selecting an addon; unselect if user
    // rejects terms
    $('.addon-select').on('change', function() {
        var that = this,
            $that = $(that);
        if ($that.is(':checked')) {
            var name = $that.attr('name');
            var capabilities = $('#capabilities-' + name).html();
            if (capabilities) {
                bootbox.confirm(
                    capabilities,
                    function(result) {
                        if (!result) {
                            $(that).attr('checked', false);
                        }
                    }
                );
            }
        }
    });

});

}());
<|endoftext|>


<commit_before>var net = require('net');
var sys = require('sys');
var zombie = require('zombie');

//
// Store a global reference to the Zombie.js
// browser object and a buffered collection
// of Zombie.js calls.
//
var browser = null;

//
// This is used as a per-browser cache to store
// NodeList results.  Subsequent TCP API calls
// will reference indexes of ELEMENTS to retrieve
// DOM attributes/properties accumulated in previous
// browser.querySelectorAll() calls.
//
var ELEMENTS = [];

//
// Simple proxy server implementation
// for proxying streamed (Javascript) content via HTTP
// to a running Zombie.js
//
// Borrowed (heavily) from the Capybara-Zombie project
// https://github.com/plataformatec/capybara-zombie
//

net.createServer(function (stream){
  stream.setEncoding('utf8');

  stream.on('data', function (data){
    if (browser == null){
      browser = new zombie.Browser();
      ELEMENTS = [];
    }
    eval(data);
  });

}).listen(process.argv[2]);

console.log('Node TCP server running on '+process.argv[2]+'...');
<commit_msg>Removed unused require('sys').<commit_after>var net = require('net');
var zombie = require('zombie');

//
// Store a global reference to the Zombie.js
// browser object and a buffered collection
// of Zombie.js calls.
//
var browser = null;

//
// This is used as a per-browser cache to store
// NodeList results.  Subsequent TCP API calls
// will reference indexes of ELEMENTS to retrieve
// DOM attributes/properties accumulated in previous
// browser.querySelectorAll() calls.
//
var ELEMENTS = [];

//
// Simple proxy server implementation
// for proxying streamed (Javascript) content via HTTP
// to a running Zombie.js
//
// Borrowed (heavily) from the Capybara-Zombie project
// https://github.com/plataformatec/capybara-zombie
//

net.createServer(function (stream){
  stream.setEncoding('utf8');

  stream.on('data', function (data){
    if (browser == null){
      browser = new zombie.Browser();
      ELEMENTS = [];
    }
    eval(data);
  });

}).listen(process.argv[2]);

console.log('Node TCP server running on '+process.argv[2]+'...');
<|endoftext|>


<commit_before>/*
---
name: ART.SplitView
description: A simple horizonal double-pane split view.
requires: [ART.Widget, ART.Sheet, Core/Element.Event, Core/Element.Style, Touch/Touch, Core/Fx.Tween]
provides: ART.SplitView
...
*/

ART.Sheet.define('splitview.art', {
	'width': 600,
	'height': 400,
	'fixed-width': 200,
	'max-fixed-width': 400,
	'min-fixed-width': null,
	'splitter-width': 3,
	'display': 'block',
	//IE doesn't support east-west resize cursor; just use east
	'splitter-cursor': Browser.Engine.trident ? 'e-resize' : 'ew-resize',

	'splitter-background-color': hsb(0, 0, 50),
	'left-background-color': '#d6dde5',

	'right-background-color': '#fff'
});

ART.Sheet.define('splitview.art:disabled', {
	'splitter-background-color': hsb(0, 0, 70),
	'left-background-color': '#e8e8e8'
});
(function(){

var splitter = {

	Extends: ART.Widget,

	Implements: [Options, Events, Chain],

	options: {
		resizable: true,
		foldable: true,
		hideSplitterOnFullFold: false
	},

	name: 'splitview',

	initialize: function(options){
		this.parent(options);
		this._orientations = {
			'left': this.options.orientation == "horizontal" ? "left" : "top",
			'right': this.options.orientation == "horizontal" ? "right" : "bottom",
			'bottom': 'bottom',
			'top': 'top',
			'dimension': this.options.orientation == "horizontal" ? "width" : "height"
		};
		if (this.options.orientation == "vertical") this.addClass('vertical');
		this._build();
	},

	_build: function(){
		document.id(this.canvas).dispose();
		var sheet = this.setSheet();

		this.element.addClass('art-splitview').setStyles({
			'position': 'relative',
			'width': sheet.width,
			'height': sheet.height,
			'display': sheet.display
		});
		var styles = this.options.orientation == "horizontal" ?
		             {'float': 'left', 'overflow-x': 'auto'} :
		             {'overflow-y': 'auto'};
		var o = this._orientations;
		this[o.left] = new Element('div', {
			'class': 'art-splitview-' + o.left,
			styles: {
				'background-color': sheet[o.left + 'BackgroundColor']
			}
		}).inject(this.element).setStyles(styles);
		this.splitter = new Element('div', {
			'class': 'art-splitview-splitter',
			styles: {
				'background-color': sheet.splitterBackgroundColor
			}
		}).inject(this.element).setStyles(styles)
			.setStyle(o.dimension,
				        sheet['splitter' + o.dimension.capitalize()]);
		this[o.right] = new Element('div', {
			'class': 'art-splitview-' + o.right,
			styles: {
				'background-color': sheet[o.right + 'BackgroundColor']
			}
		}).inject(this.element).setStyles(styles);

		this.fx = new Fx();
		this.touch = new Touch(this.splitter);
		var self = this;
		var fix = self.options.fixed;
		var Fix = fix.capitalize();

		if (this.options.resizable || this.options.foldable){
			this.touch.addEvent('start', function(){
				self.startFixSize = self[fix + o.dimension.capitalize()];
			});
		}

		if (this.options.resizable) {
			this.touch.addEvent('move', function(){
				this.moveSplitter.apply(this, arguments);
			}.bind(this));
		}
		if (this.options.foldable){
			this.touch.addEvent('cancel', function(){
				if (self[fix + 'Size'] == 0){
					self['fold' + Fix](self.previousSize);
				} else {
					self.previousSize = self.startFixSize;
					self['fold' + Fix](0);
				}
			});
		}

		this.deferDraw();
	},

	moveSplitter: function(dx, dy){
		var cs = this.currentSheet;
		var o = this._orientations;
		var targetSize = this.startFixSize + (this.options.orientation == "horizontal" ? dx : -dy);
		if (targetSize < 0) targetSize = 0;
		if (targetSize > cs[o.dimension] - cs['splitter' + o.dimension.capitalize()]) {
			targetSize = cs[o.dimension] - cs['splitter' + o.dimension.capitalize()];
		}
		var fix = {
			'top': 'left',
			'bottom': 'right'
		}[this.options.fixed] || this.options.fixed;
		this._resizeSide(fix, targetSize);
	},

	draw: function(newSheet){
		var cs = this.currentSheet;
		var o = this._orientations;
		var sheet = this.parent(newSheet);

		var sizeChanged = (sheet.width != undefined && sheet.height != undefined);

		if (sizeChanged) {
			this.currentHeight = cs.height;
			this.currentWidth = cs.width;
			this.element.setStyles({
				'width': cs.width,
				'height': cs.height
			});
		}

		if (sheet.display) this.element.setStyle('display', cs.display);

		var splitterStr = "splitter" + o.dimension.capitalize();
		if (sheet[splitterStr] != undefined) {
			this.splitter.setStyle(o.dimension, cs[splitterStr]);
			this.splitter.setStyle('background-color', cs.splitterBackgroundColor);
		}
		if (this.options.resizable) this.splitter.setStyle('cursor', cs.splitterCursor);

		if (sheet[o.left + 'BackgroundColor']) {
			this[o.left].setStyles({
				'background-color': cs[o.left + 'BackgroundColor']
			});
		}
		if (sheet[o.right + 'BackgroundColor']) {
			this[o.right].setStyles({
				'background-color': cs[o.right + 'BackgroundColor']
			});
		}

		if (sizeChanged) {
			var otherDimension = o.dimension == "width" ? "height" : "width";
			$$(this[o.left], this[o.right],
				 this.splitter).setStyle(otherDimension, cs[otherDimension]);

			var side = this.options.fixed;
			var other = {
				'top':'bottom',
				'left':'right',
				'bottom':'top',
				'right':'left'
			}[side];

			var dim = o[side] + o.dimension.capitalize();
			if (this[dim] == undefined) this[dim] = cs['fixed' + o.dimension.capitalize()];
			this._resizeSide(other, cs[o.dimension] - this[dim] - cs[splitterStr]);
		}

		return this;
	},

	resize: function(w, h){
		if (this.isDestroyed()) return;
		return this.draw({'height': h, 'width': w});
	},

	_resizeSide: function(side, width){
		var o = this._orientations;
		side = {
			'top': 'left',
			'bottom': 'right'
		}[side] || side;
		var otherSide = side == 'left' ? 'right' : 'left';
		var cs = this.currentSheet;
		var splitterStr = "splitter" + o.dimension.capitalize();
		width = width.limit(0, cs[o.dimension] - cs[splitterStr]);
		this[o[side]].setStyle(o.dimension, width);

		var sideWidth = o[side] + o.dimension.capitalize();
		var otherSideWidth = o[otherSide] + o.dimension.capitalize();

		this[sideWidth] = width;
		this[otherSideWidth] = cs[o.dimension] - cs[splitterStr] - width;
		this[o[otherSide]].setStyle(o.dimension, this[otherSideWidth]);
	},

	fold: function(side, to, hideSplitter) {
		side = {
			'top': 'left',
			'bottom': 'right'
		}[side] || side;
		var cs = this.currentSheet;
		hideSplitter = $pick(hideSplitter, this.options.hideSplitterOnFullFold);
		var self = this;
		var other = side == 'left' ? 'right' : 'left';
		this.fx.set = function(now){
			self.resizeSide(side, now);
		};
		var splitterStr = "splitter" + o.dimension.capitalize();

		var sideWidth = o[side] + o.dimension.capitalize();

		if (to > 0 && this[sideWidth] && this.splitterHidden) {
			self.splitter.setStyle('width', cs[splitterStr]);
			self[other].setStyle('width', self[other + 'Width'] - cs[splitterStr]);
			this.splitterHidden = false;
		}
		this.fx.start(this[sideWidth], to).chain(function(){
			if (hideSplitter) {
				[o.left, o.right].each(function(side) {
					var other = {
						'top':'bottom',
						'left':'right',
						'bottom':'top',
						'right':'left'
					}[side];
					var sideWidth = o[side] + o.dimension.capitalize();
					var otherWidth = o[other] + o.dimension.capitalize();
					if (self[sideWidth] == 0) {
						self.splitter.setStyle(o.dimension, 0);
						self[other].setStyle(o.dimension, self[otherWidth] + cs[splitterStr]);
						self[otherWidth] = self[otherWidth] + cs[splitterStr];
					}
				});
				this.splitterHidden = true;
			}
			this.callChain();
		}.bind(this));
		return this;
	},

	_setSideContent: function(side, content) {
		document.id(this[this._orientations[side] || side]).empty().adopt(content);
	}

};

ART.SplitView = new Class(
	$merge(splitter, {
		options: {
			orientation: 'horizontal',
			fixed: 'left'
		},
		setLeftContent: function(){
			this._setSideContent('left', arguments);
			return this;
		},

		setRightContent: function(){
			this._setSideContent('right', arguments);
			return this;
		},

		resizeLeft: function(width) {
			this._resizeSide('left', width);
		},

		resizeRight: function(width){
			this._resizeSide('right', width);
		}

	})
);

ART.Sheet.define('splitview.art.vertical', {
	'fixed-height': 100,
	'splitter-height': 3,
	//IE doesn't support east-west resize cursor; just use east
	'splitter-cursor': Browser.Engine.trident ? 's-resize' : 'ns-resize',
	'bottom-background-color': '#d6dde5',
	'top-background-color': '#fff'
});

ART.Sheet.define('splitview.art.vertical:disabled', {
	'bottom-background-color': '#e8e8e8'
});

ART.SplitView.Vertical = new Class(
	$merge(splitter, {
		options: {
			orientation: 'vertical',
			fixed: 'bottom'
		},
		setTopContent: function(){
			this._setSideContent('top', arguments);
			return this;
		},
		setBottomContent: function(){
			this._setSideContent('bottom', arguments);
			return this;
		},

		resizeTop: function(height) {
			this._resizeSide('top', height);
		},

		resizeBottom: function(height) {
			this._resizeSide('bottom', height);
		}

	})
);

})();<commit_msg>adding a toggle function to splitview<commit_after>/*
---
name: ART.SplitView
description: A simple horizonal double-pane split view.
requires: [ART.Widget, ART.Sheet, Core/Element.Event, Core/Element.Style, Touch/Touch, Core/Fx.Tween]
provides: ART.SplitView
...
*/

ART.Sheet.define('splitview.art', {
	'width': 600,
	'height': 400,
	'fixed-width': 200,
	'max-fixed-width': 400,
	'min-fixed-width': null,
	'splitter-width': 3,
	'display': 'block',
	//IE doesn't support east-west resize cursor; just use east
	'splitter-cursor': Browser.Engine.trident ? 'e-resize' : 'ew-resize',

	'splitter-background-color': hsb(0, 0, 50),
	'left-background-color': '#d6dde5',

	'right-background-color': '#fff'
});

ART.Sheet.define('splitview.art:disabled', {
	'splitter-background-color': hsb(0, 0, 70),
	'left-background-color': '#e8e8e8'
});
(function(){

var splitter = {

	Extends: ART.Widget,

	Implements: [Options, Events, Chain],

	options: {
		resizable: true,
		foldable: true,
		hideSplitterOnFullFold: false
	},

	name: 'splitview',

	initialize: function(options){
		this.parent(options);
		this._orientations = {
			'left': this.options.orientation == "horizontal" ? "left" : "top",
			'right': this.options.orientation == "horizontal" ? "right" : "bottom",
			'bottom': 'bottom',
			'top': 'top',
			'dimension': this.options.orientation == "horizontal" ? "width" : "height"
		};
		if (this.options.orientation == "vertical") this.addClass('vertical');
		this._build();
	},

	_build: function(){
		document.id(this.canvas).dispose();
		var sheet = this.setSheet();

		this.element.addClass('art-splitview').setStyles({
			'position': 'relative',
			'width': sheet.width,
			'height': sheet.height,
			'display': sheet.display
		});
		var styles = this.options.orientation == "horizontal" ?
		             {'float': 'left', 'overflow-x': 'auto'} :
		             {'overflow-y': 'auto'};
		var o = this._orientations;
		this[o.left] = new Element('div', {
			'class': 'art-splitview-' + o.left,
			styles: {
				'background-color': sheet[o.left + 'BackgroundColor']
			}
		}).inject(this.element).setStyles(styles);
		this.splitter = new Element('div', {
			'class': 'art-splitview-splitter',
			styles: {
				'background-color': sheet.splitterBackgroundColor
			}
		}).inject(this.element).setStyles(styles)
			.setStyle(o.dimension,
				        sheet['splitter' + o.dimension.capitalize()]);
		this[o.right] = new Element('div', {
			'class': 'art-splitview-' + o.right,
			styles: {
				'background-color': sheet[o.right + 'BackgroundColor']
			}
		}).inject(this.element).setStyles(styles);

		this.fx = new Fx();
		this.touch = new Touch(this.splitter);
		var self = this;
		var fix = self.options.fixed;
		var Fix = fix.capitalize();

		if (this.options.resizable || this.options.foldable){
			this.touch.addEvent('start', function(){
				self.startFixSize = self[fix + o.dimension.capitalize()];
			});
		}

		if (this.options.resizable) {
			this.touch.addEvent('move', function(){
				this.moveSplitter.apply(this, arguments);
			}.bind(this));
		}
		if (this.options.foldable){
			this.touch.addEvent('cancel', function(){
				if (self[fix + 'Size'] == 0){
					self['fold' + Fix](self.previousSize);
				} else {
					self.previousSize = self.startFixSize;
					self['fold' + Fix](0);
				}
			});
		}

		this.deferDraw();
	},

	moveSplitter: function(dx, dy){
		var cs = this.currentSheet;
		var o = this._orientations;
		var targetSize = this.startFixSize + (this.options.orientation == "horizontal" ? dx : -dy);
		if (targetSize < 0) targetSize = 0;
		if (targetSize > cs[o.dimension] - cs['splitter' + o.dimension.capitalize()]) {
			targetSize = cs[o.dimension] - cs['splitter' + o.dimension.capitalize()];
		}
		var fix = {
			'top': 'left',
			'bottom': 'right'
		}[this.options.fixed] || this.options.fixed;
		this._resizeSide(fix, targetSize);
	},

	draw: function(newSheet){
		var cs = this.currentSheet;
		var o = this._orientations;
		var sheet = this.parent(newSheet);

		var sizeChanged = (sheet.width != undefined && sheet.height != undefined);

		if (sizeChanged) {
			this.currentHeight = cs.height;
			this.currentWidth = cs.width;
			this.element.setStyles({
				'width': cs.width,
				'height': cs.height
			});
		}

		if (sheet.display) this.element.setStyle('display', cs.display);

		var splitterStr = "splitter" + o.dimension.capitalize();
		if (sheet[splitterStr] != undefined) {
			this.splitter.setStyle(o.dimension, cs[splitterStr]);
			this.splitter.setStyle('background-color', cs.splitterBackgroundColor);
		}
		if (this.options.resizable) this.splitter.setStyle('cursor', cs.splitterCursor);

		if (sheet[o.left + 'BackgroundColor']) {
			this[o.left].setStyles({
				'background-color': cs[o.left + 'BackgroundColor']
			});
		}
		if (sheet[o.right + 'BackgroundColor']) {
			this[o.right].setStyles({
				'background-color': cs[o.right + 'BackgroundColor']
			});
		}

		if (sizeChanged) {
			var otherDimension = o.dimension == "width" ? "height" : "width";
			$$(this[o.left], this[o.right],
				 this.splitter).setStyle(otherDimension, cs[otherDimension]);

			var side = this.options.fixed;
			var other = {
				'top':'bottom',
				'left':'right',
				'bottom':'top',
				'right':'left'
			}[side];

			var dim = o[side] + o.dimension.capitalize();
			if (this[dim] == undefined) this[dim] = cs['fixed' + o.dimension.capitalize()];
			this._resizeSide(other, cs[o.dimension] - this[dim] - cs[splitterStr]);
		}

		return this;
	},

	resize: function(w, h){
		if (this.isDestroyed()) return;
		return this.draw({'height': h, 'width': w});
	},

	_resizeSide: function(side, width){
		var o = this._orientations;
		side = {
			'top': 'left',
			'bottom': 'right'
		}[side] || side;
		var otherSide = side == 'left' ? 'right' : 'left';
		var cs = this.currentSheet;
		var splitterStr = "splitter" + o.dimension.capitalize();
		width = width.limit(0, cs[o.dimension] - cs[splitterStr]);
		this[o[side]].setStyle(o.dimension, width);

		var sideWidth = o[side] + o.dimension.capitalize();
		var otherSideWidth = o[otherSide] + o.dimension.capitalize();

		this[sideWidth] = width;
		this[otherSideWidth] = cs[o.dimension] - cs[splitterStr] - width;
		this[o[otherSide]].setStyle(o.dimension, this[otherSideWidth]);
	},

	fold: function(side, to, hideSplitter) {
		var o = this._orientations;

		side = {
			'top': 'left',
			'bottom': 'right'
		}[side] || side;
		var sideWidth = o[side] + o.dimension.capitalize();
		this._previous[side] = this[sideWidth];
		var cs = this.currentSheet;
		hideSplitter = to > 0 ? false : $pick(hideSplitter, this.options.hideSplitterOnFullFold);
		var self = this;
		var other = side == 'left' ? 'right' : 'left';
		this.fx.set = function(now){
			self._resizeSide(side, now);
		};
		var splitterStr = "splitter" + o.dimension.capitalize();

		if (to > 0) {
			self.splitter.setStyle(o.dimension, cs[splitterStr]);
			self[other].setStyle(o.dimension, self[other + o.dimension.capitalize()] - cs[splitterStr]);
			this.splitterHidden = false;
			hideSplitter = false;
		}
		this.fx.start(this[sideWidth], to).chain(function(){
			if (hideSplitter) {
				[o.left, o.right].each(function(side) {
					var other = {
						'top':'bottom',
						'left':'right',
						'bottom':'top',
						'right':'left'
					}[side];
					var sideWidth = o[side] + o.dimension.capitalize();
					var otherWidth = o[other] + o.dimension.capitalize();
					if (self[sideWidth] == 0) {
						self.splitter.setStyle(o.dimension, 0);
						self[other].setStyle(o.dimension, self[otherWidth] + cs[splitterStr]);
						self[otherWidth] = self[otherWidth] + cs[splitterStr];
					}
				});
				this.splitterHidden = true;
			}
			this.callChain();
		}.bind(this));
		return this;
	},

	toggle: function(side, hideSplitter) {
		var getWidthStr = function(side) {
			return {
				'left': 'leftWidth',
				'right': 'rightWidth',
				'top':'topHeight',
				'bottom':'bottomHeight'
			}[side];
		};
		var toggle = getWidthStr(side);
		var other = {
			'left':'right',
			'right':'left',
			'top':'bottom',
			'bottom':'top'
		}[side];
		var current = this[toggle];
		var previous = this._previous[side];
		if (previous == null) previous = this[getWidthStr(other)];
		var to = current == 0 ? previous : 0;
		this.fold(side, to, hideSplitter);
	},

	_previous: {},

	_setSideContent: function(side, content) {
		document.id(this[this._orientations[side] || side]).empty().adopt(content);
	}

};

ART.SplitView = new Class(
	$merge(splitter, {
		options: {
			orientation: 'horizontal',
			fixed: 'left'
		},
		setLeftContent: function(){
			this._setSideContent('left', arguments);
			return this;
		},

		setRightContent: function(){
			this._setSideContent('right', arguments);
			return this;
		},

		resizeLeft: function(width) {
			this._resizeSide('left', width);
		},

		resizeRight: function(width){
			this._resizeSide('right', width);
		}

	})
);

ART.Sheet.define('splitview.art.vertical', {
	'fixed-height': 100,
	'splitter-height': 3,
	//IE doesn't support east-west resize cursor; just use east
	'splitter-cursor': Browser.Engine.trident ? 's-resize' : 'ns-resize',
	'bottom-background-color': '#d6dde5',
	'top-background-color': '#fff'
});

ART.Sheet.define('splitview.art.vertical:disabled', {
	'bottom-background-color': '#e8e8e8'
});

ART.SplitView.Vertical = new Class(
	$merge(splitter, {
		options: {
			orientation: 'vertical',
			fixed: 'bottom'
		},
		setTopContent: function(){
			this._setSideContent('top', arguments);
			return this;
		},
		setBottomContent: function(){
			this._setSideContent('bottom', arguments);
			return this;
		},

		resizeTop: function(height) {
			this._resizeSide('top', height);
		},

		resizeBottom: function(height) {
			this._resizeSide('bottom', height);
		}

	})
);

})();<|endoftext|>


<commit_before>const nodemon = require('nodemon')
const argv = require('yargs').argv
const bs = require('browser-sync').create()
const chokidar = require('chokidar')
const async = require('async')

const fs = require('fs-extra')
const path = require('path')
const exec = require('child_process').exec

const bundler = require('./bundler')
const compile = require('./compile')
const { getDirType } = require('./util')

console.log('Starting nodemon')

nodemon({
	script: path.join(__dirname, '../.debug', 'index.js'),
	ext: false,
	watch: false,
})

bs.init({
	proxy: {
		target: "localhost:3000",
		ws: true,
	},
	files: false, //nodemon never watches
	browser: (argv.a || argv.all) ? ["firefox", "chrome", "iexplore", path.join(__dirname, ".bin", "edge.exe")] : ["chrome"], /* edge launcher from https://github.com/MicrosoftEdge/edge-launcher */
	port: 5101,
})

nodemon.on('start', () => {
	console.log('nodemon started')
	bs.reload()
})
nodemon.on('restart', files => {
	console.log('nodemon restarts')
})
nodemon.on('quit', () => {
	console.log('done')
})

process.stdin.on('data', chunk => {
	var command = (chunk + '').trim().toLowerCase()
	switch(command) {
		case 'c':
			console.log('compile started')
			compile(toBeCompiled)
			async.each(toBeBundled, (dir, done) => {
				Promise.all([bundler.js(dir), bundler.css(dir)])
				.then(() => {
					done()
				})
			},
			err => {
				if (err) {
					console.log(err)
				} else {
					nodemon.emit('restart')
				}
				initFileList()
				console.log('compile ended')
			})
			break
	}
})

initFileList()
chokidar.watch(['./admin', './app', './server'], {
	ignoreInitial: true
})
.on('add', path => {
	addFile(path)
})
.on('change', path => {
	addFile(path)
})

var toBeCompiled;
var codes = {};
var toBeBundled;
function addFile(path) {
	var type = getDirType(path)
	if (type != 'server') {
		toBeBundled.add(type)
	}
	var code = fs.readFileSync(path).toString()
	if (!codes[path] || codes[path] != code) {
		console.log(`${path} will be compiled`)
		codes[path] = code
		toBeCompiled.add(path)
	}
}

function initFileList() {
	toBeCompiled = new Set()
	toBeBundled = new Set()
}<commit_msg>Moved compile end message.<commit_after>const nodemon = require('nodemon')
const argv = require('yargs').argv
const bs = require('browser-sync').create()
const chokidar = require('chokidar')
const async = require('async')

const fs = require('fs-extra')
const path = require('path')
const exec = require('child_process').exec

const bundler = require('./bundler')
const compile = require('./compile')
const { getDirType } = require('./util')

console.log('Starting nodemon')

nodemon({
	script: path.join(__dirname, '../.debug', 'index.js'),
	ext: false,
	watch: false,
})

bs.init({
	proxy: {
		target: "localhost:3000",
		ws: true,
	},
	files: false, //nodemon never watches
	browser: (argv.a || argv.all) ? ["firefox", "chrome", "iexplore", path.join(__dirname, ".bin", "edge.exe")] : ["chrome"], /* edge launcher from https://github.com/MicrosoftEdge/edge-launcher */
	port: 5101,
})

nodemon.on('start', () => {
	console.log('nodemon started')
	bs.reload()
})
nodemon.on('restart', files => {
	console.log('nodemon restarts')
})
nodemon.on('quit', () => {
	console.log('done')
})

process.stdin.on('data', chunk => {
	var command = (chunk + '').trim().toLowerCase()
	switch(command) {
		case 'c':
			console.log('compile started')
			compile(toBeCompiled)
			console.log('compile ended')
			async.each(toBeBundled, (dir, done) => {
				Promise.all([bundler.js(dir), bundler.css(dir)])
				.then(() => {
					done()
				})
			},
			err => {
				if (err) {
					console.log(err)
				} else {
					nodemon.emit('restart')
				}
				initFileList()
			})
			break
	}
})

initFileList()
chokidar.watch(['./admin', './app', './server'], {
	ignoreInitial: true
})
.on('add', path => {
	addFile(path)
})
.on('change', path => {
	addFile(path)
})

var toBeCompiled;
var codes = {};
var toBeBundled;
function addFile(path) {
	var type = getDirType(path)
	if (type != 'server') {
		toBeBundled.add(type)
	}
	var code = fs.readFileSync(path).toString()
	if (!codes[path] || codes[path] != code) {
		console.log(`${path} will be compiled`)
		codes[path] = code
		toBeCompiled.add(path)
	}
}

function initFileList() {
	toBeCompiled = new Set()
	toBeBundled = new Set()
}<|endoftext|>


<commit_before>/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
 * http://scratchdisk.com/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

/**
 * A function scope holding all the functionality needed to convert a
 * Paper.js DOM to a SVG DOM.
 */
new function() {
    // TODO: Consider moving formatter into options object, and pass it along.
    var formatter;

    function getTransform(matrix, coordinates, center) {
        // Use new Base() so we can use Base#set() on it.
        var attrs = new Base(),
            trans = matrix.getTranslation();
        if (coordinates) {
            // If the item suppports x- and y- coordinates, we're taking out the
            // translation part of the matrix and move it to x, y attributes, to
            // produce more readable markup, and not have to use center points
            // in rotate(). To do so, SVG requries us to inverse transform the
            // translation point by the matrix itself, since they are provided
            // in local coordinates.
            matrix = matrix._shiftless();
            var point = matrix._inverseTransform(trans);
            attrs[center ? 'cx' : 'x'] = point.x;
            attrs[center ? 'cy' : 'y'] = point.y;
            trans = null;
        }
        if (!matrix.isIdentity()) {
            // See if we can decompose the matrix and can formulate it as a
            // simple translate/scale/rotate command sequence.
            var decomposed = matrix.decompose();
            if (decomposed) {
                var parts = [],
                    angle = decomposed.rotation,
                    scale = decomposed.scaling,
                    skew = decomposed.skewing;
                if (trans && !trans.isZero())
                    parts.push('translate(' + formatter.point(trans) + ')');
                if (angle)
                    parts.push('rotate(' + formatter.number(angle) + ')');
                if (!Numerical.isZero(scale.x - 1)
                        || !Numerical.isZero(scale.y - 1))
                    parts.push('scale(' + formatter.point(scale) +')');
                if (skew && skew.x)
                    parts.push('skewX(' + formatter.number(skew.x) + ')');
                if (skew && skew.y)
                    parts.push('skewY(' + formatter.number(skew.y) + ')');
                attrs.transform = parts.join(' ');
            } else {
                attrs.transform = 'matrix(' + matrix.getValues().join(',') + ')';
            }
        }
        return attrs;
    }

    function exportGroup(item, options) {
        var attrs = getTransform(item._matrix),
            children = item._children;
        var node = SvgElement.create('g', attrs, formatter);
        for (var i = 0, l = children.length; i < l; i++) {
            var child = children[i];
            var childNode = exportSVG(child, options);
            if (childNode) {
                if (child.isClipMask()) {
                    var clip = SvgElement.create('clipPath');
                    clip.appendChild(childNode);
                    setDefinition(child, clip, 'clip');
                    SvgElement.set(node, {
                        'clip-path': 'url(#' + clip.id + ')'
                    });
                } else {
                    node.appendChild(childNode);
                }
            }
        }
        return node;
    }

    function exportRaster(item, options) {
        var attrs = getTransform(item._matrix, true),
            size = item.getSize(),
            image = item.getImage();
        // Take into account that rasters are centered:
        attrs.x -= size.width / 2;
        attrs.y -= size.height / 2;
        attrs.width = size.width;
        attrs.height = size.height;
        attrs.href = options.embedImages === false && image && image.src
                || item.toDataURL();
        return SvgElement.create('image', attrs, formatter);
    }

    function exportPath(item, options) {
        var matchShapes = options.matchShapes;
        if (matchShapes) {
            var shape = item.toShape(false);
            if (shape)
                return exportShape(shape, options);
        }
        var segments = item._segments,
            length = segments.length,
            type,
            attrs = getTransform(item._matrix);
        if (matchShapes && length >= 2 && !item.hasHandles()) {
            if (length > 2) {
                type = item._closed ? 'polygon' : 'polyline';
                var parts = [];
                for(var i = 0; i < length; i++)
                    parts.push(formatter.point(segments[i]._point));
                attrs.points = parts.join(' ');
            } else {
                type = 'line';
                var start = segments[0]._point,
                    end = segments[1]._point;
                attrs.set({
                    x1: start.x,
                    y1: start.y,
                    x2: end.x,
                    y2: end.y
                });
            }
        } else {
            type = 'path';
            attrs.d = item.getPathData(null, options.precision);
        }
        return SvgElement.create(type, attrs, formatter);
    }

    function exportShape(item) {
        var type = item._type,
            radius = item._radius,
            attrs = getTransform(item._matrix, true, type !== 'rectangle');
        if (type === 'rectangle') {
            type = 'rect'; // SVG
            var size = item._size,
                width = size.width,
                height = size.height;
            attrs.x -= width / 2;
            attrs.y -= height / 2;
            attrs.width = width;
            attrs.height = height;
            if (radius.isZero())
                radius = null;
        }
        if (radius) {
            if (type === 'circle') {
                attrs.r = radius;
            } else {
                attrs.rx = radius.width;
                attrs.ry = radius.height;
            }
        }
        return SvgElement.create(type, attrs, formatter);
    }

    function exportCompoundPath(item, options) {
        var attrs = getTransform(item._matrix);
        var data = item.getPathData(null, options.precision);
        if (data)
            attrs.d = data;
        return SvgElement.create('path', attrs, formatter);
    }

    function exportSymbolItem(item, options) {
        var attrs = getTransform(item._matrix, true),
            definition = item._definition,
            node = getDefinition(definition, 'symbol'),
            definitionItem = definition._item,
            bounds = definitionItem.getBounds();
        if (!node) {
            node = SvgElement.create('symbol', {
                viewBox: formatter.rectangle(bounds)
            });
            node.appendChild(exportSVG(definitionItem, options));
            setDefinition(definition, node, 'symbol');
        }
        attrs.href = '#' + node.id;
        attrs.x += bounds.x;
        attrs.y += bounds.y;
        attrs.width = bounds.width;
        attrs.height = bounds.height;
        attrs.overflow = 'visible';
        return SvgElement.create('use', attrs, formatter);
    }

    function exportGradient(color) {
        // NOTE: As long as the fillTransform attribute is not implemented,
        // we need to create a separate gradient object for each gradient,
        // even when they share the same gradient definition.
        // http://www.svgopen.org/2011/papers/20-Separating_gradients_from_geometry/
        // TODO: Implement gradient merging in SvgImport
        var gradientNode = getDefinition(color, 'color');
        if (!gradientNode) {
            var gradient = color.getGradient(),
                radial = gradient._radial,
                origin = color.getOrigin(),
                destination = color.getDestination(),
                attrs;
            if (radial) {
                attrs = {
                    cx: origin.x,
                    cy: origin.y,
                    r: origin.getDistance(destination)
                };
                var highlight = color.getHighlight();
                if (highlight) {
                    attrs.fx = highlight.x;
                    attrs.fy = highlight.y;
                }
            } else {
                attrs = {
                    x1: origin.x,
                    y1: origin.y,
                    x2: destination.x,
                    y2: destination.y
                };
            }
            attrs.gradientUnits = 'userSpaceOnUse';
            gradientNode = SvgElement.create((radial ? 'radial' : 'linear')
                    + 'Gradient', attrs, formatter);
            var stops = gradient._stops;
            for (var i = 0, l = stops.length; i < l; i++) {
                var stop = stops[i],
                    offset = stop._rampPoint,
                    stopColor = stop._color,
                    alpha = stopColor.getAlpha();
                attrs = {};
                if (offset != null)
                    attrs.offset = offset;
                if (stopColor)
                    attrs['stop-color'] = stopColor.toCSS(true);
                // See applyStyle for an explanation of why there are separated
                // opacity / color attributes.
                if (alpha < 1)
                    attrs['stop-opacity'] = alpha;
                gradientNode.appendChild(
                        SvgElement.create('stop', attrs, formatter));
            }
            setDefinition(color, gradientNode, 'color');
        }
        return 'url(#' + gradientNode.id + ')';
    }

    function exportText(item) {
        var node = SvgElement.create('text', getTransform(item._matrix, true),
                formatter);
        node.textContent = item._content;
        return node;
    }

    var exporters = {
        Group: exportGroup,
        Layer: exportGroup,
        Raster: exportRaster,
        Path: exportPath,
        Shape: exportShape,
        CompoundPath: exportCompoundPath,
        SymbolItem: exportSymbolItem,
        PointText: exportText
    };

    function applyStyle(item, node, isRoot) {
        var attrs = {},
            parent = !isRoot && item.getParent(),
            style = [];

        if (item._name != null)
            attrs.id = item._name;

        Base.each(SvgStyles, function(entry) {
            // Get a given style only if it differs from the value on the parent
            // (A layer or group which can have style values in SVG).
            var get = entry.get,
                type = entry.type,
                value = item[get]();
            if (entry.exportFilter
                    ? entry.exportFilter(item, value)
                    : !parent || !Base.equals(parent[get](), value)) {
                if (type === 'color' && value != null) {
                    // Support for css-style rgba() values is not in SVG 1.1, so
                    // separate the alpha value of colors with alpha into the
                    // separate fill- / stroke-opacity attribute:
                    var alpha = value.getAlpha();
                    if (alpha < 1)
                        attrs[entry.attribute + '-opacity'] = alpha;
                }
                if (type === 'style') {
                    style.push(entry.attribute + ': ' + value);
                } else {
                    attrs[entry.attribute] = value == null ? 'none'
                            : type === 'color' ? value.gradient
                                // true for noAlpha, see above
                                ? exportGradient(value, item)
                                : value.toCSS(true)
                            : type === 'array' ? value.join(',')
                            : type === 'lookup' ? entry.toSVG[value]
                            : value;
                }
            }
        });

        if (style.length)
            attrs.style = style.join(';');

        if (attrs.opacity === 1)
            delete attrs.opacity;

        if (!item._visible)
            attrs.visibility = 'hidden';

        return SvgElement.set(node, attrs, formatter);
    }

    var definitions;
    function getDefinition(item, type) {
        if (!definitions)
            definitions = { ids: {}, svgs: {} };
        return item && definitions.svgs[type + '-' + item._id];
    }

    function setDefinition(item, node, type) {
        // Make sure the definitions lookup is created before we use it.
        // This is required by 'clip', where getDefinition() is not called.
        if (!definitions)
            getDefinition();
        // Have different id ranges per type
        var id = definitions.ids[type] = (definitions.ids[type] || 0) + 1;
        // Give the svg node an id, and link to it from the item id.
        node.id = type + '-' + id;
        definitions.svgs[type + '-' + item._id] = node;
    }

    function exportDefinitions(node, options) {
        var svg = node,
            defs = null;
        if (definitions) {
            // We can only use svg nodes as defintion containers. Have the loop
            // produce one if it's a single item of another type (when calling
            // #exportSVG() on an item rather than a whole project)
            // jsdom in Node.js uses uppercase values for nodeName...
            svg = node.nodeName.toLowerCase() === 'svg' && node;
            for (var i in definitions.svgs) {
                // This code is inside the loop so we only create a container if
                // we actually have svgs.
                if (!defs) {
                    if (!svg) {
                        svg = SvgElement.create('svg');
                        svg.appendChild(node);
                    }
                    defs = svg.insertBefore(SvgElement.create('defs'),
                            svg.firstChild);
                }
                defs.appendChild(definitions.svgs[i]);
            }
            // Clear definitions at the end of export
            definitions = null;
        }
        return options.asString
                ? new window.XMLSerializer().serializeToString(svg)
                : svg;
    }

    function exportSVG(item, options, isRoot) {
        var exporter = exporters[item._class],
            node = exporter && exporter(item, options);
        if (node) {
            // Support onExportItem callback, to provide mechanism to handle
            // special attributes (e.g. inkscape:transform-center)
            var onExport = options.onExport;
            if (onExport)
                node = onExport(item, node, options) || node;
            var data = JSON.stringify(item._data);
            if (data && data !== '{}' && data !== 'null')
                node.setAttribute('data-paper-data', data);
        }
        return node && applyStyle(item, node, isRoot);
    }

    function setOptions(options) {
        if (!options)
            options = {};
        formatter = new Formatter(options.precision);
        return options;
    }

    Item.inject({
        exportSVG: function(options) {
            options = setOptions(options);
            return exportDefinitions(exportSVG(this, options, true), options);
        }
    });

    Project.inject({
        exportSVG: function(options) {
            options = setOptions(options);
            var children = this._children,
                view = this.getView(),
                bounds = Base.pick(options.bounds, 'view'),
                mx = options.matrix || bounds === 'view' && view._matrix,
                matrix = mx && Matrix.read([mx]),
                rect = bounds === 'view'
                    ? new Rectangle([0, 0], view.getViewSize())
                    : bounds === 'content'
                        ? Item._getBounds(children, matrix, { stroke: true })
                        : Rectangle.read([bounds], 0, { readNull: true }),
                attrs = {
                    version: '1.1',
                    xmlns: SvgElement.svg,
                    'xmlns:xlink': SvgElement.xlink,
                };
            if (rect) {
                attrs.width = rect.width;
                attrs.height = rect.height;
                if (rect.x || rect.y)
                    attrs.viewBox = formatter.rectangle(rect);
            }
            var node = SvgElement.create('svg', attrs, formatter),
                parent = node;
            // If the view has a transformation, wrap all layers in a group with
            // that transformation applied to.
            if (matrix && !matrix.isIdentity()) {
                parent = node.appendChild(SvgElement.create('g',
                        getTransform(matrix), formatter));
            }
            for (var i = 0, l = children.length; i < l; i++) {
                parent.appendChild(exportSVG(children[i], options, true));
            }
            return exportDefinitions(node, options);
        }
    });
};
<commit_msg>Fix GradientStop support in SVG export.<commit_after>/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
 * http://scratchdisk.com/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

/**
 * A function scope holding all the functionality needed to convert a
 * Paper.js DOM to a SVG DOM.
 */
new function() {
    // TODO: Consider moving formatter into options object, and pass it along.
    var formatter;

    function getTransform(matrix, coordinates, center) {
        // Use new Base() so we can use Base#set() on it.
        var attrs = new Base(),
            trans = matrix.getTranslation();
        if (coordinates) {
            // If the item suppports x- and y- coordinates, we're taking out the
            // translation part of the matrix and move it to x, y attributes, to
            // produce more readable markup, and not have to use center points
            // in rotate(). To do so, SVG requries us to inverse transform the
            // translation point by the matrix itself, since they are provided
            // in local coordinates.
            matrix = matrix._shiftless();
            var point = matrix._inverseTransform(trans);
            attrs[center ? 'cx' : 'x'] = point.x;
            attrs[center ? 'cy' : 'y'] = point.y;
            trans = null;
        }
        if (!matrix.isIdentity()) {
            // See if we can decompose the matrix and can formulate it as a
            // simple translate/scale/rotate command sequence.
            var decomposed = matrix.decompose();
            if (decomposed) {
                var parts = [],
                    angle = decomposed.rotation,
                    scale = decomposed.scaling,
                    skew = decomposed.skewing;
                if (trans && !trans.isZero())
                    parts.push('translate(' + formatter.point(trans) + ')');
                if (angle)
                    parts.push('rotate(' + formatter.number(angle) + ')');
                if (!Numerical.isZero(scale.x - 1)
                        || !Numerical.isZero(scale.y - 1))
                    parts.push('scale(' + formatter.point(scale) +')');
                if (skew && skew.x)
                    parts.push('skewX(' + formatter.number(skew.x) + ')');
                if (skew && skew.y)
                    parts.push('skewY(' + formatter.number(skew.y) + ')');
                attrs.transform = parts.join(' ');
            } else {
                attrs.transform = 'matrix(' + matrix.getValues().join(',') + ')';
            }
        }
        return attrs;
    }

    function exportGroup(item, options) {
        var attrs = getTransform(item._matrix),
            children = item._children;
        var node = SvgElement.create('g', attrs, formatter);
        for (var i = 0, l = children.length; i < l; i++) {
            var child = children[i];
            var childNode = exportSVG(child, options);
            if (childNode) {
                if (child.isClipMask()) {
                    var clip = SvgElement.create('clipPath');
                    clip.appendChild(childNode);
                    setDefinition(child, clip, 'clip');
                    SvgElement.set(node, {
                        'clip-path': 'url(#' + clip.id + ')'
                    });
                } else {
                    node.appendChild(childNode);
                }
            }
        }
        return node;
    }

    function exportRaster(item, options) {
        var attrs = getTransform(item._matrix, true),
            size = item.getSize(),
            image = item.getImage();
        // Take into account that rasters are centered:
        attrs.x -= size.width / 2;
        attrs.y -= size.height / 2;
        attrs.width = size.width;
        attrs.height = size.height;
        attrs.href = options.embedImages === false && image && image.src
                || item.toDataURL();
        return SvgElement.create('image', attrs, formatter);
    }

    function exportPath(item, options) {
        var matchShapes = options.matchShapes;
        if (matchShapes) {
            var shape = item.toShape(false);
            if (shape)
                return exportShape(shape, options);
        }
        var segments = item._segments,
            length = segments.length,
            type,
            attrs = getTransform(item._matrix);
        if (matchShapes && length >= 2 && !item.hasHandles()) {
            if (length > 2) {
                type = item._closed ? 'polygon' : 'polyline';
                var parts = [];
                for(var i = 0; i < length; i++)
                    parts.push(formatter.point(segments[i]._point));
                attrs.points = parts.join(' ');
            } else {
                type = 'line';
                var start = segments[0]._point,
                    end = segments[1]._point;
                attrs.set({
                    x1: start.x,
                    y1: start.y,
                    x2: end.x,
                    y2: end.y
                });
            }
        } else {
            type = 'path';
            attrs.d = item.getPathData(null, options.precision);
        }
        return SvgElement.create(type, attrs, formatter);
    }

    function exportShape(item) {
        var type = item._type,
            radius = item._radius,
            attrs = getTransform(item._matrix, true, type !== 'rectangle');
        if (type === 'rectangle') {
            type = 'rect'; // SVG
            var size = item._size,
                width = size.width,
                height = size.height;
            attrs.x -= width / 2;
            attrs.y -= height / 2;
            attrs.width = width;
            attrs.height = height;
            if (radius.isZero())
                radius = null;
        }
        if (radius) {
            if (type === 'circle') {
                attrs.r = radius;
            } else {
                attrs.rx = radius.width;
                attrs.ry = radius.height;
            }
        }
        return SvgElement.create(type, attrs, formatter);
    }

    function exportCompoundPath(item, options) {
        var attrs = getTransform(item._matrix);
        var data = item.getPathData(null, options.precision);
        if (data)
            attrs.d = data;
        return SvgElement.create('path', attrs, formatter);
    }

    function exportSymbolItem(item, options) {
        var attrs = getTransform(item._matrix, true),
            definition = item._definition,
            node = getDefinition(definition, 'symbol'),
            definitionItem = definition._item,
            bounds = definitionItem.getBounds();
        if (!node) {
            node = SvgElement.create('symbol', {
                viewBox: formatter.rectangle(bounds)
            });
            node.appendChild(exportSVG(definitionItem, options));
            setDefinition(definition, node, 'symbol');
        }
        attrs.href = '#' + node.id;
        attrs.x += bounds.x;
        attrs.y += bounds.y;
        attrs.width = bounds.width;
        attrs.height = bounds.height;
        attrs.overflow = 'visible';
        return SvgElement.create('use', attrs, formatter);
    }

    function exportGradient(color) {
        // NOTE: As long as the fillTransform attribute is not implemented,
        // we need to create a separate gradient object for each gradient,
        // even when they share the same gradient definition.
        // http://www.svgopen.org/2011/papers/20-Separating_gradients_from_geometry/
        // TODO: Implement gradient merging in SvgImport
        var gradientNode = getDefinition(color, 'color');
        if (!gradientNode) {
            var gradient = color.getGradient(),
                radial = gradient._radial,
                origin = color.getOrigin(),
                destination = color.getDestination(),
                attrs;
            if (radial) {
                attrs = {
                    cx: origin.x,
                    cy: origin.y,
                    r: origin.getDistance(destination)
                };
                var highlight = color.getHighlight();
                if (highlight) {
                    attrs.fx = highlight.x;
                    attrs.fy = highlight.y;
                }
            } else {
                attrs = {
                    x1: origin.x,
                    y1: origin.y,
                    x2: destination.x,
                    y2: destination.y
                };
            }
            attrs.gradientUnits = 'userSpaceOnUse';
            gradientNode = SvgElement.create((radial ? 'radial' : 'linear')
                    + 'Gradient', attrs, formatter);
            var stops = gradient._stops;
            for (var i = 0, l = stops.length; i < l; i++) {
                var stop = stops[i],
                    stopColor = stop._color,
                    alpha = stopColor.getAlpha();
                attrs = {
                    offset: stop._rampPoint || i / (l - 1)
                };
                if (stopColor)
                    attrs['stop-color'] = stopColor.toCSS(true);
                // See applyStyle for an explanation of why there are separated
                // opacity / color attributes.
                if (alpha < 1)
                    attrs['stop-opacity'] = alpha;
                gradientNode.appendChild(
                        SvgElement.create('stop', attrs, formatter));
            }
            setDefinition(color, gradientNode, 'color');
        }
        return 'url(#' + gradientNode.id + ')';
    }

    function exportText(item) {
        var node = SvgElement.create('text', getTransform(item._matrix, true),
                formatter);
        node.textContent = item._content;
        return node;
    }

    var exporters = {
        Group: exportGroup,
        Layer: exportGroup,
        Raster: exportRaster,
        Path: exportPath,
        Shape: exportShape,
        CompoundPath: exportCompoundPath,
        SymbolItem: exportSymbolItem,
        PointText: exportText
    };

    function applyStyle(item, node, isRoot) {
        var attrs = {},
            parent = !isRoot && item.getParent(),
            style = [];

        if (item._name != null)
            attrs.id = item._name;

        Base.each(SvgStyles, function(entry) {
            // Get a given style only if it differs from the value on the parent
            // (A layer or group which can have style values in SVG).
            var get = entry.get,
                type = entry.type,
                value = item[get]();
            if (entry.exportFilter
                    ? entry.exportFilter(item, value)
                    : !parent || !Base.equals(parent[get](), value)) {
                if (type === 'color' && value != null) {
                    // Support for css-style rgba() values is not in SVG 1.1, so
                    // separate the alpha value of colors with alpha into the
                    // separate fill- / stroke-opacity attribute:
                    var alpha = value.getAlpha();
                    if (alpha < 1)
                        attrs[entry.attribute + '-opacity'] = alpha;
                }
                if (type === 'style') {
                    style.push(entry.attribute + ': ' + value);
                } else {
                    attrs[entry.attribute] = value == null ? 'none'
                            : type === 'color' ? value.gradient
                                // true for noAlpha, see above
                                ? exportGradient(value, item)
                                : value.toCSS(true)
                            : type === 'array' ? value.join(',')
                            : type === 'lookup' ? entry.toSVG[value]
                            : value;
                }
            }
        });

        if (style.length)
            attrs.style = style.join(';');

        if (attrs.opacity === 1)
            delete attrs.opacity;

        if (!item._visible)
            attrs.visibility = 'hidden';

        return SvgElement.set(node, attrs, formatter);
    }

    var definitions;
    function getDefinition(item, type) {
        if (!definitions)
            definitions = { ids: {}, svgs: {} };
        return item && definitions.svgs[type + '-' + item._id];
    }

    function setDefinition(item, node, type) {
        // Make sure the definitions lookup is created before we use it.
        // This is required by 'clip', where getDefinition() is not called.
        if (!definitions)
            getDefinition();
        // Have different id ranges per type
        var id = definitions.ids[type] = (definitions.ids[type] || 0) + 1;
        // Give the svg node an id, and link to it from the item id.
        node.id = type + '-' + id;
        definitions.svgs[type + '-' + item._id] = node;
    }

    function exportDefinitions(node, options) {
        var svg = node,
            defs = null;
        if (definitions) {
            // We can only use svg nodes as defintion containers. Have the loop
            // produce one if it's a single item of another type (when calling
            // #exportSVG() on an item rather than a whole project)
            // jsdom in Node.js uses uppercase values for nodeName...
            svg = node.nodeName.toLowerCase() === 'svg' && node;
            for (var i in definitions.svgs) {
                // This code is inside the loop so we only create a container if
                // we actually have svgs.
                if (!defs) {
                    if (!svg) {
                        svg = SvgElement.create('svg');
                        svg.appendChild(node);
                    }
                    defs = svg.insertBefore(SvgElement.create('defs'),
                            svg.firstChild);
                }
                defs.appendChild(definitions.svgs[i]);
            }
            // Clear definitions at the end of export
            definitions = null;
        }
        return options.asString
                ? new window.XMLSerializer().serializeToString(svg)
                : svg;
    }

    function exportSVG(item, options, isRoot) {
        var exporter = exporters[item._class],
            node = exporter && exporter(item, options);
        if (node) {
            // Support onExportItem callback, to provide mechanism to handle
            // special attributes (e.g. inkscape:transform-center)
            var onExport = options.onExport;
            if (onExport)
                node = onExport(item, node, options) || node;
            var data = JSON.stringify(item._data);
            if (data && data !== '{}' && data !== 'null')
                node.setAttribute('data-paper-data', data);
        }
        return node && applyStyle(item, node, isRoot);
    }

    function setOptions(options) {
        if (!options)
            options = {};
        formatter = new Formatter(options.precision);
        return options;
    }

    Item.inject({
        exportSVG: function(options) {
            options = setOptions(options);
            return exportDefinitions(exportSVG(this, options, true), options);
        }
    });

    Project.inject({
        exportSVG: function(options) {
            options = setOptions(options);
            var children = this._children,
                view = this.getView(),
                bounds = Base.pick(options.bounds, 'view'),
                mx = options.matrix || bounds === 'view' && view._matrix,
                matrix = mx && Matrix.read([mx]),
                rect = bounds === 'view'
                    ? new Rectangle([0, 0], view.getViewSize())
                    : bounds === 'content'
                        ? Item._getBounds(children, matrix, { stroke: true })
                        : Rectangle.read([bounds], 0, { readNull: true }),
                attrs = {
                    version: '1.1',
                    xmlns: SvgElement.svg,
                    'xmlns:xlink': SvgElement.xlink,
                };
            if (rect) {
                attrs.width = rect.width;
                attrs.height = rect.height;
                if (rect.x || rect.y)
                    attrs.viewBox = formatter.rectangle(rect);
            }
            var node = SvgElement.create('svg', attrs, formatter),
                parent = node;
            // If the view has a transformation, wrap all layers in a group with
            // that transformation applied to.
            if (matrix && !matrix.isIdentity()) {
                parent = node.appendChild(SvgElement.create('g',
                        getTransform(matrix), formatter));
            }
            for (var i = 0, l = children.length; i < l; i++) {
                parent.appendChild(exportSVG(children[i], options, true));
            }
            return exportDefinitions(node, options);
        }
    });
};
<|endoftext|>


<commit_before>/*
  All Emoncms code is released under the GNU Affero General Public License.
  See COPYRIGHT.txt and LICENSE.txt.
    ---------------------------------------------------------------------
    Part of the OpenEnergyMonitor project:
    http://openenergymonitor.org

    Author: Trystan Lea: trystan.lea@googlemail.com
	Enhancements done by: Andreas Messerli firefox7518@gmail.com
    If you have any questions please get in touch, try the forums here:
    http://openenergymonitor.org/emon/forum
 */

function feedvalue_widgetlist()
{
  var widgets =
  {
    "feedvalue":
    {
      "offsetx":-40,"offsety":-30,"width":120,"height":60,
      "menu":"Widgets",
      "options":    [],
      "optionstype":[],
      "optionsname":[],
      "optionshint":[],
      "optionsdata":[]
    }
  };

  var decimalsDropBoxOptions = [        // Options for the type combobox. Each item is [typeID, "description"]
        [-1,   _Tr("Automatic")],
        [0,    "0"],
        [1,    "1"],
        [2,    "2"],
        [3,    "3"],
        [4,    "4"],
        [5,    "5"],
        [6,    "6"]
    ];

	var fontoptions = [
					[9, "Arial Black"],
					[8, "Arial Narrow"],
					[7, "sans-serif"],
					[6, "Helvetica Neue"],
					[5, "Helvetica"],
					[4, "Comic Sans MS"],
					[3, "Courier New"],
					[2, "Arial"],
					[1, "Georgia"],
					[0, "Impact"]
				];

	var fstyleoptions = [
					[2, _Tr("Normal")],
					[1, _Tr("Italic")],
					[0, _Tr("Oblique")]
				];

	var fweightoptions = [
					[1, _Tr("Bold")],
					[0, _Tr("Normal")]
				];

	var sizeoptions = [
					[14, "18"], // set size 18 to the top position to be the default value for creating new feedvalue widgets otherwise size 40 would be always the default
					[13, "40"],
					[12, "36"],
					[11, "32"],
					[10, "28"],
					[9, "24"],
					[8, "22"],
					[7, "20"],
					[6, "18"],
					[5, "16"],
					[4, "14"],
					[3, "12"],
					[2, "10"],
					[1, "8"],
					[0, "6"]
				];

  var alignmentOptions = [
    ["center", _Tr("Center")],
    ["left", _Tr("Left")],
    ["right", _Tr("Right")]
  ];

	addOption(widgets["feedvalue"], "feedid",   "feedid",  _Tr("Feed"),     _Tr("Feed value"),      []);
	addOption(widgets["feedvalue"], "prepend",    "value",   _Tr("Prepend Text"),    _Tr("Prepend Text"),   []);
	addOption(widgets["feedvalue"], "append",  "value", _Tr("Append Text"), _Tr("Append Text (Units)"), []);
	addOption(widgets["feedvalue"], "decimals", "dropbox", _Tr("Decimals"), _Tr("Decimals to show"),    decimalsDropBoxOptions);
	addOption(widgets["feedvalue"], "colour",   "colour_picker",  _Tr("Colour"),     _Tr("Colour used for display"),      []);
	addOption(widgets["feedvalue"], "font",     "dropbox",  _Tr("Font"),     _Tr("Font used for display"),      fontoptions);
	addOption(widgets["feedvalue"], "fstyle",   "dropbox", _Tr("Font style"), _Tr("Font style used for display"),    fstyleoptions);
	addOption(widgets["feedvalue"], "fweight",  "dropbox", _Tr("Font weight"), _Tr("Font weight used for display"),    fweightoptions);
	addOption(widgets["feedvalue"], "size",   	"dropbox", _Tr("Size"), _Tr("Text size in px to use"),    sizeoptions);
	addOption(widgets["feedvalue"], "align",    "dropbox", _Tr("Alignment"), _Tr("Alignment"), alignmentOptions);
	addOption(widgets["feedvalue"], "timeout",  "value",   _Tr("Timeout"),    _Tr("Timeout without feed update in seconds (empty is never)"),   []);
	addOption(widgets["feedvalue"], "errormessagedisplayed",    "value",  _Tr("Error Message"),   _Tr("Error message displayed when timeout is reached"),   []);
	addOption(widgets["feedvalue"], "threshold1",  "value",   _Tr("Threshold1"),    _Tr("Threshold1 value"),   []);
	addOption(widgets["feedvalue"], "threshold2",  "value",   _Tr("Threshold2"),    _Tr("Threshold2 value"),   []);
	addOption(widgets["feedvalue"], "colour1",   "colour_picker",  _Tr("Colour1"),     _Tr("Colour for range below Threshold1"),      []);
	addOption(widgets["feedvalue"], "colour2",   "colour_picker",  _Tr("Colour2"),     _Tr("Colour for range between Threshold1 and Threshold2"),      []);
	addOption(widgets["feedvalue"], "colour3",   "colour_picker",  _Tr("Colour3"),     _Tr("Colour for range above Threshold2"),      []);
        addOption(widgets["feedvalue"], "scale", "value", _Tr("Scale"), _Tr("scale"),    []);
	return widgets;
}

function draw_feedvalue(feedvalue,font,fstyle,fweight,width,height,prepend,val,append,colour,decimals,size,align,errorCode,errorMessage,scale)
{
    colour = colour || "4444CC";
    size = size || "8";
    font = font || "5";
    fstyle = fstyle || "2";
    fweight = fweight || "1";
    align = align || "center";
    scale = scale || 1.0;

    val *= (1*scale);

    var fontsize;

    if (size === "0"){fontsize = 6;}
    if (size === "1"){fontsize = 8;}
    if (size === "2"){fontsize = 10;}
    if (size === "3"){fontsize = 12;}
    if (size === "4"){fontsize = 14;}
    if (size === "5"){fontsize = 16;}
    if (size === "6"){fontsize = 18;}
    if (size === "7"){fontsize = 20;}
    if (size === "8"){fontsize = 22;}
    if (size === "9"){fontsize = 24;}
    if (size === "10"){fontsize = 28;}
    if (size === "11"){fontsize = 32;}
    if (size === "12"){fontsize = 36;}
    if (size === "13"){fontsize = 40;}
    if (size === "14"){fontsize = 18;}  //default value so that not size 40 is always the default

    var fontname;

    if (font === "0"){fontname = "Impact";}
    if (font === "1"){fontname = "Georgia";}
    if (font === "2"){fontname = "Arial";}
    if (font === "3"){fontname = "Courier New";}
    if (font === "4"){fontname = "Comic Sans MS";}
    if (font === "5"){fontname = "Helvetica";}
    if (font === "6"){fontname = "Helvetica Neue";}
    if (font === "7"){fontname = "sans-serif";}
    if (font === "8"){fontname = "Arial Narrow";}
    if (font === "9"){fontname = "Arial Black";}

    var fontstyle;

    if (fstyle === "0"){fontstyle = "oblique";}
    if (fstyle === "1"){fontstyle = "italic";}
    if (fstyle === "2"){fontstyle = "normal";}

    var fontweight;

    if (fweight === "0"){fontweight = "normal";}
    if (fweight === "1"){fontweight = "bold";}

    if (decimals<0)
    {
        if (val>=100){
            val = val.toFixed(0);
        }
        else if (val>=10){
            val = val.toFixed(1);
        }
        else if (val<=-100){
            val = val.toFixed(0);
        }
        else if (val<=-10){
            val = val.toFixed(1);
        }
        else {
            val = val.toFixed(2);
        }
        val = parseFloat(val);
    }
    else
    {
        val = val.toFixed(decimals);
    }

    if (colour.indexOf("#") === -1) {			// Fix missing "#" on colour if needed
        colour = "#" + colour;
    }

    feedvalue.css({
        "color":colour,
        "font":fontstyle+" "+ fontweight+" "+ fontsize+"px "+fontname,"text-align":align,
        "line-height":height+"px"
    });

    if (errorCode === "1")
    {
        feedvalue.html(errorMessage);
    }
    else
    {
        feedvalue.html(prepend+val+append);
    }
}

function feedvalue_draw()
{
    $(".feedvalue").each(function(index)
    {
        var feedvalue = $(this);
        var errorMessage = $(this).attr("errormessagedisplayed");
        if (errorMessage === "" || errorMessage === undefined){            //Error Message parameter is empty
          errorMessage = "TO Error";
        }
        var errorTimeout = feedvalue.attr("timeout");
        if (errorTimeout === "" || errorTimeout === undefined){           //Timeout parameter is empty
            errorTimeout = 0;
        }

        var font = feedvalue.attr("font");
        var feedid = feedvalue.attr("feedid");
        if (assocfeed[feedid]!=undefined) feedid = assocfeed[feedid]; // convert tag:name to feedid
        if (associd[feedid] === undefined) { console.log("Review config for feed id of " + feedvalue.attr("class")); return; }
        var val = associd[feedid]["value"] * 1;

        if (val===undefined) {val = 0;}
        if (isNaN(val))  {val = 0;}

        var errorCode = "0";
        if (errorTimeout !== 0)
        {
            if (((new Date()).getTime() / 1000 - offsetofTime - (associd[feedid]["time"] * 1)) > errorTimeout)
            {
                errorCode = "1";
            }
        }

        var size = feedvalue.attr("size");

        var decimals = feedvalue.attr("decimals");

        if (decimals===undefined) {decimals = -1};

        // backwards compatibility
        var unitend = feedvalue.attr("unitend");
        var units = feedvalue.attr("units");

        // new options
        var prepend = feedvalue.attr("prepend");
        var append = feedvalue.attr("append");

        // check if new options are undefined: use old
        if (prepend==undefined && append==undefined) {
            if (unitend!=undefined && units!=undefined) {
                if (unitend ==="0") {
                    append = units;
                    prepend = ""
                } else if (unitend ==="1") {
                    prepend = units;
                    append = ""
                }
            } else {
                prepend = ""
                append = ""
            }
        }

        var textcolor = feedvalue.attr("colour");

        if($(this).attr("threshold1")!=undefined && $(this).attr("threshold1")!="" && $(this).attr("threshold2")!=undefined && $(this).attr("threshold2")!=""){
            var limit1 = $(this).attr("threshold1")*1 || 60;
            var limit2 = $(this).attr("threshold2")*2 || 120;
            if (val< limit1){
               textcolor = feedvalue.attr("colour1")|| "#019F62";
            } else if(val > limit2){
               textcolor = feedvalue.attr("colour3")|| "#F70511";
            } else{
               textcolor = feedvalue.attr("colour2")|| "#FF8425";
            }
        }

        draw_feedvalue(
            feedvalue,
            feedvalue.attr("font"),
            feedvalue.attr("fstyle"),
            feedvalue.attr("fweight"),
            feedvalue.width(),
            feedvalue.height(),
            prepend,
            val,
            append,
            textcolor,
            feedvalue.attr("decimals"),
            feedvalue.attr("size"),
            feedvalue.attr("align"),
            errorCode,
            errorMessage,
	    feedvalue.attr("scale")
        );
    });
}

function feedvalue_init()
{
    $(".feedvalue").html("");
}
function feedvalue_slowupdate()
{
	  feedvalue_draw();
}
function feedvalue_fastupdate()
{
	  feedvalue_draw();
}
<commit_msg>minor optimisations to feedvalue_render<commit_after>/*
  All Emoncms code is released under the GNU Affero General Public License.
  See COPYRIGHT.txt and LICENSE.txt.
    ---------------------------------------------------------------------
    Part of the OpenEnergyMonitor project:
    http://openenergymonitor.org

    Author: Trystan Lea: trystan.lea@googlemail.com
	Enhancements done by: Andreas Messerli firefox7518@gmail.com
    If you have any questions please get in touch, try the forums here:
    http://openenergymonitor.org/emon/forum
 */

function feedvalue_widgetlist()
{
  var widgets =
  {
    "feedvalue":
    {
      "offsetx":-40,"offsety":-30,"width":120,"height":60,
      "menu":"Widgets",
      "options":    [],
      "optionstype":[],
      "optionsname":[],
      "optionshint":[],
      "optionsdata":[]
    }
  };

  var decimalsDropBoxOptions = [        // Options for the type combobox. Each item is [typeID, "description"]
        [-1,   _Tr("Automatic")],
        [0,    "0"],
        [1,    "1"],
        [2,    "2"],
        [3,    "3"],
        [4,    "4"],
        [5,    "5"],
        [6,    "6"]
    ];

	var fontoptions = [
					[9, "Arial Black"],
					[8, "Arial Narrow"],
					[7, "sans-serif"],
					[6, "Helvetica Neue"],
					[5, "Helvetica"],
					[4, "Comic Sans MS"],
					[3, "Courier New"],
					[2, "Arial"],
					[1, "Georgia"],
					[0, "Impact"]
				];

	var fstyleoptions = [
					[2, _Tr("Normal")],
					[1, _Tr("Italic")],
					[0, _Tr("Oblique")]
				];

	var fweightoptions = [
					[1, _Tr("Bold")],
					[0, _Tr("Normal")]
				];

	var sizeoptions = [
					[14, "18"], // set size 18 to the top position to be the default value for creating new feedvalue widgets otherwise size 40 would be always the default
					[13, "40"],
					[12, "36"],
					[11, "32"],
					[10, "28"],
					[9, "24"],
					[8, "22"],
					[7, "20"],
					[6, "18"],
					[5, "16"],
					[4, "14"],
					[3, "12"],
					[2, "10"],
					[1, "8"],
					[0, "6"]
				];

  var alignmentOptions = [
    ["center", _Tr("Center")],
    ["left", _Tr("Left")],
    ["right", _Tr("Right")]
  ];

	addOption(widgets["feedvalue"], "feedid",   "feedid",  _Tr("Feed"),     _Tr("Feed value"),      []);
	addOption(widgets["feedvalue"], "prepend",    "value",   _Tr("Prepend Text"),    _Tr("Prepend Text"),   []);
	addOption(widgets["feedvalue"], "append",  "value", _Tr("Append Text"), _Tr("Append Text (Units)"), []);
	addOption(widgets["feedvalue"], "decimals", "dropbox", _Tr("Decimals"), _Tr("Decimals to show"),    decimalsDropBoxOptions);
	addOption(widgets["feedvalue"], "colour",   "colour_picker",  _Tr("Colour"),     _Tr("Colour used for display"),      []);
	addOption(widgets["feedvalue"], "font",     "dropbox",  _Tr("Font"),     _Tr("Font used for display"),      fontoptions);
	addOption(widgets["feedvalue"], "fstyle",   "dropbox", _Tr("Font style"), _Tr("Font style used for display"),    fstyleoptions);
	addOption(widgets["feedvalue"], "fweight",  "dropbox", _Tr("Font weight"), _Tr("Font weight used for display"),    fweightoptions);
	addOption(widgets["feedvalue"], "size",   	"dropbox", _Tr("Size"), _Tr("Text size in px to use"),    sizeoptions);
	addOption(widgets["feedvalue"], "align",    "dropbox", _Tr("Alignment"), _Tr("Alignment"), alignmentOptions);
	addOption(widgets["feedvalue"], "timeout",  "value",   _Tr("Timeout"),    _Tr("Timeout without feed update in seconds (empty is never)"),   []);
	addOption(widgets["feedvalue"], "errormessagedisplayed",    "value",  _Tr("Error Message"),   _Tr("Error message displayed when timeout is reached"),   []);
	addOption(widgets["feedvalue"], "threshold1",  "value",   _Tr("Threshold1"),    _Tr("Threshold1 value"),   []);
	addOption(widgets["feedvalue"], "threshold2",  "value",   _Tr("Threshold2"),    _Tr("Threshold2 value"),   []);
	addOption(widgets["feedvalue"], "colour1",   "colour_picker",  _Tr("Colour1"),     _Tr("Colour for range below Threshold1"),      []);
	addOption(widgets["feedvalue"], "colour2",   "colour_picker",  _Tr("Colour2"),     _Tr("Colour for range between Threshold1 and Threshold2"),      []);
	addOption(widgets["feedvalue"], "colour3",   "colour_picker",  _Tr("Colour3"),     _Tr("Colour for range above Threshold2"),      []);
        addOption(widgets["feedvalue"], "scale", "value", _Tr("Scale"), _Tr("scale"),    []);
	return widgets;
}

function draw_feedvalue(feedvalue,font,fstyle,fweight,width,height,prepend,val,append,colour,decimals,size,align,errorCode,errorMessage,scale)
{
    colour = colour || "4444CC";
    size = size || "8";
    font = font || "5";
    fstyle = fstyle || "2";
    fweight = fweight || "1";
    align = align || "center";
    scale = scale || 1.0;

    val *= (1*scale);

    var fontsize;

    if (size === "0"){fontsize = 6;}
    if (size === "1"){fontsize = 8;}
    if (size === "2"){fontsize = 10;}
    if (size === "3"){fontsize = 12;}
    if (size === "4"){fontsize = 14;}
    if (size === "5"){fontsize = 16;}
    if (size === "6"){fontsize = 18;}
    if (size === "7"){fontsize = 20;}
    if (size === "8"){fontsize = 22;}
    if (size === "9"){fontsize = 24;}
    if (size === "10"){fontsize = 28;}
    if (size === "11"){fontsize = 32;}
    if (size === "12"){fontsize = 36;}
    if (size === "13"){fontsize = 40;}
    if (size === "14"){fontsize = 18;}  //default value so that not size 40 is always the default

    var fontname;

    if (font === "0"){fontname = "Impact";}
    if (font === "1"){fontname = "Georgia";}
    if (font === "2"){fontname = "Arial";}
    if (font === "3"){fontname = "Courier New";}
    if (font === "4"){fontname = "Comic Sans MS";}
    if (font === "5"){fontname = "Helvetica";}
    if (font === "6"){fontname = "Helvetica Neue";}
    if (font === "7"){fontname = "sans-serif";}
    if (font === "8"){fontname = "Arial Narrow";}
    if (font === "9"){fontname = "Arial Black";}

    var fontstyle;

    if (fstyle === "0"){fontstyle = "oblique";}
    if (fstyle === "1"){fontstyle = "italic";}
    if (fstyle === "2"){fontstyle = "normal";}

    var fontweight;

    if (fweight === "0"){fontweight = "normal";}
    if (fweight === "1"){fontweight = "bold";}

    if (decimals<0)
    {
        if (val>=100){
            val = val.toFixed(0);
        }
        else if (val>=10){
            val = val.toFixed(1);
        }
        else if (val<=-100){
            val = val.toFixed(0);
        }
        else if (val<=-10){
            val = val.toFixed(1);
        }
        else {
            val = val.toFixed(2);
        }
        val = parseFloat(val);
    }
    else
    {
        val = val.toFixed(decimals);
    }

    if (colour.indexOf("#") === -1) {			// Fix missing "#" on colour if needed
        colour = "#" + colour;
    }

    feedvalue.css({
        "color":colour,
        "font":fontstyle+" "+ fontweight+" "+ fontsize+"px "+fontname,"text-align":align,
        "line-height":height+"px"
    });

    if (errorCode === "1")
    {
        feedvalue.html(errorMessage);
    }
    else
    {
        feedvalue.html(prepend+val+append);
    }
}

function feedvalue_draw()
{
    var now = (new Date()).getTime()*0.001;

    $(".feedvalue").each(function(index)
    {
        var feedvalue = $(this);

        var feedid = feedvalue.attr("feedid");
        if (assocfeed[feedid]!=undefined) feedid = assocfeed[feedid]; // convert tag:name to feedid

        var val = 0;
        var feed_update_time = now;

        if (associd[feedid] != undefined) {
            val = associd[feedid]["value"] * 1;
            feed_update_time = 1*associd[feedid]["time"];
        }

        if (val===undefined) {val = 0;}
        if (isNaN(val))  {val = 0;}

        // Timeout error
        var errorMessage = feedvalue.attr("errormessagedisplayed");
        if (errorMessage === "" || errorMessage === undefined) errorMessage = "TO Error";

        var errorTimeout = feedvalue.attr("timeout");
        if (errorTimeout === "" || errorTimeout === undefined) errorTimeout = 0;

        var errorCode = "0";
        if (errorTimeout !== 0) {
            if ((now-offsetofTime-feed_update_time) > errorTimeout) errorCode = "1";
        }

        // backwards compatibility
        var unitend = feedvalue.attr("unitend");
        var units = feedvalue.attr("units");

        // new options
        var prepend = feedvalue.attr("prepend");
        var append = feedvalue.attr("append");

        // check if new options are undefined: use old
        if (prepend==undefined && append==undefined) {
            if (unitend!=undefined && units!=undefined) {
                if (unitend ==="0") {
                    append = units;
                    prepend = ""
                } else if (unitend ==="1") {
                    prepend = units;
                    append = ""
                }
            } else {
                prepend = ""
                append = ""
            }
        }

        var textcolor = feedvalue.attr("colour");

        if($(this).attr("threshold1")!=undefined && $(this).attr("threshold1")!="" && $(this).attr("threshold2")!=undefined && $(this).attr("threshold2")!=""){
            var limit1 = $(this).attr("threshold1")*1 || 60;
            var limit2 = $(this).attr("threshold2")*2 || 120;
            if (val< limit1){
               textcolor = feedvalue.attr("colour1")|| "#019F62";
            } else if(val > limit2){
               textcolor = feedvalue.attr("colour3")|| "#F70511";
            } else{
               textcolor = feedvalue.attr("colour2")|| "#FF8425";
            }
        }

        draw_feedvalue(
            feedvalue,
            feedvalue.attr("font"),
            feedvalue.attr("fstyle"),
            feedvalue.attr("fweight"),
            feedvalue.width(),
            feedvalue.height(),
            prepend,
            val,
            append,
            textcolor,
            feedvalue.attr("decimals"),
            feedvalue.attr("size"),
            feedvalue.attr("align"),
            errorCode,
            errorMessage,
	          feedvalue.attr("scale")
        );
    });
}

function feedvalue_init()
{
    $(".feedvalue").html("");
}
function feedvalue_slowupdate()
{
	  feedvalue_draw();
}
function feedvalue_fastupdate()
{
	  if (redraw) feedvalue_draw();
}
<|endoftext|>