UNPKG

infusion

Version:

Infusion is an application framework for developing flexible stuff with JavaScript

210 lines (188 loc) 9.16 kB
/* Copyright The Infusion copyright holders See the AUTHORS.md file at the top-level directory of this distribution and at https://github.com/fluid-project/infusion/raw/master/AUTHORS.md. Licensed under the Educational Community License (ECL), Version 2.0 or the New BSD license. You may not use this file except in compliance with one these Licenses. You may obtain a copy of the ECL 2.0 License and BSD License at https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt */ var fluid_3_0_0 = fluid_3_0_0 || {}; (function ($, fluid) { "use strict"; /** NOTE: Much of this work originated from https://github.com/fluid-project/kettle/blob/master/lib/dataSource-core.js **/ /** Some common content encodings - suitable to appear as the "encoding" subcomponent of a dataSource **/ fluid.defaults("fluid.dataSource.encoding.JSON", { gradeNames: "fluid.component", invokers: { parse: "fluid.dataSource.parseJSON", render: "fluid.dataSource.stringifyJSON" }, contentType: "application/json" }); fluid.defaults("fluid.dataSource.encoding.none", { gradeNames: "fluid.component", invokers: { parse: "fluid.identity", render: "fluid.identity" }, contentType: "text/plain" }); fluid.dataSource.parseJSON = function (string) { var togo = fluid.promise(); if (!string) { togo.resolve(undefined); } else { try { togo.resolve(JSON.parse(string)); } catch (err) { togo.reject({ message: err }); } } return togo; }; fluid.dataSource.stringifyJSON = function (obj) { return obj === undefined ? "" : JSON.stringify(obj, null, 4); }; /** * The head of the hierarchy of dataSource components. These abstract * over the process of read and write access to data, following a simple CRUD-type semantic, indexed by * a coordinate model (directModel) and which may be asynchronous. * Top-level methods are: * get(directModel[, callback|options] - to get the data from data resource * set(directModel, model[, callback|options] - to set the data * * * directModel: An object expressing an "index" into some set of * state which can be read or written. * * model: The payload sent to the storage. * * options: An object expressing implementation specific details * regarding the handling of a request. Note: this does not * include details for identifying the resource. Those should be * placed in the directModel. */ fluid.defaults("fluid.dataSource", { gradeNames: ["fluid.component"], events: { // The "onRead" event is operated in a custom workflow by fluid.fireTransformEvent to // process dataSource payloads during the get process. Each listener // receives the data returned by the last. onRead: null, onError: null }, components: { encoding: { type: "fluid.dataSource.encoding.JSON" } }, listeners: { // handler for "onRead.impl" must be implemented by a concrete subgrade // Note: The intial payload (first argument) will be undefined "onRead.impl": { func: "fluid.notImplemented", priority: "first" }, "onRead.encoding": { func: "{encoding}.parse", priority: "after:impl" } }, invokers: { get: { funcName: "fluid.dataSource.get", args: ["{that}", "{arguments}.0", "{arguments}.1"] // directModel, options/callback } } }); /** * Base grade for adding write configuration to a dataSource. * * Grade linkage should be used to apply the concrete writable grade to the datasource configuration. * For example fluid.makeGradeLinkage("kettle.dataSource.CouchDB.linkage", ["fluid.dataSource.writable", "kettle.dataSource.CouchDB"], "kettle.dataSource.CouchDB.writable"); */ fluid.defaults("fluid.dataSource.writable", { gradeNames: ["fluid.component"], events: { // events "onWrite" and "onWriteResponse" are operated in a custom workflow by fluid.fireTransformEvent to // process dataSource payloads during the set process. Each listener // receives the data returned by the last. onWrite: null, onWriteResponse: null }, listeners: { "onWrite.encoding": { func: "{encoding}.render" }, // handler for "onWrite.impl" must be implemented by a concrete subgrade "onWrite.impl": { func: "fluid.notImplemented", priority: "after:encoding" }, "onWriteResponse.encoding": { func: "{encoding}.parse" } }, invokers: { set: { funcName: "fluid.dataSource.set", args: ["{that}", "{arguments}.0", "{arguments}.1", "{arguments}.2"] // directModel, model, options/callback } } }); // Registers the default promise handlers for a dataSource operation - // i) If the user has supplied a function in place of method `options`, register this function as a success handler // ii) if the user has supplied an onError handler in method `options`, this is registered - otherwise // we register the firer of the dataSource's own onError method. fluid.dataSource.registerStandardPromiseHandlers = function (that, promise, options) { promise.then(typeof(options) === "function" ? options : null, options.onError ? options.onError : that.events.onError.fire); }; fluid.dataSource.defaultiseOptions = function (componentOptions, options, directModel, isSet) { options = options || {}; options.directModel = directModel; options.operation = isSet ? "set" : "get"; options.notFoundIsEmpty = options.notFoundIsEmpty || componentOptions.notFoundIsEmpty; return options; }; /** Operate the core "transforming promise workflow" of a dataSource's `get` method. The initial listener provides the initial payload; * which then proceeds through the transform chain to arrive at the final payload. * @param that {Component} The dataSource itself * @param directModel {Object} The direct model expressing the "coordinates" of the model to be fetched * @param options {Object} A structure of options configuring the action of this get request - many of these will be specific to the particular concrete DataSource * @return {Promise} A promise for the final resolved payload */ fluid.dataSource.get = function (that, directModel, options) { options = fluid.dataSource.defaultiseOptions(that.options, options, directModel); var promise = fluid.promise.fireTransformEvent(that.events.onRead, undefined, options); fluid.dataSource.registerStandardPromiseHandlers(that, promise, options); return promise; }; /** Operate the core "transforming promise workflow" of a dataSource's `set` method. * Any return from this is then pushed forwards through a range of the transforms (typically, e.g. just decoding it as JSON) * on its way back to the user via the onWriteResponse event. * @param that {Component} The dataSource itself * @param directModel {Object} The direct model expressing the "coordinates" of the model to be written * @param model {Object} The payload to be written to the dataSource * @param options {Object} A structure of options configuring the action of this set request - many of these will be specific to the particular concrete DataSource * @return {Promise} A promise for the final resolved payload (not all DataSources will provide any for a `set` method) */ fluid.dataSource.set = function (that, directModel, model, options) { options = fluid.dataSource.defaultiseOptions(that.options, options, directModel, true); // shared and writeable between all participants var transformPromise = fluid.promise.fireTransformEvent(that.events.onWrite, model, options); var togo = fluid.promise(); transformPromise.then(function (setResponse) { var options2 = fluid.dataSource.defaultiseOptions(that.options, fluid.copy(options), directModel); var retransformed = fluid.promise.fireTransformEvent(that.events.onWriteResponse, setResponse, options2); fluid.promise.follow(retransformed, togo); }, function (error) { togo.reject(error); }); fluid.dataSource.registerStandardPromiseHandlers(that, togo, options); return togo; }; })(jQuery, fluid_3_0_0);