UNPKG

jsdav-ext

Version:

jsDAV allows you to easily add WebDAV support to a NodeJS application. jsDAV is meant to cover the entire standard, and attempts to allow integration using an easy to understand API.

260 lines (250 loc) 9.38 kB
/* vim:set ts=4 sw=4 sts=4 expandtab */ /*jshint undef: true es5: true node: true devel: true evil: true forin: true latedef: false supernew: true */ /*global define: true */ "use strict"; var UUID_INCR = 0; function binarySearchBitshift(list, val) { var min = 0; var max = list.length - 1; for(;;) { // fall back to linear search, 11 seems to be a good threshold, but this // depends on the uses comparator!! (here: ===) if (min + 11 > max) { for (var i = min; i <= max; ++i) { if (val === list[i]) { return i; } } return -1; } var mid = (min + max) >> 1; var dat = list[mid]; if (val === dat) return mid; if (val > dat) min = mid + 1; else max = mid - 1; } }; var Base = module.exports = Object.freeze(Object.create(Object.prototype, { UUID: { value: UUID_INCR }, UUIDS: { value: [UUID_INCR] }, /** * Creates an object that inherits from `this` object (Analog of * `new Object()`). * * Example: * var Dog = Base.extend({ * bark: function bark() { * return "Ruff! Ruff!"; * } * }); * var dog = Dog.new(); * * @type {Object} */ "new": { value: function create() { var object = Object.create(this); object.initialize.apply(object, arguments); return object; } }, /** * When new instance of the this prototype is created it's `initialize` * method is called with all the arguments passed to the `new`. You can * override `initialize` to set up an instance. * * @type {mixed} */ initialize: { value: function initialize() {} }, /** * Merges all the properties of the passed objects into `this` instance (This * method can be used on instances only as prototype objects are frozen). * * If two or more argument objects have own properties with the same name, * the property is overridden, with precedence from right to left, implying, * that properties of the object on the left are overridden by a same named * property of the object on the right. * * Example: * var Pet = Dog.extend({ * initialize: function initialize(options) { * // this.name = options.name -> would have thrown (frozen prototype) * this.merge(options) // will override all properties. * }, * call: function(name) { * return this.name === name ? this.bark() : ""; * }, * name: null * }); * var pet = Pet.new({ name: "Pippa", breed: "Jack Russell" }); * pet.call("Pippa"); // 'Ruff! Ruff!' * * @param {Object} [obj1] override prototype's properties with the values in this object * @type {void} */ merge: { value: function merge() { var descriptor = {}; var uuids = Array.isArray(this.UUIDS) ? [].concat(this.UUIDS) : [this.UUID]; Array.prototype.forEach.call(arguments, function(properties) { // Make sure the merged-in object has a UUID if (!properties.hasOwnProperty("UUID")) { properties.UUID = ++UUID_INCR; if (!properties.UUIDS) properties.UUIDS = []; properties.UUIDS.push(properties.UUID); } // Copy the object properties over Object.getOwnPropertyNames(properties).forEach(function(name) { if (name == "UUIDS") { properties[name].forEach(function(uuid) { if (binarySearchBitshift(uuids, uuid) == -1) uuids.push(uuid); }); // Keep the list sorted at all times (binary search) uuids.sort(function (a, b) { return a - b; }); } else descriptor[name] = Object.getOwnPropertyDescriptor(properties, name); }); }); var base = ++UUID_INCR; descriptor.UUID = { value: base }; uuids.push(base); descriptor.UUIDS = { value: uuids }; Object.defineProperties(this, descriptor); return this; } }, /** * Takes any number of argument objects and returns frozen, composite object * that inherits from `this` object and combines all of the own properties of * the argument objects. (Objects returned by this function are frozen as * they are intended to be used as types). * * If two or more argument objects have own properties with the same name, * the property is overridden, with precedence from right to left, implying, * that properties of the object on the left are overridden by a same named * property of the object on the right. * * Example: * // ### Object composition ### * * var HEX = Base.extend({ * hex: function hex() { * return "#" + this.color; * } * }); * * var RGB = Base.extend({ * red: function red() { * return parseInt(this.color.substr(0, 2), 16); * }, * green: function green() { * return parseInt(this.color.substr(2, 2), 16); * }, * blue: function blue() { * return parseInt(this.color.substr(4, 2), 16); * } * }); * * var CMYK = Base.extend(RGB, { * black: function black() { * var color = Math.max(Math.max(this.red(), this.green()), this.blue()); * return (1 - color / 255).toFixed(4); * }, * cyan: function cyan() { * var K = this.black(); * return (((1 - this.red() / 255).toFixed(4) - K) / (1 - K)).toFixed(4); * }, * magenta: function magenta() { * var K = this.black(); * return (((1 - this.green() / 255).toFixed(4) - K) / (1 - K)).toFixed(4); * }, * yellow: function yellow() { * var K = this.black(); * return (((1 - this.blue() / 255).toFixed(4) - K) / (1 - K)).toFixed(4); * } * }); * * var Color = Base.extend(HEX, RGB, CMYK, { * initialize: function Color(color) { * this.color = color; * } * }); * * // ### Prototypal inheritance ### * * var Pixel = Color.extend({ * initialize: function Pixel(x, y, hex) { * Color.initialize.call(this, hex); * this.x = x; * this.y = y; * }, * toString: function toString() { * return this.x + ":" + this.y + "@" + this.hex(); * } * }); * * var pixel = Pixel.new(11, 23, "CC3399"); * pixel.toString(); // 11:23@#CC3399 * * pixel.red(); // 204 * pixel.green(); // 51 * pixel.blue(); // 153 * * pixel.cyan(); // 0.0000 * pixel.magenta(); // 0.7500 * pixel.yellow(); // 0.2500 * * @param {Object} obj1 extend object's properties with the values in this object */ extend: { value: function extend() { return this.merge.apply(Object.create(this), arguments); } }, /** * Checks if an object was merged with this object, using Base.extend() or * Base#merge(). Each object that was merged in at least once carries a * signature in the shape of a bitflag. * * Example: * To continue with the example provided by Base.extend(): * * // an instance of Color should contain the following objects: * var color = Color.new("CC3399"); * color.hasFeature(HEX); // true * color.hasFeature(RGB); // true * color.hasFeature(CMYK); // true * color.hasFeature(Pixel); // false * * // an instance of Pixel should contain the following objects: * var pixel = Pixel.new(11, 23, "CC3399"); * pixel.hasFeature(HEX); // true * pixel.hasFeature(RGB); // true * pixel.hasFeature(CMYK); // true * pixel.hasFeature(Color); // true * * @param {Object} obj1: check if this object is part of this object */ hasFeature: { value: function hasFeature(base) { return typeof base.UUID != "undefined" && binarySearchBitshift(this.UUIDS, base.UUID) != -1; } } }));