diff --git a/src/wp-includes/js/wp-api.js b/src/wp-includes/js/wp-api.js index da16e3c491..0ce6bbce09 100644 --- a/src/wp-includes/js/wp-api.js +++ b/src/wp-includes/js/wp-api.js @@ -119,21 +119,52 @@ return str.charAt( 0 ).toUpperCase() + str.slice( 1 ); }; + /** + * Helper function that capitalizes the first word and camel cases any words starting + * after dashes, removing the dashes. + */ + wp.api.utils.capitalizeAndCamelCaseDashes = function( str ) { + if ( _.isUndefined( str ) ) { + return str; + } + str = wp.api.utils.capitalize( str ); + + return wp.api.utils.camelCaseDashes( str ); + }; + + /** + * Helper function to camel case the letter after dashes, removing the dashes. + */ + wp.api.utils.camelCaseDashes = function( str ) { + return str.replace( /-([a-z])/g, function( g ) { + return g[ 1 ].toUpperCase(); + } ); + }; + /** * Extract a route part based on negative index. * - * @param {string} route The endpoint route. - * @param {int} part The number of parts from the end of the route to retrieve. Default 1. - * Example route `/a/b/c`: part 1 is `c`, part 2 is `b`, part 3 is `a`. + * @param {string} route The endpoint route. + * @param {int} part The number of parts from the end of the route to retrieve. Default 1. + * Example route `/a/b/c`: part 1 is `c`, part 2 is `b`, part 3 is `a`. + * @param {string} [versionString] Version string, defaults to `wp.api.versionString`. + * @param {boolean} [reverse] Whether to reverse the order when extracting the route part. Optional, default false. */ - wp.api.utils.extractRoutePart = function( route, part ) { + wp.api.utils.extractRoutePart = function( route, part, versionString, reverse ) { var routeParts; - part = part || 1; + part = part || 1; + versionString = versionString || wp.api.versionString; // Remove versions string from route to avoid returning it. - route = route.replace( wp.api.versionString, '' ); - routeParts = route.split( '/' ).reverse(); + if ( 0 === route.indexOf( '/' + versionString ) ) { + route = route.substr( versionString.length + 1 ); + } + + routeParts = route.split( '/' ); + if ( reverse ) { + routeParts = routeParts.reverse(); + } if ( _.isUndefined( routeParts[ --part ] ) ) { return ''; } @@ -1126,9 +1157,14 @@ // Extract the name and any parent from the route. var modelClassName, - routeName = wp.api.utils.extractRoutePart( modelRoute.index, 2 ), - parentName = wp.api.utils.extractRoutePart( modelRoute.index, 4 ), - routeEnd = wp.api.utils.extractRoutePart( modelRoute.index, 1 ); + routeName = wp.api.utils.extractRoutePart( modelRoute.index, 2, routeModel.get( 'versionString' ), true ), + parentName = wp.api.utils.extractRoutePart( modelRoute.index, 1, routeModel.get( 'versionString' ), false ), + routeEnd = wp.api.utils.extractRoutePart( modelRoute.index, 1, routeModel.get( 'versionString' ), true ); + + // Clear the parent part of the rouite if its actually the version string. + if ( parentName === routeModel.get( 'versionString' ) ) { + parentName = ''; + } // Handle the special case of the 'me' route. if ( 'me' === routeEnd ) { @@ -1137,18 +1173,21 @@ // If the model has a parent in its route, add that to its class name. if ( '' !== parentName && parentName !== routeName ) { - modelClassName = wp.api.utils.capitalize( parentName ) + wp.api.utils.capitalize( routeName ); + modelClassName = wp.api.utils.capitalizeAndCamelCaseDashes( parentName ) + wp.api.utils.capitalizeAndCamelCaseDashes( routeName ); modelClassName = mapping.models[ modelClassName ] || modelClassName; loadingObjects.models[ modelClassName ] = wp.api.WPApiBaseModel.extend( { // Return a constructed url based on the parent and id. url: function() { - var url = routeModel.get( 'apiRoot' ) + routeModel.get( 'versionString' ) + - parentName + '/' + + var url = + routeModel.get( 'apiRoot' ) + + routeModel.get( 'versionString' ) + + parentName + '/' + ( ( _.isUndefined( this.get( 'parent' ) ) || 0 === this.get( 'parent' ) ) ? - this.get( 'parent_post' ) : - this.get( 'parent' ) ) + '/' + - routeName; + ( _.isUndefined( this.get( 'parent_post' ) ) ? '' : this.get( 'parent_post' ) + '/' ) : + this.get( 'parent' ) + '/' ) + + routeName; + if ( ! _.isUndefined( this.get( 'id' ) ) ) { url += '/' + this.get( 'id' ); } @@ -1164,7 +1203,8 @@ // Include the array of route methods for easy reference. methods: modelRoute.route.methods, - initialize: function() { + initialize: function( attributes, options ) { + wp.api.WPApiBaseModel.prototype.initialize.call( this, attributes, options ); /** * Posts and pages support trashing, other types don't support a trash @@ -1184,7 +1224,7 @@ } else { // This is a model without a parent in its route - modelClassName = wp.api.utils.capitalize( routeName ); + modelClassName = wp.api.utils.capitalizeAndCamelCaseDashes( routeName ); modelClassName = mapping.models[ modelClassName ] || modelClassName; loadingObjects.models[ modelClassName ] = wp.api.WPApiBaseModel.extend( { @@ -1212,7 +1252,11 @@ } // Add defaults to the new model, pulled form the endpoint. - wp.api.utils.decorateFromRoute( modelRoute.route.endpoints, loadingObjects.models[ modelClassName ] ); + wp.api.utils.decorateFromRoute( + modelRoute.route.endpoints, + loadingObjects.models[ modelClassName ], + routeModel.get( 'versionString' ) + ); } ); @@ -1226,12 +1270,12 @@ // Extract the name and any parent from the route. var collectionClassName, modelClassName, routeName = collectionRoute.index.slice( collectionRoute.index.lastIndexOf( '/' ) + 1 ), - parentName = wp.api.utils.extractRoutePart( collectionRoute.index, 3 ); + parentName = wp.api.utils.extractRoutePart( collectionRoute.index, 1, routeModel.get( 'versionString' ), false ); // If the collection has a parent in its route, add that to its class name. - if ( '' !== parentName && parentName !== routeName ) { + if ( '' !== parentName && parentName !== routeName && routeModel.get( 'versionString' ) !== parentName ) { - collectionClassName = wp.api.utils.capitalize( parentName ) + wp.api.utils.capitalize( routeName ); + collectionClassName = wp.api.utils.capitalizeAndCamelCaseDashes( parentName ) + wp.api.utils.capitalizeAndCamelCaseDashes( routeName ); modelClassName = mapping.models[ collectionClassName ] || collectionClassName; collectionClassName = mapping.collections[ collectionClassName ] || collectionClassName; loadingObjects.collections[ collectionClassName ] = wp.api.WPApiBaseCollection.extend( { @@ -1260,7 +1304,7 @@ } else { // This is a collection without a parent in its route. - collectionClassName = wp.api.utils.capitalize( routeName ); + collectionClassName = wp.api.utils.capitalizeAndCamelCaseDashes( routeName ); modelClassName = mapping.models[ collectionClassName ] || collectionClassName; collectionClassName = mapping.collections[ collectionClassName ] || collectionClassName; loadingObjects.collections[ collectionClassName ] = wp.api.WPApiBaseCollection.extend( { diff --git a/tests/qunit/fixtures/js-widgets-endpoint.js b/tests/qunit/fixtures/js-widgets-endpoint.js new file mode 100644 index 0000000000..cacd4237d0 --- /dev/null +++ b/tests/qunit/fixtures/js-widgets-endpoint.js @@ -0,0 +1,562 @@ +/* jshint -W109 */ +/* jshint unused:false */ +var jsWidgetsEndpointSchema = +{ + "namespace": "js-widgets\/v1", + "routes": { + "\/js-widgets\/v1": { + "namespace": "js-widgets\/v1", + "methods": ["GET"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "namespace": { "required": false, "default": "js-widgets\/v1" }, + "context": { "required": false, "default": "view" } + } + }], + "_links": { "self": "http:\/\/newtest.localhost\/wp-json\/js-widgets\/v1" } + }, + "\/js-widgets\/v1\/widgets\/pages": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "sortby": { "required": false, "default": "menu_order", "enum": ["post_title", "menu_order", "ID"], "description": "How to sort the pages.", "type": "string" }, + "exclude": { "required": false, "default": [], "description": "Page IDs to exclude.", "type": ["array", "string"] } + } + }], + "_links": { "self": "http:\/\/newtest.localhost\/wp-json\/js-widgets\/v1\/widgets\/pages" } + }, + "\/js-widgets\/v1\/widgets\/pages\/(?P\\d+)": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST", "PUT", "PATCH", "DELETE"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "default": "view", "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST", "PUT", "PATCH"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "sortby": { "required": false, "default": "menu_order", "enum": ["post_title", "menu_order", "ID"], "description": "How to sort the pages.", "type": "string" }, + "exclude": { "required": false, "default": [], "description": "Page IDs to exclude.", "type": ["array", "string"] } + } + }, { + "methods": ["DELETE"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "sortby": { "required": false, "enum": ["post_title", "menu_order", "ID"], "description": "How to sort the pages.", "type": "string" }, + "exclude": { "required": false, "description": "Page IDs to exclude.", "type": ["array", "string"] } + } + }] + }, + "\/js-widgets\/v1\/widgets\/calendar": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] } + } + }], + "_links": { "self": "http:\/\/newtest.localhost\/wp-json\/js-widgets\/v1\/widgets\/calendar" } + }, + "\/js-widgets\/v1\/widgets\/calendar\/(?P\\d+)": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST", "PUT", "PATCH", "DELETE"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "default": "view", "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST", "PUT", "PATCH"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] } + } + }, { + "methods": ["DELETE"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] } + } + }] + }, + "\/js-widgets\/v1\/widgets\/archives": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "dropdown": { "required": false, "default": false, "description": "Display as dropdown", "type": "boolean" }, + "count": { "required": false, "default": false, "description": "Show post counts", "type": "boolean" } + } + }], + "_links": { "self": "http:\/\/newtest.localhost\/wp-json\/js-widgets\/v1\/widgets\/archives" } + }, + "\/js-widgets\/v1\/widgets\/archives\/(?P\\d+)": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST", "PUT", "PATCH", "DELETE"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "default": "view", "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST", "PUT", "PATCH"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "dropdown": { "required": false, "default": false, "description": "Display as dropdown", "type": "boolean" }, + "count": { "required": false, "default": false, "description": "Show post counts", "type": "boolean" } + } + }, { + "methods": ["DELETE"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "dropdown": { "required": false, "description": "Display as dropdown", "type": "boolean" }, + "count": { "required": false, "description": "Show post counts", "type": "boolean" } + } + }] + }, + "\/js-widgets\/v1\/widgets\/meta": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] } + } + }], + "_links": { "self": "http:\/\/newtest.localhost\/wp-json\/js-widgets\/v1\/widgets\/meta" } + }, + "\/js-widgets\/v1\/widgets\/meta\/(?P\\d+)": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST", "PUT", "PATCH", "DELETE"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "default": "view", "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST", "PUT", "PATCH"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] } + } + }, { + "methods": ["DELETE"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] } + } + }] + }, + "\/js-widgets\/v1\/widgets\/search": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] } + } + }], + "_links": { "self": "http:\/\/newtest.localhost\/wp-json\/js-widgets\/v1\/widgets\/search" } + }, + "\/js-widgets\/v1\/widgets\/search\/(?P\\d+)": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST", "PUT", "PATCH", "DELETE"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "default": "view", "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST", "PUT", "PATCH"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] } + } + }, { + "methods": ["DELETE"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] } + } + }] + }, + "\/js-widgets\/v1\/widgets\/text": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "text": { "required": false, "description": "The content for the widget.", "type": ["string", "object"] }, + "filter": { "required": false, "default": false, "description": "Whether paragraphs will be added for double line breaks (wpautop).", "type": "boolean" } + } + }], + "_links": { "self": "http:\/\/newtest.localhost\/wp-json\/js-widgets\/v1\/widgets\/text" } + }, + "\/js-widgets\/v1\/widgets\/text\/(?P\\d+)": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST", "PUT", "PATCH", "DELETE"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "default": "view", "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST", "PUT", "PATCH"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "text": { "required": false, "description": "The content for the widget.", "type": ["string", "object"] }, + "filter": { "required": false, "default": false, "description": "Whether paragraphs will be added for double line breaks (wpautop).", "type": "boolean" } + } + }, { + "methods": ["DELETE"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "text": { "required": false, "description": "The content for the widget.", "type": ["string", "object"] }, + "filter": { "required": false, "description": "Whether paragraphs will be added for double line breaks (wpautop).", "type": "boolean" } + } + }] + }, + "\/js-widgets\/v1\/widgets\/categories": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "dropdown": { "required": false, "default": false, "description": "Display as dropdown", "type": "boolean" }, + "count": { "required": false, "default": false, "description": "Show post counts", "type": "boolean" }, + "hierarchical": { "required": false, "default": false, "description": "Show hierarchy", "type": "boolean" } + } + }], + "_links": { "self": "http:\/\/newtest.localhost\/wp-json\/js-widgets\/v1\/widgets\/categories" } + }, + "\/js-widgets\/v1\/widgets\/categories\/(?P\\d+)": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST", "PUT", "PATCH", "DELETE"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "default": "view", "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST", "PUT", "PATCH"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "dropdown": { "required": false, "default": false, "description": "Display as dropdown", "type": "boolean" }, + "count": { "required": false, "default": false, "description": "Show post counts", "type": "boolean" }, + "hierarchical": { "required": false, "default": false, "description": "Show hierarchy", "type": "boolean" } + } + }, { + "methods": ["DELETE"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "dropdown": { "required": false, "description": "Display as dropdown", "type": "boolean" }, + "count": { "required": false, "description": "Show post counts", "type": "boolean" }, + "hierarchical": { "required": false, "description": "Show hierarchy", "type": "boolean" } + } + }] + }, + "\/js-widgets\/v1\/widgets\/recent-posts": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "number": { "required": false, "default": 5, "description": "The number of posts to display.", "type": "integer" }, + "show_date": { "required": false, "default": false, "description": "Whether the date should be shown.", "type": "boolean" } + } + }], + "_links": { "self": "http:\/\/newtest.localhost\/wp-json\/js-widgets\/v1\/widgets\/recent-posts" } + }, + "\/js-widgets\/v1\/widgets\/recent-posts\/(?P\\d+)": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST", "PUT", "PATCH", "DELETE"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "default": "view", "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST", "PUT", "PATCH"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "number": { "required": false, "default": 5, "description": "The number of posts to display.", "type": "integer" }, + "show_date": { "required": false, "default": false, "description": "Whether the date should be shown.", "type": "boolean" } + } + }, { + "methods": ["DELETE"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "number": { "required": false, "description": "The number of posts to display.", "type": "integer" }, + "show_date": { "required": false, "description": "Whether the date should be shown.", "type": "boolean" } + } + }] + }, + "\/js-widgets\/v1\/widgets\/recent-comments": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "number": { "required": false, "default": 5, "description": "The number of comments to display.", "type": "integer" } + } + }], + "_links": { "self": "http:\/\/newtest.localhost\/wp-json\/js-widgets\/v1\/widgets\/recent-comments" } + }, + "\/js-widgets\/v1\/widgets\/recent-comments\/(?P\\d+)": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST", "PUT", "PATCH", "DELETE"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "default": "view", "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST", "PUT", "PATCH"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "number": { "required": false, "default": 5, "description": "The number of comments to display.", "type": "integer" } + } + }, { + "methods": ["DELETE"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "number": { "required": false, "description": "The number of comments to display.", "type": "integer" } + } + }] + }, + "\/js-widgets\/v1\/widgets\/rss": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "url": { "required": false, "default": "", "description": "The RSS feed URL.", "type": "string" }, + "items": { "required": false, "default": 10, "description": "The number of RSS items to display.", "type": "integer" }, + "show_summary": { "required": false, "default": false, "description": "Whether the summary should be shown.", "type": "boolean" }, + "show_author": { "required": false, "default": false, "description": "Whether the author should be shown.", "type": "boolean" }, + "show_date": { "required": false, "default": false, "description": "Whether the date should be shown.", "type": "boolean" } + } + }], + "_links": { "self": "http:\/\/newtest.localhost\/wp-json\/js-widgets\/v1\/widgets\/rss" } + }, + "\/js-widgets\/v1\/widgets\/rss\/(?P\\d+)": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST", "PUT", "PATCH", "DELETE"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "default": "view", "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST", "PUT", "PATCH"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "url": { "required": false, "default": "", "description": "The RSS feed URL.", "type": "string" }, + "items": { "required": false, "default": 10, "description": "The number of RSS items to display.", "type": "integer" }, + "show_summary": { "required": false, "default": false, "description": "Whether the summary should be shown.", "type": "boolean" }, + "show_author": { "required": false, "default": false, "description": "Whether the author should be shown.", "type": "boolean" }, + "show_date": { "required": false, "default": false, "description": "Whether the date should be shown.", "type": "boolean" } + } + }, { + "methods": ["DELETE"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "url": { "required": false, "description": "The RSS feed URL.", "type": "string" }, + "items": { "required": false, "description": "The number of RSS items to display.", "type": "integer" }, + "show_summary": { "required": false, "description": "Whether the summary should be shown.", "type": "boolean" }, + "show_author": { "required": false, "description": "Whether the author should be shown.", "type": "boolean" }, + "show_date": { "required": false, "description": "Whether the date should be shown.", "type": "boolean" } + } + }] + }, + "\/js-widgets\/v1\/widgets\/tag_cloud": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "taxonomy": { "required": false, "default": "post_tag", "enum": ["category", "post_tag"], "description": "Taxonomy", "type": "string" } + } + }], + "_links": { "self": "http:\/\/newtest.localhost\/wp-json\/js-widgets\/v1\/widgets\/tag_cloud" } + }, + "\/js-widgets\/v1\/widgets\/tag_cloud\/(?P\\d+)": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST", "PUT", "PATCH", "DELETE"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "default": "view", "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST", "PUT", "PATCH"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "taxonomy": { "required": false, "default": "post_tag", "enum": ["category", "post_tag"], "description": "Taxonomy", "type": "string" } + } + }, { + "methods": ["DELETE"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "taxonomy": { "required": false, "enum": ["category", "post_tag"], "description": "Taxonomy", "type": "string" } + } + }] + }, + "\/js-widgets\/v1\/widgets\/nav_menu": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "nav_menu": { "required": false, "default": 0, "description": "Selected nav menu", "type": "integer" } + } + }], + "_links": { "self": "http:\/\/newtest.localhost\/wp-json\/js-widgets\/v1\/widgets\/nav_menu" } + }, + "\/js-widgets\/v1\/widgets\/nav_menu\/(?P\\d+)": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST", "PUT", "PATCH", "DELETE"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "default": "view", "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST", "PUT", "PATCH"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "nav_menu": { "required": false, "default": 0, "description": "Selected nav menu", "type": "integer" } + } + }, { + "methods": ["DELETE"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "nav_menu": { "required": false, "description": "Selected nav menu", "type": "integer" } + } + }] + }, + "\/js-widgets\/v1\/widgets\/post-collection": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "show_date": { "required": false, "default": false, "description": "Whether the date should be shown.", "type": "boolean" }, + "show_featured_image": { "required": false, "default": false, "description": "Whether the featured image is shown.", "type": "boolean" }, + "show_author": { "required": false, "default": false, "description": "Whether the author is shown.", "type": "boolean" }, + "posts": { "required": false, "default": [], "description": "The IDs for the collected posts.", "type": "array" } + } + }], + "_links": { "self": "http:\/\/newtest.localhost\/wp-json\/js-widgets\/v1\/widgets\/post-collection" } + }, + "\/js-widgets\/v1\/widgets\/post-collection\/(?P\\d+)": { + "namespace": "js-widgets\/v1", + "methods": ["GET", "POST", "PUT", "PATCH", "DELETE"], + "endpoints": [{ + "methods": ["GET"], + "args": { + "context": { "required": false, "default": "view", "enum": ["view", "embed", "edit"], "description": "Scope under which the request is made; determines fields present in response.", "type": "string" } + } + }, { + "methods": ["POST", "PUT", "PATCH"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "show_date": { "required": false, "default": false, "description": "Whether the date should be shown.", "type": "boolean" }, + "show_featured_image": { "required": false, "default": false, "description": "Whether the featured image is shown.", "type": "boolean" }, + "show_author": { "required": false, "default": false, "description": "Whether the author is shown.", "type": "boolean" }, + "posts": { "required": false, "default": [], "description": "The IDs for the collected posts.", "type": "array" } + } + }, { + "methods": ["DELETE"], + "args": { + "title": { "required": false, "description": "The title for the widget.", "type": ["string", "object"] }, + "show_date": { "required": false, "description": "Whether the date should be shown.", "type": "boolean" }, + "show_featured_image": { "required": false, "description": "Whether the featured image is shown.", "type": "boolean" }, + "show_author": { "required": false, "description": "Whether the author is shown.", "type": "boolean" }, + "posts": { "required": false, "description": "The IDs for the collected posts.", "type": "array" } + } + }] + } + }, + "_links": { + "up": [ + { "href": "http:\/\/newtest.localhost\/wp-json\/" } + ] + } +}; diff --git a/tests/qunit/fixtures/wp-api.js b/tests/qunit/fixtures/wp-api.js index cbbc484174..d9d0804c89 100644 --- a/tests/qunit/fixtures/wp-api.js +++ b/tests/qunit/fixtures/wp-api.js @@ -1,4 +1,4 @@ -/* global mockedApiResponse, Backbone */ +/* global mockedApiResponse, Backbone, jsWidgetsEndpointSchema */ /** * @var mockedApiResponse defined in wp-api-generated.js */ @@ -23,7 +23,8 @@ var pathToData = { 'wp-json/wp/v2/user': mockedApiResponse.UserModel, 'wp-json/wp/v2/taxonomy': mockedApiResponse.TaxonomyModel, 'wp-json/wp/v2/status': mockedApiResponse.StatusModel, - 'wp-json/wp/v2/type': mockedApiResponse.TypeModel + 'wp-json/wp/v2/type': mockedApiResponse.TypeModel, + 'wp-json/js-widgets/v1/': jsWidgetsEndpointSchema }; /** diff --git a/tests/qunit/index.html b/tests/qunit/index.html index 22004e3711..31ae641d0e 100644 --- a/tests/qunit/index.html +++ b/tests/qunit/index.html @@ -40,6 +40,7 @@ +

TinyMCE tests

diff --git a/tests/qunit/wp-includes/js/wp-api.js b/tests/qunit/wp-includes/js/wp-api.js index 5225d9e254..acca46112e 100644 --- a/tests/qunit/wp-includes/js/wp-api.js +++ b/tests/qunit/wp-includes/js/wp-api.js @@ -192,4 +192,44 @@ } ); } ); +// Test the jswidget custom namespace and endpoints. +wp.api.init( { + 'versionString': 'js-widgets/v1/' +} ).done( function() { + var customClasses = [ + 'WidgetsArchives', + 'WidgetsCalendar', + 'WidgetsCategories', + 'WidgetsMeta', + 'WidgetsNav_menu', + 'WidgetsPages', + 'WidgetsPostCollection', + 'WidgetsRecentComments', + 'WidgetsRecentPosts', + 'WidgetsRss', + 'WidgetsSearch', + 'WidgetsTag_cloud', + 'WidgetsText' + ]; + + // Check that we have and can get each model type. + _.each( customClasses, function( className ) { + QUnit.test( 'Checking ' + className + ' class name.' , function( assert ) { + var done = assert.async(); + + assert.expect( 2 ); + + wp.api.loadPromise.done( function() { + var theModel = new wp.api.models[ className ](); + assert.ok( theModel, 'We can instantiate wp.api.models.' + className ); + var theCollection = new wp.api.collections[ className ](); + assert.ok( theCollection, 'We can instantiate wp.api.collections.' + className ); + // Trigger Qunit async completion. + done(); + } ); + } ); + } ); + + } ); + } )( window.QUnit );