<commit_before>
var express = require("express");
var router = express.Router();

var multer  = require("multer");
// Initialize multer with the tmp directory where it can
// buffer files while uploading them.
var fileUpload = multer( { dest: "/tmp" } );

var fs = require("fs");

//------------------------------------------------------------------------------
// API: For the server side, use an Open Source package to do the
// heavy lifting of parsing multipart/form-data and do the file
// uploading for us.
// Example URL: http://localhost:8080/apis/upload

// This is the "name" attribute for the upload file in fileUploader.html and
// is encoded in the multipart/form-data when the file
// is uploaded.
var uploadType = fileUpload.single("myFile");

router.post('/apis/upload', uploadType, function (httpRequest, httpResponse, next) {
    var clientIp = httpRequest.headers['x-forwarded-for'] || httpRequest.connection.remoteAddress;
    var fileName = httpRequest.file.originalname;
    console.log("Client " + clientIp + " is uploading file: " + fileName);

    // This is a temporary filepath where the file is buffered
    // while it is being uploaded.
    var tmpPath = httpRequest.file.path;

    // This is the final resting place of the file
    // after is uploaded.
    var destPath = __dirname + "/www/uploads/" + fileName;

    // Use the "fs" package to work with read and write
    // streams and the filesystem.
    var readStream = fs.createReadStream(tmpPath);
    var writeStream = fs.createWriteStream(destPath);
    readStream.pipe(writeStream);
    readStream.on("end", function() {
		httpResponse.send("Uploaded");
        console.log("Uploaded " + fileName + " to: " + destPath);
    });
    readStream.on("error", function(err) {
		httpResponse.send("Upload failed");
		console.log("Failed to upload file " + fileName + " to: " + destPath);
    });
});

module.exports = router
<commit_msg>update<commit_after>
var express = require("express");
var router = express.Router();

var multer  = require("multer");
// Initialize multer with the tmp directory where it can
// buffer files while uploading them.
var fileUpload = multer( { dest: "/tmp" } );

var fs = require("fs");

var fileList = [];

//------------------------------------------------------------------------------
// API: For the server side, use an Open Source package to do the
// heavy lifting of parsing multipart/form-data and do the file
// uploading for us.
// Example URL: http://localhost:8080/apis/upload

// This is the "name" attribute for the upload file in fileUploader.html and
// is encoded in the multipart/form-data when the file
// is uploaded.
var uploadType = fileUpload.single("myFile");

router.post('/apis/upload', uploadType, function (httpRequest, httpResponse, next) {
    var clientIp = httpRequest.headers['x-forwarded-for'] || httpRequest.connection.remoteAddress;
    var fileName = httpRequest.file.originalname;
    console.log("Client " + clientIp + " is uploading file: " + fileName);

    // This is a temporary filepath where the file is buffered
    // while it is being uploaded.
    var tmpPath = httpRequest.file.path;

    // This is the final resting place of the file
    // after is uploaded.
    var destPath = __dirname + "/www/uploads/" + fileName;

    // Use the "fs" package to work with read and write
    // streams and the filesystem.
    var readStream = fs.createReadStream(tmpPath);
    var writeStream = fs.createWriteStream(destPath);
    readStream.pipe(writeStream);
    readStream.on("end", function() {
		httpResponse.send("Uploaded");
        console.log("Uploaded " + fileName + " to: " + destPath);
		fileList.push(fileName);
    });
    readStream.on("error", function(err) {
		httpResponse.send("Upload failed");
		console.log("Failed to upload file " + fileName + " to: " + destPath);
    });
});

//------------------------------------------------------------------------------
// API simply responds with a JSON containing all files uploaded so far
//------------------------------------------------------------------------------
// URL: http://localhost:8080/apis/files
//------------------------------------------------------------------------------
router.get("/apis/files", function(httpRequest, httpResponse) {
    var clientIp = httpRequest.headers['x-forwarded-for'] || httpRequest.connection.remoteAddress;
    console.log("Client " + clientIp + " is getting file list...");
    httpResponse.send(fileList);
});

module.exports = router
<|endoftext|>


<commit_before>/**
 * @license Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved.
 * For licensing, see LICENSE.html or http://ckeditor.com/license
 */

CKEDITOR.editorConfig = function( config ) {
	// Define changes to default configuration here.
	// For the complete reference:
	// http://docs.ckeditor.com/#!/api/CKEDITOR.config

	// The toolbar groups arrangement, optimized for two toolbar rows.
	config.toolbarGroups = [
		{ name: 'clipboard',   groups: [ 'clipboard', 'undo' ] },
		{ name: 'editing',     groups: [ 'find', 'selection', 'spellchecker' ] },
	//	{ name: 'links' },
	//	{ name: 'insert' },
		{ name: 'forms' },
		{ name: 'tools' },
		{ name: 'document',	   groups: [ 'mode', 'document', 'doctools' ] },
		{ name: 'others' },
		'/',
		{ name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
		{ name: 'paragraph',   groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ] },
		{ name: 'styles' },
		{ name: 'colors' },
		{ name: 'about' }
	];

	// Remove some buttons, provided by the standard plugins, which we don't
	// need to have in the Standard(s) toolbar.
	config.removeButtons = 'Underline,Subscript,Superscript';

	// Se the most common block elements.
	config.format_tags = 'p;h1;h2;h3;pre';

	// Make dialogs simpler.
	config.removeDialogTabs = 'image:advanced;link:advanced';
};
<commit_msg>BZ:1014051 - HTML Editor doesn't pick changes made in the source code view<commit_after>/**
 * @license Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved.
 * For licensing, see LICENSE.html or http://ckeditor.com/license
 */

CKEDITOR.editorConfig = function( config ) {
	// Define changes to default configuration here.
	// For the complete reference:
	// http://docs.ckeditor.com/#!/api/CKEDITOR.config

	// The toolbar groups arrangement, optimized for two toolbar rows.
	config.toolbarGroups = [
		{ name: 'clipboard',   groups: [ 'clipboard', 'undo' ] },
		{ name: 'editing',     groups: [ 'find', 'selection', 'spellchecker' ] },
	//	{ name: 'links' },
	//	{ name: 'insert' },
		{ name: 'forms' },
		{ name: 'tools' },
		{ name: 'document',	   groups: [ 'mode', 'document', 'doctools' ] },
		{ name: 'others' },
		'/',
		{ name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
		{ name: 'paragraph',   groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ] },
		{ name: 'styles' },
		{ name: 'colors' },
		{ name: 'about' }
	];

	// Remove some buttons, provided by the standard plugins, which we don't
	// need to have in the Standard(s) toolbar.
	config.removeButtons = 'Underline,Subscript,Superscript';

	// Se the most common block elements.
	config.format_tags = 'p;h1;h2;h3;pre';

	// Make dialogs simpler.
	config.removeDialogTabs = 'image:advanced;link:advanced';

    config.allowedContent=true;

};
<|endoftext|>


<commit_before>Curiosity.controller('resultCtrl', function($scope, $modal, result, query, template, csv, context, $templateCache){
	$scope.queryData = query.info;
	$scope.templateData = template.info
	$scope.showAggregationFilter = true;
	$scope.data = result.info;

	/**
	* @desc function call by ng-init to load template in $templateCache
	*/
	$scope.init = function () {
		if ($scope.data.validate==true && $scope.data.useTemplate=='local') $scope.selectLocalTemplate('local',$scope.data.customTemplate);
	}

	/* PAGER : go to queryFactory.js for more informations*/
	$scope.nextPage = function () {
		query.nextPage();
	}
	$scope.prevPage = function () {
		query.prevPage();
	}
	$scope.firstPage = function () {
		query.firstPage();
	}
	$scope.lastPage = function ()  {
		query.lastPage();
	}
	$scope.goTo = function (page) {
		query.goTo(page);
	}
	$scope.loadContext = function(idContext) {
		context.loadContext(idContext);
	}

	$scope.selectTemplate = function(type, id) {
		result.changeCurrentTemplate(type, id);
	}

	$scope.selectLocalTemplate = function(name,data) {
		template.addTemplateToCacheFromValue(name, data);
	}

	$scope.switchDisplayMode = function (type, id) {
		result.switchDisplayMode(type, id);
	}

	$scope.addAggregationFilter = function(type ,aggr, bucket) {
		$scope.showAggregationFilter = true;
		aggregation["add"+type+"AggregationFilter"](aggr, bucket);
		if ($scope.queryData.autoRefresh){
			query.search();
		}
	}

	$scope.openModalCsv = function (size) {
		var modalInstance = $modal.open({
			templateUrl: 'partials/modal/csv_modal.html',
			controller: csvCtrl,
			size: size,
			resolve: {
				items: function () {
					return $scope.items;
				}}
			});
		modalInstance.result.then(function (selectedItem) {
			$scope.selected = selectedItem;
		}, function () {
		});
	}

	$scope.openModalAgg = function (size) {
		var modalInstance = $modal.open({
			templateUrl: 'partials/modal/aggregation_modal.html',
			controller: aggregationCtrl,
			size: size,
			resolve: {
				items: function () {
					return $scope.items;
				}}
			});
		modalInstance.result.then(function (selectedItem) {
			$scope.selected = selectedItem;
		}, function () {
		});
	}

	/**
	* @desc open a modal which contains the fields list. When closed change aggregation field attr value
	* @params 'sm' | 'lg' size modal size
	*/
	$scope.openModalTemplates = function (size, type) {
		var modalInstance = $modal.open({
			templateUrl: 'partials/modal/template_modal.html',
			controller: templateModalCtrl,
			size: size,
			resolve: {
				type: function () {
					return type;
				}}
			});
	};

	/**
	* @desc function used to open modals in results
	* @param string id : the id of the div to display in the modal
	* @param string size (optionnal) : the size (boostrap) of the modal
	*/
	$scope.openModal = function (id,size, item) {
	    var modalInstance = $modal.open({
    	  	templateUrl: id,
      		size: size,
      		controller:function($modalInstance,$scope){
      			$scope.item = item;
      			$scope.close = function() {
      				$modalInstance.close();
      			}
      		}
    	});
	}

})<commit_msg>Remove  since it's not used.<commit_after>Curiosity.controller('resultCtrl', function($scope, $modal, result, query, template, csv, context){
	$scope.queryData = query.info;
	$scope.templateData = template.info
	$scope.showAggregationFilter = true;
	$scope.data = result.info;

	/**
	* @desc function call by ng-init to load template in $templateCache
	*/
	$scope.init = function () {
		if ($scope.data.validate==true && $scope.data.useTemplate=='local') $scope.selectLocalTemplate('local',$scope.data.customTemplate);
	}

	/* PAGER : go to queryFactory.js for more informations*/
	$scope.nextPage = function () {
		query.nextPage();
	}
	$scope.prevPage = function () {
		query.prevPage();
	}
	$scope.firstPage = function () {
		query.firstPage();
	}
	$scope.lastPage = function ()  {
		query.lastPage();
	}
	$scope.goTo = function (page) {
		query.goTo(page);
	}
	$scope.loadContext = function(idContext) {
		context.loadContext(idContext);
	}

	$scope.selectTemplate = function(type, id) {
		result.changeCurrentTemplate(type, id);
	}

	$scope.selectLocalTemplate = function(name,data) {
		template.addTemplateToCacheFromValue(name, data);
	}

	$scope.switchDisplayMode = function (type, id) {
		result.switchDisplayMode(type, id);
	}

	$scope.addAggregationFilter = function(type ,aggr, bucket) {
		$scope.showAggregationFilter = true;
		aggregation["add"+type+"AggregationFilter"](aggr, bucket);
		if ($scope.queryData.autoRefresh){
			query.search();
		}
	}

	$scope.openModalCsv = function (size) {
		var modalInstance = $modal.open({
			templateUrl: 'partials/modal/csv_modal.html',
			controller: csvCtrl,
			size: size,
			resolve: {
				items: function () {
					return $scope.items;
				}}
			});
		modalInstance.result.then(function (selectedItem) {
			$scope.selected = selectedItem;
		}, function () {
		});
	}

	$scope.openModalAgg = function (size) {
		var modalInstance = $modal.open({
			templateUrl: 'partials/modal/aggregation_modal.html',
			controller: aggregationCtrl,
			size: size,
			resolve: {
				items: function () {
					return $scope.items;
				}}
			});
		modalInstance.result.then(function (selectedItem) {
			$scope.selected = selectedItem;
		}, function () {
		});
	}

	/**
	* @desc open a modal which contains the fields list. When closed change aggregation field attr value
	* @params 'sm' | 'lg' size modal size
	*/
	$scope.openModalTemplates = function (size, type) {
		var modalInstance = $modal.open({
			templateUrl: 'partials/modal/template_modal.html',
			controller: templateModalCtrl,
			size: size,
			resolve: {
				type: function () {
					return type;
				}}
			});
	};

	/**
	* @desc function used to open modals in results
	* @param string id : the id of the div to display in the modal
	* @param string size (optionnal) : the size (boostrap) of the modal
	*/
	$scope.openModal = function (id,size, item) {
	    var modalInstance = $modal.open({
    	  	templateUrl: id,
      		size: size,
      		controller:function($modalInstance,$scope){
      			$scope.item = item;
      			$scope.close = function() {
      				$modalInstance.close();
      			}
      		}
    	});
	}

})<|endoftext|>


<commit_before>/*
 * SessionWorkspace.js
 *
 * Copyright (c) 2011, OSBI Ltd. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301  USA
 */

/**
 * Object which handles sessionworkspace and stores connections and cubes
 * @param username
 * @param password
 * @returns {Session}
 */
var SessionWorkspace = Backbone.Model.extend({

    initialize: function(args, options) {
        // Attach a custom event bus to this model
        _.extend(this, Backbone.Events);
        _.bindAll(this, "process_datasources", "prefetch_dimensions");
        this.initialized = false;

        // Check expiration on localStorage
        if (localStorage && ! (localStorage.getItem('expiration') > (new Date()).getTime())) {
            localStorage.clear();
        }
        this.fetch({success:this.process_datasources},{});

    },

    refresh: function() {
        localStorage.clear();
        this.clear();
        this.fetch({success:this.process_datasources},{});
    },

    destroy: function() {
        localStorage && localStorage.clear();
        return false;
    },

    process_datasources: function(model, response) {
        // Save session in localStorage for other tabs to use
        if (localStorage && localStorage.getItem('session') === null) {
            localStorage.setItem('session', JSON.stringify(response));
        }

        // Generate cube navigation for reuse
        this.cube_navigation = _.template($("#template-cubes").html())({
            connections: response
        });

        // Create cube objects
        this.dimensions = {};
        this.measures = {};
        this.connections = response;
        _.delay(this.prefetch_dimensions, 200);

        if (!this.initialized) {
            // Show UI
            $(Saiku.toolbar.el).prependTo($("#header"));
            $("#header").show();
            Saiku.ui.unblock();
            // Add initial tab
            Saiku.tabs.render();
            if (! Settings.ACTION) {
                Saiku.tabs.add(new Workspace());
            }
            // Notify the rest of the application that login was successful
            Saiku.events.trigger('session:new', {
                session: this
            });
        } else {
            if (! Settings.ACTION) {
                Saiku.tabs.add(new Workspace());
            }

        }
    },

    prefetch_dimensions: function() {
        if (! this.measures || ! this.dimensions) {
            Log.log({
                Message: "measures or dimensions not initialized",
                Session: JSON.stringify(this)
            });
            return;
        }

        for(var i = 0; i < this.connections.length; i++) {
            var connection = this.connections[i];
            for(var j = 0; j < connection.catalogs.length; j++) {
                var catalog = connection.catalogs[j];
                for(var k = 0; k < catalog.schemas.length; k++) {
                    var schema = catalog.schemas[k];
                    for(var l = 0; l < schema.cubes.length; l++) {
                        var cube = schema.cubes[l];
                        var key = connection.name + "/" + catalog.name + "/"
                            + ((schema.name == "" || schema.name == null) ? "null" : schema.name)
                            + "/" + cube.name;

                        if (localStorage &&
                            localStorage.getItem("dimension." + key) !== null &&
                            localStorage.getItem("measure." + key) !== null) {
                            this.dimensions[key] = new Dimension(JSON.parse(localStorage.getItem("dimension." + key)));
                            this.measures[key] = new Measure(JSON.parse(localStorage.getItem("measure." + key)));
                        } else {
                            this.dimensions[key] = new Dimension({ key: key });
                            this.measures[key] = new Measure({ key: key });
                            if (Settings.DIMENSION_PREFETCH === true) {
                                this.dimensions[key].fetch();
                                this.measures[key].fetch();
                            }
                        }
                    }
                }
            }
        }

        // Start routing
        if (!this.initialized && Backbone.history) {
            Backbone.history.start();
            this.initialized = true;
        }
    },

    url: function() {
        if (!this.initialized) {
            return encodeURI(Saiku.session.username + "/discover/");
        }
        else {
            return encodeURI(Saiku.session.username + "/discover/refresh");
        }
    }
});
<commit_msg>fix refresh check<commit_after>/*
 * SessionWorkspace.js
 *
 * Copyright (c) 2011, OSBI Ltd. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301  USA
 */

/**
 * Object which handles sessionworkspace and stores connections and cubes
 * @param username
 * @param password
 * @returns {Session}
 */
var SessionWorkspace = Backbone.Model.extend({

    initialize: function(args, options) {
        // Attach a custom event bus to this model
        _.extend(this, Backbone.Events);
        _.bindAll(this, "process_datasources", "prefetch_dimensions");
        this.initialized = false;
        this.first = true;
        // Check expiration on localStorage
        if (localStorage && ! (localStorage.getItem('expiration') > (new Date()).getTime())) {
            localStorage.clear();
        }
        this.fetch({success:this.process_datasources},{});

    },

    refresh: function() {
        localStorage.clear();
        this.clear();
        this.fetch({success:this.process_datasources},{});
    },

    destroy: function() {
        localStorage && localStorage.clear();
        return false;
    },

    process_datasources: function(model, response) {
        // Save session in localStorage for other tabs to use
        if (localStorage && localStorage.getItem('session') === null) {
            localStorage.setItem('session', JSON.stringify(response));
        }

        // Generate cube navigation for reuse
        this.cube_navigation = _.template($("#template-cubes").html())({
            connections: response
        });

        // Create cube objects
        this.dimensions = {};
        this.measures = {};
        this.connections = response;
        _.delay(this.prefetch_dimensions, 200);

        if (!this.initialized) {
            // Show UI
            $(Saiku.toolbar.el).prependTo($("#header"));
            $("#header").show();
            Saiku.ui.unblock();
            // Add initial tab
            Saiku.tabs.render();
            if (! Settings.ACTION) {
                Saiku.tabs.add(new Workspace());
            }
            // Notify the rest of the application that login was successful
            Saiku.events.trigger('session:new', {
                session: this
            });
        } else {
            if (! Settings.ACTION) {
                Saiku.tabs.add(new Workspace());
            }

        }
    },

    prefetch_dimensions: function() {
        if (! this.measures || ! this.dimensions) {
            Log.log({
                Message: "measures or dimensions not initialized",
                Session: JSON.stringify(this)
            });
            return;
        }

        for(var i = 0; i < this.connections.length; i++) {
            var connection = this.connections[i];
            for(var j = 0; j < connection.catalogs.length; j++) {
                var catalog = connection.catalogs[j];
                for(var k = 0; k < catalog.schemas.length; k++) {
                    var schema = catalog.schemas[k];
                    for(var l = 0; l < schema.cubes.length; l++) {
                        var cube = schema.cubes[l];
                        var key = connection.name + "/" + catalog.name + "/"
                            + ((schema.name == "" || schema.name == null) ? "null" : schema.name)
                            + "/" + cube.name;

                        if (localStorage &&
                            localStorage.getItem("dimension." + key) !== null &&
                            localStorage.getItem("measure." + key) !== null) {
                            this.dimensions[key] = new Dimension(JSON.parse(localStorage.getItem("dimension." + key)));
                            this.measures[key] = new Measure(JSON.parse(localStorage.getItem("measure." + key)));
                        } else {
                            this.dimensions[key] = new Dimension({ key: key });
                            this.measures[key] = new Measure({ key: key });
                            if (Settings.DIMENSION_PREFETCH === true) {
                                this.dimensions[key].fetch();
                                this.measures[key].fetch();
                            }
                        }
                    }
                }
            }
        }

        // Start routing
        if (!this.initialized && Backbone.history) {
            Backbone.history.start();
            this.initialized = true;
        }
    },

    url: function() {
        if (this.first) {
            this.first = false;
            return encodeURI(Saiku.session.username + "/discover/");
        }
        else {
            return encodeURI(Saiku.session.username + "/discover/refresh");
        }
    }
});
<|endoftext|>


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

/**
 * Dialog for member selections
 */
var DrillthroughModal = Modal.extend({
    type: "drillthrough",

    buttons: [
        { text: "Ok", method: "ok" },
        { text: "Cancel", method: "close" }
    ],

    events: {
        'click .collapsed': 'select',
        'click .expand': 'select',
        'click .folder_collapsed': 'select',
        'click .folder_expanded': 'select',
        'click .dialog_footer a:' : 'call',
        'click .parent_dimension input' : 'select_dimension',
        'click .measure_tree input' : 'select_measure',
        'click input.all_measures' : 'select_all_measures',
        'click input.all_dimensions' : 'select_all_dimensions',
    },

    initialize: function(args) {
        // Initialize properties
        _.extend(this, args);
        this.options.title = args.title;
        this.query = args.workspace.query;

        this.position = args.position;
        this.action = args.action;
        Saiku.ui.unblock();
        _.bindAll(this, "ok", "drilled");

        // Resize when rendered
        this.bind('open', this.post_render);
        this.render();
               // Load template
       $(this.el).find('.dialog_body')
          .html(_.template($("#template-drillthrough").html())(this));
        // Show dialog
        $(this.el).find('.maxrows').val(this.maxrows);

        var schema = this.query.get('schema');
        var key = this.query.get('connection') + "/" +
                this.query.get('catalog') + "/"
                + ((schema == "" || schema == null) ? "null" : schema)
                + "/" + this.query.get('cube');

        var container = $("#template-drillthrough-list").html();
        var dimensions = Saiku.session.sessionworkspace.dimensions[key].get('data');
        var measures = Saiku.session.sessionworkspace.measures[key].get('data');

        if (typeof dimensions == "undefined" || typeof measures == "undefined") {
                        if (typeof localStorage !== "undefined" && localStorage &&
                            localStorage.getItem("dimension." + key) !== null &&
                            localStorage.getItem("measure." + key) !== null) {
                            Saiku.session.sessionworkspace.dimensions[key] = new Dimension(JSON.parse(localStorage.getItem("dimension." + key)));
                            Saiku.session.sessionworkspace.measures[key] = new Measure(JSON.parse(localStorage.getItem("measure." + key)));
                        } else {
                            Saiku.session.sessionworkspace.dimensions[key] = new Dimension({ key: key });
                            Saiku.session.sessionworkspace.measures[key] = new Measure({ key: key });
                            Saiku.session.sessionworkspace.dimensions[key].fetch({ async : false });
                            Saiku.session.sessionworkspace.measures[key].fetch({ async : false });
                        }
                        dimensions = Saiku.session.sessionworkspace.dimensions[key].get('data');
                        measures = Saiku.session.sessionworkspace.measures[key].get('data');
        }

        var templ_dim =_.template($("#template-drillthrough-dimensions").html())({dimensions: dimensions});
        var templ_measure =_.template($("#template-drillthrough-measures").html())({measures: measures});

        $(container).appendTo($(this.el).find('.dialog_body'));
        $(this.el).find('.sidebar').height(($("body").height() / 2) + ($("body").height() / 6) );
        $(this.el).find('.sidebar').width(380);

        $(this.el).find('.dimension_tree').html('').append($(templ_dim));
        $(this.el).find('.measure_tree').html('').append($(templ_measure));

		Saiku.i18n.translate();
    },

    select: function(event) {
        var $target = $(event.target).hasClass('root')
            ? $(event.target) : $(event.target).parent().find('span');
        if ($target.hasClass('root')) {
            $target.find('a').toggleClass('folder_collapsed').toggleClass('folder_expand');
            $target.toggleClass('collapsed').toggleClass('expand');
            $target.parents('li').find('ul').children('li').toggle();
        }

        return false;
    },

    select_dimension: function(event) {
        var $target = $(event.target);
        var checked = $target.is(':checked');
        $target.parent().find('input').attr('checked', checked);
    },

    select_all_dimensions: function(event) {
        var $target = $(event.target);
        var checked = $target.is(':checked');
        $(this.el).find('.dimension_tree input').attr('checked', checked);
    },

    select_all_measures: function(event) {
        var $target = $(event.target);
        var checked = $target.is(':checked');
        $(this.el).find('.measure_tree input').attr('checked', checked);
    },

    select_measure: function(event) {
        var $target = $(event.target);
        var checked = $target.is(':checked');
        if(checked) {
            //$target.parent().siblings().find('input').attr('checked', false);
        }
    },

    post_render: function(args) {
        $(args.modal.el).parents('.ui-dialog').css({ width: "150px" });
    },

    ok: function() {
        // Notify user that updates are in progress
        var $loading = $("
Drilling through...
");
        $(this.el).find('.dialog_body').children().hide();
        $(this.el).find('.dialog_body').prepend($loading);
        var selections = ""
        $(this.el).find('.check_level:checked').each( function(index) {
            if (index > 0) {
                selections += ", ";
            }
            selections += $(this).val();
        });

        var maxrows = $(this.el).find('.maxrows').val();
        var params = "?maxrows=" + maxrows;
        params = params + (typeof this.position !== "undefined" ? "&position=" + this.position : "" );
        params += "&returns=" + selections;
        if (this.action == "export") {
            var location = Settings.REST_URL +
                Saiku.session.username + "/query/" +
                this.query.id + "/drillthrough/export/csv" + params;
            this.close();
            window.open(location);
        } else if (this.action == "table") {
            Saiku.ui.block("Executing drillthrough...");
            this.query.action.get("/drillthrough", { data: { position: this.position, maxrows: maxrows , returns: selections}, success: this.drilled } );
            this.close();
        }

        return false;
    },

    drilled: function(model, response) {
        var table = new Table({ workspace: this.workspace });
        table.render({ data: response }, true);

        Saiku.ui.unblock();
        var html = '

' + $(table.el).html() + '

';
        this.remove();
        table.remove();
        $.fancybox(html
            ,
            {
            'autoDimensions'    : false,
            'autoScale'         : false,
            'height'            :  ($("body").height() - 100),
            'width'             :  ($("body").width() - 100),
            'transitionIn'      : 'none',
            'transitionOut'     : 'none'
            }
        );

    },

    finished: function() {
        $(this.el).dialog('destroy').remove();
        this.query.run();
    }
});<commit_msg>fix drillthrough issue not showing table<commit_after>/*
 *   Copyright 2012 OSBI Ltd
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

/**
 * Dialog for member selections
 */
var DrillthroughModal = Modal.extend({
    type: "drillthrough",

    buttons: [
        { text: "Ok", method: "ok" },
        { text: "Cancel", method: "close" }
    ],

    events: {
        'click .collapsed': 'select',
        'click .expand': 'select',
        'click .folder_collapsed': 'select',
        'click .folder_expanded': 'select',
        'click .dialog_footer a:' : 'call',
        'click .parent_dimension input' : 'select_dimension',
        'click .measure_tree input' : 'select_measure',
        'click input.all_measures' : 'select_all_measures',
        'click input.all_dimensions' : 'select_all_dimensions',
    },

    initialize: function(args) {
        // Initialize properties
        _.extend(this, args);
        this.options.title = args.title;
        this.query = args.workspace.query;

        this.position = args.position;
        this.action = args.action;
        Saiku.ui.unblock();
        _.bindAll(this, "ok", "drilled");

        // Resize when rendered
        this.bind('open', this.post_render);
        this.render();
               // Load template
       $(this.el).find('.dialog_body')
          .html(_.template($("#template-drillthrough").html())(this));
        // Show dialog
        $(this.el).find('.maxrows').val(this.maxrows);

        var schema = this.query.get('schema');
        var key = this.query.get('connection') + "/" +
                this.query.get('catalog') + "/"
                + ((schema == "" || schema == null) ? "null" : schema)
                + "/" + this.query.get('cube');

        var container = $("#template-drillthrough-list").html();
        var dimensions = Saiku.session.sessionworkspace.dimensions[key].get('data');
        var measures = Saiku.session.sessionworkspace.measures[key].get('data');

        if (typeof dimensions == "undefined" || typeof measures == "undefined") {
                        if (typeof localStorage !== "undefined" && localStorage &&
                            localStorage.getItem("dimension." + key) !== null &&
                            localStorage.getItem("measure." + key) !== null) {
                            Saiku.session.sessionworkspace.dimensions[key] = new Dimension(JSON.parse(localStorage.getItem("dimension." + key)));
                            Saiku.session.sessionworkspace.measures[key] = new Measure(JSON.parse(localStorage.getItem("measure." + key)));
                        } else {
                            Saiku.session.sessionworkspace.dimensions[key] = new Dimension({ key: key });
                            Saiku.session.sessionworkspace.measures[key] = new Measure({ key: key });
                            Saiku.session.sessionworkspace.dimensions[key].fetch({ async : false });
                            Saiku.session.sessionworkspace.measures[key].fetch({ async : false });
                        }
                        dimensions = Saiku.session.sessionworkspace.dimensions[key].get('data');
                        measures = Saiku.session.sessionworkspace.measures[key].get('data');
        }

        var templ_dim =_.template($("#template-drillthrough-dimensions").html())({dimensions: dimensions});
        var templ_measure =_.template($("#template-drillthrough-measures").html())({measures: measures});

        $(container).appendTo($(this.el).find('.dialog_body'));
        $(this.el).find('.sidebar').height(($("body").height() / 2) + ($("body").height() / 6) );
        $(this.el).find('.sidebar').width(380);

        $(this.el).find('.dimension_tree').html('').append($(templ_dim));
        $(this.el).find('.measure_tree').html('').append($(templ_measure));

		Saiku.i18n.translate();
    },

    select: function(event) {
        var $target = $(event.target).hasClass('root')
            ? $(event.target) : $(event.target).parent().find('span');
        if ($target.hasClass('root')) {
            $target.find('a').toggleClass('folder_collapsed').toggleClass('folder_expand');
            $target.toggleClass('collapsed').toggleClass('expand');
            $target.parents('li').find('ul').children('li').toggle();
        }

        return false;
    },

    select_dimension: function(event) {
        var $target = $(event.target);
        var checked = $target.is(':checked');
        $target.parent().find('input').attr('checked', checked);
    },

    select_all_dimensions: function(event) {
        var $target = $(event.target);
        var checked = $target.is(':checked');
        $(this.el).find('.dimension_tree input').attr('checked', checked);
    },

    select_all_measures: function(event) {
        var $target = $(event.target);
        var checked = $target.is(':checked');
        $(this.el).find('.measure_tree input').attr('checked', checked);
    },

    select_measure: function(event) {
        var $target = $(event.target);
        var checked = $target.is(':checked');
        if(checked) {
            //$target.parent().siblings().find('input').attr('checked', false);
        }
    },

    post_render: function(args) {
        $(args.modal.el).parents('.ui-dialog').css({ width: "150px" });
    },

    ok: function() {
        // Notify user that updates are in progress
        var $loading = $("
Drilling through...
");
        $(this.el).find('.dialog_body').children().hide();
        $(this.el).find('.dialog_body').prepend($loading);
        var selections = ""
        $(this.el).find('.check_level:checked').each( function(index) {
            if (index > 0) {
                selections += ", ";
            }
            selections += $(this).val();
        });

        var maxrows = $(this.el).find('.maxrows').val();
        var params = "?maxrows=" + maxrows;
        params = params + (typeof this.position !== "undefined" ? "&position=" + this.position : "" );
        params += "&returns=" + selections;
        if (this.action == "export") {
            var location = Settings.REST_URL +
                Saiku.session.username + "/query/" +
                this.query.id + "/drillthrough/export/csv" + params;
            this.close();
            window.open(location);
        } else if (this.action == "table") {
            Saiku.ui.block("Executing drillthrough...");
            this.query.action.get("/drillthrough", { data: { position: this.position, maxrows: maxrows , returns: selections}, success: this.drilled } );
            this.close();
        }

        return false;
    },

    drilled: function(model, response) {
        var table = new Table({ workspace: this.workspace });
        if (response != null && response.error != null) {
            $(table.el).html('
' + safe_tags_replace(args.data.error) + '
');
        } else {
            table.process_data(response.cellset);
        }

        //table.render({ data: response }, true);

        Saiku.ui.unblock();
        var html = '

' + $(table.el).html() + '

';
        this.remove();
        table.remove();
        $.fancybox(html
            ,
            {
            'autoDimensions'    : false,
            'autoScale'         : false,
            'height'            :  ($("body").height() - 100),
            'width'             :  ($("body").width() - 100),
            'transitionIn'      : 'none',
            'transitionOut'     : 'none'
            }
        );

    },

    finished: function() {
        $(this.el).dialog('destroy').remove();
        this.query.run();
    }
});<|endoftext|>


<commit_before>/*
 * HOMER 5 UI (Xenophon)
 *
 * Copyright (C) 2011-2015 Alexandr Dubovikov <alexandr.dubovikov@gmail.com>
 * Copyright (C) 2011-2015 Lorenzo Mangani <lorenzo.mangani@gmail.com> QXIP B.V.
 * License AGPL-3.0 http://opensource.org/licenses/AGPL-3.0
 *
*/

'use strict';

angular.module('homer.widgets.ripesearch', ['adf.provider'])
  .value('RIPEServiceUrl', 'https://stat.ripe.net/data/visibility/data.json?resource=')
  .config(function(dashboardProvider){
    dashboardProvider
      .widget('ripesearch', {
        title: 'RIPE DB Search',
        description: 'Display RIPE Visibility for a given IP/AS',
        templateUrl: 'js/widgets/ripesearch/ripesearch.html',
        controller: 'ripeCtrl',
        reload: true,
        resolve: {
          data: function(weatcherService, config){
            if (!config.rscount){ config.rscount = 4; }
            if (config.location){
              return weatcherService.get(config.location,config.rscount);
            }
          }
        },
        edit: {
          templateUrl: 'js/widgets/ripesearch/edit.html'
        }
      });
  })
  .service('weatcherService', function($q, $http, RIPEServiceUrl){
    return {
      get: function(location,counter){
        var deferred = $q.defer();
        var url = RIPEServiceUrl + location;
        $http.get(url)
          .success(function(data){
	    // console.log('RIPE-QUERY:',data);
            if (data && data.status === "ok"){
              deferred.resolve(data);
            } else {
              deferred.reject();
            }
          })
          .error(function(){
            deferred.reject();
          });
        return deferred.promise;
      }
    };
  })
  .controller('ripeCtrl', function($scope, data, config){
    $scope.data = data;
    $scope.data.config = config;
  });
<commit_msg>fix: ripeSearchService, not weatcherService<commit_after>/*
 * HOMER 5 UI (Xenophon)
 *
 * Copyright (C) 2011-2015 Alexandr Dubovikov <alexandr.dubovikov@gmail.com>
 * Copyright (C) 2011-2015 Lorenzo Mangani <lorenzo.mangani@gmail.com> QXIP B.V.
 * License AGPL-3.0 http://opensource.org/licenses/AGPL-3.0
 *
*/

'use strict';

angular.module('homer.widgets.ripesearch', ['adf.provider'])
  .value('RIPEServiceUrl', 'https://stat.ripe.net/data/visibility/data.json?resource=')
  .config(function(dashboardProvider){
    dashboardProvider
      .widget('ripesearch', {
        title: 'RIPE DB Search',
        description: 'Display RIPE Visibility for a given IP/AS',
        templateUrl: 'js/widgets/ripesearch/ripesearch.html',
        controller: 'ripeCtrl',
        reload: true,
        resolve: {
          data: function(ripeSearchService, config){
            if (!config.rscount){ config.rscount = 4; }
            if (config.location){
              return ripeSearchService.get(config.location,config.rscount);
            }
          }
        },
        edit: {
          templateUrl: 'js/widgets/ripesearch/edit.html'
        }
      });
  })
  .service('ripeSearchService', function($q, $http, RIPEServiceUrl){
    return {
      get: function(location,counter){
        var deferred = $q.defer();
        var url = RIPEServiceUrl + location;
        $http.get(url)
          .success(function(data){
	    // console.log('RIPE-QUERY:',data);
            if (data && data.status === "ok"){
              deferred.resolve(data);
            } else {
              deferred.reject();
            }
          })
          .error(function(){
            deferred.reject();
          });
        return deferred.promise;
      }
    };
  })
  .controller('ripeCtrl', function($scope, data, config){
    $scope.data = data;
    $scope.data.config = config;
  });
<|endoftext|>


<commit_before>#!/usr/bin/env node
const octicons = require('octicons')
const fse = require('fs-extra')
const {join, resolve} = require('path')

const srcDir = resolve(__dirname, '../src/__generated__')
const iconsFile = join(srcDir, 'icons.js')

function CamelCase(str) {
  return str.replace(/(^|-)([a-z])/g, (_, __, c) => c.toUpperCase())
}

const icons = [...Object.entries(octicons)].map(([key, octicon]) => {
  const name = CamelCase(key)
  const {width, height, path} = octicon
  // convert attributes like fill-rule into JSX equivalents, e.g. fillRule
  const svg = path.replace(/([a-z]+)-([a-z]+)=/g, (_, a, b) => `${a}${CamelCase(b)}=`)
  const code = `function ${name}() {
  return ${svg}
}
${name}.size = [${width}, ${height}]
`

  return {
    key,
    name,
    octicon,
    code
  }
})
.sort((a, b) => a.key.localeCompare(b.key))

function writeIcons(file) {
  const count = icons.length
  const code = `/* THIS FILE IS GENERATED. DO NOT EDIT IT. */
import React from 'react'

${icons.map(({code}) => code).join('\n')}

const iconsByName = {
  ${icons.map(({key, name}) => `'${key}': ${name}`).join(',\n  ')}
}

function getIconByName(name) {
  return iconsByName[name]
}

export {
  getIconByName,
  iconsByName,
  ${icons.map(({name}) => name).join(',\n  ')}
}`
  return fse.writeFile(file, code, 'utf8').then(() => {
    console.warn('wrote %s with %d exports', file, count)
    return icons
  })
}

fse.mkdirs(srcDir)
  .then(() => writeIcons(iconsFile))
  .catch(error => {
    console.error(error)
    process.exit(1)
  })
<commit_msg>lint script/build.js<commit_after>#!/usr/bin/env node
const octicons = require('octicons')
const fse = require('fs-extra')
const {join, resolve} = require('path')

const srcDir = resolve(__dirname, '../src/__generated__')
const iconsFile = join(srcDir, 'icons.js')

function CamelCase(str) {
  return str.replace(/(^|-)([a-z])/g, (_, __, c) => c.toUpperCase())
}

const icons = [...Object.entries(octicons)]
  .map(([key, octicon]) => {
    const name = CamelCase(key)
    const {width, height, path} = octicon
    // convert attributes like fill-rule into JSX equivalents, e.g. fillRule
    const svg = path.replace(/([a-z]+)-([a-z]+)=/g, (_, a, b) => `${a}${CamelCase(b)}=`)
    const code = `function ${name}() {
  return ${svg}
}
${name}.size = [${width}, ${height}]
`

    return {
      key,
      name,
      octicon,
      code
    }
  })
  .sort((a, b) => a.key.localeCompare(b.key))

function writeIcons(file) {
  const count = icons.length
  const code = `/* THIS FILE IS GENERATED. DO NOT EDIT IT. */
import React from 'react'

${icons.map(({code}) => code).join('\n')}

const iconsByName = {
  ${icons.map(({key, name}) => `'${key}': ${name}`).join(',\n  ')}
}

function getIconByName(name) {
  return iconsByName[name]
}

export {
  getIconByName,
  iconsByName,
  ${icons.map(({name}) => name).join(',\n  ')}
}`
  return fse.writeFile(file, code, 'utf8').then(() => {
    console.warn('wrote %s with %d exports', file, count)
    return icons
  })
}

fse
  .mkdirs(srcDir)
  .then(() => writeIcons(iconsFile))
  .catch(error => {
    console.error(error)
    process.exit(1)
  })
<|endoftext|>


<commit_before>import Orbit from 'orbit/main';
import { assert } from 'orbit/lib/assert';
import { isArray, isObject } from 'orbit/lib/objects';
import Operation from 'orbit/operation';
import Source from './source';
import Serializer from './serializer';
import JSONAPISerializer from './jsonapi-serializer';
import { OperationNotAllowed, RecordNotFoundException, RecordAlreadyExistsException } from './lib/exceptions';

/**
 Source for accessing a JSON API compliant RESTful API with AJAX

 @class JSONAPISource
 @extends Source
 @namespace OC
 @param schema
 @param options
 @constructor
 */
export default Source.extend({

  init: function(schema, options) {
    assert('JSONAPISource requires Orbit.Promise be defined', Orbit.Promise);
    assert('JSONAPISource requires Orbit.ajax be defined', Orbit.ajax);

    this._super.apply(this, arguments);

    options = options || {};
    this.namespace        = options.namespace || this.namespace;
    this.host             = options.host || this.host;
    this.headers          = options.headers || this.headers;
    this.SerializerClass  = options.SerializerClass || this.SerializerClass;

    // If `SerializerClass` is obtained through the _super chain, dereference
    // its wrapped function, which will be the constructor.
    //
    // Note: This is only necessary when retrieving a *constructor* from a
    //       class hierarchy. Otherwise, `superWrapper` "just works".
    if (this.SerializerClass && this.SerializerClass.wrappedFunction) {
      this.SerializerClass = this.SerializerClass.wrappedFunction;
    }

    this.serializer = new this.SerializerClass(schema);

    assert('Serializer must be an instance of OC.Serializer', this.serializer instanceof Serializer);
  },

  namespace: null,
  host: null,
  headers: null,
  SerializerClass: JSONAPISerializer,

  /////////////////////////////////////////////////////////////////////////////
  // Transformable interface implementation
  /////////////////////////////////////////////////////////////////////////////

  _transform: function(operation) {
    var _this = this;
    var op    = operation.op;
    var path  = operation.path;

    // console.log('jsonapi#_transform', op, path, operation.value);

    if (path.length > 2) {
      if (path[2] === '__rel') {
        if (op === 'add') {
          return _this._transformAddLink(operation);
        } else if (op === 'remove') {
          return _this._transformRemoveLink(operation);
        } else if (op === 'replace') {
          return _this._transformReplaceLink(operation);
        }
      } else {
        return _this._transformUpdateAttribute(operation);
      }

    } else if (path.length > 1) {
      if (op === 'add') {
        return _this._transformAdd(operation);

      } else if (op === 'replace') {
        return _this._transformReplace(operation);

      } else if (op === 'remove') {
        return _this._transformRemove(operation);
      }
    }

    throw new OperationNotAllowed('JSONAPISource#transform could not process operation: ' + operation.op +
                                  ' with path: ' + operation.path.join('/'));
  },

  /////////////////////////////////////////////////////////////////////////////
  // Requestable interface implementation
  /////////////////////////////////////////////////////////////////////////////

  _find: function(type, id) {
    if (id && (typeof id === 'number' || typeof id === 'string')) {
      return this._findOne(type, id);

    } else if (id && isArray(id)) {
      return this._findMany(type, id);

    } else {
      var resourceKey = this.serializer.resourceKey(type);

      if (id && typeof id === 'object' && id[resourceKey]) {
        return this._findOne(type, id);

      } else {
        return this._findQuery(type, id);
      }
    }
  },

  _findLink: function(type, id, link) {
    var _this = this;
    return this.ajax(this.resourceLinkURL(type, id, link), 'GET').then(
      function(raw) {
        var relId = _this.serializer.deserializeLink(raw.data);
        return _this.settleTransforms().then(function() {
          return relId;
        });
      }
    );
  },

 _findLinked: function(type, id, link, relId) {
   var _this = this;

   if (relId === undefined) {
     return this.ajax(this.resourceLinkedURL(type, id, link), 'GET').then(
       function(raw) {
         var linkDef = _this.schema.linkDefinition(type, link);

         var records = _this.deserialize(linkDef.model, null, raw);

         return _this.settleTransforms().then(function() {
           return isArray(records) ? records : [records];
         });
       }
     );
   } else {
     return this._super.apply(this, arguments);
   }
 },

  /////////////////////////////////////////////////////////////////////////////
  // Internals
  /////////////////////////////////////////////////////////////////////////////

  _transformAdd: function(operation) {
    var _this = this;
    var type = operation.path[0];
    var id = operation.path[1];
    var json = this.serializer.serialize(type, operation.value);

    return this.ajax(this.resourceURL(type), 'POST', {data: json}).then(
      function(raw) {
        _this.deserialize(type, id, raw, operation);
      }
    );
  },

  _transformReplace: function(operation) {
    var _this = this;
    var type = operation.path[0];
    var id = operation.path[1];
    var value = operation.value;

    var json = this.serializer.serialize(type, value);

    return this.ajax(this.resourceURL(type, id), 'PATCH', {data: json}).then(
      function(raw) {
        // TODO - better 204 (no content) checking
        if (raw && Object.keys(raw).length > 0) {
          _this.deserialize(type, id, raw, operation);
        } else {
          _this._transformCache(operation);
        }
      }
    );
  },

  _transformRemove: function(operation) {
    var _this = this;
    var type = operation.path[0];
    var id = operation.path[1];

    return this.ajax(this.resourceURL(type, id), 'DELETE').then(function() {
      _this._transformCache({op: 'remove', path: [type, id]});
    });
  },

  _transformAddLink: function(operation) {
    var _this = this;

    var type = operation.path[0];
    var id = operation.path[1];
    var link = operation.path[3];
    var relId = operation.path[4] || operation.value;
    var relType = this.schema.linkDefinition(type, link).model;
    var method = 'POST';
    var json = {
      data: [this.serializer.serializeRelationshipIdentifier(relType, relId)]
    };

    return this.ajax(this.resourceLinkURL(type, id, link), method, {data: json}).then(
      function() {
        _this._transformCache(operation);
      }
    );
  },

  _transformRemoveLink: function(operation) {
    var _this = this;

    var type = operation.path[0];
    var id = operation.path[1];
    var link = operation.path[3];
    var relId = operation.path[4];
    var relType = this.schema.linkDefinition(type, link).model;
    var method = 'DELETE';
    var json = {
      data: [this.serializer.serializeRelationshipIdentifier(relType, relId)]
    };

    return this.ajax(this.resourceLinkURL(type, id, link), method, {data: json}).then(
      function() {
        _this._transformCache(operation);
      }
    );
  },

  _transformReplaceLink: function(operation) {
    var _this = this;

    var type = operation.path[0];
    var id = operation.path[1];
    var link = operation.path[3];
    var relId = operation.path[4] || operation.value;
    var linkDef = this.schema.linkDefinition(type, link);
    var relType = linkDef.model;
    var data;

    if (linkDef.type === 'hasMany') {
      // Convert a map of ids to an array
      if (isObject(relId)) {
        data = Object.keys(relId).map(function(id) {
          return this.serializer.serializeRelationshipIdentifier(relType, id);
        }, this);
      } else {
        data = [this.serializer.serializeRelationshipIdentifier(relType, relId)];
      }
    } else {
      data = this.serializer.serializeRelationshipIdentifier(relType, relId);
    }

    var method = 'PATCH';
    var json = {
      data: data
    };

    return this.ajax(this.resourceLinkURL(type, id, link), method, {data: json}).then(
      function() {
        _this._transformCache(operation);
      }
    );
  },

  _transformUpdateAttribute: function(operation) {
    var _this = this;
    var type = operation.path[0];
    var id = operation.path[1];
    var attr = operation.path[2];
    var modelSchema = this.schema.models[type];

    var record = {};
    record[attr] = operation.value;
    record[modelSchema.primaryKey.name] = id;

    var json = this.serializer.serialize(type, record);

    return this.ajax(this.resourceURL(type, id), 'PATCH', {data: json}).then(
      function(raw) {
        _this._transformCache(operation);
      }
    );
  },

  _addRecordsToCache: function(type, records, parentOperation) {
    var _this = this;
    records.forEach(function(record) {
      _this._addRecordToCache(type, record, parentOperation);
    });
  },

  _addRecordToCache: function(type, record, parentOperation) {
    var operation = {
      op: 'add',
      path: [type, this.getId(type, record)],
      value: record
    };

    if (parentOperation) operation = parentOperation.spawn(operation);

    this._transformCache(operation);
  },

  _findOne: function(type, id) {
    var _this = this;
    return this.ajax(this.resourceURL(type, id), 'GET').then(
      function(raw) {
        var record = _this.deserialize(type, null, raw);
        return _this.settleTransforms().then(function() {
          return record;
        });
      }
    );
  },

  _findMany: function(type, ids) {
    var _this = this;
    return this.ajax(this.resourceURL(type, ids), 'GET').then(
      function(raw) {
        var records = _this.deserialize(type, null, raw);
        return _this.settleTransforms().then(function() {
          return isArray(records) ? records : [records];
        });
      }
    );
  },

  _findQuery: function(type, query) {
    var _this = this;

    return this.ajax(this.resourceURL(type), 'GET', {data: {filter: query}}).then(
      function(raw) {
        var records = _this.deserialize(type, null, raw);
        return _this.settleTransforms().then(function() {
          return records;
        });
      }
    );
  },

  _transformCache: function(operation) {
    var pathToVerify,
        inverse;

    if (operation.op === 'add') {
      pathToVerify = operation.path.slice(0, operation.path.length - 1);
    } else {
      pathToVerify = operation.path;
    }

    if (this.retrieve(pathToVerify) !== undefined) {
      // transforming the cache will trigger a call to `_cacheDidTransform`,
      // which will then trigger `didTransform`
      inverse = this._cache.transform(operation);

    } else if (operation.op === 'replace') {
      // try adding instead of replacing if the cache does not yet contain
      // the data
      operation.op = 'add';
      inverse = this._transformCache(operation);

    } else {
      // if the cache can't be transformed because, still trigger `didTransform`
      //
      // NOTE: this is not an error condition, since the local cache will often
      // be sparsely populated compared with the remote store
      inverse = [];
    }

    this.didTransform(operation, []);
  },

  _resourceIdURLSegment: function(type, id) {
    var resourceId = this.serializer.resourceId(type, id);
    if (isArray(resourceId)) {
      resourceId = resourceId.join(',');
    }
    return resourceId;
  },

  /////////////////////////////////////////////////////////////////////////////
  // Publicly accessible methods particular to JSONAPISource
  /////////////////////////////////////////////////////////////////////////////

  ajax: function(url, method, hash) {
    var _this = this;

    return new Orbit.Promise(function(resolve, reject) {
      hash = hash || {};
      hash.url = url;
      hash.type = method;
      hash.dataType = 'json';
      hash.context = _this;

      // console.log('ajax start', method, url);

      if (hash.data && method !== 'GET') {
        if (!hash.contentType) {
          hash.contentType = _this.ajaxContentType(hash);
        }
        hash.data = JSON.stringify(hash.data);
      }

      if (_this.ajaxHeaders) {
        var headers = _this.ajaxHeaders();
        hash.beforeSend = function (xhr) {
          for (var key in headers) {
            if (headers.hasOwnProperty(key)) {
              xhr.setRequestHeader(key, headers[key]);
            }
          }
        };
      }

      hash.success = function(json) {
        // console.log('ajax success', method, json);
        resolve(json);
      };

      hash.error = function(jqXHR, textStatus, errorThrown) {
        if (jqXHR) {
          jqXHR.then = null;
        }
        // console.log('ajax error', method, jqXHR);

        reject(jqXHR);
      };

      Orbit.ajax(hash);
    });
  },

  ajaxContentType: function(url, method) {
    return 'application/vnd.api+json; charset=utf-8';
  },

  ajaxHeaders: function() {
    return this.headers;
  },

  resourceNamespace: function(type) {
    return this.namespace;
  },

  resourceHost: function(type) {
    return this.host;
  },

  resourcePath: function(type, id) {
    var path = [this.serializer.resourceType(type)];
    if (id) {
      path.push(this._resourceIdURLSegment(type, id));
    }
    return path.join('/');
  },

  resourceURL: function(type, id) {
    var host = this.resourceHost(type),
        namespace = this.resourceNamespace(type),
        url = [];

    if (host) { url.push(host); }
    if (namespace) { url.push(namespace); }
    url.push(this.resourcePath(type, id));

    url = url.join('/');
    if (!host) { url = '/' + url; }

    return url;
  },

  resourceLinkURL: function(type, id, link, relId) {
    var url = this.resourceURL(type, id);
    url += '/relationships/' + this.serializer.resourceLink(type, link);

    if (relId) {
      var linkDef = this.schema.linkDefinition(type, link);

      url += '/' + this._resourceIdURLSegment(linkDef.model, relId);
    }

    return url;
  },

  resourceLinkedURL: function(type, id, link) {
    var url = this.resourceURL(type, id);
    url += '/' + this.serializer.resourceLink(type, link);
    return url;
  },

  deserialize: function(type, id, data, parentOperation) {
    var records = this.serializer.deserialize(type, id, data);
    var primaryRecords = records.primary;

    // Create a new parent operation, if necessary, to ensure that subsequent
    // operations are related and will be settled together in the same
    // transformation.
    //
    // Note: this parent operation is not actually performed on this source.
    // It is only created to establish a common ancestor.
    if (!parentOperation) {
      parentOperation = new Operation();
    }

    if (this._cache) {
      if (isArray(primaryRecords)) {
        this._addRecordsToCache(type, primaryRecords, parentOperation);
      } else {
        this._addRecordToCache(type, primaryRecords, parentOperation);
      }

      if (records.included) {
        Object.keys(records.included).forEach(function(relType) {
          var relRecords = records.included[relType];
          this._addRecordsToCache(relType, relRecords, parentOperation);
        }, this);
      }
    }

    return primaryRecords;
  }
});
<commit_msg>Rebase on master<commit_after>import Orbit from 'orbit/main';
import { assert } from 'orbit/lib/assert';
import { isArray, isObject } from 'orbit/lib/objects';
import Operation from 'orbit/operation';
import Source from './source';
import Serializer from './serializer';
import JSONAPISerializer from './jsonapi-serializer';
import { OperationNotAllowed, RecordNotFoundException, RecordAlreadyExistsException } from './lib/exceptions';

/**
 Source for accessing a JSON API compliant RESTful API with AJAX

 @class JSONAPISource
 @extends Source
 @namespace OC
 @param schema
 @param options
 @constructor
 */
export default Source.extend({

  init: function(schema, options) {
    assert('JSONAPISource requires Orbit.Promise be defined', Orbit.Promise);
    assert('JSONAPISource requires Orbit.ajax be defined', Orbit.ajax);

    this._super.apply(this, arguments);

    options = options || {};
    this.namespace        = options.namespace || this.namespace;
    this.host             = options.host || this.host;
    this.headers          = options.headers || this.headers;
    this.SerializerClass  = options.SerializerClass || this.SerializerClass;

    // If `SerializerClass` is obtained through the _super chain, dereference
    // its wrapped function, which will be the constructor.
    //
    // Note: This is only necessary when retrieving a *constructor* from a
    //       class hierarchy. Otherwise, `superWrapper` "just works".
    if (this.SerializerClass && this.SerializerClass.wrappedFunction) {
      this.SerializerClass = this.SerializerClass.wrappedFunction;
    }

    this.serializer = new this.SerializerClass(schema);

    assert('Serializer must be an instance of OC.Serializer', this.serializer instanceof Serializer);
  },

  namespace: null,
  host: null,
  headers: null,
  SerializerClass: JSONAPISerializer,

  /////////////////////////////////////////////////////////////////////////////
  // Transformable interface implementation
  /////////////////////////////////////////////////////////////////////////////

  _transform: function(operation) {
    var _this = this;
    var op    = operation.op;
    var path  = operation.path;

    // console.log('jsonapi#_transform', op, path, operation.value);

    if (path.length > 2) {
      if (path[2] === '__rel') {
        if (op === 'add') {
          return _this._transformAddLink(operation);
        } else if (op === 'remove') {
          return _this._transformRemoveLink(operation);
        } else if (op === 'replace') {
          return _this._transformReplaceLink(operation);
        }
      } else {
        return _this._transformUpdateAttribute(operation);
      }

    } else if (path.length > 1) {
      if (op === 'add') {
        return _this._transformAdd(operation);

      } else if (op === 'replace') {
        return _this._transformReplace(operation);

      } else if (op === 'remove') {
        return _this._transformRemove(operation);
      }
    }

    throw new OperationNotAllowed('JSONAPISource#transform could not process operation: ' + operation.op +
                                  ' with path: ' + operation.path.join('/'));
  },

  /////////////////////////////////////////////////////////////////////////////
  // Requestable interface implementation
  /////////////////////////////////////////////////////////////////////////////

  _find: function(type, id) {
    if (id && (typeof id === 'number' || typeof id === 'string')) {
      return this._findOne(type, id);

    } else if (id && isArray(id)) {
      return this._findMany(type, id);

    } else {
      var resourceKey = this.serializer.resourceKey(type);

      if (id && typeof id === 'object' && id[resourceKey]) {
        return this._findOne(type, id);

      } else {
        return this._findQuery(type, id);
      }
    }
  },

  _findLink: function(type, id, link) {
    var _this = this;
    return this.ajax(this.resourceLinkURL(type, id, link), 'GET').then(
      function(raw) {
        var relId = _this.serializer.deserializeLink(raw.data);
        return _this.settleTransforms().then(function() {
          return relId;
        });
      }
    );
  },

 _findLinked: function(type, id, link, relId) {
   var _this = this;

   if (relId === undefined) {
     return this.ajax(this.resourceLinkedURL(type, id, link), 'GET').then(
       function(raw) {
         var linkDef = _this.schema.linkDefinition(type, link);

         var records = _this.deserialize(linkDef.model, null, raw);

         return _this.settleTransforms().then(function() {
           return isArray(records) ? records : [records];
         });
       }
     );
   } else {
     return this._super.apply(this, arguments);
   }
 },

  /////////////////////////////////////////////////////////////////////////////
  // Internals
  /////////////////////////////////////////////////////////////////////////////

  _transformAdd: function(operation) {
    var _this = this;
    var type = operation.path[0];
    var id = operation.path[1];
    var json = this.serializer.serialize(type, operation.value);

    return this.ajax(this.resourceURL(type), 'POST', {data: json}).then(
      function(raw) {
        _this.deserialize(type, id, raw, operation);
      }
    );
  },

  _transformReplace: function(operation) {
    var _this = this;
    var type = operation.path[0];
    var id = operation.path[1];
    var value = operation.value;

    var json = this.serializer.serialize(type, value);

    return this.ajax(this.resourceURL(type, id), 'PATCH', {data: json}).then(
      function(raw) {
        // TODO - better 204 (no content) checking
        if (raw && Object.keys(raw).length > 0) {
          _this.deserialize(type, id, raw, operation);
        } else {
          _this._transformCache(operation);
        }
      }
    );
  },

  _transformRemove: function(operation) {
    var _this = this;
    var type = operation.path[0];
    var id = operation.path[1];

    return this.ajax(this.resourceURL(type, id), 'DELETE').then(function() {
      _this._transformCache({op: 'remove', path: [type, id]});
    });
  },

  _transformAddLink: function(operation) {
    var _this = this;

    var type = operation.path[0];
    var id = operation.path[1];
    var link = operation.path[3];
    var relId = operation.path[4] || operation.value;
    var relType = this.schema.linkDefinition(type, link).model;
    var method = 'POST';
    var json = {
      data: [this.serializer.serializeRelationshipIdentifier(relType, relId)]
    };

    return this.ajax(this.resourceLinkURL(type, id, link), method, {data: json}).then(
      function() {
        _this._transformCache(operation);
      }
    );
  },

  _transformRemoveLink: function(operation) {
    var _this = this;

    var type = operation.path[0];
    var id = operation.path[1];
    var link = operation.path[3];
    var relId = operation.path[4];
    var relType = this.schema.linkDefinition(type, link).model;
    var method = 'DELETE';
    var json = {
      data: [this.serializer.serializeRelationshipIdentifier(relType, relId)]
    };

    return this.ajax(this.resourceLinkURL(type, id, link), method, {data: json}).then(
      function() {
        _this._transformCache(operation);
      }
    );
  },

  _transformReplaceLink: function(operation) {
    var _this = this;

    var type = operation.path[0];
    var id = operation.path[1];
    var link = operation.path[3];
    var relId = operation.path[4] || operation.value;
    var linkDef = this.schema.linkDefinition(type, link);
    var relType = linkDef.model;
    var data;

    if (linkDef.type === 'hasMany') {
      // Convert a map of ids to an array
      if (isObject(relId)) {
        data = Object.keys(relId).map(function(id) {
          return this.serializer.serializeRelationshipIdentifier(relType, id);
        }, this);
      } else {
        data = [this.serializer.serializeRelationshipIdentifier(relType, relId)];
      }
    } else {
      data = this.serializer.serializeRelationshipIdentifier(relType, relId);
    }

    var method = 'PATCH';
    var json = {
      data: data
    };

    return this.ajax(this.resourceLinkURL(type, id, link), method, {data: json}).then(
      function() {
        _this._transformCache(operation);
      }
    );
  },

  _transformUpdateAttribute: function(operation) {
    var _this = this;
    var type = operation.path[0];
    var id = operation.path[1];
    var attr = operation.path[2];
    var modelSchema = this.schema.models[type];

    var record = {};
    record[attr] = operation.value;
    record[modelSchema.primaryKey.name] = id;

    var json = this.serializer.serialize(type, record);

    return this.ajax(this.resourceURL(type, id), 'PATCH', {data: json}).then(
      function(raw) {
        _this._transformCache(operation);
      }
    );
  },

  _addRecordsToCache: function(type, records, parentOperation) {
    var _this = this;
    records.forEach(function(record) {
      _this._addRecordToCache(type, record, parentOperation);
    });
  },

  _addRecordToCache: function(type, record, parentOperation) {
    var operation = {
      op: 'add',
      path: [type, this.getId(type, record)],
      value: record
    };

    if (parentOperation) operation = parentOperation.spawn(operation);

    this._transformCache(operation);
  },

  _findOne: function(type, id) {
    var _this = this;
    return this.ajax(this.resourceURL(type, id), 'GET').then(
      function(raw) {
        var record = _this.deserialize(type, null, raw);
        return _this.settleTransforms().then(function() {
          return record;
        });
      }
    );
  },

  _findMany: function(type, ids) {
    var _this = this;
    return this.ajax(this.resourceURL(type, ids), 'GET').then(
      function(raw) {
        var records = _this.deserialize(type, null, raw);
        return _this.settleTransforms().then(function() {
          return isArray(records) ? records : [records];
        });
      }
    );
  },

  _findQuery: function(type, query) {
    var _this = this;

    return this.ajax(this.resourceURL(type), 'GET', {data: {filter: query}}).then(
      function(raw) {
        var records = _this.deserialize(type, null, raw);
        return _this.settleTransforms().then(function() {
          return records;
        });
      }
    );
  },

  _transformCache: function(operation) {
    var pathToVerify,
        inverse;

    if (operation.op === 'add') {
      pathToVerify = operation.path.slice(0, operation.path.length - 1);
    } else {
      pathToVerify = operation.path;
    }

    if (this.retrieve(pathToVerify) !== undefined) {
      // transforming the cache will trigger a call to `_cacheDidTransform`,
      // which will then trigger `didTransform`
      inverse = this._cache.transform(operation);

    } else if (operation.op === 'replace') {
      // try adding instead of replacing if the cache does not yet contain
      // the data
      operation.op = 'add';
      inverse = this._transformCache(operation);

    } else {
      // if the cache can't be transformed because, still trigger `didTransform`
      //
      // NOTE: this is not an error condition, since the local cache will often
      // be sparsely populated compared with the remote store
      inverse = [];
    }

    this.didTransform(operation, []);
  },

  _resourceIdURLSegment: function(type, id) {
    var resourceId = this.serializer.resourceId(type, id);
    if (isArray(resourceId)) {
      resourceId = resourceId.join(',');
    }
    return resourceId;
  },

  /////////////////////////////////////////////////////////////////////////////
  // Publicly accessible methods particular to JSONAPISource
  /////////////////////////////////////////////////////////////////////////////

  ajax: function(url, method, hash) {
    var _this = this;

    return new Orbit.Promise(function(resolve, reject) {
      hash = hash || {};
      hash.url = url;
      hash.type = method;
      hash.dataType = 'json';
      hash.context = _this;

      // console.log('ajax start', method, url);

      if (hash.data && method !== 'GET') {
        if (!hash.contentType) {
          hash.contentType = _this.ajaxContentType(hash);
        }
        hash.data = JSON.stringify(hash.data);
      }

      if (_this.ajaxHeaders) {
        var headers = _this.ajaxHeaders();
        hash.beforeSend = function (xhr) {
          for (var key in headers) {
            if (headers.hasOwnProperty(key)) {
              xhr.setRequestHeader(key, headers[key]);
            }
          }
        };
      }

      hash.success = function(json) {
        // console.log('ajax success', method, json);
        resolve(json);
      };

      hash.error = function(jqXHR, textStatus, errorThrown) {
        if (jqXHR) {
          jqXHR.then = null;
        }
        // console.log('ajax error', method, jqXHR);

        reject(jqXHR);
      };

      Orbit.ajax(hash);
    });
  },

  ajaxContentType: function(url, method) {
    return 'application/vnd.api+json; charset=utf-8';
  },

  ajaxHeaders: function() {
    return this.headers;
  },

  resourceNamespace: function(type) {
    return this.namespace;
  },

  resourceHost: function(type) {
    return this.host;
  },

  resourcePath: function(type, id) {
    var path = [this.serializer.resourceType(type)];
    if (id) {
      path.push(this._resourceIdURLSegment(type, id));
    }
    return path.join('/');
  },

  resourceURL: function(type, id) {
    var host = this.resourceHost(type),
        namespace = this.resourceNamespace(type),
        url = [];

    if (host) { url.push(host); }
    if (namespace) { url.push(namespace); }
    url.push(this.resourcePath(type, id));

    url = url.join('/');
    if (!host) { url = '/' + url; }

    return url;
  },

  resourceLinkURL: function(type, id, link, relId) {
    var url = this.resourceURL(type, id);
    url += '/relationships/' + this.serializer.resourceLink(type, link);

    if (relId) {
      var linkDef = this.schema.linkDefinition(type, link);

      url += '/' + this._resourceIdURLSegment(linkDef.model, relId);
    }

    return url;
  },

  resourceLinkedURL: function(type, id, link) {
    var url = this.resourceURL(type, id);
    url += '/' + this.serializer.resourceLink(type, link);
    return url;
  },

  deserialize: function(type, id, data, parentOperation) {
    var records = this.serializer.deserialize(type, id, data);
    var primaryRecords = records.primary;

    // Create a new parent operation, if necessary, to ensure that subsequent
    // operations are related and will be settled together in the same
    // transformation.
    //
    // Note: this parent operation is not actually performed on this source.
    // It is only created to establish a common ancestor.
    if (!parentOperation) {
      parentOperation = new Operation();
    }

    if (this._cache) {
      if (isArray(primaryRecords)) {
        this._addRecordsToCache(type, primaryRecords, parentOperation);
      } else {
        this._addRecordToCache(type, primaryRecords, parentOperation);
      }

      if (records.included) {
        Object.keys(records.included).forEach(function(relType) {
          var relRecords = records.included[relType];
          this._addRecordsToCache(relType, relRecords, parentOperation);
        }, this);
      }
    }

    return primaryRecords;
  }
});<|endoftext|>


<commit_before>/**
 * @author Gilles Coomans <gilles.coomans@gmail.com>
 * DOM only.
 * Container : The missing DOM node's type : a simple virtual nodes container that could (un)mounted somewhere in other dom nodes.
 */
var utils = require('../../utils'),
	Emitter = require('../../emitter');
var Container = function(parent) {
	this.__yContainer__ = true;
	this.parent = parent;
	this.childNodes = [];
};

Container.prototype = new Emitter();

var proto = {
	appendChildrenToFragment: function(frag, parentNode, mounted) {
		this.parentNode = parentNode;
		if (this.witness)
			frag.appendChild(this.witness);
		if (mounted)
			mounted.push(this);
		for (var i = 0, len = this.childNodes.length; i < len; ++i) {
			var child = this.childNodes[i];
			if (child.__yContainer__)
				child.appendChildrenToFragment(frag, parentNode, mounted);
			else
				frag.appendChild(child);
		}
		return this;
	},
	empty: function() {
		utils.destroyChildren(this.childNodes, true);
		this.childNodes = [];
		return this;
	},
	mount: function(node) {
		if (typeof node === 'string')
			node = document.querySelector(node);
		if (this.mounted && node === this.parentNode) {
			if (this.closing && this.transitionIn)
				this.transitionIn();
			return this;
		}
		utils.emptyNode(node);
		return this.appendTo(node);
	},
	appendTo: function(parent) {
		var par = parent;
		if (typeof parent === 'string')
			parent = document.querySelector(parent);
		if (this.mounted && parent === this.parentNode) {
			if (this.closing && this.transitionIn)
				this.transitionIn();
			return this;
		}
		this.mounted = true;
		if (!parent)
			throw new Error('could not mount container : no parent found with ' + par);
		if (parent.__yContainer__)
			parent.appendChild(this);
		else {
			if (this.witness)
				parent.appendChild(this.witness);
			this.parentNode = parent;
			for (var i = 0, len = this.childNodes.length; i < len; ++i) {
				var child = this.childNodes[i];
				if (child.__yContainer__)
					child.appendTo(parent);
				else
					parent.appendChild(child);
			}
		}
		this.emit('mounted', this);
		return this;
	},
	insertBeforeNode: function(node) {
		if (!node.parentNode)
			throw new Error('insertBeforeNode error : given node has no parent.');
		this.mounted = true;
		var frag = document.createDocumentFragment(),
			mounted = [];
		this.appendChildrenToFragment(frag, node.parentNode, mounted);
		node.parentNode.insertBefore(frag, node);
		for (var i = 0, len = mounted.length; i < len; ++i)
			mounted[i].emit('mounted', this);
		return this;
	},
	setWitness: function(witness) {
		this.witness = witness;
	},
	addWitness: function(title, parent) {
		if (this.witness)
			return this;
		this.witness = document.createComment(title);
		if (parent) {
			parent.appendChild(this.witness);
			return this;
		}
		if (!this.parentNode)
			return this;
		if (!this.childNodes.length) {
			console.warn('addWitness : container has been mounted without witness and children. Appending witness in parent.', this);
			this.parentNode.appendChild(this.witness);
		} else
			this.parentNode.insertBefore(this.witness, this.firstChild);
		return this;
	},
	removeWitness: function() {
		if (!this.witness)
			return this;
		if (this.witness.parentNode)
			this.witness.parentNode.removeChild(this.witness);
		this.witness = null;
		return this;
	},
	remount: function() {
		if (!this.witness.parentNode)
			throw new Error('container could not be remounted : witness has been unmounted.');
		if (this.mounted)
			if (this.closing && this.transitionIn) {
				this.transitionIn();
				return this;
			}
		var nextSibling = this.witness.nextSibling;
		if (nextSibling)
			this.insertBeforeNode(nextSibling);
		else
			this.appendTo(this.witness.parentNode);
		return this;
	},
	doUnmount: function(keepWitness) {
		this.mounted = false;
		if (!this.parentNode)
			return this;
		if (this.witness && !keepWitness)
			this.parentNode.removeChild(this.witness);
		for (var i = 0, len = this.childNodes.length; i < len; ++i) {
			var child = this.childNodes[i];
			if (child.__yContainer__)
				child.doUnmount();
			else if (child.parentNode)
				child.parentNode.removeChild(child);
		}
		this.parentNode = null;
		this.emit('unmounted', this);
		return this;
	},
	unmount: function(keepWitness) {
		if (!this.parentNode) // container hasn't been mounted
			return this;
		if (!this._beforeUnmount)
			return this.doUnmount(keepWitness);
		var self = this;
		this._beforeUnmount(function() {
			self.doUnmount(keepWitness);
		});
		return this;
	},
	appendChild: function(child) {
		if (this.parentNode) { // container has been mounted
			var nextSibling = this.nextSibling;
			if (nextSibling) {
				if (child.__yContainer__)
					child.insertBeforeNode(nextSibling);
				else
					this.parentNode.insertBefore(child, nextSibling);
			} else if (child.__yContainer__)
				child.appendTo(this.parentNode);
			else
				this.parentNode.appendChild(child);
		}
		this.childNodes.push(child);
		return this;
	},
	removeChild: function(child) {
		if (typeof child === 'number') {
			var index = child;
			child = this.childNodes[index];
			if (!child)
				throw new Error('container.removeChild not found : ', index);
			this.childNodes.splice(index, 1);
		} else
			utils.array.remove(this.childNodes, child);
		if (this.parentNode) { // container has been mounted
			if (child.__yContainer__)
				child.unmount();
			else
				this.parentNode.removeChild(child);
		}
		return this;
	},
	destroyer: function() {
		var self = this;
		return function() {
			self.destroy();
		};
	},
	destroy: function() {
		this.emit('destroy', this);
		utils.destroyElement(this, true);
		this.destroyed = true;
		this.comment = null;
		this.parentNode = null;
	},
	hide: function() {
		this.childNodes.forEach(function(child) {
			if (child.__yContainer__)
				return child.hide();
			if (child.style)
				child.style.display = 'none';
		});
		return this;
	},
	show: function() {
		this.childNodes.forEach(function(child) {
			if (child.__yContainer__)
				return child.show();
			if (child.style)
				child.style.display = '';
		});
		return this;
	},
	beforeUnmount: function(handler) {
		this._beforeUnmount = handler;
	}
};

Object.defineProperty(Container.prototype, "nextSibling", {
	get: function() {
		if (!this.childNodes.length && this.witness)
			return this.witness.nextSibling;
		if (!this.parentNode)
			return null;
		var last = this.childNodes[this.childNodes.length - 1];
		if (last)
			return last.nextSibling;
		return null;
	}
});
Object.defineProperty(Container.prototype, "firstChild", {
	get: function() {
		var first = this.childNodes[0];
		if (first)
			if (first.__yContainer__)
				return first.firstChild;
			else
				return first;
		return null;
	}
});
Object.defineProperty(Container.prototype, "lastChild", {
	get: function() {
		var last = this.childNodes[this.childNodes.length - 1];
		if (last)
			if (last.__yContainer__)
				return last.lastChild;
			else
				return last;
		return null;
	}
});
utils.shallowMerge(proto, Container.prototype);

module.exports = Container;
<commit_msg>Container : unmount : add "done" management<commit_after>/**
 * @author Gilles Coomans <gilles.coomans@gmail.com>
 * DOM only.
 * Container : The missing DOM node's type : a simple virtual nodes container that could (un)mounted somewhere in other dom nodes.
 */
var utils = require('../../utils'),
	Emitter = require('../../emitter');
var Container = function(parent) {
	this.__yContainer__ = true;
	this.parent = parent;
	this.childNodes = [];
};

Container.prototype = new Emitter();

var proto = {
	appendChildrenToFragment: function(frag, parentNode, mounted) {
		this.parentNode = parentNode;
		if (this.witness)
			frag.appendChild(this.witness);
		if (mounted)
			mounted.push(this);
		for (var i = 0, len = this.childNodes.length; i < len; ++i) {
			var child = this.childNodes[i];
			if (child.__yContainer__)
				child.appendChildrenToFragment(frag, parentNode, mounted);
			else
				frag.appendChild(child);
		}
		return this;
	},
	empty: function() {
		utils.destroyChildren(this.childNodes, true);
		this.childNodes = [];
		return this;
	},
	mount: function(node) {
		if (typeof node === 'string')
			node = document.querySelector(node);
		if (this.mounted && node === this.parentNode) {
			if (this.closing && this.transitionIn)
				this.transitionIn();
			return this;
		}
		utils.emptyNode(node);
		return this.appendTo(node);
	},
	appendTo: function(parent) {
		var par = parent;
		if (typeof parent === 'string')
			parent = document.querySelector(parent);
		if (this.mounted && parent === this.parentNode) {
			if (this.closing && this.transitionIn)
				this.transitionIn();
			return this;
		}
		this.mounted = true;
		if (!parent)
			throw new Error('could not mount container : no parent found with ' + par);
		if (parent.__yContainer__)
			parent.appendChild(this);
		else {
			if (this.witness)
				parent.appendChild(this.witness);
			this.parentNode = parent;
			for (var i = 0, len = this.childNodes.length; i < len; ++i) {
				var child = this.childNodes[i];
				if (child.__yContainer__)
					child.appendTo(parent);
				else
					parent.appendChild(child);
			}
		}
		this.emit('mounted', this);
		return this;
	},
	insertBeforeNode: function(node) {
		if (!node.parentNode)
			throw new Error('insertBeforeNode error : given node has no parent.');
		this.mounted = true;
		var frag = document.createDocumentFragment(),
			mounted = [];
		this.appendChildrenToFragment(frag, node.parentNode, mounted);
		node.parentNode.insertBefore(frag, node);
		for (var i = 0, len = mounted.length; i < len; ++i)
			mounted[i].emit('mounted', this);
		return this;
	},
	setWitness: function(witness) {
		this.witness = witness;
	},
	addWitness: function(title, parent) {
		if (this.witness)
			return this;
		this.witness = document.createComment(title);
		if (parent) {
			parent.appendChild(this.witness);
			return this;
		}
		if (!this.parentNode)
			return this;
		if (!this.childNodes.length) {
			console.warn('addWitness : container has been mounted without witness and children. Appending witness in parent.', this);
			this.parentNode.appendChild(this.witness);
		} else
			this.parentNode.insertBefore(this.witness, this.firstChild);
		return this;
	},
	removeWitness: function() {
		if (!this.witness)
			return this;
		if (this.witness.parentNode)
			this.witness.parentNode.removeChild(this.witness);
		this.witness = null;
		return this;
	},
	remount: function() {
		if (!this.witness.parentNode)
			throw new Error('container could not be remounted : witness has been unmounted.');
		if (this.mounted)
			if (this.closing && this.transitionIn) {
				this.transitionIn();
				return this;
			}
		var nextSibling = this.witness.nextSibling;
		if (nextSibling)
			this.insertBeforeNode(nextSibling);
		else
			this.appendTo(this.witness.parentNode);
		return this;
	},
	doUnmount: function(keepWitness) {
		this.mounted = false;
		if (!this.parentNode)
			return this;
		if (this.witness && !keepWitness)
			this.parentNode.removeChild(this.witness);
		for (var i = 0, len = this.childNodes.length; i < len; ++i) {
			var child = this.childNodes[i];
			if (child.__yContainer__)
				child.doUnmount();
			else if (child.parentNode)
				child.parentNode.removeChild(child);
		}
		this.parentNode = null;
		this.emit('unmounted', this);
		return this;
	},
	unmount: function(keepWitness, done) {
		if (!this.parentNode) // container hasn't been mounted
			return this;
		if (!this._beforeUnmount) {
			this.doUnmount(keepWitness);
			if (done)
				done(this);
			return this;
		}
		var self = this;
		this._beforeUnmount(function() {
			self.doUnmount(keepWitness);
			if (done)
				done(self);
		});
		return this;
	},
	appendChild: function(child) {
		if (this.parentNode) { // container has been mounted
			var nextSibling = this.nextSibling;
			if (nextSibling) {
				if (child.__yContainer__)
					child.insertBeforeNode(nextSibling);
				else
					this.parentNode.insertBefore(child, nextSibling);
			} else if (child.__yContainer__)
				child.appendTo(this.parentNode);
			else
				this.parentNode.appendChild(child);
		}
		this.childNodes.push(child);
		return this;
	},
	removeChild: function(child) {
		if (typeof child === 'number') {
			var index = child;
			child = this.childNodes[index];
			if (!child)
				throw new Error('container.removeChild not found : ', index);
			this.childNodes.splice(index, 1);
		} else
			utils.array.remove(this.childNodes, child);
		if (this.parentNode) { // container has been mounted
			if (child.__yContainer__)
				child.unmount();
			else
				this.parentNode.removeChild(child);
		}
		return this;
	},
	destroyer: function() {
		var self = this;
		return function() {
			self.destroy();
		};
	},
	destroy: function() {
		this.emit('destroy', this);
		utils.destroyElement(this, true);
		this.destroyed = true;
		this.comment = null;
		this.parentNode = null;
	},
	hide: function() {
		this.childNodes.forEach(function(child) {
			if (child.__yContainer__)
				return child.hide();
			if (child.style)
				child.style.display = 'none';
		});
		return this;
	},
	show: function() {
		this.childNodes.forEach(function(child) {
			if (child.__yContainer__)
				return child.show();
			if (child.style)
				child.style.display = '';
		});
		return this;
	},
	beforeUnmount: function(handler) {
		this._beforeUnmount = handler;
	}
};

Object.defineProperty(Container.prototype, "nextSibling", {
	get: function() {
		if (!this.childNodes.length && this.witness)
			return this.witness.nextSibling;
		if (!this.parentNode)
			return null;
		var last = this.childNodes[this.childNodes.length - 1];
		if (last)
			return last.nextSibling;
		return null;
	}
});
Object.defineProperty(Container.prototype, "firstChild", {
	get: function() {
		var first = this.childNodes[0];
		if (first)
			if (first.__yContainer__)
				return first.firstChild;
			else
				return first;
		return null;
	}
});
Object.defineProperty(Container.prototype, "lastChild", {
	get: function() {
		var last = this.childNodes[this.childNodes.length - 1];
		if (last)
			if (last.__yContainer__)
				return last.lastChild;
			else
				return last;
		return null;
	}
});
utils.shallowMerge(proto, Container.prototype);

module.exports = Container;
<|endoftext|>


<commit_before>module.exports = HttpConnection;

var request = require('requestretry');
var HttpConfig = require("./HttpConfig");
var PaymayaApiError = require("./PaymayaApiError");

function HttpConnection(httpConfig) {
	this._httpConfig = httpConfig;
};

HttpConnection.prototype = {

	/* PUBLIC FUNCTIONS */
	execute: function(data, callback) {
		var httpOptions = {
		  url: this._httpConfig.getUrl(),
		  method: this._httpConfig.getMethod(),
		  headers: this._httpConfig.getHeaders(),
		  maxAttempts: this._httpConfig.getMaximumRequestAttempt()
		};

		if(data) {
		  httpOptions['body'] = JSON.stringify(data);
		}

		request(httpOptions, function(err, response, body) {
		  if(err) {
		    return callback(err);
		  }

		  if(!body && response.statusCode >= 400) {
		    var err = new PaymayaApiError(response.statusCode);
		    return callback(err);
		  }

		  if(typeof body != 'object') {
		    body = JSON.parse(body);
		  }

		  if(body.error) {
		    var err = new PaymayaApiError(response.statusCode, body.error);
		    return callback(err.message);
		  }

		  if(body.message && response.statusCode != 200) {
		  	return callback(body.message);
		  }

		  callback(null, body);
		});
	}
};<commit_msg>Change duplicate variable<commit_after>module.exports = HttpConnection;

var request = require('requestretry');
var HttpConfig = require("./HttpConfig");
var PaymayaApiError = require("./PaymayaApiError");

function HttpConnection(httpConfig) {
	this._httpConfig = httpConfig;
};

HttpConnection.prototype = {

	/* PUBLIC FUNCTIONS */
	execute: function(data, callback) {
		var httpOptions = {
		  url: this._httpConfig.getUrl(),
		  method: this._httpConfig.getMethod(),
		  headers: this._httpConfig.getHeaders(),
		  maxAttempts: this._httpConfig.getMaximumRequestAttempt()
		};

		if(data) {
		  httpOptions['body'] = JSON.stringify(data);
		}

		request(httpOptions, function(err, response, body) {
		  if(err) {
		    return callback(err);
		  }

		  if(!body && response.statusCode >= 400) {
		    var err = new PaymayaApiError(response.statusCode);
		    return callback(err);
		  }

		  if(typeof body != 'object') {
		    body = JSON.parse(body);
		  }

		  if(body.error) {
		    var paymayaApiError = new PaymayaApiError(response.statusCode, body.error);
		    return callback(paymayaApiError.message);
		  }

		  if(body.message && response.statusCode != 200) {
		  	return callback(body.message);
		  }

		  callback(null, body);
		});
	}
};<|endoftext|>


<commit_before>// Copyright 2020 Google LLC

// 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

//     https://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.

function fetchMealInfo() {
    fetch('/meal-info').then(response => response.json()).then((meal) =>
    {
        const { title, description, ingredients } = meal;
        const titleElement = document.getElementById("title");
        titleElement.innerText = title;
        const descriptionElement = document.getElementById("description");
        descriptionElement.innerText = description;
        const ingredientsElement = document.getElementById("ingredients");
        for (const ingredient of ingredients) {
            ingredientsElement.appendChild(createElementByTag(ingredient, 'li'));
        }
        createMap();
    });
}

function createElementByTag(text, tag) {
  const element = document.createElement(tag);
  element.innerText = text;
  return element;
}

/** Creates a map and adds it to the page. */
function createMap() {
  const userLocation = new google.maps.LatLng(55.746514, 37.627022);
  const mapOptions = {
    zoom: 16,
    center: userLocation
  };
  const map = new google.maps.Map(document.getElementById("map"), mapOptions);
  // TODO(grenlayk): implement real geolocation here
  // TODO(grenlayk): change "You are here" marker on custom one
  const locationMarker = new google.maps.Marker({
    position: userLocation,
    map,
    title: "You are here",
    animation: google.maps.Animation.DROP,
  });
  // TODO(grenlayk): implement restaurants search here
}<commit_msg>Add encoding check<commit_after>// Copyright 2020 Google LLC

// 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

//     https://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.

function fetchMealInfo() {
    fetch('/meal-info').then(response => response.json()).then((meal) =>
    {
        const { title, description, ingredients } = meal;
        const titleElement = document.getElementById("title");
        titleElement.innerText = encodingCheck(title);
        const descriptionElement = document.getElementById("description");
        descriptionElement.innerText = encodingCheck(description);
        const ingredientsElement = document.getElementById("ingredients");
        for (const ingredient of ingredients) {
            ingredientsElement.appendChild(createElementByTag(encodingCheck(ingredient), 'li'));
        }
        createMap();
    });
}

function encodingCheck(string) {
    return JSON.parse(JSON.stringify(string));
}

function createElementByTag(text, tag) {
  const element = document.createElement(tag);
  element.innerText = text;
  return element;
}

/** Creates a map and adds it to the page. */
function createMap() {
  const userLocation = new google.maps.LatLng(55.746514, 37.627022);
  const mapOptions = {
    zoom: 16,
    center: userLocation
  };
  const map = new google.maps.Map(document.getElementById("map"), mapOptions);
  // TODO(grenlayk): implement real geolocation here
  // TODO(grenlayk): change "You are here" marker on custom one
  const locationMarker = new google.maps.Marker({
    position: userLocation,
    map,
    title: "You are here",
    animation: google.maps.Animation.DROP,
  });
  // TODO(grenlayk): implement restaurants search here
}<|endoftext|>