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

var activeTab;
var outerLayout, innerLayout;

function hideDialog(){
    innerLayout.close("south");
}

function popDialog(content){
    $("#dialog").html(content);
    innerLayout.open("south");
}

function popDialogLoading(){
    var loading = '

';
    popDialog(loading);
}

function showTab(tabname,highlight_tab){
    //Since menu items no longer have an  element
    //we no longer expect #tab_id here, but simply tab_id
    //So safety check - remove # from #tab_id if present to ensure compatibility

    $('tbody input.check_item:checked').click();
    $('td').removeClass('markrowchecked markrowselected');
    last_select_row = null;

    if (tabname.indexOf('#') == 0)
        tabname = tabname.substring(1);
    if (highlight_tab && highlight_tab.indexOf('#') == 0)
        highlight_tab == highlight.substring(1);

    var activeTab = tabname;

    if (!highlight_tab) highlight_tab = activeTab;

    //clean selected menu
    $("#navigation li").removeClass("navigation-active-li");
    $("div#header ul#menutop_ul li").removeClass("navigation-active-li");

    //select tab in left menu
    var li = $("#navigation li#li_"+highlight_tab)
    li.addClass("navigation-active-li");

    //select tab in top menu
    var top_li = $("div#header ul#menutop_ul li#top_"+highlight_tab);
    top_li.addClass("navigation-active-li");

    //show tab
    $(".tab").hide();
    $('#'+activeTab).show();
    innerLayout.close("south");
}

function setupTabs(){

    var topTabs = $(".outer-west ul li.topTab");
    var subTabs = $(".outer-west ul li.subTab");

    subTabs.live("click",function(){
        //leave floor to topTab listener in case of tabs with both classes
        if ($(this).hasClass('topTab')) return false;

        var tab = $(this).attr('id').substring(3);
        showTab(tab);
        return false;
    });

    topTabs.live("click",function(e){
        var tab = $(this).attr('id').substring(3);
        //Subtabs have a class with the name of  this tab
        var subtabs = $('div#menu li.'+tab);

        //toggle subtabs only when clicking on the icon or when clicking on an
        //already selected menu
        if ($(e.target).is('span') ||
            $(this).hasClass("navigation-active-li") ||
            $(this).hasClass("tab_with_no_content")){
            //for each subtab, we hide the subsubtabs
            subtabs.each(function(){
                //for each subtab, hide its subtabs
                var subsubtabs = $(this).attr('id').substr(3);
                //subsubtabs class
                subsubtabs = $('div#menu li.'+subsubtabs);
                subsubtabs.hide();
            });
            //hide subtabs and reset icon to + position, since all subsubtabs
            //are hidden
            subtabs.fadeToggle('fast');
            $(this).removeClass('active');
            $('span',subtabs).removeClass(' icon-caret-down');
            $('span',subtabs).addClass(' icon-caret-left');
            //toggle icon on this tab
            $('span',this).toggleClass(' icon-caret-left  icon-caret-down');
            return false;
        }
        else {
            showTab(tab);
            return false;
        }
        //if we are clicking on the icon only, do not show the tab
        if ($(e.target).is('span')) return false;

    });

};

function setupTopMenu(){
    $('div#header ul#menutop_ul li').live('click',function(){
        var tab = "#" + $(this).attr('id').substring(4);
        showTab(tab);
    });
};

$(document).ready(function () {
    $(".tab").hide();

    setupTabs();
    setupTopMenu();

    outerLayout = $('body').layout({
        applyDefaultStyles:       false
    ,   center__paneSelector:	".outer-center"
    ,	west__paneSelector:		".outer-west"
    ,	west__size:				245
    ,	north__size:			26
    ,   south__size:            26
    ,	spacing_open:			0 // ALL panes
    ,	spacing_closed:			0 // ALL panes
    //,	north__spacing_open:	0
    //,	south__spacing_open:	0
    ,	north__maxSize:			200
    ,	south__maxSize:			200
    ,   south__closable:        false
    ,   north__closable:        false
    ,   west__closable:         false
    ,   south__resizable:       false
    ,   north__resizable:       false
    ,   west__resizable:        false
    });

    var factor = 0.6;
    var dialog_height = Math.floor($(".outer-center").height()*factor);

    innerLayout = $('div.outer-center').layout({
        fxName:                 "slide"
    ,   initClosed:             true
    ,   center__paneSelector:	".inner-center"
    ,	south__paneSelector:	".inner-south"
    ,   south__size:            dialog_height
    ,   south__resizable:       true
    ,   south__spacing_open:      10
    ,   north__resizable:       true
    ,   north__spacing_open:      10
    ,	spacing_open:			5  // ALL panes
    ,	spacing_closed:			5 // ALL panes
    });

});
<commit_msg>feature #1664: refresh datatable onchange tab<commit_after>/* -------------------------------------------------------------------------- */
/* Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        */
/*                                                                            */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may    */
/* not use this file except in compliance with the License. You may obtain    */
/* a copy of the License at                                                   */
/*                                                                            */
/* http://www.apache.org/licenses/LICENSE-2.0                                 */
/*                                                                            */
/* Unless required by applicable law or agreed to in writing, software        */
/* distributed under the License is distributed on an "AS IS" BASIS,          */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   */
/* See the License for the specific language governing permissions and        */
/* limitations under the License.                                             */
/* -------------------------------------------------------------------------- */

var activeTab;
var outerLayout, innerLayout;

function hideDialog(){
    innerLayout.close("south");
}

function popDialog(content){
    $("#dialog").html(content);
    innerLayout.open("south");
}

function popDialogLoading(){
    var loading = '

';
    popDialog(loading);
}

function showTab(tabname,highlight_tab){
    //Since menu items no longer have an  element
    //we no longer expect #tab_id here, but simply tab_id
    //So safety check - remove # from #tab_id if present to ensure compatibility

    $('tbody input.check_item:checked').click();
    $('td').removeClass('markrowchecked markrowselected');
    last_select_row = null;

    if (tabname.indexOf('#') == 0)
        tabname = tabname.substring(1);
    if (highlight_tab && highlight_tab.indexOf('#') == 0)
        highlight_tab == highlight.substring(1);

    var activeTab = tabname;

    if (!highlight_tab) highlight_tab = activeTab;

    //clean selected menu
    $("#navigation li").removeClass("navigation-active-li");
    $("div#header ul#menutop_ul li").removeClass("navigation-active-li");

    //select tab in left menu
    var li = $("#navigation li#li_"+highlight_tab)
    li.addClass("navigation-active-li");

    //select tab in top menu
    var top_li = $("div#header ul#menutop_ul li#top_"+highlight_tab);
    top_li.addClass("navigation-active-li");

    //show tab
    $(".tab").hide();
    $('#'+activeTab).show();

    $("#refresh_buttons button", $('#'+activeTab)).click()

    innerLayout.close("south");
}

function setupTabs(){

    var topTabs = $(".outer-west ul li.topTab");
    var subTabs = $(".outer-west ul li.subTab");

    subTabs.live("click",function(){
        //leave floor to topTab listener in case of tabs with both classes
        if ($(this).hasClass('topTab')) return false;

        var tab = $(this).attr('id').substring(3);
        showTab(tab);
        return false;
    });

    topTabs.live("click",function(e){
        var tab = $(this).attr('id').substring(3);
        //Subtabs have a class with the name of  this tab
        var subtabs = $('div#menu li.'+tab);

        //toggle subtabs only when clicking on the icon or when clicking on an
        //already selected menu
        if ($(e.target).is('span') ||
            $(this).hasClass("navigation-active-li") ||
            $(this).hasClass("tab_with_no_content")){
            //for each subtab, we hide the subsubtabs
            subtabs.each(function(){
                //for each subtab, hide its subtabs
                var subsubtabs = $(this).attr('id').substr(3);
                //subsubtabs class
                subsubtabs = $('div#menu li.'+subsubtabs);
                subsubtabs.hide();
            });
            //hide subtabs and reset icon to + position, since all subsubtabs
            //are hidden
            subtabs.fadeToggle('fast');
            $(this).removeClass('active');
            $('span',subtabs).removeClass(' icon-caret-down');
            $('span',subtabs).addClass(' icon-caret-left');
            //toggle icon on this tab
            $('span',this).toggleClass(' icon-caret-left  icon-caret-down');
            return false;
        }
        else {
            showTab(tab);
            return false;
        }
        //if we are clicking on the icon only, do not show the tab
        if ($(e.target).is('span')) return false;

    });

};

function setupTopMenu(){
    $('div#header ul#menutop_ul li').live('click',function(){
        var tab = "#" + $(this).attr('id').substring(4);
        showTab(tab);
    });
};

$(document).ready(function () {
    $(".tab").hide();

    setupTabs();
    setupTopMenu();

    outerLayout = $('body').layout({
        applyDefaultStyles:       false
    ,   center__paneSelector:	".outer-center"
    ,	west__paneSelector:		".outer-west"
    ,	west__size:				245
    ,	north__size:			26
    ,   south__size:            26
    ,	spacing_open:			0 // ALL panes
    ,	spacing_closed:			0 // ALL panes
    //,	north__spacing_open:	0
    //,	south__spacing_open:	0
    ,	north__maxSize:			200
    ,	south__maxSize:			200
    ,   south__closable:        false
    ,   north__closable:        false
    ,   west__closable:         false
    ,   south__resizable:       false
    ,   north__resizable:       false
    ,   west__resizable:        false
    });

    var factor = 0.6;
    var dialog_height = Math.floor($(".outer-center").height()*factor);

    innerLayout = $('div.outer-center').layout({
        fxName:                 "slide"
    ,   initClosed:             true
    ,   center__paneSelector:	".inner-center"
    ,	south__paneSelector:	".inner-south"
    ,   south__size:            dialog_height
    ,   south__resizable:       true
    ,   south__spacing_open:      10
    ,   north__resizable:       true
    ,   north__spacing_open:      10
    ,	spacing_open:			5  // ALL panes
    ,	spacing_closed:			5 // ALL panes
    });

});
<|endoftext|>


<commit_before>/*##################################################|*/
/* #CMS# */
(function($) {
// CMS.$ will be passed for $
$(document).ready(function () {
	/*!
	 * StructureBoard
	 * handles drag & drop, mode switching and
	 */
	CMS.StructureBoard = new CMS.Class({

		implement: [CMS.API.Helpers],

		options: {
			'speed': 300
		},

		initialize: function (options) {
			this.container = $('.cms_structure');
			this.options = $.extend(true, {}, this.options, options);
			this.config = CMS.config;
			this.settings = CMS.settings;

			// elements
			this.toolbar = $('#cms_toolbar');
			this.sortables = $('.cms_draggables'); // use global scope
			this.plugins = $('.cms_plugin');
			this.render_model = $('.cms_render_model');
			this.placeholders = $('.cms_placeholder');
			this.dragitems = $('.cms_draggable');
			this.dragareas = $('.cms_dragarea');
			this.dropareas = $('.cms_droppable');
			this.dimmer = this.container.find('.cms_structure-dimmer');
			this.clipboard = $('.cms_clipboard');

			// states
			this.click = (document.ontouchstart !== null) ? 'click.cms' : 'tap.cms';
			this.timer = function () {};
			this.interval = function () {};
			this.state = false;
			this.dragging = false;

			// setup initial stuff
			this._setup();

			// setup events
			this._events();
		},

		// initial methods
		_setup: function () {
			var that = this;

			// cancel if there are no dragareas
			if(!this.dragareas.length) return false;

			// setup toolbar mode
			if(this.settings.mode === 'structure') setTimeout(function () { that.show(true); }, 100);

			// check if modes should be visible
			if(this.placeholders.length) {
				this.toolbar.find('.cms_toolbar-item-cms-mode-switcher').show();
			}

			// add drag & drop functionality
			this._drag();
			// prevent click events to detect double click
			this.preventEvents(this.plugins);
		},

		_events: function () {
			var that = this;
			var modes = this.toolbar.find('.cms_toolbar-item-cms-mode-switcher a');

			// show edit mode
			modes.eq(0).bind(this.click, function (e) {
				e.preventDefault();
				// cancel if already active
				if(that.settings.mode === 'edit') return false;
				// otherwise hide
				that.hide();
			});
			// show structure mode
			modes.eq(1).bind(this.click, function (e) {
				e.preventDefault();
				// cancel if already active
				if(that.settings.mode === 'structure') return false;
				// otherwise show
				that.show();
			});

			// keyboard handling
			$(document).bind('keydown', function (e) {
				// check if we have an important focus
				var fields = $('*:focus');
				// 32 = space
				if(e.keyCode === 32 && that.settings.mode === 'structure' && !fields.length) {
					e.preventDefault();
					that.hide();
				} else if(e.keyCode === 32 && that.settings.mode === 'edit' && !fields.length) {
					e.preventDefault();
					that.show();
				}
			});
		},

		// public methods
		show: function (init) {
			// cancel show if live modus is active
			if(CMS.config.mode === 'live') return false;

			// set active item
			var modes = this.toolbar.find('.cms_toolbar-item-cms-mode-switcher a');
				modes.removeClass('cms_btn-active').eq(1).addClass('cms_btn-active');

			// show clipboard
			this.clipboard.css('opacity', 1).fadeIn(this.options.speed);

			// apply new settings
			this.settings.mode = 'structure';
			if(!init) this.settings = this.setSettings(this.settings);

			// ensure all elements are visible
			this.dragareas.show();

			// show canvas
			this._showBoard();
		},

		hide: function (init) {
			// cancel show if live modus is active
			if(CMS.config.mode === 'live') return false;

			// set active item
			var modes = this.toolbar.find('.cms_toolbar-item-cms-mode-switcher a');
				modes.removeClass('cms_btn-active').eq(0).addClass('cms_btn-active');

			// hide clipboard if in edit mode
			this.container.find('.cms_clipboard').hide();

			// hide clipboard
			this.clipboard.hide();

			this.settings.mode = 'edit';
			if(!init) this.settings = this.setSettings(this.settings);

			// hide canvas
			this._hideBoard();
		},

		getId: function (el) {
			// cancel if no element is defined
			if(el === undefined || el === null || el.length <= 0) return false;

			var id = null;
			var cls = el.attr('class').split(' ')[1];

			if(el.hasClass('cms_plugin')) {
				id = cls.replace('cms_plugin-', '');
			} else if(el.hasClass('cms_draggable')) {
				id = cls.replace('cms_draggable-', '');
			} else if(el.hasClass('cms_placeholder')) {
				id = cls.replace('cms_placeholder-', '');
			} else if(el.hasClass('cms_dragbar')) {
				id = cls.replace('cms_dragbar-', '');
			} else if(el.hasClass('cms_dragarea')) {
				id = cls.replace('cms_dragarea-', '');
			}

			return id;
		},

		getIds: function (els) {
			var that = this;
			var array = [];
			els.each(function () {
				array.push(that.getId($(this)));
			});
			return array;
		},

		setActive: function (id, state) {
			var that = this;
			// resets
			this.dragitems.removeClass('cms_draggable-selected');
			this.plugins.removeClass('cms_plugin-active');
			this.dragitems.unbind('mousedown.cms.longclick');

			// only reset if no id is provided
			if(id === false) return false;

			// attach active class to current element
			var dragitem = $('.cms_draggable-' + id);
			var plugin = $('.cms_plugin-' + id);

			// if we switch from content to edit, show only a single plcaeholder
			if(state) {
				// quick show
				this._showBoard();

				// show clipboard
				this.clipboard.show().css('opacity', 0.2);

				// prevent default visibility
				this.dragareas.css('opacity', 0.2);

				// show single placeholder
				dragitem.closest('.cms_dragarea').show().css('opacity', 1);

				// attach event to switch to fullmode when dragging
				this.dragitems.bind('mousedown.cms.longclick', function () {
					that.show();
					that.setActive(false);
				});

			// otherwise hide and reset the board
			} else {
				this.hide();
			}

			// collapse all previous elements
			var collapsed = dragitem.parentsUntil('.cms_dragarea').siblings().not('.cms_dragitem-expanded');
				collapsed.trigger(this.click);

			// set new classes
			dragitem.addClass('cms_draggable-selected');
			plugin.addClass('cms_plugin-active');
		},

		preventEvents: function (elements) {
			var clicks = 0;
			var delay = 500;
			var timer = function () {};

			// unbind click event if already initialized
			elements.find('a').bind(this.click, function (e) {
				e.preventDefault();

				// increment
				clicks++;

				// single click
				if(clicks === 1) {
					timer = setTimeout(function () {
						clicks = 0;
						// cancel if link contains a hash
						if($(e.currentTarget).attr('href').indexOf('#') === 0) return false;
						// we need to redirect to the default behaviours
						// all events will be lost in edit mode, use '#' if href should not be triggered
						window.location.href = $(e.currentTarget).attr('href');
					}, delay);
				}

				// double click
				if(clicks === 2) {
					clearTimeout(timer);
					clicks = 0;
				}
			});
		},

		// private methods
		_showBoard: function () {
			var that = this;
			var interval = 10;
			var timer = function () {};

			// show container
			this.container.show();
			this.dimmer.fadeIn(100);
			this.dragareas.css('opacity', 1);

			// add dimmer close
			this.dimmer.bind('mousedown mouseup', function (e) {
				// cancel on rightclick
				if(e.which === 3 || e.button === 2) return false;
				// proceed
				clearTimeout(timer);
				timer = setTimeout(function () {
					that.hide();
				}, 500);

				if(e.type === 'mouseup') clearTimeout(timer);
			});

			this.plugins.not(this.render_model).hide();
			this.placeholders.show();

			// attach event
			$(window).bind('resize.sideframe', function () {
				that._resizeBoard();
			}).trigger('resize.sideframe');

			// setup an interval
			this.interval = setInterval(function () {
				$(window).trigger('resize.sideframe');
			}, interval);
		},

		_hideBoard: function () {
			// hide elements
			this.container.hide();
			this.plugins.show();
			this.placeholders.hide();
			this.dimmer.hide();

			// detach event
			$(window).unbind('resize.sideframe');

			// clear interval
			clearInterval(this.interval);
		},

		_resizeBoard: function () {
			// calculate placeholder position
			var id = null;
			var area = null;
			var min = null;

			// start calculating
			this.placeholders.each(function (index, item) {
				item = $(item);
				id = item.data('settings').placeholder_id;
				area = $('.cms_dragarea-' + id);
				// to calculate the correct offset, we need to set the
				// placeholders correct heights and than set the according position
				item.height(area.outerHeight(true));
				// set min width
				min = (item.width()) ? 0 : 150;
				area.css({
					'top': item.offset().top - 5,
					'left': item.offset().left - min,
					'width': item.width() + min
				});
			});
		},

		_drag: function () {
			var that = this;
			var dropped = false;
			var droparea = null;
			var dropzone = null;

			this.sortables.nestedSortable({
				'items': '.cms_draggable',
				'handle': '.cms_dragitem',
				'placeholder': 'cms_droppable',
				'connectWith': this.sortables,
				'tolerance': 'pointer',
				'toleranceElement': '> div',
				'dropOnEmpty': true,
				'forcePlaceholderSize': true,
				'helper': 'clone',
				'appendTo': 'body',
				'cursor': 'move',
				'opacity': 0.4,
				'zIndex': 9999999,
				'delay': 100,
				'refreshPositions': true,
				// nestedSortable
				'listType': 'div.cms_draggables',
				'doNotClear': true,
				'disableNestingClass': 'cms_draggable-disabled',
				'errorClass': 'cms_draggable-disallowed',
				'hoveringClass': 'cms_draggable-hover',
				// methods
				'start': function (e, ui) {
					that.dragging = true;
					// show empty
					$('.cms_dragbar-empty-wrapper').show();
					// ensure all menus are closed
					$('.cms_dragitem .cms_submenu').hide();
					// remove classes from empty dropzones
					$('.cms_dragbar-empty').removeClass('cms_draggable-disallowed');
					// fixes placeholder height
					ui.placeholder.height(ui.item.height());
					// show placeholder without entries
					$('.cms_draggables').each(function () {
						if($(this).children().length === 0) {
							$(this).show();
						}
					});
				},

				'stop': function (event, ui) {
					that.dragging = false;
					// hide empty
					$('.cms_dragbar-empty-wrapper').hide();

					// cancel if isAllowed returns false
					if(!that.state) return false;

					// handle dropped event
					if(dropped) {
						droparea.prepend(ui.item);
						dropped = false;
					}

					// we pass the id to the updater which checks within the backend the correct place
					//var id = ui.item.attr('class').replace('cms_draggable cms_draggable-', '');
					var id = that.getId(ui.item);
					var plugin = $('.cms_plugin-' + id);

					// check if we copy/paste a plugin or not
					if(plugin.closest('.cms_clipboard').length) {
						plugin.trigger('cms.plugin.update');
					} else {
						plugin.trigger('cms.plugins.update');
					}

					// reset placeholder without entries
					$('.cms_draggables').each(function () {
						if($(this).children().length === 0) {
							$(this).hide();
						}
					});
				},
				'isAllowed': function(placeholder, placeholderParent, originalItem) {
					// cancel if action is excecuted
					if(CMS.API.locked) return false;
					// getting restriction array
					var bounds = [];
					// save original state events
					var original = $('.cms_plugin-' + that.getId(originalItem));
					// cancel if item has no settings
					if(original.length === 0 || original.data('settings') === null) return false;
					var type = original.data('settings').plugin_type;
					// prepare variables for bound
					var holderId = that.getId(placeholder.closest('.cms_dragarea'));
					var holder = $('.cms_placeholder-' + holderId);
					var plugin = $('.cms_plugin-' + that.getId(placeholder.closest('.cms_draggable')));

					// now set the correct bounds
					if(dropzone) bounds = dropzone.data('settings').plugin_restriction;
					if(holder.length) bounds = holder.data('settings').plugin_restriction;
					if(plugin.length) bounds = plugin.data('settings').plugin_restriction;

					// if parent has class disabled, dissalow drop
					if(placeholder.parent().hasClass('cms_draggable-disabled')) return false;

					// if restrictions is still empty, proceed
					that.state = (bounds.length <= 0 || $.inArray(type, bounds) !== -1) ? true : false;

					return that.state;
				}
			});

			// attach escape event to cancel dragging
			$(document).bind('keyup.cms', function(e, cancel){
				if(e.keyCode === 27 || cancel) {
					that.state = false;
					that.sortables.sortable('cancel');
				}
			});

			// define droppable helpers
			this.dropareas.droppable({
				'greedy': true,
				'accept': '.cms_draggable',
				'tolerance': 'pointer',
				'activeClass': 'cms_draggable-allowed',
				'hoverClass': 'cms_draggable-hover-allowed',
				'over': function (event) {
					dropzone = $('.cms_placeholder-' + that.getId($(event.target).parent().prev()));
					if(!that.state) $(event.target).addClass('cms_draggable-disallowed');
				},
				'out': function (event) {
					dropzone = null;
					$(event.target).removeClass('cms_draggable-disallowed');
				},
				'drop': function (event) {
					dropped = true;
					droparea = $(event.target).parent().nextAll('.cms_draggables').first();
				}
			});
		}

	});

});
})(CMS.$);<commit_msg>fixes js button switch<commit_after>/*##################################################|*/
/* #CMS# */
(function($) {
// CMS.$ will be passed for $
$(document).ready(function () {
	/*!
	 * StructureBoard
	 * handles drag & drop, mode switching and
	 */
	CMS.StructureBoard = new CMS.Class({

		implement: [CMS.API.Helpers],

		options: {
			'speed': 300
		},

		initialize: function (options) {
			this.container = $('.cms_structure');
			this.options = $.extend(true, {}, this.options, options);
			this.config = CMS.config;
			this.settings = CMS.settings;

			// elements
			this.toolbar = $('#cms_toolbar');
			this.sortables = $('.cms_draggables'); // use global scope
			this.plugins = $('.cms_plugin');
			this.render_model = $('.cms_render_model');
			this.placeholders = $('.cms_placeholder');
			this.dragitems = $('.cms_draggable');
			this.dragareas = $('.cms_dragarea');
			this.dropareas = $('.cms_droppable');
			this.dimmer = this.container.find('.cms_structure-dimmer');
			this.clipboard = $('.cms_clipboard');

			// states
			this.click = (document.ontouchstart !== null) ? 'click.cms' : 'tap.cms';
			this.timer = function () {};
			this.interval = function () {};
			this.state = false;
			this.dragging = false;

			// setup initial stuff
			this._setup();

			// setup events
			this._events();
		},

		// initial methods
		_setup: function () {
			var that = this;

			// cancel if there are no dragareas
			if(!this.dragareas.length) return false;

			// setup toolbar mode
			if(this.settings.mode === 'structure') setTimeout(function () { that.show(true); }, 100);

			// check if modes should be visible
			if(this.placeholders.length) {
				this.toolbar.find('.cms_toolbar-item-cms-mode-switcher').show();
			}

			// add drag & drop functionality
			this._drag();
			// prevent click events to detect double click
			this.preventEvents(this.plugins);
		},

		_events: function () {
			var that = this;
			var modes = this.toolbar.find('.cms_toolbar-item-cms-mode-switcher a');

			// show edit mode
			modes.eq(1).bind(this.click, function (e) {
				e.preventDefault();
				// cancel if already active
				if(that.settings.mode === 'edit') return false;
				// otherwise hide
				that.hide();
			});
			// show structure mode
			modes.eq(0).bind(this.click, function (e) {
				e.preventDefault();
				// cancel if already active
				if(that.settings.mode === 'structure') return false;
				// otherwise show
				that.show();
			});

			// keyboard handling
			$(document).bind('keydown', function (e) {
				// check if we have an important focus
				var fields = $('*:focus');
				// 32 = space
				if(e.keyCode === 32 && that.settings.mode === 'structure' && !fields.length) {
					e.preventDefault();
					that.hide();
				} else if(e.keyCode === 32 && that.settings.mode === 'edit' && !fields.length) {
					e.preventDefault();
					that.show();
				}
			});
		},

		// public methods
		show: function (init) {
			// cancel show if live modus is active
			if(CMS.config.mode === 'live') return false;

			// set active item
			var modes = this.toolbar.find('.cms_toolbar-item-cms-mode-switcher a');
				modes.removeClass('cms_btn-active').eq(0).addClass('cms_btn-active');

			// show clipboard
			this.clipboard.css('opacity', 1).fadeIn(this.options.speed);

			// apply new settings
			this.settings.mode = 'structure';
			if(!init) this.settings = this.setSettings(this.settings);

			// ensure all elements are visible
			this.dragareas.show();

			// show canvas
			this._showBoard();
		},

		hide: function (init) {
			// cancel show if live modus is active
			if(CMS.config.mode === 'live') return false;

			// set active item
			var modes = this.toolbar.find('.cms_toolbar-item-cms-mode-switcher a');
				modes.removeClass('cms_btn-active').eq(1).addClass('cms_btn-active');

			// hide clipboard if in edit mode
			this.container.find('.cms_clipboard').hide();

			// hide clipboard
			this.clipboard.hide();

			this.settings.mode = 'edit';
			if(!init) this.settings = this.setSettings(this.settings);

			// hide canvas
			this._hideBoard();
		},

		getId: function (el) {
			// cancel if no element is defined
			if(el === undefined || el === null || el.length <= 0) return false;

			var id = null;
			var cls = el.attr('class').split(' ')[1];

			if(el.hasClass('cms_plugin')) {
				id = cls.replace('cms_plugin-', '');
			} else if(el.hasClass('cms_draggable')) {
				id = cls.replace('cms_draggable-', '');
			} else if(el.hasClass('cms_placeholder')) {
				id = cls.replace('cms_placeholder-', '');
			} else if(el.hasClass('cms_dragbar')) {
				id = cls.replace('cms_dragbar-', '');
			} else if(el.hasClass('cms_dragarea')) {
				id = cls.replace('cms_dragarea-', '');
			}

			return id;
		},

		getIds: function (els) {
			var that = this;
			var array = [];
			els.each(function () {
				array.push(that.getId($(this)));
			});
			return array;
		},

		setActive: function (id, state) {
			var that = this;
			// resets
			this.dragitems.removeClass('cms_draggable-selected');
			this.plugins.removeClass('cms_plugin-active');
			this.dragitems.unbind('mousedown.cms.longclick');

			// only reset if no id is provided
			if(id === false) return false;

			// attach active class to current element
			var dragitem = $('.cms_draggable-' + id);
			var plugin = $('.cms_plugin-' + id);

			// if we switch from content to edit, show only a single plcaeholder
			if(state) {
				// quick show
				this._showBoard();

				// show clipboard
				this.clipboard.show().css('opacity', 0.2);

				// prevent default visibility
				this.dragareas.css('opacity', 0.2);

				// show single placeholder
				dragitem.closest('.cms_dragarea').show().css('opacity', 1);

				// attach event to switch to fullmode when dragging
				this.dragitems.bind('mousedown.cms.longclick', function () {
					that.show();
					that.setActive(false);
				});

			// otherwise hide and reset the board
			} else {
				this.hide();
			}

			// collapse all previous elements
			var collapsed = dragitem.parentsUntil('.cms_dragarea').siblings().not('.cms_dragitem-expanded');
				collapsed.trigger(this.click);

			// set new classes
			dragitem.addClass('cms_draggable-selected');
			plugin.addClass('cms_plugin-active');
		},

		preventEvents: function (elements) {
			var clicks = 0;
			var delay = 500;
			var timer = function () {};

			// unbind click event if already initialized
			elements.find('a').bind(this.click, function (e) {
				e.preventDefault();

				// increment
				clicks++;

				// single click
				if(clicks === 1) {
					timer = setTimeout(function () {
						clicks = 0;
						// cancel if link contains a hash
						if($(e.currentTarget).attr('href').indexOf('#') === 0) return false;
						// we need to redirect to the default behaviours
						// all events will be lost in edit mode, use '#' if href should not be triggered
						window.location.href = $(e.currentTarget).attr('href');
					}, delay);
				}

				// double click
				if(clicks === 2) {
					clearTimeout(timer);
					clicks = 0;
				}
			});
		},

		// private methods
		_showBoard: function () {
			var that = this;
			var interval = 10;
			var timer = function () {};

			// show container
			this.container.show();
			this.dimmer.fadeIn(100);
			this.dragareas.css('opacity', 1);

			// add dimmer close
			this.dimmer.bind('mousedown mouseup', function (e) {
				// cancel on rightclick
				if(e.which === 3 || e.button === 2) return false;
				// proceed
				clearTimeout(timer);
				timer = setTimeout(function () {
					that.hide();
				}, 500);

				if(e.type === 'mouseup') clearTimeout(timer);
			});

			this.plugins.not(this.render_model).hide();
			this.placeholders.show();

			// attach event
			$(window).bind('resize.sideframe', function () {
				that._resizeBoard();
			}).trigger('resize.sideframe');

			// setup an interval
			this.interval = setInterval(function () {
				$(window).trigger('resize.sideframe');
			}, interval);
		},

		_hideBoard: function () {
			// hide elements
			this.container.hide();
			this.plugins.show();
			this.placeholders.hide();
			this.dimmer.hide();

			// detach event
			$(window).unbind('resize.sideframe');

			// clear interval
			clearInterval(this.interval);
		},

		_resizeBoard: function () {
			// calculate placeholder position
			var id = null;
			var area = null;
			var min = null;

			// start calculating
			this.placeholders.each(function (index, item) {
				item = $(item);
				id = item.data('settings').placeholder_id;
				area = $('.cms_dragarea-' + id);
				// to calculate the correct offset, we need to set the
				// placeholders correct heights and than set the according position
				item.height(area.outerHeight(true));
				// set min width
				min = (item.width()) ? 0 : 150;
				area.css({
					'top': item.offset().top - 5,
					'left': item.offset().left - min,
					'width': item.width() + min
				});
			});
		},

		_drag: function () {
			var that = this;
			var dropped = false;
			var droparea = null;
			var dropzone = null;

			this.sortables.nestedSortable({
				'items': '.cms_draggable',
				'handle': '.cms_dragitem',
				'placeholder': 'cms_droppable',
				'connectWith': this.sortables,
				'tolerance': 'pointer',
				'toleranceElement': '> div',
				'dropOnEmpty': true,
				'forcePlaceholderSize': true,
				'helper': 'clone',
				'appendTo': 'body',
				'cursor': 'move',
				'opacity': 0.4,
				'zIndex': 9999999,
				'delay': 100,
				'refreshPositions': true,
				// nestedSortable
				'listType': 'div.cms_draggables',
				'doNotClear': true,
				'disableNestingClass': 'cms_draggable-disabled',
				'errorClass': 'cms_draggable-disallowed',
				'hoveringClass': 'cms_draggable-hover',
				// methods
				'start': function (e, ui) {
					that.dragging = true;
					// show empty
					$('.cms_dragbar-empty-wrapper').show();
					// ensure all menus are closed
					$('.cms_dragitem .cms_submenu').hide();
					// remove classes from empty dropzones
					$('.cms_dragbar-empty').removeClass('cms_draggable-disallowed');
					// fixes placeholder height
					ui.placeholder.height(ui.item.height());
					// show placeholder without entries
					$('.cms_draggables').each(function () {
						if($(this).children().length === 0) {
							$(this).show();
						}
					});
				},

				'stop': function (event, ui) {
					that.dragging = false;
					// hide empty
					$('.cms_dragbar-empty-wrapper').hide();

					// cancel if isAllowed returns false
					if(!that.state) return false;

					// handle dropped event
					if(dropped) {
						droparea.prepend(ui.item);
						dropped = false;
					}

					// we pass the id to the updater which checks within the backend the correct place
					//var id = ui.item.attr('class').replace('cms_draggable cms_draggable-', '');
					var id = that.getId(ui.item);
					var plugin = $('.cms_plugin-' + id);

					// check if we copy/paste a plugin or not
					if(plugin.closest('.cms_clipboard').length) {
						plugin.trigger('cms.plugin.update');
					} else {
						plugin.trigger('cms.plugins.update');
					}

					// reset placeholder without entries
					$('.cms_draggables').each(function () {
						if($(this).children().length === 0) {
							$(this).hide();
						}
					});
				},
				'isAllowed': function(placeholder, placeholderParent, originalItem) {
					// cancel if action is excecuted
					if(CMS.API.locked) return false;
					// getting restriction array
					var bounds = [];
					// save original state events
					var original = $('.cms_plugin-' + that.getId(originalItem));
					// cancel if item has no settings
					if(original.length === 0 || original.data('settings') === null) return false;
					var type = original.data('settings').plugin_type;
					// prepare variables for bound
					var holderId = that.getId(placeholder.closest('.cms_dragarea'));
					var holder = $('.cms_placeholder-' + holderId);
					var plugin = $('.cms_plugin-' + that.getId(placeholder.closest('.cms_draggable')));

					// now set the correct bounds
					if(dropzone) bounds = dropzone.data('settings').plugin_restriction;
					if(holder.length) bounds = holder.data('settings').plugin_restriction;
					if(plugin.length) bounds = plugin.data('settings').plugin_restriction;

					// if parent has class disabled, dissalow drop
					if(placeholder.parent().hasClass('cms_draggable-disabled')) return false;

					// if restrictions is still empty, proceed
					that.state = (bounds.length <= 0 || $.inArray(type, bounds) !== -1) ? true : false;

					return that.state;
				}
			});

			// attach escape event to cancel dragging
			$(document).bind('keyup.cms', function(e, cancel){
				if(e.keyCode === 27 || cancel) {
					that.state = false;
					that.sortables.sortable('cancel');
				}
			});

			// define droppable helpers
			this.dropareas.droppable({
				'greedy': true,
				'accept': '.cms_draggable',
				'tolerance': 'pointer',
				'activeClass': 'cms_draggable-allowed',
				'hoverClass': 'cms_draggable-hover-allowed',
				'over': function (event) {
					dropzone = $('.cms_placeholder-' + that.getId($(event.target).parent().prev()));
					if(!that.state) $(event.target).addClass('cms_draggable-disallowed');
				},
				'out': function (event) {
					dropzone = null;
					$(event.target).removeClass('cms_draggable-disallowed');
				},
				'drop': function (event) {
					dropped = true;
					droparea = $(event.target).parent().nextAll('.cms_draggables').first();
				}
			});
		}

	});

});
})(CMS.$);<|endoftext|>


<commit_before>goog.provide('gmf.QueryManager');

goog.require('gmf');
goog.require('gmf.Themes');
goog.require('ngeo.Query');

/**
 * The QueryManager service, uses the
 * c2cgeoportal's themes to configure ngeo's query service with each layer
 * found.
 *
 * Used UI metadata:
 *
 *  * identifierAttributeField: Field used to identify the feature (like a title).
 *  * queryLayers: The alternate layers used to do the query.
 *  * wmsLayers: The layers used to do the query, used if queryLayers is not provided.
 *  * wmsUrl: An alternate wmsUrl used to do the query (essential to query WMTS layer).
 *
 * @constructor
 * @struct
 * @param {ngeo.Query} ngeoQuery The ngeo Query service.
 * @param {gmf.Themes} gmfThemes The gmf Themes service.
 * @param {angular.$q} $q Angular q service
 * @ngInject
 * @ngdoc service
 * @ngname gmfThemes
 */
gmf.QueryManager = function(ngeoQuery, gmfThemes, $q) {

  /**
   * @type {ngeo.Query}
   * @private
   */
  this.ngeoQuery_ = ngeoQuery;

  /**
   * @type {gmf.Themes}
   * @private
   */
  this.gmfThemes_ = gmfThemes;

  /**
   * @type {angular.$q}
   * @private
   */
  this.$q_ = $q;

  /**
   * @type {Array.<ngeox.QuerySource>}
   * @private
   */
  this.sources_ = [];

  /**
   * @type {Object.<number|string, ngeox.QuerySource>}
   * @private
   */
  this.cache_ = {};

  ol.events.listen(this.gmfThemes_, gmf.ThemesEventType.CHANGE,
    this.handleThemesChange_, this);
};

/**
 * @param {Object.<string, string>} dimensions The global dimensions object.
 * @export
 */
gmf.QueryManager.prototype.setDimensions = function(dimensions) {
  this.ngeoQuery_.dimensions = dimensions;
};

/**
 * Called when the themes change. Remove any existing sources first, then
 * create and add sources from the loaded themes.
 * @private
 */
gmf.QueryManager.prototype.handleThemesChange_ = function() {

  this.sources_.length = 0;
  this.cache_ = {};
  this.ngeoQuery_.removeAllSources();

  this.gmfThemes_.getOgcServersObject().then(function(ogcServers) {
    var promiseThemes = this.gmfThemes_.getThemesObject().then(function(themes) {
      // create sources for each themes
      for (var i = 0, leni = themes.length; i < leni; i++) {
        var theme = themes[i];
        for (var j = 0, lenj = theme.children.length; j < lenj; j++) {
          this.createSources_(theme.children[j], theme.children[j], ogcServers);
        }
      }
    }.bind(this));

    var promiseBgLayers = this.gmfThemes_.getBackgroundLayersObject().then(function(backgroundLayers) {
      // create a source for each background layer
      for (var i = 0, len = backgroundLayers.length; i < len; i++) {
        this.createSources_(backgroundLayers[i], backgroundLayers[i], ogcServers);
      }
    }.bind(this));

    // then add all sources to the query service
    this.$q_.all([promiseThemes, promiseBgLayers]).then(function() {
      this.ngeoQuery_.addSources(this.sources_);
    }.bind(this));
  }.bind(this));
};

/**
 * Create and add a source for the query service from the GMF theme node if
 * it has no children, otherwise create the sources for each child node if
 * it has any.
 * @param {gmfThemes.GmfGroup} firstLevelGroup A node.
 * @param {gmfThemes.GmfGroup|gmfThemes.GmfLayer} node A node.
 * @param {gmfThemes.GmfOgcServers} ogcServers OGC servers.
 * @private
 */
gmf.QueryManager.prototype.createSources_ = function(firstLevelGroup, node, ogcServers) {
  var children = node.children;

  // First we handle the groups
  if (children) {
    for (var i = 0, len = children.length; i < len; i++) {
      this.createSources_(firstLevelGroup, children[i], ogcServers);
    }
    return;
  }

  // We are now on a leaf so we can cast node.metadata to the typed
  // (and non minified) version.

  var id = node.id;
  var meta = /** @type {gmfThemes.GmfMetaData} */ (node.metadata);
  var identifierAttributeField = meta.identifierAttributeField;
  var layers;
  var childLayers;
  var name = node.name;
  var validateLayerParams = false;
  var gmfLayer = /** @type gmfThemes.GmfLayer */ (node);
  var ogcServer;

  // Don't create sources for WMTS layers without wmsUrl and ogcServer,
  // they are not queryable.
  if (gmfLayer.type === 'WMTS') {
    layers = meta.queryLayers || meta.wmsLayers;
    if (layers && meta.ogcServer && ogcServers[meta.ogcServer]) {
      ogcServer = ogcServers[meta.ogcServer];
    } else {
      return;
    }
  }

  validateLayerParams = gmfLayer.type === 'WMS';
  var gmfLayerWMS;
  if (gmfLayer.type === 'WMS') {
    gmfLayerWMS = /** @type gmfThemes.GmfLayerWMS */ (gmfLayer);
    layers = gmfLayerWMS.layers;
    childLayers = layers;
    if (firstLevelGroup.mixed) {
      goog.asserts.assert(gmfLayerWMS.ogcServer);
      ogcServer = ogcServers[/** @type string */ (gmfLayerWMS.ogcServer)];
    } else {
      goog.asserts.assert(firstLevelGroup.ogcServer);
      ogcServer = ogcServers[/** @type string */ (firstLevelGroup.ogcServer)];
    }
  }
  if (!this.cache_[id]) {
    if (validateLayerParams) {
      // Some nodes have child layers, i.e. a list of layer names that are
      // part of a group. The name of the group itself can't be used 'as-is'
      // as an identifier of the layers for this source. For example, a
      // group named 'osm' might result in returning 'restaurant' features.
      // This override makes sure that those layer names are used instead of
      // the original one.
      if (gmfLayerWMS.childLayers && gmfLayerWMS.childLayers.length) {
        // skip layers with no queryable childLayer
        var isQueryable = function(item) {
          return item.queryable;
        };
        if (!gmfLayerWMS.childLayers.some(isQueryable)) {
          return;
        }

        var childLayerNames = [];
        gmfLayerWMS.childLayers.forEach(function(childLayer) {
          if (childLayer.queryable) {
            childLayerNames.push(childLayer.name);
          }
        }, this);
        childLayers = childLayerNames.join(',');
      }
    }

    goog.asserts.assert(ogcServer.urlWfs);
    goog.asserts.assert(childLayers);
    goog.asserts.assert(layers);

    var source = {
      'id': id,
      'identifierAttributeField': identifierAttributeField,
      'label': name,
      'params': {'LAYERS': childLayers},
      'layers': layers,
      'dimensions': node.dimensions || firstLevelGroup.dimensions,
      'url': ogcServer.urlWfs,
      'validateLayerParams': validateLayerParams,
      'wfsQuery': ogcServer.wfsSupport
    };
    this.cache_[id] = source;
    this.sources_.push(source);
  }
};

gmf.module.service('gmfQueryManager', gmf.QueryManager);
<commit_msg>(Query) Childlayers based on layers for WMTS<commit_after>goog.provide('gmf.QueryManager');

goog.require('gmf');
goog.require('gmf.Themes');
goog.require('ngeo.Query');

/**
 * The QueryManager service, uses the
 * c2cgeoportal's themes to configure ngeo's query service with each layer
 * found.
 *
 * Used UI metadata:
 *
 *  * identifierAttributeField: Field used to identify the feature (like a title).
 *  * queryLayers: The alternate layers used to do the query.
 *  * wmsLayers: The layers used to do the query, used if queryLayers is not provided.
 *  * wmsUrl: An alternate wmsUrl used to do the query (essential to query WMTS layer).
 *
 * @constructor
 * @struct
 * @param {ngeo.Query} ngeoQuery The ngeo Query service.
 * @param {gmf.Themes} gmfThemes The gmf Themes service.
 * @param {angular.$q} $q Angular q service
 * @ngInject
 * @ngdoc service
 * @ngname gmfThemes
 */
gmf.QueryManager = function(ngeoQuery, gmfThemes, $q) {

  /**
   * @type {ngeo.Query}
   * @private
   */
  this.ngeoQuery_ = ngeoQuery;

  /**
   * @type {gmf.Themes}
   * @private
   */
  this.gmfThemes_ = gmfThemes;

  /**
   * @type {angular.$q}
   * @private
   */
  this.$q_ = $q;

  /**
   * @type {Array.<ngeox.QuerySource>}
   * @private
   */
  this.sources_ = [];

  /**
   * @type {Object.<number|string, ngeox.QuerySource>}
   * @private
   */
  this.cache_ = {};

  ol.events.listen(this.gmfThemes_, gmf.ThemesEventType.CHANGE,
    this.handleThemesChange_, this);
};

/**
 * @param {Object.<string, string>} dimensions The global dimensions object.
 * @export
 */
gmf.QueryManager.prototype.setDimensions = function(dimensions) {
  this.ngeoQuery_.dimensions = dimensions;
};

/**
 * Called when the themes change. Remove any existing sources first, then
 * create and add sources from the loaded themes.
 * @private
 */
gmf.QueryManager.prototype.handleThemesChange_ = function() {

  this.sources_.length = 0;
  this.cache_ = {};
  this.ngeoQuery_.removeAllSources();

  this.gmfThemes_.getOgcServersObject().then(function(ogcServers) {
    var promiseThemes = this.gmfThemes_.getThemesObject().then(function(themes) {
      // create sources for each themes
      for (var i = 0, leni = themes.length; i < leni; i++) {
        var theme = themes[i];
        for (var j = 0, lenj = theme.children.length; j < lenj; j++) {
          this.createSources_(theme.children[j], theme.children[j], ogcServers);
        }
      }
    }.bind(this));

    var promiseBgLayers = this.gmfThemes_.getBackgroundLayersObject().then(function(backgroundLayers) {
      // create a source for each background layer
      for (var i = 0, len = backgroundLayers.length; i < len; i++) {
        this.createSources_(backgroundLayers[i], backgroundLayers[i], ogcServers);
      }
    }.bind(this));

    // then add all sources to the query service
    this.$q_.all([promiseThemes, promiseBgLayers]).then(function() {
      this.ngeoQuery_.addSources(this.sources_);
    }.bind(this));
  }.bind(this));
};

/**
 * Create and add a source for the query service from the GMF theme node if
 * it has no children, otherwise create the sources for each child node if
 * it has any.
 * @param {gmfThemes.GmfGroup} firstLevelGroup A node.
 * @param {gmfThemes.GmfGroup|gmfThemes.GmfLayer} node A node.
 * @param {gmfThemes.GmfOgcServers} ogcServers OGC servers.
 * @private
 */
gmf.QueryManager.prototype.createSources_ = function(firstLevelGroup, node, ogcServers) {
  var children = node.children;

  // First we handle the groups
  if (children) {
    for (var i = 0, len = children.length; i < len; i++) {
      this.createSources_(firstLevelGroup, children[i], ogcServers);
    }
    return;
  }

  // We are now on a leaf so we can cast node.metadata to the typed
  // (and non minified) version.

  var id = node.id;
  var meta = /** @type {gmfThemes.GmfMetaData} */ (node.metadata);
  var identifierAttributeField = meta.identifierAttributeField;
  var layers;
  var name = node.name;
  var validateLayerParams = false;
  var gmfLayer = /** @type gmfThemes.GmfLayer */ (node);
  var ogcServer;

  // Don't create sources for WMTS layers without wmsUrl and ogcServer,
  // they are not queryable.
  if (gmfLayer.type === 'WMTS') {
    layers = meta.queryLayers || meta.wmsLayers;
    if (layers && meta.ogcServer && ogcServers[meta.ogcServer]) {
      ogcServer = ogcServers[meta.ogcServer];
    } else {
      return;
    }
  }

  validateLayerParams = gmfLayer.type === 'WMS';
  var gmfLayerWMS;
  if (gmfLayer.type === 'WMS') {
    gmfLayerWMS = /** @type gmfThemes.GmfLayerWMS */ (gmfLayer);
    layers = gmfLayerWMS.layers;
    if (firstLevelGroup.mixed) {
      goog.asserts.assert(gmfLayerWMS.ogcServer);
      ogcServer = ogcServers[/** @type string */ (gmfLayerWMS.ogcServer)];
    } else {
      goog.asserts.assert(firstLevelGroup.ogcServer);
      ogcServer = ogcServers[/** @type string */ (firstLevelGroup.ogcServer)];
    }
  }
  var childLayers = layers;
  if (!this.cache_[id]) {
    if (validateLayerParams) {
      // Some nodes have child layers, i.e. a list of layer names that are
      // part of a group. The name of the group itself can't be used 'as-is'
      // as an identifier of the layers for this source. For example, a
      // group named 'osm' might result in returning 'restaurant' features.
      // This override makes sure that those layer names are used instead of
      // the original one.
      if (gmfLayerWMS.childLayers && gmfLayerWMS.childLayers.length) {
        // skip layers with no queryable childLayer
        var isQueryable = function(item) {
          return item.queryable;
        };
        if (!gmfLayerWMS.childLayers.some(isQueryable)) {
          return;
        }

        var childLayerNames = [];
        gmfLayerWMS.childLayers.forEach(function(childLayer) {
          if (childLayer.queryable) {
            childLayerNames.push(childLayer.name);
          }
        }, this);
        childLayers = childLayerNames.join(',');
      }
    }

    goog.asserts.assert(ogcServer.urlWfs);
    goog.asserts.assert(childLayers);
    goog.asserts.assert(layers);

    var source = {
      'id': id,
      'identifierAttributeField': identifierAttributeField,
      'label': name,
      'params': {'LAYERS': childLayers},
      'layers': layers,
      'dimensions': node.dimensions || firstLevelGroup.dimensions,
      'url': ogcServer.urlWfs,
      'validateLayerParams': validateLayerParams,
      'wfsQuery': ogcServer.wfsSupport
    };
    this.cache_[id] = source;
    this.sources_.push(source);
  }
};

gmf.module.service('gmfQueryManager', gmf.QueryManager);
<|endoftext|>


<commit_before>var Tensor = require('../../tensor.js');
var ad = require('../../ad');
var Network = require('../network.js');

// Images are represented as in convolution.js

// Max pooling ----------------------------------------------------------------

function MaxPoolNetwork(fW, fH, sX, sY, pX, pY) {
	Network.call(this);
	this.filterWidth = fW;
	this.filterHeight = fH;
	this.strideX = sX;
	this.strideY = sY;
	this.padX = pX;
	this.padY = pY;
	this.name = 'maxpool';
}
MaxPoolNetwork.prototype = Object.create(Network.prototype);

MaxPoolNetwork.prototype.serializeJSON = function() {
	return {
		type: 'maxpool',
		filterWidth: this.filterWidth,
		filterHeight: this.filterHeight,
		strideX: this.strideX,
		strideY: this.strideY,
		padX: this.padX,
		padY: this.padY
	};
}
Network.deserializers.maxpool = function(json) {
	return new MaxPoolNetwork(json.filterWidth, json.filterHeight,
		json.strideX, json.strideY, json.padX, json.padY);
};

// Adapted from:
// https://github.com/karpathy/convnetjs/blob/master/src/convnet_layers_pool.js
// Store the indices of where the maxes came from, for more efficient backprop
var maxIndices;
var maxpoolingImpl = ad.newFunction({
	OutputType: Tensor,
	name: 'maxpooling',
	forward: function(inImg, fW, fH, sX, sY, pX, pY) {
		inImg = ad.value(inImg);

		var D = inImg.dims[0];
		var iH = inImg.dims[1];
		var iW = inImg.dims[2];
		var oH = Math.floor((iH + 2*pY - fH) / sY + 1);
		var oW = Math.floor((iW + 2*pX - fW) / sX + 1);

		var outImg = new Tensor([D, oH, oW]);
		maxIndices = new Int32Array(D*oH*oW);

		for (var d = 0; d < D; d++) {
			var x = -pX;
			var y = -pY;
			for (var ay = 0; ay < oH; y += sY, ay++) {
				x = -pX;
				for (var ax = 0; ax < oW; x += sX, ax++) {
					// Find max within filter window
					var maxval = -Infinity;
					var maxidx = -1;
					for (var fy = 0; fy < fH; fy++) {
						var iy = y + fy;
						for (var fx = 0; fx < fW; fx++) {
							var ix = x + fx;
							if (iy>=0 && iy<iH && ix>=0 && ix<iW) {
								var idx = ix+iW*(iy+iH*d);
								var v = inImg.data[idx];
								if (v > maxval) {
									maxval = v;
									maxidx = idx;
								}
							}
						}
					}
					// Set ouput pixel
					var outidx = ax+oW*(ay+oH*d);
					outImg.data[outidx] = maxval;
					maxIndices[outidx] = maxidx;
				}
			}
		}

		return outImg;
	},
	backward: function(inImg, fW, fH, sX, sY, pX, pY) {
		// No need for an 'isLifted' check: there's only one possible lifted
		//    argument (inImg), so if we are backprop'ing, it must be lifted.
		var D = inImg.x.dims[0];
		var iH = inImg.x.dims[1];
		var iW = inImg.x.dims[2];
		var oH = this.x.dims[1];
		var oW = this.x.dims[2];

		for (var d = 0; d < D; d++) {
			var x = -pX;
			var y = -pY;
			for (var ay = 0; ay < oH; y += sY, ay++) {
				x = -pX;
				for (var ax = 0; ax < oW; x += sX, ax++) {
					// Accumulate into correct derivative using maxIndices
					var outidx = ax+oW*(ay+oH*d);
					var inidx = this.maxIndices[outidx];
					inImg.dx.data[inidx] += this.dx.data[outidx];
				}
			}
		}
	},
	getParents: function(inImg, fW, fH, sX, sY, pX, pY) {
		return ad.isLifted(inImg) ? [inImg] : [];
	}
});
function maxpooling(inImg, fW, fH, sX, sY, pX, pY) {
	var outImg = maxpoolingImpl(inImg, fW, fH, sX, sY, pX, pY);
	if (ad.isLifted(outImg)) {
		outImg.maxIndices = maxIndices;
	}
	return outImg;
}

MaxPoolNetwork.prototype.eval = function(img) {
	return maxpooling(img, this.filterWidth, this.filterHeight, this.strideX,
		this.strideY, this.padX, this.padY);
};

function maxpool(opts) {
	var fW = opts.filterWidth || opts.filterSize;
	var fH = opts.filterHeight || opts.filterSize;
	var sX = opts.strideX || opts.stride || fW;
	var sY = opts.strideY || opts.stride || fH;
	var pX = opts.padX || opts.pad || 0;
	var pY = opts.padY || opts.pad || 0;
	return new MaxPoolNetwork(fW, fH, sX, sY, pX, pY);
}

// Mean (i.e. average) pooling ------------------------------------------------

function MeanPoolNetwork(fW, fH, sX, sY, pX, pY) {
	Network.call(this);
	this.filterWidth = fW;
	this.filterHeight = fH;
	this.strideX = sX;
	this.strideY = sY;
	this.padX = pX;
	this.padY = pY;
	this.name = 'meanpool';
}
MeanPoolNetwork.prototype = Object.create(Network.prototype);

MeanPoolNetwork.prototype.serializeJSON = function() {
	return {
		type: 'meanpool',
		filterWidth: this.filterWidth,
		filterHeight: this.filterHeight,
		strideX: this.strideX,
		strideY: this.strideY,
		padX: this.padX,
		padY: this.padY
	};
}
Network.deserializers.meanpool = function(json) {
	return new MeanPoolNetwork(json.filterWidth, json.filterHeight,
		json.strideX, json.strideY, json.padX, json.padY);
};

var meanpooling = ad.newFunction({
	OutputType: Tensor,
	name: 'meanpooling',
	forward: function(inImg, fW, fH, sX, sY, pX, pY) {
		inImg = ad.value(inImg);

		var D = inImg.dims[0];
		var iH = inImg.dims[1];
		var iW = inImg.dims[2];
		var oH = Math.floor((iH + 2*pY - fH) / sY + 1);
		var oW = Math.floor((iW + 2*pX - fW) / sX + 1);
		var fN = fW*fH;

		var outImg = new Tensor([D, oH, oW]);

		for (var d = 0; d < D; d++) {
			var x = -pX;
			var y = -pY;
			for (var ay = 0; ay < oH; y += sY, ay++) {
				x = -pX;
				for (var ax = 0; ax < oW; x += sX, ax++) {
					// Compute average within filter window
					var avgval = 0;
					for (var fy = 0; fy < fH; fy++) {
						var iy = y + fy;
						for (var fx = 0; fx < fW; fx++) {
							var ix = x + fx;
							if (iy>=0 && iy<iH && ix>=0 && ix<iW) {
								var idx = ix+iW*(iy+iH*d);
								var v = inImg.data[idx];
								avgval += v;
							}
						}
					}
					// Set ouput pixel
					var outidx = ax+oW*(ay+oH*d);
					outImg.data[outidx] = avgval / fN;
				}
			}
		}

		return outImg;
	},
	backward: function(inImg, fW, fH, sX, sY, pX, pY) {
		// No need for an 'isLifted' check: there's only one possible lifted
		//    argument (inImg), so if we are backprop'ing, it must be lifted.
		var D = inImg.x.dims[0];
		var iH = inImg.x.dims[1];
		var iW = inImg.x.dims[2];
		var oH = this.x.dims[1];
		var oW = this.x.dims[2];
		var fN = fW*fH;

		for (var d = 0; d < D; d++) {
			var x = -pX;
			var y = -pY;
			for (var ay = 0; ay < oH; y += sY, ay++) {
				x = -pX;
				for (var ax = 0; ax < oW; x += sX, ax++) {
					var outidx = ax+oW*(ay+oH*d);
					var outDx = this.dx.data[outidx] / fN;
					for (var fy = 0; fy < fH; fy++) {
						var iy = y + fy;
						for (var fx = 0; fx < fW; fx++) {
							var ix = x + fx;
							if (iy>=0 && iy<iH && ix>=0 && ix<iW) {
								var inidx = ix+iW*(iy+iH*d);
								inImg.dx.data[inidx] += outDx;
							}
						}
					}
				}
			}
		}
	},
	getParents: function(inImg, fW, fH, sX, sY, pX, pY) {
		return ad.isLifted(inImg) ? [inImg] : [];
	}
});

MeanPoolNetwork.prototype.eval = function(img) {
	return meanpooling(img, this.filterWidth, this.filterHeight, this.strideX,
		this.strideY, this.padX, this.padY);
};

function meanpool(opts) {
	var fW = opts.filterWidth || opts.filterSize;
	var fH = opts.filterHeight || opts.filterSize;
	var sX = opts.strideX || opts.stride || fW;
	var sY = opts.strideY || opts.stride || fH;
	var pX = opts.padX || opts.pad || 0;
	var pY = opts.padY || opts.pad || 0;
	return new MeanPoolNetwork(fW, fH, sX, sY, pX, pY);
}

// Module exports -------------------------------------------------------------

module.exports = {
	maxpool: maxpool,
	meanpool: meanpool
};

<commit_msg>Min pooling network.<commit_after>var Tensor = require('../../tensor.js');
var ad = require('../../ad');
var Network = require('../network.js');

// Images are represented as in convolution.js

// Max pooling ----------------------------------------------------------------

function MaxPoolNetwork(fW, fH, sX, sY, pX, pY) {
	Network.call(this);
	this.filterWidth = fW;
	this.filterHeight = fH;
	this.strideX = sX;
	this.strideY = sY;
	this.padX = pX;
	this.padY = pY;
	this.name = 'maxpool';
}
MaxPoolNetwork.prototype = Object.create(Network.prototype);

MaxPoolNetwork.prototype.serializeJSON = function() {
	return {
		type: 'maxpool',
		filterWidth: this.filterWidth,
		filterHeight: this.filterHeight,
		strideX: this.strideX,
		strideY: this.strideY,
		padX: this.padX,
		padY: this.padY
	};
}
Network.deserializers.maxpool = function(json) {
	return new MaxPoolNetwork(json.filterWidth, json.filterHeight,
		json.strideX, json.strideY, json.padX, json.padY);
};

// Adapted from:
// https://github.com/karpathy/convnetjs/blob/master/src/convnet_layers_pool.js
// Store the indices of where the maxes came from, for more efficient backprop
var maxIndices;
var maxpoolingImpl = ad.newFunction({
	OutputType: Tensor,
	name: 'maxpooling',
	forward: function(inImg, fW, fH, sX, sY, pX, pY) {
		inImg = ad.value(inImg);

		var D = inImg.dims[0];
		var iH = inImg.dims[1];
		var iW = inImg.dims[2];
		var oH = Math.floor((iH + 2*pY - fH) / sY + 1);
		var oW = Math.floor((iW + 2*pX - fW) / sX + 1);

		var outImg = new Tensor([D, oH, oW]);
		maxIndices = new Int32Array(D*oH*oW);

		for (var d = 0; d < D; d++) {
			var x = -pX;
			var y = -pY;
			for (var ay = 0; ay < oH; y += sY, ay++) {
				x = -pX;
				for (var ax = 0; ax < oW; x += sX, ax++) {
					// Find max within filter window
					var maxval = -Infinity;
					var maxidx = -1;
					for (var fy = 0; fy < fH; fy++) {
						var iy = y + fy;
						for (var fx = 0; fx < fW; fx++) {
							var ix = x + fx;
							if (iy>=0 && iy<iH && ix>=0 && ix<iW) {
								var idx = ix+iW*(iy+iH*d);
								var v = inImg.data[idx];
								if (v > maxval) {
									maxval = v;
									maxidx = idx;
								}
							}
						}
					}
					// Set ouput pixel
					var outidx = ax+oW*(ay+oH*d);
					outImg.data[outidx] = maxval;
					maxIndices[outidx] = maxidx;
				}
			}
		}

		return outImg;
	},
	backward: function(inImg, fW, fH, sX, sY, pX, pY) {
		// No need for an 'isLifted' check: there's only one possible lifted
		//    argument (inImg), so if we are backprop'ing, it must be lifted.
		var D = inImg.x.dims[0];
		var iH = inImg.x.dims[1];
		var iW = inImg.x.dims[2];
		var oH = this.x.dims[1];
		var oW = this.x.dims[2];

		for (var d = 0; d < D; d++) {
			var x = -pX;
			var y = -pY;
			for (var ay = 0; ay < oH; y += sY, ay++) {
				x = -pX;
				for (var ax = 0; ax < oW; x += sX, ax++) {
					// Accumulate into correct derivative using maxIndices
					var outidx = ax+oW*(ay+oH*d);
					var inidx = this.maxIndices[outidx];
					inImg.dx.data[inidx] += this.dx.data[outidx];
				}
			}
		}
	},
	getParents: function(inImg, fW, fH, sX, sY, pX, pY) {
		return ad.isLifted(inImg) ? [inImg] : [];
	}
});
function maxpooling(inImg, fW, fH, sX, sY, pX, pY) {
	var outImg = maxpoolingImpl(inImg, fW, fH, sX, sY, pX, pY);
	if (ad.isLifted(outImg)) {
		outImg.maxIndices = maxIndices;
	}
	return outImg;
}

MaxPoolNetwork.prototype.eval = function(img) {
	return maxpooling(img, this.filterWidth, this.filterHeight, this.strideX,
		this.strideY, this.padX, this.padY);
};

function maxpool(opts) {
	var fW = opts.filterWidth || opts.filterSize;
	var fH = opts.filterHeight || opts.filterSize;
	var sX = opts.strideX || opts.stride || fW;
	var sY = opts.strideY || opts.stride || fH;
	var pX = opts.padX || opts.pad || 0;
	var pY = opts.padY || opts.pad || 0;
	return new MaxPoolNetwork(fW, fH, sX, sY, pX, pY);
}

// Min pooling ----------------------------------------------------------------

function MinPoolNetwork(fW, fH, sX, sY, pX, pY) {
	Network.call(this);
	this.filterWidth = fW;
	this.filterHeight = fH;
	this.strideX = sX;
	this.strideY = sY;
	this.padX = pX;
	this.padY = pY;
	this.name = 'minpool';
}
MinPoolNetwork.prototype = Object.create(Network.prototype);

MinPoolNetwork.prototype.serializeJSON = function() {
	return {
		type: 'minpool',
		filterWidth: this.filterWidth,
		filterHeight: this.filterHeight,
		strideX: this.strideX,
		strideY: this.strideY,
		padX: this.padX,
		padY: this.padY
	};
}
Network.deserializers.minpool = function(json) {
	return new MinPoolNetwork(json.filterWidth, json.filterHeight,
		json.strideX, json.strideY, json.padX, json.padY);
};

var minIndices;
var minpoolingImpl = ad.newFunction({
	OutputType: Tensor,
	name: 'maxpooling',
	forward: function(inImg, fW, fH, sX, sY, pX, pY) {
		inImg = ad.value(inImg);

		var D = inImg.dims[0];
		var iH = inImg.dims[1];
		var iW = inImg.dims[2];
		var oH = Math.floor((iH + 2*pY - fH) / sY + 1);
		var oW = Math.floor((iW + 2*pX - fW) / sX + 1);

		var outImg = new Tensor([D, oH, oW]);
		minIndices = new Int32Array(D*oH*oW);

		for (var d = 0; d < D; d++) {
			var x = -pX;
			var y = -pY;
			for (var ay = 0; ay < oH; y += sY, ay++) {
				x = -pX;
				for (var ax = 0; ax < oW; x += sX, ax++) {
					// Find min within filter window
					var minval = Infinity;
					var minidx = -1;
					for (var fy = 0; fy < fH; fy++) {
						var iy = y + fy;
						for (var fx = 0; fx < fW; fx++) {
							var ix = x + fx;
							if (iy>=0 && iy<iH && ix>=0 && ix<iW) {
								var idx = ix+iW*(iy+iH*d);
								var v = inImg.data[idx];
								if (v < minval) {
									minval = v;
									minidx = idx;
								}
							}
						}
					}
					// Set ouput pixel
					var outidx = ax+oW*(ay+oH*d);
					outImg.data[outidx] = minval;
					minIndices[outidx] = minidx;
				}
			}
		}

		return outImg;
	},
	backward: function(inImg, fW, fH, sX, sY, pX, pY) {
		// No need for an 'isLifted' check: there's only one possible lifted
		//    argument (inImg), so if we are backprop'ing, it must be lifted.
		var D = inImg.x.dims[0];
		var iH = inImg.x.dims[1];
		var iW = inImg.x.dims[2];
		var oH = this.x.dims[1];
		var oW = this.x.dims[2];

		for (var d = 0; d < D; d++) {
			var x = -pX;
			var y = -pY;
			for (var ay = 0; ay < oH; y += sY, ay++) {
				x = -pX;
				for (var ax = 0; ax < oW; x += sX, ax++) {
					// Accumulate into correct derivative using minIndices
					var outidx = ax+oW*(ay+oH*d);
					var inidx = this.minIndices[outidx];
					inImg.dx.data[inidx] += this.dx.data[outidx];
				}
			}
		}
	},
	getParents: function(inImg, fW, fH, sX, sY, pX, pY) {
		return ad.isLifted(inImg) ? [inImg] : [];
	}
});
function minpooling(inImg, fW, fH, sX, sY, pX, pY) {
	var outImg = minpoolingImpl(inImg, fW, fH, sX, sY, pX, pY);
	if (ad.isLifted(outImg)) {
		outImg.minIndices = minIndices;
	}
	return outImg;
}

MinPoolNetwork.prototype.eval = function(img) {
	return minpooling(img, this.filterWidth, this.filterHeight, this.strideX,
		this.strideY, this.padX, this.padY);
};

function minpool(opts) {
	var fW = opts.filterWidth || opts.filterSize;
	var fH = opts.filterHeight || opts.filterSize;
	var sX = opts.strideX || opts.stride || fW;
	var sY = opts.strideY || opts.stride || fH;
	var pX = opts.padX || opts.pad || 0;
	var pY = opts.padY || opts.pad || 0;
	return new MinPoolNetwork(fW, fH, sX, sY, pX, pY);
}

// Mean (i.e. average) pooling ------------------------------------------------

function MeanPoolNetwork(fW, fH, sX, sY, pX, pY) {
	Network.call(this);
	this.filterWidth = fW;
	this.filterHeight = fH;
	this.strideX = sX;
	this.strideY = sY;
	this.padX = pX;
	this.padY = pY;
	this.name = 'meanpool';
}
MeanPoolNetwork.prototype = Object.create(Network.prototype);

MeanPoolNetwork.prototype.serializeJSON = function() {
	return {
		type: 'meanpool',
		filterWidth: this.filterWidth,
		filterHeight: this.filterHeight,
		strideX: this.strideX,
		strideY: this.strideY,
		padX: this.padX,
		padY: this.padY
	};
}
Network.deserializers.meanpool = function(json) {
	return new MeanPoolNetwork(json.filterWidth, json.filterHeight,
		json.strideX, json.strideY, json.padX, json.padY);
};

var meanpooling = ad.newFunction({
	OutputType: Tensor,
	name: 'meanpooling',
	forward: function(inImg, fW, fH, sX, sY, pX, pY) {
		inImg = ad.value(inImg);

		var D = inImg.dims[0];
		var iH = inImg.dims[1];
		var iW = inImg.dims[2];
		var oH = Math.floor((iH + 2*pY - fH) / sY + 1);
		var oW = Math.floor((iW + 2*pX - fW) / sX + 1);
		var fN = fW*fH;

		var outImg = new Tensor([D, oH, oW]);

		for (var d = 0; d < D; d++) {
			var x = -pX;
			var y = -pY;
			for (var ay = 0; ay < oH; y += sY, ay++) {
				x = -pX;
				for (var ax = 0; ax < oW; x += sX, ax++) {
					// Compute average within filter window
					var avgval = 0;
					for (var fy = 0; fy < fH; fy++) {
						var iy = y + fy;
						for (var fx = 0; fx < fW; fx++) {
							var ix = x + fx;
							if (iy>=0 && iy<iH && ix>=0 && ix<iW) {
								var idx = ix+iW*(iy+iH*d);
								var v = inImg.data[idx];
								avgval += v;
							}
						}
					}
					// Set ouput pixel
					var outidx = ax+oW*(ay+oH*d);
					outImg.data[outidx] = avgval / fN;
				}
			}
		}

		return outImg;
	},
	backward: function(inImg, fW, fH, sX, sY, pX, pY) {
		// No need for an 'isLifted' check: there's only one possible lifted
		//    argument (inImg), so if we are backprop'ing, it must be lifted.
		var D = inImg.x.dims[0];
		var iH = inImg.x.dims[1];
		var iW = inImg.x.dims[2];
		var oH = this.x.dims[1];
		var oW = this.x.dims[2];
		var fN = fW*fH;

		for (var d = 0; d < D; d++) {
			var x = -pX;
			var y = -pY;
			for (var ay = 0; ay < oH; y += sY, ay++) {
				x = -pX;
				for (var ax = 0; ax < oW; x += sX, ax++) {
					var outidx = ax+oW*(ay+oH*d);
					var outDx = this.dx.data[outidx] / fN;
					for (var fy = 0; fy < fH; fy++) {
						var iy = y + fy;
						for (var fx = 0; fx < fW; fx++) {
							var ix = x + fx;
							if (iy>=0 && iy<iH && ix>=0 && ix<iW) {
								var inidx = ix+iW*(iy+iH*d);
								inImg.dx.data[inidx] += outDx;
							}
						}
					}
				}
			}
		}
	},
	getParents: function(inImg, fW, fH, sX, sY, pX, pY) {
		return ad.isLifted(inImg) ? [inImg] : [];
	}
});

MeanPoolNetwork.prototype.eval = function(img) {
	return meanpooling(img, this.filterWidth, this.filterHeight, this.strideX,
		this.strideY, this.padX, this.padY);
};

function meanpool(opts) {
	var fW = opts.filterWidth || opts.filterSize;
	var fH = opts.filterHeight || opts.filterSize;
	var sX = opts.strideX || opts.stride || fW;
	var sY = opts.strideY || opts.stride || fH;
	var pX = opts.padX || opts.pad || 0;
	var pY = opts.padY || opts.pad || 0;
	return new MeanPoolNetwork(fW, fH, sX, sY, pX, pY);
}

// Module exports -------------------------------------------------------------

module.exports = {
	maxpool: maxpool,
	minpool: minpool,
	meanpool: meanpool
};

<|endoftext|>


<commit_before>var mongodb = require('../data/mongodb');
var report = require('../data/report');
var reportSchema = report.Report;

exports.report = function(req, res) {
	console.log('user/report: ' + req.session.user);
	if (req.url.indexOf('?') > 0) {
		var query = require('url').parse(req.url, true).query;
		var indicator_key = query.i;
		res.render('report.ejs', {
			currPage : 'editor',
			hasHashKey : false,
			host : req.protocol + '://' + req.get('host'),
			userEmail : req.session.user ? req.session.user.email : null,
			username : req.session.user ? req.session.user.username : null,
			title : '',
			description : '',
			initIndicator : indicator_key
		});
		return;
	}
	var hashid = req.url.substr(3);
	if (hashid === '') {
		res.render('report.ejs', {
			currPage : 'editor',
			hasHashKey : false,
			host : req.protocol + '://' + req.get('host'),
			userEmail : req.session.user ? req.session.user.email : null,
			username : req.session.user ? req.session.user.username : null,
			title : '',
			description : '',
			initIndicator : ''
		});
		return;
	}
	reportSchema.findOne({
		hashid : hashid
	}, function(err, doc) {
		if (err)
			throw err;
		if (doc === null) {
			res.send('404 Sorry, no such page...');
		} else {
			if (doc.qubeInfo == null)
				doc.qubeInfo = {
					dimensions : [],
					measures : []
				};
			if (doc.queryParam.filters == null)
				doc.queryParam.filters = {};
			if (doc.autoScale == null)
				doc.autoScale = false;
			if (doc.showLegend == null)
				doc.showLegend = true;
			res.render('report.ejs', {
				currPage : 'editor',
				hasHashKey : true,
				host : req.protocol + '://' + req.get('host'),
				hashid : doc.hashid,
				qubeInfo : JSON.stringify(doc.qubeInfo),
				queryParam : JSON.stringify(doc.queryParam),
				rptMode : doc.rptMode,
				chartMode : doc.chartMode,
				autoScale : JSON.stringify(doc.autoScale),
				showLegend : JSON.stringify(doc.showLegend),
				title : doc.title != null ? doc.title : '',
				user_name : doc.user_name != null ? doc.user_name : '',
				creation_date : doc.creation_date,
				modification_date : doc.modification_date,
				description : doc.description != null ? doc.description : '',
				initIndicator : '',
				userEmail : req.session.user ? req.session.user.email : null,
				username : req.session.user ? req.session.user.username : null
			});
		}
	});
};

exports.newIndex = function(req, res) {
	reportSchema.find({
		"enableQuery" : true
	}).select('-_id').sort({
		'creation_date' : -1
	}).limit(6).exec(function(err, reports) {
		if (err)
			console.log('Exception: ' + err);
		else {
			res.render('newIndex.ejs', {
				currPage : 'home',
				hasHashKey : false,
				host : req.protocol + '://' + req.get('host'),
				userEmail : req.session.user ? req.session.user.email : null,
				username : req.session.user ? req.session.user.username : null,
				reports : reports
			});
		}
	})
};

exports.allReports = function(req, res) {
	reportSchema.find({
		"enableQuery" : true
	}).select('-_id').sort({
		'creation_date' : -1
	}).limit(10).exec(function(err, reports) {
		if (err)
			console.log('Exception: ' + err);
		else {
			res.render('allreports.ejs', {
				currPage : 'reports',
				hasHashKey : false,
				host : req.protocol + '://' + req.get('host'),
				userEmail : req.session.user ? req.session.user.email : null,
				username : req.session.user ? req.session.user.username : null,
				reports : reports
			});
		}
	})
};

exports.helloworld = function(req, res) {
	res.send('Hello, World!');
};<commit_msg>increase number of showcase on homepage<commit_after>var mongodb = require('../data/mongodb');
var report = require('../data/report');
var reportSchema = report.Report;

exports.report = function(req, res) {
	console.log('user/report: ' + req.session.user);
	if (req.url.indexOf('?') > 0) {
		var query = require('url').parse(req.url, true).query;
		var indicator_key = query.i;
		res.render('report.ejs', {
			currPage : 'editor',
			hasHashKey : false,
			host : req.protocol + '://' + req.get('host'),
			userEmail : req.session.user ? req.session.user.email : null,
			username : req.session.user ? req.session.user.username : null,
			title : '',
			description : '',
			initIndicator : indicator_key
		});
		return;
	}
	var hashid = req.url.substr(3);
	if (hashid === '') {
		res.render('report.ejs', {
			currPage : 'editor',
			hasHashKey : false,
			host : req.protocol + '://' + req.get('host'),
			userEmail : req.session.user ? req.session.user.email : null,
			username : req.session.user ? req.session.user.username : null,
			title : '',
			description : '',
			initIndicator : ''
		});
		return;
	}
	reportSchema.findOne({
		hashid : hashid
	}, function(err, doc) {
		if (err)
			throw err;
		if (doc === null) {
			res.send('404 Sorry, no such page...');
		} else {
			if (doc.qubeInfo == null)
				doc.qubeInfo = {
					dimensions : [],
					measures : []
				};
			if (doc.queryParam.filters == null)
				doc.queryParam.filters = {};
			if (doc.autoScale == null)
				doc.autoScale = false;
			if (doc.showLegend == null)
				doc.showLegend = true;
			res.render('report.ejs', {
				currPage : 'editor',
				hasHashKey : true,
				host : req.protocol + '://' + req.get('host'),
				hashid : doc.hashid,
				qubeInfo : JSON.stringify(doc.qubeInfo),
				queryParam : JSON.stringify(doc.queryParam),
				rptMode : doc.rptMode,
				chartMode : doc.chartMode,
				autoScale : JSON.stringify(doc.autoScale),
				showLegend : JSON.stringify(doc.showLegend),
				title : doc.title != null ? doc.title : '',
				user_name : doc.user_name != null ? doc.user_name : '',
				creation_date : doc.creation_date,
				modification_date : doc.modification_date,
				description : doc.description != null ? doc.description : '',
				initIndicator : '',
				userEmail : req.session.user ? req.session.user.email : null,
				username : req.session.user ? req.session.user.username : null
			});
		}
	});
};

exports.newIndex = function(req, res) {
	reportSchema.find({
		"enableQuery" : true
	}).select('-_id').sort({
		'creation_date' : -1
	}).limit(9).exec(function(err, reports) {
		if (err)
			console.log('Exception: ' + err);
		else {
			res.render('newIndex.ejs', {
				currPage : 'home',
				hasHashKey : false,
				host : req.protocol + '://' + req.get('host'),
				userEmail : req.session.user ? req.session.user.email : null,
				username : req.session.user ? req.session.user.username : null,
				reports : reports
			});
		}
	})
};

exports.allReports = function(req, res) {
	reportSchema.find({
		"enableQuery" : true
	}).select('-_id').sort({
		'creation_date' : -1
	}).limit(10).exec(function(err, reports) {
		if (err)
			console.log('Exception: ' + err);
		else {
			res.render('allreports.ejs', {
				currPage : 'reports',
				hasHashKey : false,
				host : req.protocol + '://' + req.get('host'),
				userEmail : req.session.user ? req.session.user.email : null,
				username : req.session.user ? req.session.user.username : null,
				reports : reports
			});
		}
	})
};

exports.helloworld = function(req, res) {
	res.send('Hello, World!');
};<|endoftext|>


<commit_before>/**
 * NodeJs Server-Side Example for Fine Uploader S3.
 * Maintained by Widen Enterprises.
 *
 * This example:
 *  - handles non-CORS environments
 *  - handles delete file requests assuming the method is DELETE
 *  - Ensures again the file size does not exceed the max (after file is in S3)
 *  - signs policy documents (simple uploads) and REST requests
 *    (chunked/multipart uploads)
 *  - supports version 2 and version 4 signatures
 *
 * Requirements:
 *  - express 3.3.5+ (for handling requests)
 *  - crypto-js 3.1.5+ (for signing requests)
 *  - aws-sdk 2.1.10+ (only if utilizing the AWS SDK for deleting files or otherwise examining them)
 *
 * Notes:
 *
 *  Change `expectedMinSize` and `expectedMaxSize` from `null` to integers
 *  to enable policy doc verification on size. The `validation.minSizeLimit`
 *  and `validation.maxSizeLimit` options **must** be set client-side and
 *  match the values you set below.
 *
 */

var express = require("express"),
    CryptoJS = require("crypto-js"),
    aws = require("aws-sdk"),
    app = express(),
    clientSecretKey = process.env.CLIENT_SECRET_KEY,

    // These two keys are only needed if you plan on using the AWS SDK
    serverPublicKey = process.env.SERVER_PUBLIC_KEY,
    serverSecretKey = process.env.SERVER_SECRET_KEY,

    // Set these two values to match your environment
    expectedBucket = "fineuploadertest",
    expectedHostname = "fineuploadertest.s3.amazonaws.com",

    // CHANGE TO INTEGERS TO ENABLE POLICY DOCUMENT VERIFICATION ON FILE SIZE
    // (recommended)
    expectedMinSize = null,
    expectedMaxSize = null,
    // EXAMPLES DIRECTLY BELOW:
    //expectedMinSize = 0,
    //expectedMaxSize = 15000000,

    s3;

// Init S3, given your server-side keys.  Only needed if using the AWS SDK.
aws.config.update({
    accessKeyId: serverPublicKey,
    secretAccessKey: serverSecretKey
});
s3 = new aws.S3();

app.use(express.bodyParser());
app.use(express.static(__dirname)); //only needed if serving static content as well
app.listen(8000);

// Handles all signature requests and the success request FU S3 sends after the file is in S3
// You will need to adjust these paths/conditions based on your setup.
app.post("/s3handler", function(req, res) {
    if (typeof req.query.success !== "undefined") {
        verifyFileInS3(req, res);
    }
    else {
        signRequest(req, res);
    }
});

// Handles the standard DELETE (file) request sent by Fine Uploader S3.
// Omit if you don't want to support this feature.
app.delete("/s3handler/*", function(req, res) {
    deleteFile(req.query.bucket, req.query.key, function(err) {
        if (err) {
            console.log("Problem deleting file: " + err);
            res.status(500);
        }

        res.end();
    });
});

// Signs any requests.  Delegate to a more specific signer based on type of request.
function signRequest(req, res) {
    if (req.body.headers) {
        signRestRequest(req, res);
    }
    else {
        signPolicy(req, res);
    }
}

// Signs multipart (chunked) requests.  Omit if you don't want to support chunking.
function signRestRequest(req, res) {
    var version = req.query.v4 ? 4 : 2,
        stringToSign = req.body.headers,
        signature = version === 4 ? signV4RestRequest(stringToSign) : signV2RestRequest(stringToSign);

    var jsonResponse = {
        signature: signature
    };

    res.setHeader("Content-Type", "application/json");

    if (isValidRestRequest(stringToSign, version)) {
        res.end(JSON.stringify(jsonResponse));
    }
    else {
        res.status(400);
        res.end(JSON.stringify({invalid: true}));
    }
}

function signV2RestRequest(headersStr) {
    return getV2SignatureKey(clientSecretKey, headersStr);
}

function signV4RestRequest(headersStr) {
    var matches = /.+\n.+\n(\d+)\/(.+)\/s3\/aws4_request\n([\s\S]+)/.exec(headersStr),
        hashedCanonicalRequest = CryptoJS.SHA256(matches[3]),
        stringToSign = headersStr.replace(/(.+s3\/aws4_request\n)[\s\S]+/, '$1' + hashedCanonicalRequest);

    return getV4SignatureKey(clientSecretKey, matches[1], matches[2], "s3", stringToSign);
}

// Signs "simple" (non-chunked) upload requests.
function signPolicy(req, res) {
    var policy = req.body,
        base64Policy = new Buffer(JSON.stringify(policy)).toString("base64"),
        signature = req.query.v4 ? signV4Policy(policy, base64Policy) : signV2Policy(base64Policy);

    var jsonResponse = {
        policy: base64Policy,
        signature: signature
    };

    res.setHeader("Content-Type", "application/json");

    if (isPolicyValid(req.body)) {
        res.end(JSON.stringify(jsonResponse));
    }
    else {
        res.status(400);
        res.end(JSON.stringify({invalid: true}));
    }
}

function signV2Policy(base64Policy) {
    return getV2SignatureKey(clientSecretKey, base64Policy);
}

function signV4Policy(policy, base64Policy) {
    var conditions = policy.conditions,
        credentialCondition;

    for (var i = 0; i < conditions.length; i++) {
        credentialCondition = conditions[i]["x-amz-credential"];
        if (credentialCondition != null) {
            break;
        }
    }

    var matches = /.+\/(.+)\/(.+)\/s3\/aws4_request/.exec(credentialCondition);
    return getV4SignatureKey(clientSecretKey, matches[1], matches[2], "s3", base64Policy);
}

// Ensures the REST request is targeting the correct bucket.
// Omit if you don't want to support chunking.
function isValidRestRequest(headerStr, version) {
    if (version === 4) {
        return new RegExp("host:" + expectedHostname).exec(headerStr) != null;
    }

    return new RegExp("\/" + expectedBucket + "\/.+$").exec(headerStr) != null;
}

// Ensures the policy document associated with a "simple" (non-chunked) request is
// targeting the correct bucket and the min/max-size is as expected.
// Comment out the expectedMaxSize and expectedMinSize variables near
// the top of this file to disable size validation on the policy document.
function isPolicyValid(policy) {
    var bucket, parsedMaxSize, parsedMinSize, isValid;

    policy.conditions.forEach(function(condition) {
        if (condition.bucket) {
            bucket = condition.bucket;
        }
        else if (condition instanceof Array && condition[0] === "content-length-range") {
            parsedMinSize = condition[1];
            parsedMaxSize = condition[2];
        }
    });

    isValid = bucket === expectedBucket;

    // If expectedMinSize and expectedMax size are not null (see above), then
    // ensure that the client and server have agreed upon the exact same
    // values.
    if (expectedMinSize != null && expectedMaxSize != null) {
        isValid = isValid && (parsedMinSize === expectedMinSize.toString())
            && (parsedMaxSize === expectedMaxSize.toString());
    }

    return isValid;
}

// After the file is in S3, make sure it isn't too big.
// Omit if you don't have a max file size, or add more logic as required.
function verifyFileInS3(req, res) {
    function headReceived(err, data) {
        if (err) {
            res.status(500);
            console.log(err);
            res.end(JSON.stringify({error: "Problem querying S3!"}));
        }
        else if (data.ContentLength > expectedMaxSize) {
            res.status(400);
            res.write(JSON.stringify({error: "Too big!"}));
            deleteFile(req.body.bucket, req.body.key, function(err) {
                if (err) {
                    console.log("Couldn't delete invalid file!");
                }

                res.end();
            });
        }
        else {
            res.end();
        }
    }

    callS3("head", {
        bucket: req.body.bucket,
        key: req.body.key
    }, headReceived);
}

function getV2SignatureKey(key, stringToSign) {
    var words = CryptoJS.HmacSHA1(stringToSign, key);
    return CryptoJS.enc.Base64.stringify(words);
}

function getV4SignatureKey(key, dateStamp, regionName, serviceName, stringToSign) {
    var kDate = CryptoJS.HmacSHA256(dateStamp, "AWS4" + key),
        kRegion = CryptoJS.HmacSHA256(regionName, kDate),
        kService = CryptoJS.HmacSHA256(serviceName, kRegion),
        kSigning = CryptoJS.HmacSHA256("aws4_request", kService);

    return CryptoJS.HmacSHA256(stringToSign, kSigning).toString();
}

function deleteFile(bucket, key, callback) {
    callS3("delete", {
        bucket: bucket,
        key: key
    }, callback);
}

function callS3(type, spec, callback) {
    s3[type + "Object"]({
        Bucket: spec.bucket,
        Key: spec.key
    }, callback)
}
<commit_msg>Fix max size check (#63)<commit_after>/**
 * NodeJs Server-Side Example for Fine Uploader S3.
 * Maintained by Widen Enterprises.
 *
 * This example:
 *  - handles non-CORS environments
 *  - handles delete file requests assuming the method is DELETE
 *  - Ensures again the file size does not exceed the max (after file is in S3)
 *  - signs policy documents (simple uploads) and REST requests
 *    (chunked/multipart uploads)
 *  - supports version 2 and version 4 signatures
 *
 * Requirements:
 *  - express 3.3.5+ (for handling requests)
 *  - crypto-js 3.1.5+ (for signing requests)
 *  - aws-sdk 2.1.10+ (only if utilizing the AWS SDK for deleting files or otherwise examining them)
 *
 * Notes:
 *
 *  Change `expectedMinSize` and `expectedMaxSize` from `null` to integers
 *  to enable policy doc verification on size. The `validation.minSizeLimit`
 *  and `validation.maxSizeLimit` options **must** be set client-side and
 *  match the values you set below.
 *
 */

var express = require("express"),
    CryptoJS = require("crypto-js"),
    aws = require("aws-sdk"),
    app = express(),
    clientSecretKey = process.env.CLIENT_SECRET_KEY,

    // These two keys are only needed if you plan on using the AWS SDK
    serverPublicKey = process.env.SERVER_PUBLIC_KEY,
    serverSecretKey = process.env.SERVER_SECRET_KEY,

    // Set these two values to match your environment
    expectedBucket = "fineuploadertest",
    expectedHostname = "fineuploadertest.s3.amazonaws.com",

    // CHANGE TO INTEGERS TO ENABLE POLICY DOCUMENT VERIFICATION ON FILE SIZE
    // (recommended)
    expectedMinSize = null,
    expectedMaxSize = null,
    // EXAMPLES DIRECTLY BELOW:
    //expectedMinSize = 0,
    //expectedMaxSize = 15000000,

    s3;

// Init S3, given your server-side keys.  Only needed if using the AWS SDK.
aws.config.update({
    accessKeyId: serverPublicKey,
    secretAccessKey: serverSecretKey
});
s3 = new aws.S3();

app.use(express.bodyParser());
app.use(express.static(__dirname)); //only needed if serving static content as well
app.listen(8000);

// Handles all signature requests and the success request FU S3 sends after the file is in S3
// You will need to adjust these paths/conditions based on your setup.
app.post("/s3handler", function(req, res) {
    if (typeof req.query.success !== "undefined") {
        verifyFileInS3(req, res);
    }
    else {
        signRequest(req, res);
    }
});

// Handles the standard DELETE (file) request sent by Fine Uploader S3.
// Omit if you don't want to support this feature.
app.delete("/s3handler/*", function(req, res) {
    deleteFile(req.query.bucket, req.query.key, function(err) {
        if (err) {
            console.log("Problem deleting file: " + err);
            res.status(500);
        }

        res.end();
    });
});

// Signs any requests.  Delegate to a more specific signer based on type of request.
function signRequest(req, res) {
    if (req.body.headers) {
        signRestRequest(req, res);
    }
    else {
        signPolicy(req, res);
    }
}

// Signs multipart (chunked) requests.  Omit if you don't want to support chunking.
function signRestRequest(req, res) {
    var version = req.query.v4 ? 4 : 2,
        stringToSign = req.body.headers,
        signature = version === 4 ? signV4RestRequest(stringToSign) : signV2RestRequest(stringToSign);

    var jsonResponse = {
        signature: signature
    };

    res.setHeader("Content-Type", "application/json");

    if (isValidRestRequest(stringToSign, version)) {
        res.end(JSON.stringify(jsonResponse));
    }
    else {
        res.status(400);
        res.end(JSON.stringify({invalid: true}));
    }
}

function signV2RestRequest(headersStr) {
    return getV2SignatureKey(clientSecretKey, headersStr);
}

function signV4RestRequest(headersStr) {
    var matches = /.+\n.+\n(\d+)\/(.+)\/s3\/aws4_request\n([\s\S]+)/.exec(headersStr),
        hashedCanonicalRequest = CryptoJS.SHA256(matches[3]),
        stringToSign = headersStr.replace(/(.+s3\/aws4_request\n)[\s\S]+/, '$1' + hashedCanonicalRequest);

    return getV4SignatureKey(clientSecretKey, matches[1], matches[2], "s3", stringToSign);
}

// Signs "simple" (non-chunked) upload requests.
function signPolicy(req, res) {
    var policy = req.body,
        base64Policy = new Buffer(JSON.stringify(policy)).toString("base64"),
        signature = req.query.v4 ? signV4Policy(policy, base64Policy) : signV2Policy(base64Policy);

    var jsonResponse = {
        policy: base64Policy,
        signature: signature
    };

    res.setHeader("Content-Type", "application/json");

    if (isPolicyValid(req.body)) {
        res.end(JSON.stringify(jsonResponse));
    }
    else {
        res.status(400);
        res.end(JSON.stringify({invalid: true}));
    }
}

function signV2Policy(base64Policy) {
    return getV2SignatureKey(clientSecretKey, base64Policy);
}

function signV4Policy(policy, base64Policy) {
    var conditions = policy.conditions,
        credentialCondition;

    for (var i = 0; i < conditions.length; i++) {
        credentialCondition = conditions[i]["x-amz-credential"];
        if (credentialCondition != null) {
            break;
        }
    }

    var matches = /.+\/(.+)\/(.+)\/s3\/aws4_request/.exec(credentialCondition);
    return getV4SignatureKey(clientSecretKey, matches[1], matches[2], "s3", base64Policy);
}

// Ensures the REST request is targeting the correct bucket.
// Omit if you don't want to support chunking.
function isValidRestRequest(headerStr, version) {
    if (version === 4) {
        return new RegExp("host:" + expectedHostname).exec(headerStr) != null;
    }

    return new RegExp("\/" + expectedBucket + "\/.+$").exec(headerStr) != null;
}

// Ensures the policy document associated with a "simple" (non-chunked) request is
// targeting the correct bucket and the min/max-size is as expected.
// Comment out the expectedMaxSize and expectedMinSize variables near
// the top of this file to disable size validation on the policy document.
function isPolicyValid(policy) {
    var bucket, parsedMaxSize, parsedMinSize, isValid;

    policy.conditions.forEach(function(condition) {
        if (condition.bucket) {
            bucket = condition.bucket;
        }
        else if (condition instanceof Array && condition[0] === "content-length-range") {
            parsedMinSize = condition[1];
            parsedMaxSize = condition[2];
        }
    });

    isValid = bucket === expectedBucket;

    // If expectedMinSize and expectedMax size are not null (see above), then
    // ensure that the client and server have agreed upon the exact same
    // values.
    if (expectedMinSize != null && expectedMaxSize != null) {
        isValid = isValid && (parsedMinSize === expectedMinSize.toString())
            && (parsedMaxSize === expectedMaxSize.toString());
    }

    return isValid;
}

// After the file is in S3, make sure it isn't too big.
// Omit if you don't have a max file size, or add more logic as required.
function verifyFileInS3(req, res) {
    function headReceived(err, data) {
        if (err) {
            res.status(500);
            console.log(err);
            res.end(JSON.stringify({error: "Problem querying S3!"}));
        }
        else if (expectedMaxSize != null && data.ContentLength > expectedMaxSize) {
            res.status(400);
            res.write(JSON.stringify({error: "Too big!"}));
            deleteFile(req.body.bucket, req.body.key, function(err) {
                if (err) {
                    console.log("Couldn't delete invalid file!");
                }

                res.end();
            });
        }
        else {
            res.end();
        }
    }

    callS3("head", {
        bucket: req.body.bucket,
        key: req.body.key
    }, headReceived);
}

function getV2SignatureKey(key, stringToSign) {
    var words = CryptoJS.HmacSHA1(stringToSign, key);
    return CryptoJS.enc.Base64.stringify(words);
}

function getV4SignatureKey(key, dateStamp, regionName, serviceName, stringToSign) {
    var kDate = CryptoJS.HmacSHA256(dateStamp, "AWS4" + key),
        kRegion = CryptoJS.HmacSHA256(regionName, kDate),
        kService = CryptoJS.HmacSHA256(serviceName, kRegion),
        kSigning = CryptoJS.HmacSHA256("aws4_request", kService);

    return CryptoJS.HmacSHA256(stringToSign, kSigning).toString();
}

function deleteFile(bucket, key, callback) {
    callS3("delete", {
        bucket: bucket,
        key: key
    }, callback);
}

function callS3(type, spec, callback) {
    s3[type + "Object"]({
        Bucket: spec.bucket,
        Key: spec.key
    }, callback)
}
<|endoftext|>


<commit_before>const User = require('../../services/user')

const lokaliseConfig = {
  AWS_ACCESS_KEY: process.env.AWS_ACCESS_KEY,
  AWS_REGION: process.env.AWS_REGION,
  AWS_S3_BUCKET: process.env.AWS_S3_BUCKET,
  AWS_SECRET_KEY: process.env.AWS_SECRET_KEY,
  LOKALISE_API_TOKEN: process.env.LOKALISE_API_TOKEN,
  LOKALISE_BASE_PATH: process.env.LOKALISE_BASE_PATH,
  LOKALISE_PROJECT_ID: process.env.LOKALISE_PROJECT_ID,
}

const lokalise = require('bots-lokalise')(lokaliseConfig)

const handler = ([action, ...rest]) => {
  const actor = User.get(actorId)
  if (!actor || !actor.isAdmin) {
    return Promise.resolve('No Permission')
  }

  switch (action) {
    case 'release':
      return lokalise.handler(rest)
    default:
      return Promise.resolve(`usage:
lokalise release`)
  }
}

module.exports = handler

<commit_msg>Fix actorId not found<commit_after>const User = require('../../services/user')

const lokaliseConfig = {
  AWS_ACCESS_KEY: process.env.AWS_ACCESS_KEY,
  AWS_REGION: process.env.AWS_REGION,
  AWS_S3_BUCKET: process.env.AWS_S3_BUCKET,
  AWS_SECRET_KEY: process.env.AWS_SECRET_KEY,
  LOKALISE_API_TOKEN: process.env.LOKALISE_API_TOKEN,
  LOKALISE_BASE_PATH: process.env.LOKALISE_BASE_PATH,
  LOKALISE_PROJECT_ID: process.env.LOKALISE_PROJECT_ID,
}

const lokalise = require('bots-lokalise')(lokaliseConfig)

const handler = ([action, ...rest], actorId) => {
  const actor = User.get(actorId)
  if (!actor || !actor.isAdmin) {
    return Promise.resolve('No Permission')
  }

  switch (action) {
    case 'release':
      return lokalise.handler(rest)
    default:
      return Promise.resolve(`usage:
lokalise release`)
  }
}

module.exports = handler

<|endoftext|>


<commit_before>if("undefined"==typeof OGX)var OGX=function(){};OGX.Templater=function(){},OGX.Templater.templatize=function(__obj,__template){"use strict";function evalOp(__op){var reg=new RegExp("\\@","g");return __op=__op.replace(reg,"__obj."),eval(__op),!0}function extractOps(){var op,e,html,prop,temp,ver,reg=new RegExp("\\$\\(loop ([^]*)\\)\\$","gi"),match=__template.match(reg);if(match)for(var j=0;j<match.length;j++)if(op=match[j].substr(2).split(" "),op.shift(),prop=op.shift().substr(1),temp=op.join(" "),temp=temp.substring(0,temp.length-2),ver=eval("__obj."+prop)){html="";for(var i=0;i<ver.length;i++)html+=temp.replace(/\.\$\./g,"["+i+"].");__template=__template.replace(match[j],html)}if(reg=new RegExp("\\$\\([^]*\\)\\$","g"),match=__template.match(reg))for(var i=0;i<match.length;i++)e=match[i].substr(1),e=e.substring(0,e.length-1),__template=__template.replace(match[i],""),evalOp(e)}function replaceVals(){var reg=new RegExp("\\$([a-zA-Z0-9_\\-\\[\\]\\.\\(\\)]+)","g"),match=__template.match(reg),m,val;if(match)for(var i=0;i<match.length;i++)m=match[i].replace(/((^[\$])(\.)?)/g,""),val=eval("__obj."+m),"undefined"!=typeof val&&(__template=__template.replace(match[i],val))}return extractOps(),replaceVals(),__template};<commit_msg><commit_after>if("undefined"==typeof OGX)var OGX=function(){};OGX.Templater=function(){},OGX.Templater.templatize=function(__obj,__template){"use strict";function evalOp(__op){var reg=new RegExp("\\@","g");return __op=__op.replace(reg,"__obj."),eval(__op),!0}function extractOps(){var op,e,html,prop,temp,ver,reg=new RegExp("\\$\\(loop ([^]*)\\)\\$","gi"),match=__template.match(reg);if(match)for(var j=0;j<match.length;j++)if(op=match[j].substr(2).split(" "),op.shift(),prop=op.shift().substr(1),temp=op.join(" "),temp=temp.substring(0,temp.length-2),ver=eval("__obj."+prop)){html="";for(var i=0;i<ver.length;i++)html+=temp.replace(/\.\$\./g,"["+i+"].");__template=__template.replace(match[j],html)}if(reg=new RegExp("\\$\\((((?!(\\)\\$)).)*)\\)\\$","g"),match=__template.match(reg))for(var i=0;i<match.length;i++)e=match[i].substr(1),e=e.substring(0,e.length-1),console.log("remove",match[i]),__template=__template.replace(match[i],""),evalOp(e)}function replaceVals(){var reg=new RegExp("\\$([a-zA-Z0-9_\\-\\[\\]\\.\\(\\)]+)","g"),match=__template.match(reg),m,val;if(match)for(var i=0;i<match.length;i++)m=match[i].replace(/((^[\$])(\.)?)/g,""),val=eval("__obj."+m),"undefined"!=typeof val&&(__template=__template.replace(match[i],val))}return extractOps(),replaceVals(),__template};<|endoftext|>