Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
YUI.add('app-content', function (Y, NAME) {
2
 
3
/**
4
`Y.App` extension that provides pjax-style content fetching and handling.
5
 
6
@module app
7
@submodule app-content
8
@since 3.7.0
9
**/
10
 
11
var PjaxContent = Y.PjaxContent;
12
 
13
/**
14
`Y.App` extension that provides pjax-style content fetching and handling.
15
 
16
This makes it easy to fetch server rendered content for URLs using Ajax. The
17
HTML content returned from the server will be view-ified and set as the app's
18
main content, making it seamless to use a mixture of server and client rendered
19
views.
20
 
21
When the `"app-content"` module is used, it will automatically mix itself into
22
`Y.App`, and it provides three main features:
23
 
24
  - **`Y.App.Content.route`**: A stack of middleware which forms a pjax-style
25
    content route.
26
 
27
  - **`loadContent()`**: Route middleware which load content from a server. This
28
    makes an Ajax request for the requested URL, parses the returned content and
29
    puts it on the route's response object.
30
 
31
  - **`showContent()`**: Method which provides an easy way to view-ify HTML
32
    content which should be shown as an app's active/visible view.
33
 
34
The following is an example of how these features can be used:
35
 
36
    // Creates a new app and registers the `"post"` view.
37
    var app = new Y.App({
38
        views: {
39
            post: {type: Y.PostView}
40
        }
41
    });
42
 
43
    // Uses a simple server rendered content route for the About page.
44
    app.route('/about/', Y.App.Content.route);
45
 
46
    // Uses the `loadContent()` middleware to fetch the contents of the post
47
    // from the server and shows that content in a `"post"` view.
48
    app.route('/posts/:id/', 'loadContent', function (req, res, next) {
49
        this.showContent(res.content.node, {view: 'post'});
50
    });
51
 
52
@class App.Content
53
@uses PjaxContent
54
@extensionfor App
55
@since 3.7.0
56
**/
57
function AppContent() {
58
    PjaxContent.apply(this, arguments);
59
}
60
 
61
/**
62
A stack of middleware which forms a pjax-style content route.
63
 
64
This route will load the rendered HTML content from the server, then create and
65
show a new view using those contents.
66
 
67
@property route
68
@type Array
69
@static
70
@since 3.7.0
71
**/
72
AppContent.route = ['loadContent', '_contentRoute'];
73
 
74
AppContent.prototype = {
75
    // -- Public Methods -------------------------------------------------------
76
 
77
    /**
78
    Sets this app's `activeView` attribute using the specified `content`.
79
 
80
    This provides an easy way to view-ify HTML content which should be shown as
81
    this app's active/visible view. This method will determine the appropriate
82
    view `container` node based on the specified `content`. By default, a new
83
    `Y.View` instance will be created unless `options.view` is specified.
84
 
85
    Under the hood, this method calls the `showView()` method, so refer to its
86
    docs for more information.
87
 
88
    @method showContent
89
    @param {HTMLElement|Node|String} content The content to show, it may be
90
        provided as a selector string, a DOM element, or a `Y.Node` instance.
91
    @param {Object} [options] Optional objects containing any of the following
92
        properties in addition to any `showView()` options:
93
 
94
      @param {Object|String} [options.view] The name of a view defined in this
95
          app's `views`, or an object with the following properties:
96
 
97
        @param {String} options.view.name The name of a view defined in this
98
            app's `views`.
99
        @param {Object} [options.view.config] Optional configuration to use when
100
            creating the new view instance. This config object can also be used
101
            to update an existing or preserved view's attributes when
102
            `options.update` is `true`. **Note:** If a `container` is specified,
103
            it will be overridden by the `content` specified in the first
104
            argument.
105
 
106
    @param {Function} [callback] Optional callback function to call after the
107
        new `activeView` is ready to use. **Note:** this will override
108
        `options.callback` and it can be specified as either the second or third
109
        argument. The function will be passed the following:
110
 
111
      @param {View} callback.view A reference to the new `activeView`.
112
 
113
    @chainable
114
    @since 3.7.0
115
    @see App.showView()
116
    **/
117
    showContent: function (content, options, callback) {
118
        // Makes sure we have a node instance, and will query selector strings.
119
        content = Y.one(content);
120
 
121
        // Support the callback function being either the second or third arg.
122
        if (typeof options === 'function') {
123
            options  = {callback: options};
124
            callback = null;
125
        }
126
 
127
        // Mix in default option to *not* render the view because presumably we
128
        // have pre-rendered content here. This also creates a copy so we can
129
        // modify the object.
130
        options = Y.merge({render: false}, options);
131
 
132
        var view       = options.view || '',
133
            viewName   = typeof view === 'string' ? view : view.name,
134
            viewConfig = typeof view !== 'string' ? view.config : {},
135
            viewInfo   = this.getViewInfo(viewName),
136
            container, template, type, ViewConstructor;
137
 
138
        // Remove `view` from the `options` which will be passed along to the
139
        // `showView()` method.
140
        delete options.view;
141
 
142
        // When the specified `content` is a document fragment, we want to see
143
        // if it only contains a single node, and use that as the content. This
144
        // checks `childNodes` which will include text nodes.
145
        if (content && content.isFragment() &&
146
                content.get('childNodes').size() === 1) {
147
 
148
            content = content.get('firstChild');
149
        }
150
 
151
        // When the `content` is an element node (`nodeType` 1), we can use it
152
        // as-is for the `container`. Otherwise, we'll construct a new container
153
        // based on the `options.view`'s `containerTemplate`.
154
        if (content && content.get('nodeType') === 1) {
155
            container = content;
156
        } else {
157
            type = (viewInfo && viewInfo.type) || Y.View;
158
 
159
            // Looks for a namespaced constructor function on `Y`.
160
            ViewConstructor = typeof type === 'string' ?
161
                    Y.Object.getValue(Y, type.split('.')) : type;
162
 
163
            // Find the correct node template for the view.
164
            template  = ViewConstructor.prototype.containerTemplate;
165
            container = Y.Node.create(template);
166
 
167
            // Append the document fragment to the newly created `container`
168
            // node. This is the worst case where we have to create a wrapper
169
            // node around the `content`.
170
            container.append(content);
171
        }
172
 
173
        // Makes sure the view is created using _our_ `container` node.
174
        viewConfig = Y.merge(viewConfig, {container: container});
175
 
176
        // Finally switch to the new `activeView`. We want to make sure `view`
177
        // is a string if it's falsy, that way a new view will be created.
178
        return this.showView(viewName, viewConfig, options, callback);
179
    },
180
 
181
    // -- Protected Methods ----------------------------------------------------
182
 
183
    /**
184
    Provides a default content route which will show a server rendered view.
185
 
186
    **Note:** This route callback assumes that it's called after the
187
    `loadContent()` middleware.
188
 
189
    @method _contentRoute
190
    @param {Object} req Request object.
191
    @param {Object} res Response Object.
192
    @param {Function} next Function to pass control to the next route callback.
193
    @protected
194
    @since 3.7.0
195
    @see Y.App.Content.route
196
    **/
197
    _contentRoute: function (req, res, next) {
198
        var content = res.content,
199
            doc     = Y.config.doc,
200
            activeViewHandle;
201
 
202
        // We must have some content to work with.
203
        if (!(content && content.node)) { return next(); }
204
 
205
        if (content.title && doc) {
206
            // Make sure the `activeView` does actually change before we go
207
            // messing with the page title.
208
            activeViewHandle = this.onceAfter('activeViewChange', function () {
209
                doc.title = content.title;
210
            });
211
        }
212
 
213
        this.showContent(content.node);
214
 
215
        // Detach the handle just in case.
216
        if (activeViewHandle) {
217
            activeViewHandle.detach();
218
        }
219
 
220
        next();
221
    }
222
};
223
 
224
// Mix statics.
225
AppContent.ATTRS = Y.Attribute.protectAttrs(PjaxContent.ATTRS);
226
 
227
// Mix prototype.
228
Y.mix(AppContent, PjaxContent, false, null, 1);
229
 
230
// -- Namespace ----------------------------------------------------------------
231
Y.App.Content = AppContent;
232
Y.Base.mix(Y.App, [AppContent]);
233
 
234
 
235
}, '3.18.1', {"requires": ["app-base", "pjax-content"]});