PNG  IHDR;IDATxܻn0K )(pA 7LeG{ §㻢|ذaÆ 6lذaÆ 6lذaÆ 6lom$^yذag5bÆ 6lذaÆ 6lذa{ 6lذaÆ `}HFkm,mӪôô! x|'ܢ˟;E:9&ᶒ}{v]n&6 h_tڠ͵-ҫZ;Z$.Pkž)!o>}leQfJTu іچ\X=8Rن4`Vwl>nG^is"ms$ui?wbs[m6K4O.4%/bC%t Mז -lG6mrz2s%9s@-k9=)kB5\+͂Zsٲ Rn~GRC wIcIn7jJhۛNCS|j08yiHKֶۛkɈ+;SzL/F*\Ԕ#"5m2[S=gnaPeғL lذaÆ 6l^ḵaÆ 6lذaÆ 6lذa; _ذaÆ 6lذaÆ 6lذaÆ RIENDB` /* * Copyright (c) 2015 * * This file is licensed under the Affero General Public License version 3 * or later. * * See the COPYING-README file. * */ /** * Webdav transport for Backbone. * * This makes it possible to use Webdav endpoints when * working with Backbone models and collections. * * Requires the davclient.js library. * * Usage example: * * var PersonModel = OC.Backbone.Model.extend({ * // make it use the DAV transport * sync: OC.Backbone.davSync, * * // DAV properties mapping * davProperties: { * 'id': '{http://example.com/ns}id', * 'firstName': '{http://example.com/ns}first-name', * 'lastName': '{http://example.com/ns}last-name', * 'age': '{http://example.com/ns}age' * }, * * // additional parsing, if needed * parse: function(props) { * // additional parsing (DAV property values are always strings) * props.age = parseInt(props.age, 10); * return props; * } * }); * * var PersonCollection = OC.Backbone.Collection.extend({ * // make it use the DAV transport * sync: OC.Backbone.davSync, * * // use person model * // note that davProperties will be inherited * model: PersonModel, * * // DAV collection URL * url: function() { * return OC.linkToRemote('dav') + '/person/'; * }, * }); */ /* global dav */ (function(Backbone) { var methodMap = { 'create': 'POST', 'update': 'PROPPATCH', 'patch': 'PROPPATCH', 'delete': 'DELETE', 'read': 'PROPFIND' }; // Throw an error when a URL is needed, and none is supplied. function urlError() { throw new Error('A "url" property or function must be specified'); } /** * Convert a single propfind result to JSON * * @param {Object} result * @param {Object} davProperties properties mapping */ function parsePropFindResult(result, davProperties) { if (_.isArray(result)) { return _.map(result, function(subResult) { return parsePropFindResult(subResult, davProperties); }); } var props = { href: result.href }; _.each(result.propStat, function(propStat) { if (propStat.status !== 'HTTP/1.1 200 OK') { return; } for (var key in propStat.properties) { var propKey = key; if (key in davProperties) { propKey = davProperties[key]; } props[propKey] = propStat.properties[key]; } }); if (!props.id) { // parse id from href props.id = parseIdFromLocation(props.href); } return props; } /** * Parse ID from location * * @param {string} url url * @return {string} id */ function parseIdFromLocation(url) { var queryPos = url.indexOf('?'); if (queryPos > 0) { url = url.substr(0, queryPos); } var parts = url.split('/'); var result; do { result = parts[parts.length - 1]; parts.pop(); // note: first result can be empty when there is a trailing slash, // so we take the part before that } while (!result && parts.length > 0); return decodeURIComponent(result); } function isSuccessStatus(status) { return status >= 200 && status <= 299; } function convertModelAttributesToDavProperties(attrs, davProperties) { var props = {}; var key; for (key in attrs) { var changedProp = davProperties[key]; var value = attrs[key]; if (!changedProp) { // no matching DAV property for property, skip continue; } if (_.isBoolean(value) || _.isNumber(value)) { // convert to string value = '' + value; } props[changedProp] = value; } return props; } function callPropFind(client, options, model, headers) { return client.propFind( options.url, _.values(options.davProperties) || [], options.depth, headers ).then(function(response) { if (isSuccessStatus(response.status)) { if (_.isFunction(options.success)) { var propsMapping = _.invert(options.davProperties); var results = parsePropFindResult(response.body, propsMapping); if (options.depth > 0) { // discard root entry results.shift(); } options.success(results); return; } } else if (_.isFunction(options.error)) { options.error(response); } }); } function callPropPatch(client, options, model, headers) { var changes = model.changed; if (options.wait && _.isEmpty(changes)) { // usually with "wait" mode, the changes aren't set yet, changes = options.data; // if options.patch is not set, then data contains all the data // instead of just the properties to patch if (!options.patch) { // remove reserved properties delete changes.href; delete changes[_.result(model, 'idAttribute')]; // note: there is no way to diff with previous values here so // we just send everything } } return client.propPatch( options.url, convertModelAttributesToDavProperties(changes, options.davProperties), headers ).then(function(result) { if (result.status === 207 && result.body && result.body.length > 0) { if (_.find(result.body[0].propStat, function(propStat) { var statusCode = parseInt(propStat.status.split(' ')[1], 10); return statusCode >= 400; })) { // in REST, validation errors are usually represented with 422 Unprocessable Entity, result.status = 422; } } if (isSuccessStatus(result.status)) { // with wait, we set the changes only after success if (options.wait) { model.set(changes, options); } if (_.isFunction(options.success)) { // pass the object's own values because the server // does not return the updated model options.success(model.toJSON()); } } else if (_.isFunction(options.error)) { options.error(result); } }); } function callMkCol(client, options, model, headers) { var props = convertModelAttributesToDavProperties(model.attributes, options.davProperties); if (!props['{DAV:}resourcetype']) { props['{DAV:}resourcetype'] = ''; } return client.mkcol( options.url, props, headers ).then(function(result) { if (isSuccessStatus(result.status)) { if (_.isFunction(options.success)) { // pass the object's own values because the server // does not return the updated model options.success(model.toJSON()); } } else if (_.isFunction(options.error)) { options.error(result); } }); } function callMethod(client, options, model, headers) { var data = options.data; if (_.isObject(data)) { headers['Content-Type'] = 'application/json'; data = JSON.stringify(data); } else if (_.isString(data) && data.substr(0, 6) === '