├── .editorconfig ├── .gitignore ├── .travis.yml ├── LICENSE.txt ├── README.md ├── bower.json ├── build ├── wp-angular.js └── wp-angular.min.js ├── demo ├── index.html └── style.css ├── gulpfile.js ├── jsdoc2md └── README.hbs ├── package.json ├── src ├── wp-services.js └── wp.js └── tests ├── karma.conf.js └── spec ├── have-posts-single.js ├── have-posts.js ├── the-content.js ├── the-date.js ├── the-excerpt.js ├── the-id.js ├── the-post-thumbnail.js ├── the-title.js └── wp-services.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | indent_style = tab 9 | indent_size = 4 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle 2 | node_modules 3 | npm-debug.log 4 | vendor 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '6' 4 | - '5' 5 | - '4' 6 | - '0.11' 7 | - '0.10' 8 | before_script: 9 | - npm install 10 | script: 11 | - npm test 12 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Takayuki Miyauchi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wp-angularjs 2 | 3 | [![Build Status](https://travis-ci.org/miya0001/wp-angularjs.svg?branch=master)](https://travis-ci.org/miya0001/wp-angularjs) 4 | 5 | A WP-API Client for [AngularJS](https://angularjs.org/). 6 | 7 | ## Getting Started 8 | 9 | ``` 10 | $ npm install wp-angularjs --save 11 | ``` 12 | 13 | Or 14 | 15 | ``` 16 | $ bower install wp-angularjs --save 17 | ``` 18 | 19 | ```html 20 | 22 | 23 |

24 |
25 | 26 |
27 |
28 | ``` 29 | 30 | Demo: http://miya0001.github.io/wp-angularjs/demo/ 31 | 32 | ## Requires 33 | 34 | * [AngularJS](https://angularjs.org/) 35 | * [ngResource](https://github.com/angular/angular.js/tree/master/src/ngResource) 36 | * [ngSanitize](https://github.com/angular/angular.js/tree/master/src/ngSanitize) 37 | 38 | Recommended: 39 | 40 | * [ngInfiniteScroll](https://sroze.github.io/ngInfiniteScroll/) 41 | * [jQuery](https://jquery.com/) 42 | 43 | ## API Reference 44 | 45 | * [<have-posts>](#have-posts) 46 | * [<the-title>](#the-title) 47 | * [<the-content>](#the-content) 48 | * [<the-post-thumbnail>](#the-post-thumbnail) 49 | * [<the-id>](#the-id) 50 | * [<the-excerpt>](#the-excerpt) 51 | * [<the-date>](#the-date) 52 | 53 | --- 54 | 55 | ### <have-posts> 56 | The `havePosts` directive is a WordPress loop. 57 | 58 | **Attributes** 59 | 60 | | Attribute | Type | Details | 61 | |-----------|--------|----------------------------------------------------------------| 62 | | api-root | string | Root url of the API. e.g. http://example.com/wp-json/wp/v2 | 63 | | post-type | string | `posts` or `pages` or `media` or custom post type. | 64 | | per-page | number | The number of posts per page. Default is 10. | 65 | | offset | number | The number of post to displace or pass over. Default is 0. | 66 | | post-id | number | The ID of the post. | 67 | | filter | object | The object of the filter. | 68 | 69 | **Example** 70 | ```html 71 | 72 |

73 |
74 |
75 | ``` 76 | 77 | If you want to get single post, you can use `post-id`. 78 | 79 | ```html 80 | 81 |

82 |
83 |
84 | ``` 85 | 86 | You can pass filters to 87 | [WP_Query](https://codex.wordpress.org/Class_Reference/WP_Query) 88 | through via the `filter` argument. 89 | 90 | ```html 91 | 93 |

94 |
95 |
96 | ``` 97 | --- 98 | ### <the-title> 99 | Displays the post title of the current post. 100 | This tag must be used within The ``. 101 | 102 | **Attributes** 103 | 104 | | Attribute | Type | Details | 105 | |-----------|--------|----------------------------------------------------------------| 106 | | href | string | Specify a link URL like `#/app/posts/:id`. | 107 | 108 | **Example** 109 | ```html 110 | 111 | ``` 112 | Then: 113 | ```html 114 |
Hello World
115 | ``` 116 | If you need a link to the post on your app. Please add `href` as attribute. 117 | ```html 118 | 119 | ``` 120 | Then: 121 | ```html 122 |
Hello World
123 | ``` 124 | `:id` is a placeholder of the post's id. You can use `:slug` as post's slug too. 125 | ```html 126 | 127 | ``` 128 | Then: 129 | ```html 130 |
Hello World
131 | ``` 132 | --- 133 | ### <the-content> 134 | Displays the post content of the current post. 135 | This tag must be used within The ``. 136 | 137 | **Example** 138 | ```html 139 | 140 | ``` 141 | Then: 142 | ```html 143 |

Hello World

144 | ``` 145 | --- 146 | ### <the-post-thumbnail> 147 | Displays the post thumbnail of the current post. 148 | This tag must be used within The ``. 149 | 150 | **Attributes** 151 | 152 | | Attribute | Type | Details | 153 | |-----------|--------|----------------------------------------------------------------| 154 | | size | string | Size of the post thumbnail. Default is `full`. | 155 | | href | string | Specify a link URL like `#/app/posts/:id`. | 156 | 157 | **Example** 158 | ```html 159 | 160 | ``` 161 | Then: 162 | ``` 163 |
164 | ``` 165 | Uses `size` attribute. 166 | ```html 167 | 168 | ``` 169 | Then: 170 | ``` 171 |
172 | ``` 173 | If you need a link to the post on your app. Please add `href` as attribute. 174 | ```html 175 | 176 | ``` 177 | Then: 178 | ```html 179 |
180 | 181 |
182 | ``` 183 | `:id` is a placeholder of the post's id. You can use `:slug` as post's slug too. 184 | 185 | ```html 186 | 187 | ``` 188 | Then: 189 | ```html 190 |
191 | 192 |
193 | ``` 194 | --- 195 | ### <the-id> 196 | Displays the ID of the current post. 197 | This tag must be used within The ``. 198 | 199 | **Example** 200 | ``` 201 | 202 | ``` 203 | Then: 204 | ``` 205 |
123
206 | ``` 207 | --- 208 | ### <the-excerpt> 209 | Displays the excerpt of the current post. 210 | This tag must be used within The ``. 211 | 212 | **Example** 213 | Place the code like following into your HTML. 214 | ``` 215 | 216 | ``` 217 | Then you will get like following. 218 | ``` 219 |

Hello World.

220 | ``` 221 | --- 222 | ### <the-date> 223 | Displays the date of the current post. 224 | This tag must be used within The ``. 225 | 226 | **Attributes** 227 | 228 | | Attribute | Type | Details | 229 | |-----------|--------|----------------------------------------------------------------| 230 | | format | string | See https://docs.angularjs.org/api/ng/filter/date | 231 | 232 | **Example** 233 | Place the code like following into your HTML. 234 | ``` 235 | 236 | ``` 237 | Then you will get like following. 238 | ``` 239 |
2016-02-16 13:54:13
240 | ``` 241 | 242 | You can set format string like following. 243 | See https://docs.angularjs.org/api/ng/filter/date. 244 | ``` 245 | 246 | ``` 247 | Then you will get like following. 248 | ``` 249 |
2016-02-16
250 | ``` 251 | --- 252 | 253 | ## Creates your custom template tag 254 | 255 | ```js 256 | // Registers your module, you should import `wp`. 257 | var myapp = angular.module( "myapp", [ "wp" ] ); 258 | 259 | // Creates a `` as custom template tag. 260 | // If you place it in your HTML, 261 | // then you can get `Hello`. 262 | myapp.directive( "myPermalink", [ '$sce', function( $sce ) { 263 | return{ 264 | restrict:'E', 265 | replace: true, 266 | require : '^havePosts', 267 | compile: function( tElement, tAttrs, transclude ) { 268 | return { 269 | post: function postLink( scope, element, attrs, controller ) { 270 | var post = scope.$parent.post; // post object 271 | scope.post_id = post.id; 272 | scope.title = post.title.rendered; 273 | } 274 | } 275 | }, 276 | template: "{{ title }}" 277 | } 278 | } ] ); 279 | ``` 280 | 281 | ## Enables Infinite Scroll 282 | 283 | Please load [ngInfiniteScroll](https://sroze.github.io/ngInfiniteScroll/) like following. 284 | 285 | ```html 286 | 287 | 288 | 289 | 290 | 291 | ``` 292 | 293 | Add `infinite-scroll` as a dependency. 294 | 295 | ```js 296 | angular.module( "app", [ "wp", "infinite-scroll" ] ); 297 | ``` 298 | 299 | That's it. 300 | 301 | ## How to contribute 302 | 303 | ``` 304 | $ npm install 305 | ``` 306 | 307 | Run testing. 308 | 309 | ``` 310 | $ npm test 311 | ``` 312 | 313 | Build `js/wp-angular.min.js`. 314 | 315 | ``` 316 | $ npm run build 317 | ``` 318 | 319 | Build documentation. 320 | 321 | ``` 322 | $ npm run docs 323 | ``` 324 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wp-angularjs", 3 | "description": "WP-API client for AngularJS", 4 | "main": "build/wp-angular.min.js", 5 | "authors": [ 6 | "Takayuki Miyauchi" 7 | ], 8 | "license": "MIT", 9 | "homepage": "https://github.com/miya0001/wp-angularjs", 10 | "ignore": [ 11 | "**/.*", 12 | "node_modules", 13 | "bower_components", 14 | "test", 15 | "tests" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /build/wp-angular.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module wp 3 | */ 4 | angular.module( "wp", [ 5 | "wp.services", 6 | "ngResource", 7 | "ngSanitize" 8 | ] ) 9 | 10 | /** 11 | * @name have-posts 12 | * 13 | * @description 14 | * 15 | * The `havePosts` directive is a WordPress loop. 16 | * 17 | * **Attributes** 18 | * 19 | * | Attribute | Type | Details | 20 | * |-----------|--------|----------------------------------------------------------------| 21 | * | api-root | string | Root url of the API. e.g. http://example.com/wp-json/wp/v2 | 22 | * | post-type | string | `posts` or `pages` or `media` or custom post type. | 23 | * | per-page | number | The number of posts per page. Default is 10. | 24 | * | offset | number | The number of post to displace or pass over. Default is 0. | 25 | * | post-id | number | The ID of the post. | 26 | * | filter | object | The object of the filter. | 27 | * 28 | * @example 29 | * 30 | * ```html 31 | * 32 | *

33 | *
34 | *
35 | * ``` 36 | * 37 | * If you want to get single post, you can use `post-id`. 38 | * 39 | * ```html 40 | * 41 | *

42 | *
43 | *
44 | * ``` 45 | * 46 | * You can pass filters to 47 | * [WP_Query](https://codex.wordpress.org/Class_Reference/WP_Query) 48 | * through via the `filter` argument. 49 | * 50 | * ```html 51 | * 53 | *

54 | *
55 | *
56 | * ``` 57 | * 58 | */ 59 | .directive( "havePosts", [ "WP", function( WP ) { 60 | return { 61 | restrict: "E", 62 | replace: true, 63 | transclude: true, 64 | scope: { 65 | postType: '@', 66 | postId: '@', 67 | apiRoot: '@', 68 | perPage: '@', 69 | offset: '@', 70 | filter: '=' 71 | }, 72 | controller: [ "$scope", function( $scope ) { 73 | $scope.load = function() { 74 | if ( $scope.query == $scope.last_query ) { 75 | return; 76 | } 77 | $scope.last_query = $scope.query; 78 | if ( $scope.postId ) { 79 | WP.Query( $scope.apiRoot ).get( $scope.query ).$promise 80 | .then( function( posts ) { 81 | $scope.posts.push( posts ); 82 | } ); 83 | } else if ( $scope.filter && $scope.filter.name ) { 84 | WP.Query( $scope.apiRoot ).query( $scope.query ).$promise 85 | .then( function( posts ) { 86 | if ( posts.length ) { 87 | $scope.is_nextpage = false; 88 | $scope.posts = posts; 89 | } 90 | } ); 91 | } else { 92 | WP.Query( $scope.apiRoot ).query( $scope.query ).$promise 93 | .then( function( posts ) { 94 | if ( posts.length ) { 95 | $scope.is_nextpage = true; 96 | $scope.posts = $scope.posts.concat( posts ); 97 | $scope.last_query = {}; 98 | $scope.query.offset = parseInt( $scope.query.offset ) 99 | + parseInt( $scope.perPage); 100 | // for ionic framework 101 | $scope.$broadcast( 'scroll.infiniteScrollComplete' ); 102 | $scope.$broadcast( 'scroll.refreshComplete'); 103 | } else { 104 | $scope.is_nextpage = false; 105 | } 106 | } ); 107 | } 108 | } 109 | } ], 110 | compile: function( tElement, tAttrs, transclude ) { 111 | return { 112 | pre: function preLink( scope, element, attrs, controller ) { 113 | scope.posts = []; 114 | if ( scope.postId ) { 115 | scope.query = { 116 | 'endpoint': scope.postType, 117 | 'id': scope.postId, 118 | '_embed': true 119 | } 120 | } else { 121 | if ( ! scope.perPage ) { 122 | scope.perPage = 10; 123 | } 124 | if ( ! scope.offset ) { 125 | scope.offset = 0; 126 | } 127 | var query = { 128 | 'endpoint': scope.postType, 129 | 'per_page': scope.perPage, 130 | 'offset': scope.offset, 131 | 'filter[orderby]': 'date', 132 | 'filter[order]': 'DESC', 133 | '_embed': true 134 | } 135 | 136 | scope.query = angular.extend( 137 | query, 138 | WP.parseFilters( scope.filter ) 139 | ); 140 | } 141 | scope.load(); 142 | } 143 | } 144 | }, 145 | link: function( $scope ) { 146 | $scope.$watch( 'filter', function( newValue ) { 147 | $scope.posts = []; 148 | scope.query = angular.extend( 149 | scope.query, 150 | WP.parseFilters( newValue ) 151 | ); 152 | scope.load(); 153 | } ); 154 | }, 155 | template: function( tElement, tAttrs ) { 156 | try { 157 | if ( !! angular.module( 'infinite-scroll' ) ) { 158 | return "
" 159 | + "
" 162 | + "
" 164 | + "
" 165 | + "
"; 166 | } 167 | } catch( e ) { 168 | try { 169 | if ( !! angular.module( 'ionic' ) ) { 170 | return "
" 171 | + "
" 173 | + "
" 174 | + "" 179 | + "" 180 | + "
"; 181 | } 182 | } catch( e ) { 183 | return "
" 184 | + "
" 186 | + "
" 187 | + "
"; 188 | } 189 | } 190 | } 191 | } 192 | } ] ) 193 | 194 | /** 195 | * @name the-title 196 | * 197 | * @description 198 | * 199 | * Displays the post title of the current post. 200 | * This tag must be used within The ``. 201 | * 202 | * **Attributes** 203 | * 204 | * | Attribute | Type | Details | 205 | * |-----------|--------|----------------------------------------------------------------| 206 | * | href | string | Specify a link URL like `#/app/posts/:id`. | 207 | * 208 | * @example 209 | * 210 | * ```html 211 | * 212 | * ``` 213 | * Then: 214 | * ```html 215 | *
Hello World
216 | * ``` 217 | * If you need a link to the post on your app. Please add `href` as attribute. 218 | * ```html 219 | * 220 | * ``` 221 | * Then: 222 | * ```html 223 | * 224 | * ``` 225 | * `:id` is a placeholder of the post's id. You can use `:slug` as post's slug too. 226 | * ```html 227 | * 228 | * ``` 229 | * Then: 230 | * ```html 231 | * 232 | * ``` 233 | */ 234 | .directive( "theTitle", [ "$sce", function( $sce ) { 235 | return{ 236 | restrict:'E', 237 | replace: true, 238 | require : '^havePosts', 239 | transclude: true, 240 | compile: function( tElement, tAttrs, transclude ) { 241 | return { 242 | post: function postLink( scope, element, attrs, controller ) { 243 | var post = scope.$parent.post; 244 | scope.title = post.title.rendered; 245 | if ( tAttrs.href ) { 246 | scope.permalink = tAttrs.href; 247 | scope.permalink = scope.permalink.replace( ':id', post.id ); 248 | scope.permalink = scope.permalink.replace( ':slug', post.slug ); 249 | } else { 250 | scope.permalink = ''; 251 | } 252 | } 253 | } 254 | }, 255 | template: function( tElement, tAttrs ) { 256 | if ( tAttrs.href ) { 257 | return ""; 260 | } else { 261 | return "
" 262 | + "{{ title }}
"; 263 | } 264 | } 265 | } 266 | } ] ) 267 | 268 | /** 269 | * @name the-content 270 | * 271 | * @description 272 | * 273 | * Displays the post content of the current post. 274 | * This tag must be used within The ``. 275 | * 276 | * @example 277 | * 278 | * ```html 279 | * 280 | * ``` 281 | * Then: 282 | * ```html 283 | *

Hello World

284 | * ``` 285 | */ 286 | .directive( "theContent", [ "$sce", function( $sce ) { 287 | return{ 288 | restrict:'E', 289 | replace: true, 290 | require : '^havePosts', 291 | compile: function( tElement, tAttrs, transclude ) { 292 | return { 293 | post: function postLink( scope, element, attrs, controller ) { 294 | var post = scope.$parent.post; 295 | scope.content = $sce.trustAsHtml( post.content.rendered ); 296 | } 297 | } 298 | }, 299 | template: "
" 300 | + "{{ content }}
" 301 | } 302 | } ] ) 303 | 304 | /** 305 | * @name the-post-thumbnail 306 | * 307 | * @description 308 | * 309 | * Displays the post thumbnail of the current post. 310 | * This tag must be used within The ``. 311 | * 312 | * **Attributes** 313 | * 314 | * | Attribute | Type | Details | 315 | * |-----------|--------|----------------------------------------------------------------| 316 | * | size | string | Size of the post thumbnail. Default is `full`. | 317 | * | href | string | Specify a link URL like `#/app/posts/:id`. | 318 | * 319 | * @example 320 | * 321 | * ```html 322 | * 323 | * ``` 324 | * Then: 325 | * ``` 326 | *
327 | * ``` 328 | * Uses `size` attribute. 329 | * ```html 330 | * 331 | * ``` 332 | * Then: 333 | * ``` 334 | *
335 | * ``` 336 | * If you need a link to the post on your app. Please add `href` as attribute. 337 | * ```html 338 | * 339 | * ``` 340 | * Then: 341 | * ```html 342 | *
343 | * 344 | *
345 | * ``` 346 | * `:id` is a placeholder of the post's id. You can use `:slug` as post's slug too. 347 | * 348 | * ```html 349 | * 350 | * ``` 351 | * Then: 352 | * ```html 353 | *
354 | * 355 | *
356 | * ``` 357 | */ 358 | .directive( "thePostThumbnail", [ function() { 359 | return{ 360 | restrict:'E', 361 | replace: true, 362 | require : '^havePosts', 363 | compile: function( tElement, tAttrs, transclude ) { 364 | return { 365 | post: function postLink( scope, element, attrs, controller ) { 366 | if ( ! attrs.size ) { 367 | attrs.size = 'post-thumbnail'; 368 | } 369 | var scheme = 'https://api.w.org/featuredmedia'; 370 | var _embedded = scope.$parent.post._embedded; 371 | var img; 372 | if ( _embedded && _embedded[scheme] && _embedded[scheme].length ) { 373 | if ( _embedded[scheme][0].media_details.sizes[attrs.size] ) { 374 | img = _embedded[scheme][0].media_details 375 | .sizes[attrs.size].source_url; 376 | } else { 377 | img = _embedded[scheme][0].media_details 378 | .sizes['full'].source_url; 379 | } 380 | } 381 | if ( img ) { 382 | scope.image_src = img; 383 | } 384 | 385 | var post = scope.$parent.post; 386 | if ( tAttrs.href ) { 387 | scope.permalink = tAttrs.href; 388 | scope.permalink = scope.permalink.replace( ':id', post.id ); 389 | scope.permalink = scope.permalink.replace( ':slug', post.slug ); 390 | } else { 391 | scope.permalink = ''; 392 | } 393 | } 394 | } 395 | }, 396 | template: function( tElement, tAttrs ) { 397 | if ( tAttrs.href ) { 398 | return "
" 399 | + "" 400 | + "
"; 401 | } else { 402 | return "
" 403 | + "
" 404 | } 405 | } 406 | } 407 | } ] ) 408 | 409 | /** 410 | * @name the-id 411 | * 412 | * @description 413 | * 414 | * Displays the ID of the current post. 415 | * This tag must be used within The ``. 416 | * 417 | * @example 418 | * 419 | * ``` 420 | * 421 | * ``` 422 | * Then: 423 | * ``` 424 | *
123
425 | * ``` 426 | */ 427 | .directive( "theId", [ function() { 428 | return{ 429 | restrict:'E', 430 | replace: true, 431 | require : '^havePosts', 432 | compile: function( tElement, tAttrs, transclude ) { 433 | return { 434 | post: function postLink( scope, element, attrs, controller ) { 435 | scope.post_id = scope.$parent.post.id; 436 | } 437 | } 438 | }, 439 | template: "
{{ post_id }}
" 440 | } 441 | } ] ) 442 | 443 | /** 444 | * @name the-excerpt 445 | * 446 | * @description 447 | * 448 | * Displays the excerpt of the current post. 449 | * This tag must be used within The ``. 450 | * 451 | * @example 452 | * 453 | * Place the code like following into your HTML. 454 | * ``` 455 | * 456 | * ``` 457 | * Then you will get like following. 458 | * ``` 459 | *

Hello World.

460 | * ``` 461 | */ 462 | .directive( "theExcerpt", [ '$sce', function( $sce ) { 463 | return{ 464 | restrict:'E', 465 | replace: true, 466 | require : '^havePosts', 467 | compile: function( tElement, tAttrs, transclude ) { 468 | return { 469 | post: function postLink( scope, element, attrs, controller ) { 470 | var post = scope.$parent.post; 471 | scope.excerpt = $sce.trustAsHtml( post.excerpt.rendered ); 472 | } 473 | } 474 | }, 475 | template: "
" 476 | + "{{ excerpt }}
" 477 | } 478 | } ] ) 479 | 480 | /** 481 | * @name the-date 482 | * 483 | * @description 484 | * 485 | * Displays the date of the current post. 486 | * This tag must be used within The ``. 487 | * 488 | * **Attributes** 489 | * 490 | * | Attribute | Type | Details | 491 | * |-----------|--------|----------------------------------------------------------------| 492 | * | format | string | See https://docs.angularjs.org/api/ng/filter/date | 493 | * 494 | * @example 495 | * 496 | * Place the code like following into your HTML. 497 | * ``` 498 | * 499 | * ``` 500 | * Then you will get like following. 501 | * ``` 502 | *
2016-02-16 13:54:13
503 | * ``` 504 | * 505 | * You can set format string like following. 506 | * See https://docs.angularjs.org/api/ng/filter/date. 507 | * ``` 508 | * 509 | * ``` 510 | * Then you will get like following. 511 | * ``` 512 | *
2016-02-16
513 | * ``` 514 | */ 515 | .directive( "theDate", [ function() { 516 | return{ 517 | restrict:'E', 518 | replace: true, 519 | require : '^havePosts', 520 | compile: function( tElement, tAttrs, transclude ) { 521 | return { 522 | post: function postLink( scope, element, attrs, controller ) { 523 | if ( ! attrs.format ) { 524 | scope.format = "yyyy/MM/ddTH:mm:ssZ"; 525 | } else { 526 | scope.format = attrs.format; 527 | } 528 | var date = scope.$parent.post.date_gmt + "Z"; 529 | scope.date = date; 530 | } 531 | } 532 | }, 533 | template: "
{{ date | date: format }}
" 534 | } 535 | } ] ) 536 | 537 | ; 538 | 539 | /** 540 | * @module wp.services 541 | */ 542 | angular.module( "wp.services", [ "ngResource" ] ) 543 | 544 | .service( "WP", [ "$resource", function( $resource ) { 545 | /** 546 | * @name WP.Query 547 | * 548 | * @description 549 | * Gets the WordPress objects from wp-api. 550 | */ 551 | this.Query = function( apiRoot ) { 552 | var api = apiRoot + "/:endpoint/:id"; 553 | var params = { 554 | endpoint: '@endpoint', 555 | id: '@id' 556 | }; 557 | var actions = {}; 558 | return $resource( api, params, actions ); 559 | } 560 | 561 | this.parseFilters = function( filters ) { 562 | 563 | var filter_strings = {}; 564 | for ( var key in filters ) { 565 | filter_strings[ 'filter[' + key + ']' ] = filters[key]; 566 | } 567 | 568 | return filter_strings; 569 | } 570 | } ] ) 571 | 572 | ; 573 | -------------------------------------------------------------------------------- /build/wp-angular.min.js: -------------------------------------------------------------------------------- 1 | angular.module("wp",["wp.services","ngResource","ngSanitize"]).directive("havePosts",["WP",function(e){return{restrict:"E",replace:!0,transclude:!0,scope:{postType:"@",postId:"@",apiRoot:"@",perPage:"@",offset:"@",filter:"="},controller:["$scope",function(t){t.load=function(){t.query!=t.last_query&&(t.last_query=t.query,t.postId?e.Query(t.apiRoot).get(t.query).$promise.then(function(e){t.posts.push(e)}):t.filter&&t.filter.name?e.Query(t.apiRoot).query(t.query).$promise.then(function(e){e.length&&(t.is_nextpage=!1,t.posts=e)}):e.Query(t.apiRoot).query(t.query).$promise.then(function(e){e.length?(t.is_nextpage=!0,t.posts=t.posts.concat(e),t.last_query={},t.query.offset=parseInt(t.query.offset)+parseInt(t.perPage),t.$broadcast("scroll.infiniteScrollComplete"),t.$broadcast("scroll.refreshComplete")):t.is_nextpage=!1}))}}],compile:function(t,r,i){return{pre:function(t,r,i,n){if(t.posts=[],t.postId)t.query={endpoint:t.postType,id:t.postId,_embed:!0};else{t.perPage||(t.perPage=10),t.offset||(t.offset=0);var s={endpoint:t.postType,per_page:t.perPage,offset:t.offset,"filter[orderby]":"date","filter[order]":"DESC",_embed:!0};t.query=angular.extend(s,e.parseFilters(t.filter))}t.load()}}},link:function(t){t.$watch("filter",function(r){t.posts=[],scope.query=angular.extend(scope.query,e.parseFilters(r)),scope.load()})},template:function(e,t){try{if(angular.module("infinite-scroll"))return'
'}catch(r){try{if(angular.module("ionic"))return'
'}catch(r){return'
'}}}}}]).directive("theTitle",["$sce",function(e){return{restrict:"E",replace:!0,require:"^havePosts",transclude:!0,compile:function(e,t,r){return{post:function(e,r,i,n){var s=e.$parent.post;e.title=s.title.rendered,t.href?(e.permalink=t.href,e.permalink=e.permalink.replace(":id",s.id),e.permalink=e.permalink.replace(":slug",s.slug)):e.permalink=""}}},template:function(e,t){return t.href?'':'
{{ title }}
'}}}]).directive("theContent",["$sce",function(e){return{restrict:"E",replace:!0,require:"^havePosts",compile:function(t,r,i){return{post:function(t,r,i,n){var s=t.$parent.post;t.content=e.trustAsHtml(s.content.rendered)}}},template:'
{{ content }}
'}}]).directive("thePostThumbnail",[function(){return{restrict:"E",replace:!0,require:"^havePosts",compile:function(e,t,r){return{post:function(e,r,i,n){i.size||(i.size="post-thumbnail");var s,o="https://api.w.org/featuredmedia",a=e.$parent.post._embedded;a&&a[o]&&a[o].length&&(s=a[o][0].media_details.sizes[i.size]?a[o][0].media_details.sizes[i.size].source_url:a[o][0].media_details.sizes.full.source_url),s&&(e.image_src=s);var l=e.$parent.post;t.href?(e.permalink=t.href,e.permalink=e.permalink.replace(":id",l.id),e.permalink=e.permalink.replace(":slug",l.slug)):e.permalink=""}}},template:function(e,t){return t.href?'
':'
'}}}]).directive("theId",[function(){return{restrict:"E",replace:!0,require:"^havePosts",compile:function(e,t,r){return{post:function(e,t,r,i){e.post_id=e.$parent.post.id}}},template:'
{{ post_id }}
'}}]).directive("theExcerpt",["$sce",function(e){return{restrict:"E",replace:!0,require:"^havePosts",compile:function(t,r,i){return{post:function(t,r,i,n){var s=t.$parent.post;t.excerpt=e.trustAsHtml(s.excerpt.rendered)}}},template:'
{{ excerpt }}
'}}]).directive("theDate",[function(){return{restrict:"E",replace:!0,require:"^havePosts",compile:function(e,t,r){return{post:function(e,t,r,i){r.format?e.format=r.format:e.format="yyyy/MM/ddTH:mm:ssZ";var n=e.$parent.post.date_gmt+"Z";e.date=n}}},template:'
{{ date | date: format }}
'}}]),angular.module("wp.services",["ngResource"]).service("WP",["$resource",function(e){this.Query=function(t){var r=t+"/:endpoint/:id",i={endpoint:"@endpoint",id:"@id"},n={};return e(r,i,n)},this.parseFilters=function(e){var t={};for(var r in e)t["filter["+r+"]"]=e[r];return t}}]); -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WP-Angular 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | 23 |
24 | 25 |

26 | 29 |
30 |
31 | 32 |
33 |
34 | 35 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/style.css: -------------------------------------------------------------------------------- 1 | h1, 2 | h2, 3 | h3, 4 | h4, 5 | h5, 6 | h6 7 | { 8 | clear: both; 9 | } 10 | 11 | body 12 | { 13 | width: 970px; 14 | max-width: 95%; 15 | margin: 10px auto; 16 | } 17 | 18 | img 19 | { 20 | max-width: 100%; 21 | height: auto; 22 | box-sizing: border-box; 23 | } 24 | 25 | article 26 | { 27 | margin-bottom: 60px; 28 | } 29 | 30 | .entry-title 31 | { 32 | font-size: 400%; 33 | border-bottom: 1px solid #cccccc; 34 | } 35 | 36 | .banner 37 | { 38 | background-color: #cccccc; 39 | padding: 40px; 40 | margin: 0 -40px; 41 | } 42 | 43 | pre 44 | { 45 | white-space: pre-wrap; 46 | } 47 | 48 | .wp-caption 49 | { 50 | padding: 1em; 51 | margin: 0; 52 | max-width: 100%; 53 | height: auto; 54 | box-sizing: border-box; 55 | } 56 | 57 | .wp-caption 58 | { 59 | border: 1px solid #cccccc; 60 | background-color: #f5f5f5; 61 | } 62 | 63 | .wp-caption img 64 | { 65 | padding: 0; 66 | } 67 | 68 | .wp-caption-text 69 | { 70 | margin-top: 0.5em; 71 | } 72 | 73 | .alignleft 74 | { 75 | display: block; 76 | margin-right: 1em; 77 | margin-bottom: 1em; 78 | float: left; 79 | } 80 | 81 | .alignright 82 | { 83 | display: block; 84 | margin-left: 1em; 85 | margin-bottom: 1em; 86 | float: right; 87 | } 88 | 89 | .alignnone 90 | { 91 | display: block; 92 | clear: both; 93 | } 94 | 95 | .aligncenter 96 | { 97 | display: block; 98 | clear: both; 99 | margin-left: auto; 100 | margin-right: auto; 101 | } 102 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require( "gulp" ), 4 | uglify = require( "gulp-uglifyjs" ), 5 | concat = require( "gulp-concat" ); 6 | 7 | gulp.task( 'concat', function() { 8 | return gulp.src( [ 'src/wp.js', 'src/wp-services.js' ] ) 9 | .pipe( concat( 'wp-angular.js' ) ) 10 | .pipe( gulp.dest( 'build' ) ); 11 | }); 12 | 13 | gulp.task( 'uglify', function() { 14 | return gulp.src( [ 'src/wp.js', 'src/wp-services.js' ] ) 15 | .pipe( uglify( 'wp-angular.min.js' ) ) 16 | .pipe( gulp.dest( 'build' ) ); 17 | }); 18 | 19 | gulp.task( 'default', [ 'concat', 'uglify' ], function () { 20 | 21 | } ); 22 | -------------------------------------------------------------------------------- /jsdoc2md/README.hbs: -------------------------------------------------------------------------------- 1 | # wp-angularjs 2 | 3 | [![Build Status](https://travis-ci.org/miya0001/wp-angularjs.svg?branch=master)](https://travis-ci.org/miya0001/wp-angularjs) 4 | 5 | A WP-API Client for [AngularJS](https://angularjs.org/). 6 | 7 | ## Getting Started 8 | 9 | ``` 10 | $ npm install wp-angularjs --save 11 | ``` 12 | 13 | ```html 14 | 16 | 17 |

18 | 21 |
22 | ``` 23 | 24 | Demo: http://miya0001.github.io/wp-angularjs/demo/ 25 | 26 | ## Requires 27 | 28 | * [AngularJS](https://angularjs.org/) 29 | * [ngResource](https://github.com/angular/angular.js/tree/master/src/ngResource) 30 | * [ngSanitize](https://github.com/angular/angular.js/tree/master/src/ngSanitize) 31 | 32 | Recommended: 33 | 34 | * [ngInfiniteScroll](https://sroze.github.io/ngInfiniteScroll/) 35 | * [jQuery](https://jquery.com/) 36 | 37 | ## API Reference 38 | 39 | {{#module name="wp"}} 40 | {{#children inherited=undefined ~}} 41 | * [<{{name}}>](#{{name}}) 42 | {{/children~}} 43 | {{/module}} 44 | 45 | --- 46 | 47 | {{#module name="wp"}} 48 | {{#children inherited=undefined ~}} 49 | ### <{{name}}> 50 | {{>description~}} 51 | {{>examples~}} 52 | --- 53 | {{/children~}} 54 | {{/module}} 55 | 56 | ## Creates your custom template tag 57 | 58 | ```js 59 | // Registers your module, you should import `wp`. 60 | var myapp = angular.module( "myapp", [ "wp" ] ); 61 | 62 | // Creates a `` as custom template tag. 63 | // If you place it in your HTML, 64 | // then you can get `Hello`. 65 | myapp.directive( "myPermalink", [ '$sce', function( $sce ) { 66 | return{ 67 | restrict:'E', 68 | replace: true, 69 | require : '^havePosts', 70 | compile: function( tElement, tAttrs, transclude ) { 71 | return { 72 | post: function postLink( scope, element, attrs, controller ) { 73 | var post = scope.$parent.post; // post object 74 | scope.post_id = post.id; 75 | scope.title = post.title.rendered; 76 | } 77 | } 78 | }, 79 | template: "\{{ title }}" 80 | } 81 | } ] ); 82 | ``` 83 | 84 | ## Enables Infinite Scroll 85 | 86 | Please load [ngInfiniteScroll](https://sroze.github.io/ngInfiniteScroll/) like following. 87 | 88 | ```html 89 | 90 | 91 | 92 | 93 | 94 | ``` 95 | 96 | Add `infinite-scroll` as a dependency. 97 | 98 | ```js 99 | angular.module( "app", [ "wp", "infinite-scroll" ] ); 100 | ``` 101 | 102 | That's it. 103 | 104 | ## How to contribute 105 | 106 | ``` 107 | $ npm install 108 | ``` 109 | 110 | Run testing. 111 | 112 | ``` 113 | $ npm test 114 | ``` 115 | 116 | Build `js/wp-angular.min.js`. 117 | 118 | ``` 119 | $ npm run build 120 | ``` 121 | 122 | Build documentation. 123 | 124 | ``` 125 | $ npm run docs 126 | ``` 127 | 128 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wp-angularjs", 3 | "version": "1.2.3", 4 | "description": "WP-API client for AngularJS", 5 | "scripts": { 6 | "build": "npm test && npm run docs", 7 | "test": "./node_modules/.bin/gulp && ./node_modules/.bin/karma start tests/karma.conf.js", 8 | "docs": "./node_modules/.bin/jsdoc2md -t jsdoc2md/README.hbs src/*.js > README.md" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/miya0001/wp-angularjs" 13 | }, 14 | "author": "Takayuki Miyauchi", 15 | "license": "MIT", 16 | "main": "build/wp-angular.min.js", 17 | "devDependencies": { 18 | "angular-mocks": "^1.5.0", 19 | "dmd": "^1.3.10", 20 | "gulp": "^3.9.1", 21 | "gulp-concat": "^2.6.0", 22 | "gulp-uglify": "^1.5.3", 23 | "gulp-uglifyjs": "^0.6.2", 24 | "jasmine-core": "^2.4.1", 25 | "jsdoc-to-markdown": "^1.3.3", 26 | "karma": "^0.13.21", 27 | "karma-jasmine": "^0.3.7", 28 | "karma-phantomjs-launcher": "^1.0.0", 29 | "phantomjs": "^2.1.3", 30 | "phantomjs-prebuilt": "^2.1.4" 31 | }, 32 | "dependencies": { 33 | "angular": "^1.5", 34 | "angular-resource": "^1.5", 35 | "angular-sanitize": "^1.5", 36 | "jquery": "^2.2", 37 | "ng-infinite-scroll": "^1.2" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/wp-services.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module wp.services 3 | */ 4 | angular.module( "wp.services", [ "ngResource" ] ) 5 | 6 | .service( "WP", [ "$resource", function( $resource ) { 7 | /** 8 | * @name WP.Query 9 | * 10 | * @description 11 | * Gets the WordPress objects from wp-api. 12 | */ 13 | this.Query = function( apiRoot ) { 14 | var api = apiRoot + "/:endpoint/:id"; 15 | var params = { 16 | endpoint: '@endpoint', 17 | id: '@id' 18 | }; 19 | var actions = {}; 20 | return $resource( api, params, actions ); 21 | } 22 | 23 | this.parseFilters = function( filters ) { 24 | 25 | var filter_strings = {}; 26 | for ( var key in filters ) { 27 | filter_strings[ 'filter[' + key + ']' ] = filters[key]; 28 | } 29 | 30 | return filter_strings; 31 | } 32 | } ] ) 33 | 34 | ; 35 | -------------------------------------------------------------------------------- /src/wp.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module wp 3 | */ 4 | angular.module( "wp", [ 5 | "wp.services", 6 | "ngResource", 7 | "ngSanitize" 8 | ] ) 9 | 10 | /** 11 | * @name have-posts 12 | * 13 | * @description 14 | * 15 | * The `havePosts` directive is a WordPress loop. 16 | * 17 | * **Attributes** 18 | * 19 | * | Attribute | Type | Details | 20 | * |-----------|--------|----------------------------------------------------------------| 21 | * | api-root | string | Root url of the API. e.g. http://example.com/wp-json/wp/v2 | 22 | * | post-type | string | `posts` or `pages` or `media` or custom post type. | 23 | * | per-page | number | The number of posts per page. Default is 10. | 24 | * | offset | number | The number of post to displace or pass over. Default is 0. | 25 | * | post-id | number | The ID of the post. | 26 | * | filter | object | The object of the filter. | 27 | * 28 | * @example 29 | * 30 | * ```html 31 | * 32 | *

33 | *
34 | *
35 | * ``` 36 | * 37 | * If you want to get single post, you can use `post-id`. 38 | * 39 | * ```html 40 | * 41 | *

42 | *
43 | *
44 | * ``` 45 | * 46 | * You can pass filters to 47 | * [WP_Query](https://codex.wordpress.org/Class_Reference/WP_Query) 48 | * through via the `filter` argument. 49 | * 50 | * ```html 51 | * 53 | *

54 | *
55 | *
56 | * ``` 57 | * 58 | */ 59 | .directive( "havePosts", [ "WP", function( WP ) { 60 | return { 61 | restrict: "E", 62 | replace: true, 63 | transclude: true, 64 | scope: { 65 | postType: '@', 66 | postId: '@', 67 | apiRoot: '@', 68 | perPage: '@', 69 | offset: '@', 70 | filter: '=' 71 | }, 72 | controller: [ "$scope", function( $scope ) { 73 | $scope.load = function() { 74 | if ( $scope.query == $scope.last_query ) { 75 | return; 76 | } 77 | $scope.last_query = $scope.query; 78 | if ( $scope.postId ) { 79 | WP.Query( $scope.apiRoot ).get( $scope.query ).$promise 80 | .then( function( posts ) { 81 | $scope.posts.push( posts ); 82 | } ); 83 | } else if ( $scope.filter && $scope.filter.name ) { 84 | WP.Query( $scope.apiRoot ).query( $scope.query ).$promise 85 | .then( function( posts ) { 86 | if ( posts.length ) { 87 | $scope.is_nextpage = false; 88 | $scope.posts = posts; 89 | } 90 | } ); 91 | } else { 92 | WP.Query( $scope.apiRoot ).query( $scope.query ).$promise 93 | .then( function( posts ) { 94 | if ( posts.length ) { 95 | $scope.is_nextpage = true; 96 | $scope.posts = $scope.posts.concat( posts ); 97 | $scope.last_query = {}; 98 | $scope.query.offset = parseInt( $scope.query.offset ) 99 | + parseInt( $scope.perPage); 100 | // for ionic framework 101 | $scope.$broadcast( 'scroll.infiniteScrollComplete' ); 102 | $scope.$broadcast( 'scroll.refreshComplete'); 103 | } else { 104 | $scope.is_nextpage = false; 105 | } 106 | } ); 107 | } 108 | } 109 | } ], 110 | compile: function( tElement, tAttrs, transclude ) { 111 | return { 112 | pre: function preLink( scope, element, attrs, controller ) { 113 | scope.posts = []; 114 | if ( scope.postId ) { 115 | scope.query = { 116 | 'endpoint': scope.postType, 117 | 'id': scope.postId, 118 | '_embed': true 119 | } 120 | } else { 121 | if ( ! scope.perPage ) { 122 | scope.perPage = 10; 123 | } 124 | if ( ! scope.offset ) { 125 | scope.offset = 0; 126 | } 127 | var query = { 128 | 'endpoint': scope.postType, 129 | 'per_page': scope.perPage, 130 | 'offset': scope.offset, 131 | 'filter[orderby]': 'date', 132 | 'filter[order]': 'DESC', 133 | '_embed': true 134 | } 135 | 136 | scope.query = angular.extend( 137 | query, 138 | WP.parseFilters( scope.filter ) 139 | ); 140 | } 141 | scope.load(); 142 | } 143 | } 144 | }, 145 | link: function( $scope ) { 146 | $scope.$watch( 'filter', function( newValue ) { 147 | $scope.posts = []; 148 | scope.query = angular.extend( 149 | scope.query, 150 | WP.parseFilters( newValue ) 151 | ); 152 | scope.load(); 153 | } ); 154 | }, 155 | template: function( tElement, tAttrs ) { 156 | try { 157 | if ( !! angular.module( 'infinite-scroll' ) ) { 158 | return "
" 159 | + "
" 162 | + "
" 164 | + "
" 165 | + "
"; 166 | } 167 | } catch( e ) { 168 | try { 169 | if ( !! angular.module( 'ionic' ) ) { 170 | return "
" 171 | + "
" 173 | + "
" 174 | + "" 179 | + "" 180 | + "
"; 181 | } 182 | } catch( e ) { 183 | return "
" 184 | + "
" 186 | + "
" 187 | + "
"; 188 | } 189 | } 190 | } 191 | } 192 | } ] ) 193 | 194 | /** 195 | * @name the-title 196 | * 197 | * @description 198 | * 199 | * Displays the post title of the current post. 200 | * This tag must be used within The ``. 201 | * 202 | * **Attributes** 203 | * 204 | * | Attribute | Type | Details | 205 | * |-----------|--------|----------------------------------------------------------------| 206 | * | href | string | Specify a link URL like `#/app/posts/:id`. | 207 | * 208 | * @example 209 | * 210 | * ```html 211 | * 212 | * ``` 213 | * Then: 214 | * ```html 215 | *
Hello World
216 | * ``` 217 | * If you need a link to the post on your app. Please add `href` as attribute. 218 | * ```html 219 | * 220 | * ``` 221 | * Then: 222 | * ```html 223 | * 224 | * ``` 225 | * `:id` is a placeholder of the post's id. You can use `:slug` as post's slug too. 226 | * ```html 227 | * 228 | * ``` 229 | * Then: 230 | * ```html 231 | * 232 | * ``` 233 | */ 234 | .directive( "theTitle", [ "$sce", function( $sce ) { 235 | return{ 236 | restrict:'E', 237 | replace: true, 238 | require : '^havePosts', 239 | transclude: true, 240 | compile: function( tElement, tAttrs, transclude ) { 241 | return { 242 | post: function postLink( scope, element, attrs, controller ) { 243 | var post = scope.$parent.post; 244 | scope.title = post.title.rendered; 245 | if ( tAttrs.href ) { 246 | scope.permalink = tAttrs.href; 247 | scope.permalink = scope.permalink.replace( ':id', post.id ); 248 | scope.permalink = scope.permalink.replace( ':slug', post.slug ); 249 | } else { 250 | scope.permalink = ''; 251 | } 252 | } 253 | } 254 | }, 255 | template: function( tElement, tAttrs ) { 256 | if ( tAttrs.href ) { 257 | return ""; 260 | } else { 261 | return "
" 262 | + "{{ title }}
"; 263 | } 264 | } 265 | } 266 | } ] ) 267 | 268 | /** 269 | * @name the-content 270 | * 271 | * @description 272 | * 273 | * Displays the post content of the current post. 274 | * This tag must be used within The ``. 275 | * 276 | * @example 277 | * 278 | * ```html 279 | * 280 | * ``` 281 | * Then: 282 | * ```html 283 | *

Hello World

284 | * ``` 285 | */ 286 | .directive( "theContent", [ "$sce", function( $sce ) { 287 | return{ 288 | restrict:'E', 289 | replace: true, 290 | require : '^havePosts', 291 | compile: function( tElement, tAttrs, transclude ) { 292 | return { 293 | post: function postLink( scope, element, attrs, controller ) { 294 | var post = scope.$parent.post; 295 | scope.content = $sce.trustAsHtml( post.content.rendered ); 296 | } 297 | } 298 | }, 299 | template: "
" 300 | + "{{ content }}
" 301 | } 302 | } ] ) 303 | 304 | /** 305 | * @name the-post-thumbnail 306 | * 307 | * @description 308 | * 309 | * Displays the post thumbnail of the current post. 310 | * This tag must be used within The ``. 311 | * 312 | * **Attributes** 313 | * 314 | * | Attribute | Type | Details | 315 | * |-----------|--------|----------------------------------------------------------------| 316 | * | size | string | Size of the post thumbnail. Default is `full`. | 317 | * | href | string | Specify a link URL like `#/app/posts/:id`. | 318 | * 319 | * @example 320 | * 321 | * ```html 322 | * 323 | * ``` 324 | * Then: 325 | * ``` 326 | *
327 | * ``` 328 | * Uses `size` attribute. 329 | * ```html 330 | * 331 | * ``` 332 | * Then: 333 | * ``` 334 | *
335 | * ``` 336 | * If you need a link to the post on your app. Please add `href` as attribute. 337 | * ```html 338 | * 339 | * ``` 340 | * Then: 341 | * ```html 342 | *
343 | * 344 | *
345 | * ``` 346 | * `:id` is a placeholder of the post's id. You can use `:slug` as post's slug too. 347 | * 348 | * ```html 349 | * 350 | * ``` 351 | * Then: 352 | * ```html 353 | *
354 | * 355 | *
356 | * ``` 357 | */ 358 | .directive( "thePostThumbnail", [ function() { 359 | return{ 360 | restrict:'E', 361 | replace: true, 362 | require : '^havePosts', 363 | compile: function( tElement, tAttrs, transclude ) { 364 | return { 365 | post: function postLink( scope, element, attrs, controller ) { 366 | if ( ! attrs.size ) { 367 | attrs.size = 'post-thumbnail'; 368 | } 369 | var scheme = 'https://api.w.org/featuredmedia'; 370 | var _embedded = scope.$parent.post._embedded; 371 | var img; 372 | if ( _embedded && _embedded[scheme] && _embedded[scheme].length ) { 373 | if ( _embedded[scheme][0].media_details.sizes[attrs.size] ) { 374 | img = _embedded[scheme][0].media_details 375 | .sizes[attrs.size].source_url; 376 | } else { 377 | img = _embedded[scheme][0].media_details 378 | .sizes['full'].source_url; 379 | } 380 | } 381 | if ( img ) { 382 | scope.image_src = img; 383 | } 384 | 385 | var post = scope.$parent.post; 386 | if ( tAttrs.href ) { 387 | scope.permalink = tAttrs.href; 388 | scope.permalink = scope.permalink.replace( ':id', post.id ); 389 | scope.permalink = scope.permalink.replace( ':slug', post.slug ); 390 | } else { 391 | scope.permalink = ''; 392 | } 393 | } 394 | } 395 | }, 396 | template: function( tElement, tAttrs ) { 397 | if ( tAttrs.href ) { 398 | return "
" 399 | + "" 400 | + "
"; 401 | } else { 402 | return "
" 403 | + "
" 404 | } 405 | } 406 | } 407 | } ] ) 408 | 409 | /** 410 | * @name the-id 411 | * 412 | * @description 413 | * 414 | * Displays the ID of the current post. 415 | * This tag must be used within The ``. 416 | * 417 | * @example 418 | * 419 | * ``` 420 | * 421 | * ``` 422 | * Then: 423 | * ``` 424 | *
123
425 | * ``` 426 | */ 427 | .directive( "theId", [ function() { 428 | return{ 429 | restrict:'E', 430 | replace: true, 431 | require : '^havePosts', 432 | compile: function( tElement, tAttrs, transclude ) { 433 | return { 434 | post: function postLink( scope, element, attrs, controller ) { 435 | scope.post_id = scope.$parent.post.id; 436 | } 437 | } 438 | }, 439 | template: "
{{ post_id }}
" 440 | } 441 | } ] ) 442 | 443 | /** 444 | * @name the-excerpt 445 | * 446 | * @description 447 | * 448 | * Displays the excerpt of the current post. 449 | * This tag must be used within The ``. 450 | * 451 | * @example 452 | * 453 | * Place the code like following into your HTML. 454 | * ``` 455 | * 456 | * ``` 457 | * Then you will get like following. 458 | * ``` 459 | *

Hello World.

460 | * ``` 461 | */ 462 | .directive( "theExcerpt", [ '$sce', function( $sce ) { 463 | return{ 464 | restrict:'E', 465 | replace: true, 466 | require : '^havePosts', 467 | compile: function( tElement, tAttrs, transclude ) { 468 | return { 469 | post: function postLink( scope, element, attrs, controller ) { 470 | var post = scope.$parent.post; 471 | scope.excerpt = $sce.trustAsHtml( post.excerpt.rendered ); 472 | } 473 | } 474 | }, 475 | template: "
" 476 | + "{{ excerpt }}
" 477 | } 478 | } ] ) 479 | 480 | /** 481 | * @name the-date 482 | * 483 | * @description 484 | * 485 | * Displays the date of the current post. 486 | * This tag must be used within The ``. 487 | * 488 | * **Attributes** 489 | * 490 | * | Attribute | Type | Details | 491 | * |-----------|--------|----------------------------------------------------------------| 492 | * | format | string | See https://docs.angularjs.org/api/ng/filter/date | 493 | * 494 | * @example 495 | * 496 | * Place the code like following into your HTML. 497 | * ``` 498 | * 499 | * ``` 500 | * Then you will get like following. 501 | * ``` 502 | *
2016-02-16 13:54:13
503 | * ``` 504 | * 505 | * You can set format string like following. 506 | * See https://docs.angularjs.org/api/ng/filter/date. 507 | * ``` 508 | * 509 | * ``` 510 | * Then you will get like following. 511 | * ``` 512 | *
2016-02-16
513 | * ``` 514 | */ 515 | .directive( "theDate", [ function() { 516 | return{ 517 | restrict:'E', 518 | replace: true, 519 | require : '^havePosts', 520 | compile: function( tElement, tAttrs, transclude ) { 521 | return { 522 | post: function postLink( scope, element, attrs, controller ) { 523 | if ( ! attrs.format ) { 524 | scope.format = "yyyy/MM/ddTH:mm:ssZ"; 525 | } else { 526 | scope.format = attrs.format; 527 | } 528 | var date = scope.$parent.post.date_gmt + "Z"; 529 | scope.date = date; 530 | } 531 | } 532 | }, 533 | template: "
{{ date | date: format }}
" 534 | } 535 | } ] ) 536 | 537 | ; 538 | -------------------------------------------------------------------------------- /tests/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Wed Mar 02 2016 18:28:12 GMT+0900 (JST) 3 | 4 | module.exports = function( config ) { 5 | config.set( { 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '', 9 | 10 | // frameworks to use 11 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 12 | frameworks: [ 'jasmine' ], 13 | 14 | plugins : [ 15 | 'karma-jasmine', 16 | 'karma-phantomjs-launcher' 17 | ], 18 | 19 | // list of files / patterns to load in the browser 20 | files: [ 21 | '../node_modules/jquery/dist/jquery.min.js', 22 | '../node_modules/angular/angular.min.js', 23 | '../node_modules/angular-resource/angular-resource.min.js', 24 | '../node_modules/angular-mocks/angular-mocks.js', 25 | '../node_modules/angular-sanitize/angular-sanitize.min.js', 26 | '../node_modules/ng-infinite-scroll/build/ng-infinite-scroll.min.js', 27 | '../build/wp-angular.min.js', 28 | '../tests/spec/**/*.js' 29 | ], 30 | 31 | 32 | // list of files to exclude 33 | exclude: [ 34 | ], 35 | 36 | 37 | // preprocess matching files before serving them to the browser 38 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 39 | preprocessors: { 40 | }, 41 | 42 | 43 | // test results reporter to use 44 | // possible values: 'dots', 'progress' 45 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 46 | reporters: [ 'dots' ], 47 | 48 | 49 | // web server port 50 | port: 9876, 51 | 52 | 53 | // enable / disable colors in the output (reporters and logs) 54 | colors: true, 55 | 56 | 57 | // level of logging 58 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 59 | logLevel: config.LOG_INFO, 60 | 61 | 62 | // enable / disable watching file and executing tests whenever any file changes 63 | autoWatch: true, 64 | 65 | 66 | // start these browsers 67 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 68 | browsers: [ 'PhantomJS' ], 69 | 70 | 71 | // Continuous Integration mode 72 | // if true, Karma captures browsers, runs the tests and exits 73 | singleRun: true, 74 | 75 | // Concurrency level 76 | // how many browser should be started simultaneous 77 | concurrency: Infinity 78 | } ) 79 | } 80 | -------------------------------------------------------------------------------- /tests/spec/have-posts-single.js: -------------------------------------------------------------------------------- 1 | describe( 'havePosts directive', function() { 2 | 3 | var $compile, 4 | $rootScope; 5 | 6 | beforeEach( module( 'wp' ) ); // It should be module for testing. 7 | 8 | beforeEach( inject( function( _$httpBackend_, _$compile_, _$rootScope_ ) { 9 | $httpBackend = _$httpBackend_; 10 | $compile = _$compile_; 11 | $rootScope = _$rootScope_; 12 | 13 | // get singular content 14 | $httpBackend.when( 'GET', /\/(posts)|(pages)\/[0-9]+/ ).respond( 200, { 15 | id: '3', 16 | title: { 17 | rendered: 'Title(3)' 18 | }, 19 | content: { 20 | rendered: 'Hello World(3)' 21 | } 22 | } ); 23 | } ) ); 24 | 25 | afterEach(function() { 26 | $httpBackend.verifyNoOutstandingExpectation(); 27 | $httpBackend.verifyNoOutstandingRequest(); 28 | }); 29 | 30 | var api = "http://example.jp"; 31 | 32 | it( 'module "wp" should be exists', inject( function( $rootScope, $compile ) { 33 | expect( angular.module( 'wp' ) ).not.toBeNull() 34 | } ) ); 35 | 36 | it( 'module "wp" requires "ngResource"', inject( function( $rootScope, $compile ) { 37 | expect( angular.module( 'wp' ).requires ).toContain( 'ngResource' ) 38 | } ) ); 39 | 40 | it( 'post id should be 3', 41 | inject( function( $rootScope, $compile ) { 42 | var html = '' 44 | var element = $compile( html )( $rootScope ); 45 | $rootScope.$digest(); 46 | $httpBackend.flush(); 47 | expect( $rootScope.$$childTail.postId ).toEqual( "3" ); 48 | } ) ); 49 | 50 | it( 'query should be correct', 51 | inject( function( $rootScope, $compile ) { 52 | var html = '' 54 | var element = $compile( html )( $rootScope ); 55 | $rootScope.$digest(); 56 | $httpBackend.flush(); 57 | expect( $rootScope.$$childTail.query ) 58 | .toEqual( { endpoint: 'posts', id: '3', _embed: true } ); 59 | } ) ); 60 | 61 | it( 'template tag should be working', 62 | inject( function( $rootScope, $compile ) { 63 | var html = '' 65 | var element = $compile( html )( $rootScope ); 66 | $rootScope.$digest(); 67 | $httpBackend.flush(); 68 | expect( $( '.the-id', element ).eq( 0 ).text() ).toEqual( "3" ); 69 | } ) ); 70 | } ); 71 | -------------------------------------------------------------------------------- /tests/spec/have-posts.js: -------------------------------------------------------------------------------- 1 | describe( 'havePosts directive', function() { 2 | 3 | /** 4 | * Example of the custom template tag for testing 5 | */ 6 | var myapp = angular.module( "myapp", [ "wp" ] ); 7 | 8 | myapp.directive( "myPermalink", [ '$sce', function( $sce ) { 9 | return{ 10 | restrict:'E', 11 | replace: true, 12 | require : '^havePosts', 13 | compile: function( tElement, tAttrs, transclude ) { 14 | return { 15 | post: function postLink( scope, element, attrs, controller ) { 16 | var post = scope.$parent.post; // post object 17 | scope.id = post.id; 18 | scope.title = post.title.rendered; 19 | } 20 | } 21 | }, 22 | template: "{{ title }}" 23 | } 24 | } ] ); 25 | // end custom template tag 26 | 27 | var $compile, 28 | $rootScope; 29 | 30 | beforeEach( module( 'myapp' ) ); // It should be module for testing. 31 | 32 | beforeEach( inject( function( _$httpBackend_, _$compile_, _$rootScope_ ) { 33 | $httpBackend = _$httpBackend_; 34 | $compile = _$compile_; 35 | $rootScope = _$rootScope_; 36 | 37 | // list of the posts or pages 38 | $httpBackend.when( 'GET', /\/(posts)|(pages)\?/ ).respond( 200, [ 39 | { 40 | id: '1', 41 | title: { 42 | rendered: 'Title(1)' 43 | }, 44 | content: { 45 | rendered: '

Hello World(1)

' 46 | }, 47 | excerpt: { 48 | rendered: '

This is the excerpt. (1)

' 49 | }, 50 | date_gmt: '2016-02-16T13:54:13' 51 | }, 52 | { 53 | id: '2', 54 | title: { 55 | rendered: 'Title(2)' 56 | }, 57 | content: { 58 | rendered: '

Hello World(2)

' 59 | }, 60 | excerpt: { 61 | rendered: '

This is the excerpt. (2)

' 62 | }, 63 | date_gmt: '2016-02-16T13:54:13' 64 | }, 65 | { 66 | id: '3', 67 | title: { 68 | rendered: 'Title(3)' 69 | }, 70 | content: { 71 | rendered: '

Hello World(3)

' 72 | }, 73 | excerpt: { 74 | rendered: '

This is the excerpt. (3)

' 75 | }, 76 | date_gmt: '2016-02-16T13:54:13' 77 | } 78 | ] ); 79 | } ) ); 80 | 81 | afterEach(function() { 82 | $httpBackend.verifyNoOutstandingExpectation(); 83 | $httpBackend.verifyNoOutstandingRequest(); 84 | }); 85 | 86 | var api = "http://example.jp"; 87 | 88 | it( 'module "wp" should be exists', inject( function( $rootScope, $compile ) { 89 | expect( angular.module( 'wp' ) ).not.toBeNull() 90 | } ) ); 91 | 92 | it( 'module "wp" requires "ngResource"', inject( function( $rootScope, $compile ) { 93 | expect( angular.module( 'wp' ).requires ).toContain( 'ngResource' ) 94 | } ) ); 95 | 96 | it( 'scope.apiRoot should be "http://example.jp"', 97 | inject( function( $rootScope, $compile ) { 98 | var html = 'Post type is {{ postType }}' 100 | var element = $compile( html )( $rootScope ); 101 | $rootScope.$digest(); 102 | $httpBackend.flush(); 103 | expect( $rootScope.$$childTail.apiRoot ).toEqual( api ); 104 | } ) ); 105 | 106 | it( 'perPage should be 3', inject( function( $rootScope, $compile ) { 107 | var html = '' 108 | + ''; 109 | var element = $compile( html )( $rootScope ); 110 | $rootScope.$digest(); 111 | $httpBackend.flush(); 112 | expect( $rootScope.$$childTail.query.per_page ).toEqual( "3" ); 113 | } ) ); 114 | 115 | it( 'offset should be 11', inject( function( $rootScope, $compile ) { 116 | var html = '' 117 | + ''; 118 | var element = $compile( html )( $rootScope ); 119 | $rootScope.$digest(); 120 | $httpBackend.flush(); 121 | // offset should be 11 + 10, because it is updated after load. 122 | expect( $rootScope.$$childTail.query.offset ).toEqual( 21 ); 123 | } ) ); 124 | 125 | it( ' should be div', inject( function( $rootScope, $compile ) { 126 | var html = 'Post type is {{ postType }}' 128 | var element = $compile( html )( $rootScope ); 129 | $rootScope.$digest(); 130 | $httpBackend.flush(); 131 | expect( element.prop( 'tagName' ) ).toEqual( 'DIV' ); 132 | } ) ); 133 | 134 | it( ' should have class `posts`', 135 | inject( function( $rootScope, $compile ) { 136 | var html = ''; 137 | var element = $compile( html )( $rootScope ); 138 | $rootScope.$digest(); 139 | $httpBackend.flush(); 140 | expect( element.hasClass( 'have-posts' ) ).toEqual( true ); 141 | } ) ); 142 | 143 | it( 'should have class "pages"', inject( function( $rootScope, $compile ) { 144 | var html = ''; 145 | var element = $compile( html )( $rootScope ); 146 | $rootScope.$digest(); 147 | $httpBackend.flush(); 148 | var e = angular.element( 'article', element ).eq( 0 ); 149 | expect( e.hasClass( 'pages' ) ).toEqual( true ); 150 | } ) ); 151 | 152 | it( 'postType should be posts', inject( function( $rootScope, $compile ) { 153 | var html = ''; 154 | var element = $compile( html )( $rootScope ); 155 | $rootScope.$digest(); 156 | $httpBackend.flush(); 157 | expect( $rootScope.$$childTail.postType ).toEqual( 'posts' ); 158 | } ) ); 159 | 160 | it( 'orderBy should be "ABC"', inject( function( $rootScope, $compile ) { 161 | var html = '"; 163 | var element = $compile( html )( $rootScope ); 164 | $rootScope.$digest(); 165 | $httpBackend.flush(); 166 | expect( $rootScope.$$childTail.query ).toEqual( { 167 | "endpoint": 'posts', 168 | "per_page": 10, 169 | "offset": 10, 170 | "filter[orderby]": 'ABC', 171 | "filter[order]": 'DESC', 172 | "_embed": true, 173 | "filter[cat]": 123 174 | } ); 175 | } ) ); 176 | 177 | it( 'Creates a custom template tag', inject( function( $rootScope, $compile ) { 178 | var html = '' 179 | + ''; 180 | var element = $compile( html )( $rootScope ); 181 | $rootScope.$digest(); 182 | $httpBackend.flush(); 183 | for ( var i = 0; i < angular.element( 'a', element ).length; i++ ) { 184 | var n = i + 1; 185 | expect( angular.element( 'a', element ).eq(i).text() ) 186 | .toEqual( 'Title(' + n + ')' ); 187 | expect( angular.element( 'a', element ).eq(i).attr( 'href' ) ) 188 | .toEqual( '#!/post/' + n ); 189 | } 190 | } ) ); 191 | 192 | it( 'Tests for angular.extend()', inject( function( $rootScope, $compile ) { 193 | var dst = { key1: 'dst1', key2: 'dst2' }; 194 | var src = { key1: 'src1', key3: 'src3' }; 195 | var res = angular.extend( dst, src ); 196 | expect( res ).toEqual( { key1: 'src1', key2: 'dst2', key3: 'src3' } ); 197 | } ) ); 198 | } ); 199 | -------------------------------------------------------------------------------- /tests/spec/the-content.js: -------------------------------------------------------------------------------- 1 | describe( 'theContent directive', function() { 2 | 3 | var $compile, 4 | $rootScope; 5 | 6 | beforeEach( module( 'wp' ) ); // It should be module for testing. 7 | 8 | beforeEach( inject( function( _$httpBackend_, _$compile_, _$rootScope_ ) { 9 | $httpBackend = _$httpBackend_; 10 | $compile = _$compile_; 11 | $rootScope = _$rootScope_; 12 | 13 | // list of the posts or pages 14 | $httpBackend.when( 'GET', /\/(posts)|(pages)\?/ ).respond( 200, [ 15 | { 16 | id: '1', 17 | title: { 18 | rendered: 'Title(1)' 19 | }, 20 | content: { 21 | rendered: '

Hello World(1)

' 22 | }, 23 | excerpt: { 24 | rendered: '

This is the excerpt. (1)

' 25 | }, 26 | date_gmt: '2016-02-16T13:54:13' 27 | }, 28 | { 29 | id: '2', 30 | title: { 31 | rendered: 'Title(2)' 32 | }, 33 | content: { 34 | rendered: '

Hello World(2)

' 35 | }, 36 | excerpt: { 37 | rendered: '

This is the excerpt. (2)

' 38 | }, 39 | date_gmt: '2016-02-16T13:54:13' 40 | }, 41 | { 42 | id: '3', 43 | title: { 44 | rendered: 'Title(3)' 45 | }, 46 | content: { 47 | rendered: '

Hello World(3)

' 48 | }, 49 | excerpt: { 50 | rendered: '

This is the excerpt. (3)

' 51 | }, 52 | date_gmt: '2016-02-16T13:54:13' 53 | } 54 | ] ); 55 | } ) ); 56 | 57 | afterEach(function() { 58 | $httpBackend.verifyNoOutstandingExpectation(); 59 | $httpBackend.verifyNoOutstandingRequest(); 60 | }); 61 | 62 | var api = "http://example.jp"; 63 | 64 | it( 'Tests for ', inject( function( $rootScope, $compile ) { 65 | var html = '' 66 | + ''; 67 | var element = $compile( html )( $rootScope ); 68 | $rootScope.$digest(); 69 | $httpBackend.flush(); 70 | expect( angular.element( '.the-content', element ).length ).toEqual( 3 ); 71 | for ( var i = 0; i < angular.element( '.the-content', element ).length; i++ ) { 72 | var n = i + 1; 73 | expect( angular.element( '.the-content', element ).eq(i).html() ) 74 | .toEqual( '

Hello World(' + n + ')

' ); 75 | } 76 | } ) ); 77 | } ); 78 | -------------------------------------------------------------------------------- /tests/spec/the-date.js: -------------------------------------------------------------------------------- 1 | describe( 'theDate directive', function() { 2 | 3 | var $compile, 4 | $rootScope; 5 | 6 | beforeEach( module( 'wp' ) ); // It should be module for testing. 7 | 8 | beforeEach( inject( function( _$httpBackend_, _$compile_, _$rootScope_ ) { 9 | $httpBackend = _$httpBackend_; 10 | $compile = _$compile_; 11 | $rootScope = _$rootScope_; 12 | 13 | // list of the posts or pages 14 | $httpBackend.when( 'GET', /\/(posts)|(pages)\?/ ).respond( 200, [ 15 | { 16 | id: '1', 17 | title: { 18 | rendered: 'Title(1)' 19 | }, 20 | content: { 21 | rendered: '

Hello World(1)

' 22 | }, 23 | excerpt: { 24 | rendered: '

This is the excerpt. (1)

' 25 | }, 26 | date_gmt: '2016-02-16T13:54:13' 27 | }, 28 | { 29 | id: '2', 30 | title: { 31 | rendered: 'Title(2)' 32 | }, 33 | content: { 34 | rendered: '

Hello World(2)

' 35 | }, 36 | excerpt: { 37 | rendered: '

This is the excerpt. (2)

' 38 | }, 39 | date_gmt: '2016-02-16T13:54:13' 40 | }, 41 | { 42 | id: '3', 43 | title: { 44 | rendered: 'Title(3)' 45 | }, 46 | content: { 47 | rendered: '

Hello World(3)

' 48 | }, 49 | excerpt: { 50 | rendered: '

This is the excerpt. (3)

' 51 | }, 52 | date_gmt: '2016-02-16T13:54:13' 53 | } 54 | ] ); 55 | } ) ); 56 | 57 | afterEach(function() { 58 | $httpBackend.verifyNoOutstandingExpectation(); 59 | $httpBackend.verifyNoOutstandingRequest(); 60 | }); 61 | 62 | var api = "http://example.jp"; 63 | 64 | it( 'Tests for ', inject( function( $filter, $rootScope, $compile ) { 65 | var date = '2016-02-16T13:54:13Z'; 66 | var format = 'yyyy/MM/ddTH:mm:ssZ'; 67 | var html = '' 68 | + ''; 69 | var element = $compile( html )( $rootScope ); 70 | $rootScope.$digest(); 71 | $httpBackend.flush(); 72 | expect( angular.element( '.the-date', element ).length ).toEqual( 3 ); 73 | for ( var i = 0; i < angular.element( '.the-date', element ).length; i++ ) { 74 | var n = i + 1; 75 | expect( angular.element( '.the-date', element ).eq(i).text() ) 76 | .toEqual( $filter('date')( date, format, 'Z' ) ); 77 | } 78 | } ) ); 79 | 80 | it( 'Tests for with format', 81 | inject( function( $filter, $rootScope, $compile ) { 82 | var html = '' 83 | + ''; 84 | var element = $compile( html )( $rootScope ); 85 | $rootScope.$digest(); 86 | $httpBackend.flush(); 87 | expect( angular.element( '.the-date', element ).length ).toEqual( 3 ); 88 | for ( var i = 0; i < angular.element( '.the-date', element ).length; i++ ) { 89 | var n = i + 1; 90 | expect( angular.element( '.the-date', element ).eq(i).text() ) 91 | .toEqual( $filter('date')( '2016-02-16T13:54:13Z', 'yyyy/MM/dd', 'Z' ) ); 92 | } 93 | } ) ); 94 | } ); 95 | -------------------------------------------------------------------------------- /tests/spec/the-excerpt.js: -------------------------------------------------------------------------------- 1 | describe( 'theExcerpt directive', function() { 2 | 3 | var $compile, 4 | $rootScope; 5 | 6 | beforeEach( module( 'wp' ) ); // It should be module for testing. 7 | 8 | beforeEach( inject( function( _$httpBackend_, _$compile_, _$rootScope_ ) { 9 | $httpBackend = _$httpBackend_; 10 | $compile = _$compile_; 11 | $rootScope = _$rootScope_; 12 | 13 | // list of the posts or pages 14 | $httpBackend.when( 'GET', /\/(posts)|(pages)\?/ ).respond( 200, [ 15 | { 16 | id: '1', 17 | title: { 18 | rendered: 'Title(1)' 19 | }, 20 | content: { 21 | rendered: '

Hello World(1)

' 22 | }, 23 | excerpt: { 24 | rendered: '

This is the excerpt. (1)

' 25 | }, 26 | date_gmt: '2016-02-16T13:54:13' 27 | }, 28 | { 29 | id: '2', 30 | title: { 31 | rendered: 'Title(2)' 32 | }, 33 | content: { 34 | rendered: '

Hello World(2)

' 35 | }, 36 | excerpt: { 37 | rendered: '

This is the excerpt. (2)

' 38 | }, 39 | date_gmt: '2016-02-16T13:54:13' 40 | }, 41 | { 42 | id: '3', 43 | title: { 44 | rendered: 'Title(3)' 45 | }, 46 | content: { 47 | rendered: '

Hello World(3)

' 48 | }, 49 | excerpt: { 50 | rendered: '

This is the excerpt. (3)

' 51 | }, 52 | date_gmt: '2016-02-16T13:54:13' 53 | } 54 | ] ); 55 | } ) ); 56 | 57 | afterEach(function() { 58 | $httpBackend.verifyNoOutstandingExpectation(); 59 | $httpBackend.verifyNoOutstandingRequest(); 60 | }); 61 | 62 | var api = "http://example.jp"; 63 | 64 | it( 'Tests for ', inject( function( $rootScope, $compile ) { 65 | var html = '' 66 | + ''; 67 | var element = $compile( html )( $rootScope ); 68 | $rootScope.$digest(); 69 | $httpBackend.flush(); 70 | expect( angular.element( '.the-excerpt', element ).length ).toEqual( 3 ); 71 | for ( var i = 0; i < angular.element( '.the-excerpt', element ).length; i++ ) { 72 | var n = i + 1; 73 | expect( angular.element( '.the-excerpt', element ).eq(i).html() ) 74 | .toEqual( '

This is the excerpt. (' + n + ')

' ); 75 | } 76 | } ) ); 77 | } ); 78 | -------------------------------------------------------------------------------- /tests/spec/the-id.js: -------------------------------------------------------------------------------- 1 | describe( 'theId directive', function() { 2 | 3 | var $compile, 4 | $rootScope; 5 | 6 | beforeEach( module( 'wp' ) ); // It should be module for testing. 7 | 8 | beforeEach( inject( function( _$httpBackend_, _$compile_, _$rootScope_ ) { 9 | $httpBackend = _$httpBackend_; 10 | $compile = _$compile_; 11 | $rootScope = _$rootScope_; 12 | 13 | // list of the posts or pages 14 | $httpBackend.when( 'GET', /\/(posts)|(pages)\?/ ).respond( 200, [ 15 | { 16 | id: '1', 17 | title: { 18 | rendered: 'Title(1)' 19 | }, 20 | content: { 21 | rendered: '

Hello World(1)

' 22 | }, 23 | excerpt: { 24 | rendered: '

This is the excerpt. (1)

' 25 | }, 26 | date_gmt: '2016-02-16T13:54:13' 27 | }, 28 | { 29 | id: '2', 30 | title: { 31 | rendered: 'Title(2)' 32 | }, 33 | content: { 34 | rendered: '

Hello World(2)

' 35 | }, 36 | excerpt: { 37 | rendered: '

This is the excerpt. (2)

' 38 | }, 39 | date_gmt: '2016-02-16T13:54:13' 40 | }, 41 | { 42 | id: '3', 43 | title: { 44 | rendered: 'Title(3)' 45 | }, 46 | content: { 47 | rendered: '

Hello World(3)

' 48 | }, 49 | excerpt: { 50 | rendered: '

This is the excerpt. (3)

' 51 | }, 52 | date_gmt: '2016-02-16T13:54:13' 53 | } 54 | ] ); 55 | } ) ); 56 | 57 | afterEach(function() { 58 | $httpBackend.verifyNoOutstandingExpectation(); 59 | $httpBackend.verifyNoOutstandingRequest(); 60 | }); 61 | 62 | var api = "http://example.jp"; 63 | 64 | it( 'the-id should be like 123', inject( function( $rootScope, $compile ) { 65 | var html = '' 66 | + '' 67 | var element = $compile( html )( $rootScope ); 68 | $rootScope.$digest(); 69 | $httpBackend.flush(); 70 | expect( angular.element( '.the-id', element ).length ).toEqual( 3 ); 71 | for ( var i = 0; i < angular.element( '.the-id', element ).length; i++ ) { 72 | var n = i + 1; 73 | expect( angular.element( '.the-id', element ).eq(i).text() ).toEqual( ( n ) 74 | .toString() ); 75 | } 76 | } ) ); 77 | } ); 78 | -------------------------------------------------------------------------------- /tests/spec/the-post-thumbnail.js: -------------------------------------------------------------------------------- 1 | describe( 'Directives', function() { 2 | 3 | var $compile, 4 | $rootScope; 5 | 6 | var full_image = 'https://www.evernote.com/l/' 7 | + 'ABURHaZ_cIJCyrUTUkp0urCtits38Jfl69sB/image.png'; 8 | var thumbnail_image = 'https://www.evernote.com/l/' 9 | + 'ABWrCUwgQt9BIJYGmO1A5dsqBTKobFqPlnYB/image.png'; 10 | 11 | beforeEach( module( 'wp' ) ); // It should be module for testing. 12 | 13 | beforeEach( inject( function( _$httpBackend_, _$compile_, _$rootScope_ ) { 14 | $httpBackend = _$httpBackend_; 15 | $compile = _$compile_; 16 | $rootScope = _$rootScope_; 17 | 18 | // list of the posts or pages 19 | $httpBackend.when( 'GET', /\/(posts)|(pages)\?/ ).respond( 200, [ 20 | { 21 | id: '1', 22 | title: { 23 | rendered: 'Title(1)' 24 | }, 25 | content: { 26 | rendered: '

Hello World(1)

' 27 | }, 28 | excerpt: { 29 | rendered: '

This is the excerpt. (1)

' 30 | }, 31 | date_gmt: '2016-02-16T13:54:13', 32 | _embedded: { 33 | 'https://api.w.org/featuredmedia': [ 34 | { 35 | media_details: { 36 | sizes: { 37 | full: { 38 | source_url: full_image 39 | }, 40 | 'post-thumbnail': { 41 | source_url: thumbnail_image 42 | } 43 | } 44 | } 45 | } 46 | ] 47 | } 48 | }, 49 | { 50 | id: '2', 51 | title: { 52 | rendered: 'Title(2)' 53 | }, 54 | content: { 55 | rendered: '

Hello World(2)

' 56 | }, 57 | excerpt: { 58 | rendered: '

This is the excerpt. (2)

' 59 | }, 60 | date_gmt: '2016-02-16T13:54:13' 61 | }, 62 | { 63 | id: '3', 64 | title: { 65 | rendered: 'Title(3)' 66 | }, 67 | content: { 68 | rendered: '

Hello World(3)

' 69 | }, 70 | excerpt: { 71 | rendered: '

This is the excerpt. (3)

' 72 | }, 73 | date_gmt: '2016-02-16T13:54:13' 74 | } 75 | ] ); 76 | } ) ); 77 | 78 | afterEach(function() { 79 | $httpBackend.verifyNoOutstandingExpectation(); 80 | $httpBackend.verifyNoOutstandingRequest(); 81 | }); 82 | 83 | var api = "http://example.jp"; 84 | 85 | it( 'Tests for ', inject( function( $rootScope, $compile ) { 86 | var html = '' 87 | + ''; 88 | var element = $compile( html )( $rootScope ); 89 | $rootScope.$digest(); 90 | $httpBackend.flush(); 91 | expect( angular.element( 'img', element ).length ).toEqual( 3 ); 92 | expect( angular.element( 'img', element ).eq( 0 ).attr( 'src' ) ) 93 | .toEqual( thumbnail_image ); 94 | } ) ); 95 | 96 | it( 'Tests for ', 97 | inject( function( $rootScope, $compile ) { 98 | var html = '' 99 | + '' 100 | + ''; 101 | var element = $compile( html )( $rootScope ); 102 | $rootScope.$digest(); 103 | $httpBackend.flush(); 104 | expect( angular.element( 'img', element ).length ).toEqual( 3 ); 105 | expect( angular.element( 'img', element ).eq( 0 ).attr( 'src' ) ) 106 | .toEqual( full_image ); 107 | } ) ); 108 | 109 | it( 'Image size should be full', inject( function( $rootScope, $compile ) { 110 | var html = '' 111 | + '' 112 | +''; 113 | var element = $compile( html )( $rootScope ); 114 | $rootScope.$digest(); 115 | $httpBackend.flush(); 116 | expect( angular.element( 'img', element ).length ).toEqual( 3 ); 117 | expect( angular.element( 'img', element ).eq( 0 ).attr( 'src' ) ) 118 | .toEqual( full_image ); 119 | expect( angular.element( '.the-post-thumbnail a', element ).length ).toEqual( 0 ); 120 | } ) ); 121 | 122 | it( 'A should be', inject( function( $rootScope, $compile ) { 123 | var html = '' 124 | + '' 125 | + ''; 126 | var element = $compile( html )( $rootScope ); 127 | $rootScope.$digest(); 128 | $httpBackend.flush(); 129 | expect( angular.element( '.the-post-thumbnail > a', element ).length ) 130 | .toEqual( 3 ); 131 | expect( angular.element( '.the-post-thumbnail > a', element ) 132 | .eq( 0 ).attr( 'href' ) ).toEqual( '#/p/1' ); 133 | expect( angular.element( '.the-post-thumbnail > a > img', element ).length ) 134 | .toEqual( 3 ); 135 | expect( angular.element( '.the-post-thumbnail > a > img', element ) 136 | .eq( 0 ).attr( 'src' ) ).toEqual( full_image ); 137 | } ) ); 138 | } ); 139 | -------------------------------------------------------------------------------- /tests/spec/the-title.js: -------------------------------------------------------------------------------- 1 | describe( 'Directives', function() { 2 | 3 | var $compile, 4 | $rootScope; 5 | 6 | beforeEach( module( 'wp' ) ); // It should be module for testing. 7 | 8 | beforeEach( inject( function( _$httpBackend_, _$compile_, _$rootScope_ ) { 9 | $httpBackend = _$httpBackend_; 10 | $compile = _$compile_; 11 | $rootScope = _$rootScope_; 12 | 13 | // list of the posts or pages 14 | $httpBackend.when( 'GET', /\/(posts)|(pages)\?/ ).respond( 200, [ 15 | { 16 | id: '1', 17 | title: { 18 | rendered: 'Title(1)' 19 | }, 20 | content: { 21 | rendered: '

Hello World(1)

' 22 | }, 23 | excerpt: { 24 | rendered: '

This is the excerpt. (1)

' 25 | }, 26 | date_gmt: '2016-02-16T13:54:13' 27 | }, 28 | { 29 | id: '2', 30 | title: { 31 | rendered: 'Title(2)' 32 | }, 33 | content: { 34 | rendered: '

Hello World(2)

' 35 | }, 36 | excerpt: { 37 | rendered: '

This is the excerpt. (2)

' 38 | }, 39 | date_gmt: '2016-02-16T13:54:13' 40 | }, 41 | { 42 | id: '3', 43 | title: { 44 | rendered: 'Title(3)' 45 | }, 46 | content: { 47 | rendered: '

Hello World(3)

' 48 | }, 49 | excerpt: { 50 | rendered: '

This is the excerpt. (3)

' 51 | }, 52 | date_gmt: '2016-02-16T13:54:13' 53 | } 54 | ] ); 55 | } ) ); 56 | 57 | afterEach(function() { 58 | $httpBackend.verifyNoOutstandingExpectation(); 59 | $httpBackend.verifyNoOutstandingRequest(); 60 | }); 61 | 62 | var api = "http://example.jp"; 63 | 64 | it( 'Tests for ', inject( function( $rootScope, $compile ) { 65 | var html = '' 66 | + ''; 67 | var element = $compile( html )( $rootScope ); 68 | $rootScope.$digest(); 69 | $httpBackend.flush(); 70 | expect( angular.element( '.the-title', element ).length ).toEqual( 3 ); 71 | for ( var i = 0; i < angular.element( '.the-title', element ).length; i++ ) { 72 | var n = i + 1; 73 | expect( angular.element( '.the-title', element ).eq(i).html() ) 74 | .toEqual( 'Title(' + n + ')' ); 75 | } 76 | expect( angular.element( '.the-title a', element ).length ).toEqual( 0 ); 77 | } ) ); 78 | 79 | it( 'A should be', inject( function( $rootScope, $compile ) { 80 | var html = '' 81 | + ''; 82 | var element = $compile( html )( $rootScope ); 83 | $rootScope.$digest(); 84 | $httpBackend.flush(); 85 | expect( angular.element( '.the-title > a', element ).length ).toEqual( 3 ); 86 | expect( angular.element( '.the-title > a', element ).eq( 0 ).attr( 'href' ) ) 87 | .toEqual( '#/posts/1' ); 88 | } ) ); 89 | } ); 90 | -------------------------------------------------------------------------------- /tests/spec/wp-services.js: -------------------------------------------------------------------------------- 1 | describe( 'Tests of the wp.services', function() { 2 | 3 | var $rootScope; 4 | 5 | beforeEach( module( 'wp' ) ); // It should be module for testing. 6 | 7 | beforeEach( inject( function( _$rootScope_ ) { 8 | $rootScope = _$rootScope_; 9 | } ) ); 10 | 11 | 12 | it( 'module "wp.services" should be exists', inject( function( $rootScope ) { 13 | expect( angular.module( 'wp.services' ) ).not.toBeNull(); 14 | } ) ); 15 | 16 | it( 'module "wp" requires "wp.services"', inject( function( $rootScope ) { 17 | expect( angular.module( 'wp' ).requires ).toContain( 'wp.services' ); 18 | } ) ); 19 | 20 | it( 'Filters should be empty"', inject( function( $rootScope, WP ) { 21 | expect( WP.parseFilters() ).toEqual( {} ); 22 | } ) ); 23 | 24 | it( 'Filters should be empty"', inject( function( $rootScope, WP ) { 25 | expect( WP.parseFilters( { 26 | test1: 1, 27 | test2: 2 28 | } ) ).toEqual( { 29 | 'filter[test1]': 1, 30 | 'filter[test2]': 2 31 | } ); 32 | } ) ); 33 | 34 | it( 'Filters should be empty"', inject( function( $rootScope, WP ) { 35 | expect( WP.parseFilters( { 36 | test1: 1, 37 | test2: 2 38 | } ) ).toEqual( { 39 | 'filter[test1]': 1, 40 | 'filter[test2]': 2 41 | } ); 42 | } ) ); 43 | 44 | it( 'Filters should be empty"', inject( function( $rootScope, WP ) { 45 | var query = { 46 | "filter[test1]": "cherry", 47 | "filter[test3]": "pine" 48 | } 49 | 50 | var result = angular.extend( query, WP.parseFilters( { 51 | test1: "apple", 52 | test2: "orange" 53 | } ) ); 54 | 55 | expect( result ).toEqual( { 56 | "filter[test1]": "apple", 57 | "filter[test2]": "orange", 58 | "filter[test3]": "pine" 59 | } ); 60 | } ) ); 61 | } ); 62 | --------------------------------------------------------------------------------