1 /*
  2  * Copyright ©2012 SARA bv, The Netherlands
  3  *
  4  * This file is part of js-webdav-client.
  5  *
  6  * js-webdav-client is free software: you can redistribute it and/or modify
  7  * it under the terms of the GNU Lesser General Public License as published
  8  * by the Free Software Foundation, either version 3 of the License, or
  9  * (at your option) any later version.
 10  *
 11  * js-webdav-client is distributed in the hope that it will be useful,
 12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14  * GNU Lesser General Public License for more details.
 15  *
 16  * You should have received a copy of the GNU Lesser General Public License
 17  * along with js-webdav-client.  If not, see <http://www.gnu.org/licenses/>.
 18  */
 19 "use strict";
 20 
 21 // If nl.sara.webdav.Privilege is already defined, we have a namespace clash!
 22 if (nl.sara.webdav.Privilege !== undefined) {
 23   throw new nl.sara.webdav.Exception('Namespace nl.sara.webdav.Privilege already taken, could not load JavaScript library for WebDAV connectivity.', nl.sara.webdav.Exception.NAMESPACE_TAKEN);
 24 }
 25 
 26 /**
 27  * @class WebDAV ACL privilege
 28  *
 29  * @param  {Node}  [xmlNode]  Optional; the xmlNode describing the privilege object
 30  * @property  {String}    namespace  The namespace
 31  * @property  {String}    tagname    The tag name
 32  * @property  {NodeList}  xmlvalue   A NodeList with the value of this privilege
 33  */
 34 nl.sara.webdav.Privilege = function(xmlNode) {
 35   // First define private attributes
 36   Object.defineProperty(this, '_xmlvalue', {
 37     'value': null,
 38     'enumerable': false,
 39     'configurable': false,
 40     'writable': true
 41   });
 42   // Second define public attributes
 43   Object.defineProperty(this, 'namespace', {
 44     'value': null,
 45     'enumerable': true,
 46     'configurable': false,
 47     'writable': true
 48   });
 49   Object.defineProperty(this, 'tagname', {
 50     'value': null,
 51     'enumerable': true,
 52     'configurable': false,
 53     'writable': true
 54   });
 55 
 56   // Constructor logic
 57   if (typeof xmlNode !== 'undefined') {
 58     this.namespace = xmlNode.namespaceURI;
 59     this.tagname = nl.sara.webdav.Ie.getLocalName(xmlNode);
 60     this.xmlvalue = xmlNode.childNodes;
 61   }
 62 };
 63 
 64 //######################### DEFINE PUBLIC ATTRIBUTES ###########################
 65 (function() {
 66   // This creates a (private) static variable. It will contain all codecs
 67   var codecNamespaces = {};
 68 
 69   Object.defineProperty(nl.sara.webdav.Privilege.prototype, 'xmlvalue', {
 70     'set': function(value) {
 71       if (value === null) {
 72         this._xmlvalue = null;
 73         return;
 74       }
 75       if (!nl.sara.webdav.Ie.isIE && !(value instanceof NodeList)) {
 76         throw new nl.sara.webdav.Exception('xmlvalue must be an instance of NodeList', nl.sara.webdav.Exception.WRONG_TYPE);
 77       }
 78       this._xmlvalue = value;
 79     },
 80     'get': function() {
 81       return this._xmlvalue;
 82     }
 83   });
 84 
 85 //########################## DEFINE PUBLIC METHODS #############################
 86   /**
 87    * Adds functions to encode or decode properties
 88    *
 89    * This allows exact control in how Privilege.xmlvalue is parsed when
 90    * getParsedValue() is called and how XML is rebuild when
 91    * setValueAndRebuildXml() is called. You can specify two functions: 'fromXML
 92    * and 'toXML'. These should be complementary. That is, toXML should be able
 93    * to create a NodeList based on the output of fromXML. For example:
 94    * A == toXML(fromXML(A)) &&
 95    * B == fromXML(toXML(B))
 96    *
 97    * @param    {nl.sara.webdav.Codec}  codec  The codec to add
 98    * @returns  {void}
 99    */
100   nl.sara.webdav.Privilege.addCodec = function(codec) {
101     if (typeof codec.namespace !== 'string') {
102       throw new nl.sara.webdav.Exception('addCodec: codec.namespace must be a String', nl.sara.webdav.Exception.WRONG_TYPE);
103     }
104     if (typeof codec.tagname !== 'string') {
105       throw new nl.sara.webdav.Exception('addCodec: codec.tagname must be a String', nl.sara.webdav.Exception.WRONG_TYPE);
106     }
107     if (codecNamespaces[codec.namespace] === undefined) {
108       codecNamespaces[codec.namespace] = {};
109     }
110     codecNamespaces[codec.namespace][codec.tagname] = {
111       'fromXML': (codec.fromXML ? codec.fromXML : undefined),
112       'toXML': (codec.toXML ? codec.toXML : undefined)
113     };
114   };
115 
116   /**
117    * Sets a new value and rebuilds xmlvalue
118    *
119    * If a codec for this privilege is specified, it will use this codec to
120    * rebuild xmlvallue. Else it will attempt to create one CDATA element with
121    * the string value of whatever was fiven as parameter.
122    *
123    * @param   {mixed}  value  The object to base the xmlvalue on
124    * @return  {void}
125    */
126   nl.sara.webdav.Privilege.prototype.setValueAndRebuildXml = function(value) {
127     // Call codec to automatically create correct 'xmlvalue'
128     var xmlDoc = document.implementation.createDocument(this.namespace, this.tagname, null);
129     if ((codecNamespaces[this.namespace] === undefined) ||
130         (codecNamespaces[this.namespace][this.tagname] === undefined) ||
131         (codecNamespaces[this.namespace][this.tagname]['toXML'] === undefined)) {
132       // No 'toXML' function set, so create a NodeList with just one CDATA node
133       if (value !== null) { // If the value is NULL, then we should add anything to the NodeList
134         var cdata = xmlDoc.createCDATASection(value);
135         xmlDoc.documentElement.appendChild(cdata);
136       }
137       this._xmlvalue = xmlDoc.documentElement.childNodes;
138     }else{
139       this._xmlvalue = codecNamespaces[this.namespace][this.tagname]['toXML'](value, xmlDoc).documentElement.childNodes;
140     }
141   };
142 
143   /**
144    * Parses the xmlvalue
145    *
146    * If a codec for this privilege is specified, it will use this codec to parse
147    * the XML nodes. Else it will attempt to parse it as text or CDATA elements.
148    *
149    * @return  {mixed}  If a codec is specified, the return type depends on that
150    * codec. If no codec is specified and at least one node in xmlvalue is not a
151    * text or CDATA node, it will return undefined. If xmlvalue is empty, it will
152    * return null.
153    */
154   nl.sara.webdav.Privilege.prototype.getParsedValue = function() {
155     // Call codec to automatically create correct 'value'
156     if (this._xmlvalue.length > 0) {
157       if ((codecNamespaces[this.namespace] === undefined) ||
158           (codecNamespaces[this.namespace][this.tagname] === undefined) ||
159           (codecNamespaces[this.namespace][this.tagname]['fromXML'] === undefined)) {
160         // No 'fromXML' function set, so try to create a text value based on TextNodes and CDATA nodes. If other nodes are present, set 'value' to null
161         var parsedValue = '';
162         for (var i = 0; i < this._xmlvalue.length; i++) {
163           var node = this._xmlvalue.item(i);
164           if ((node.nodeType === 3) || (node.nodeType === 4)) { // Make sure text and CDATA content is stored
165             parsedValue += node.nodeValue;
166           }else{ // If even one of the nodes is not text or CDATA, then we don't parse a text value at all
167             parsedValue = undefined;
168             break;
169           }
170         }
171         return parsedValue;
172       }else{
173         return codecNamespaces[this.namespace][this.tagname]['fromXML'](this._xmlvalue);
174       }
175     }
176     return null;
177   };
178 })(); // Ends the static scope
179 
180 /**
181  * Overloads the default toString() method so it returns the value of this privilege
182  *
183  * @returns  {String}  A string representation of this privilege
184  */
185 nl.sara.webdav.Privilege.prototype.toString = function() {
186   return this.getParsedValue();
187 };
188 
189 // End of library
190