1 /**
  2  * Copyright (C) 2012 KO GmbH <aditya.bhatt@kogmbh.com>
  3  *
  4  * @licstart
  5  * This file is part of WebODF.
  6  *
  7  * WebODF is free software: you can redistribute it and/or modify it
  8  * under the terms of the GNU Affero General Public License (GNU AGPL)
  9  * as published by the Free Software Foundation, either version 3 of
 10  * the License, or (at your option) any later version.
 11  *
 12  * WebODF is distributed in the hope that it will be useful, but
 13  * WITHOUT ANY WARRANTY; without even the implied warranty of
 14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15  * GNU Affero General Public License for more details.
 16  *
 17  * You should have received a copy of the GNU Affero General Public License
 18  * along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
 19  * @licend
 20  *
 21  * @source: http://www.webodf.org/
 22  * @source: https://github.com/kogmbh/WebODF/
 23  */
 24 
 25 /*global core*/
 26 
 27 /**
 28  * A collection of useful utility functions
 29  * @constructor
 30  */
 31 core.Utils = function Utils() {
 32     "use strict";
 33 
 34     /**
 35      * Simple string hash
 36      * Based off http://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript-jquery
 37      * @param {!string} value
 38      * @return {!number}
 39      */
 40     function hashString(value) {
 41         var hash = 0, i, l;
 42         for (i = 0, l = value.length; i < l; i += 1) {
 43             /*jslint bitwise:true*/
 44             hash = ((hash << 5) - hash) + value.charCodeAt(i);
 45             hash |= 0; // Convert to 32bit integer
 46             /*jslint bitwise:false*/
 47         }
 48         return hash;
 49     }
 50     this.hashString = hashString;
 51 
 52     var mergeObjects;
 53     /**
 54      * @param {*} destination
 55      * @param {*} source
 56      * @return {*}
 57      */
 58     function mergeItems(destination, source) {
 59         // Property in destination object set; update its value.
 60         if (source && Array.isArray(source)) {
 61             // create destination array if it does not exist yet
 62             destination = destination || [];
 63             if (!Array.isArray(destination)) {
 64                 throw "Destination is not an array.";
 65             }
 66             // An array will report as a type of object, but this is not able to
 67             // mapped using mergeObjects
 68             // The following will clone each individual item in the source array
 69             // and append them to the end of the destination array
 70             destination = /**@type{!Array.<*>}*/(destination).concat(
 71                 /**@type{!Array.<*>}*/(source).map(function (obj) {
 72                     return mergeItems(null, obj);
 73                 })
 74             );
 75         } else if (source && typeof source === 'object') {
 76             destination = destination || {};
 77             if (typeof destination !== 'object') {
 78                 throw "Destination is not an object.";
 79             }
 80             Object.keys(/**@type{!Object}*/(source)).forEach(function (p) {
 81                 destination[p] = mergeItems(destination[p], source[p]);
 82             });
 83         } else {
 84             destination = source;
 85         }
 86         return destination;
 87     }
 88     /**
 89      * Recursively merge properties of two objects
 90      * Merge behaviours for the object members are:
 91      *  array => array - Append clones of source array onto the end of the
 92      *                   destination array
 93      *  object => object - Map each individual key from source onto destination
 94      *                     (recursive, so these are clones)
 95      *  primitive => primitive - return primitive value
 96      *
 97      * @param {!Object.<string,*>} destination
 98      * @param {!Object.<string,*>} source
 99      * @return {!Object.<string,*>}
100      */
101     mergeObjects = function (destination, source) {
102         Object.keys(source).forEach(function (p) {
103             destination[p] = mergeItems(destination[p], source[p]);
104         });
105         return destination;
106     };
107     this.mergeObjects = mergeObjects;
108 };
109 
110