summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/jetpack/modules')
-rw-r--r--plugins/jetpack/modules/after-the-deadline.php205
-rw-r--r--plugins/jetpack/modules/after-the-deadline/atd-autoproofread.js33
-rw-r--r--plugins/jetpack/modules/after-the-deadline/atd-l10n.php40
-rw-r--r--plugins/jetpack/modules/after-the-deadline/atd-nonvis-editor-plugin.js143
-rw-r--r--plugins/jetpack/modules/after-the-deadline/atd-rtl.css122
-rw-r--r--plugins/jetpack/modules/after-the-deadline/atd-rtl.min.css1
-rw-r--r--plugins/jetpack/modules/after-the-deadline/atd.core.js296
-rw-r--r--plugins/jetpack/modules/after-the-deadline/atd.css17
-rw-r--r--plugins/jetpack/modules/after-the-deadline/atd.min.css1
-rw-r--r--plugins/jetpack/modules/after-the-deadline/config-options.php10
-rw-r--r--plugins/jetpack/modules/after-the-deadline/config-unignore.php4
-rw-r--r--plugins/jetpack/modules/after-the-deadline/install_atd_l10n.js24
-rw-r--r--plugins/jetpack/modules/after-the-deadline/jquery.atd.js179
-rw-r--r--plugins/jetpack/modules/after-the-deadline/proxy.php72
-rw-r--r--plugins/jetpack/modules/after-the-deadline/rtl/atd-rtl.css124
-rw-r--r--plugins/jetpack/modules/after-the-deadline/tinymce/css/content.min.css1
-rw-r--r--plugins/jetpack/modules/after-the-deadline/tinymce/editor_plugin.js167
-rw-r--r--plugins/jetpack/modules/after-the-deadline/tinymce/plugin.js427
-rw-r--r--plugins/jetpack/modules/carousel.php8
-rw-r--r--plugins/jetpack/modules/carousel/README1
-rw-r--r--plugins/jetpack/modules/carousel/images/arrows-2x.pngbin10916 -> 10063 bytes
-rw-r--r--plugins/jetpack/modules/carousel/images/arrows.pngbin5382 -> 4529 bytes
-rw-r--r--plugins/jetpack/modules/carousel/images/carousel-sprite-2x.pngbin3108 -> 2076 bytes
-rw-r--r--plugins/jetpack/modules/carousel/images/carousel-sprite.pngbin2167 -> 1318 bytes
-rw-r--r--plugins/jetpack/modules/carousel/jetpack-carousel-ie8fix.css15
-rw-r--r--plugins/jetpack/modules/carousel/jetpack-carousel.css96
-rw-r--r--plugins/jetpack/modules/carousel/jetpack-carousel.js1019
-rw-r--r--plugins/jetpack/modules/carousel/jetpack-carousel.php120
-rw-r--r--plugins/jetpack/modules/carousel/rtl/jetpack-carousel-rtl.css114
-rw-r--r--plugins/jetpack/modules/comments.php16
-rw-r--r--plugins/jetpack/modules/comments/base.php7
-rw-r--r--plugins/jetpack/modules/comments/comments.php38
-rw-r--r--plugins/jetpack/modules/contact-form.php8
-rw-r--r--plugins/jetpack/modules/contact-form/admin.php260
-rw-r--r--plugins/jetpack/modules/contact-form/css/grunion.css4
-rw-r--r--plugins/jetpack/modules/contact-form/css/menu-alter-rtl.css73
-rw-r--r--plugins/jetpack/modules/contact-form/css/menu-alter-rtl.min.css1
-rw-r--r--plugins/jetpack/modules/contact-form/css/menu-alter.css63
-rw-r--r--plugins/jetpack/modules/contact-form/css/menu-alter.min.css1
-rw-r--r--plugins/jetpack/modules/contact-form/css/rtl/grunion-rtl.css6
-rw-r--r--plugins/jetpack/modules/contact-form/css/rtl/menu-alter-rtl.css54
-rw-r--r--plugins/jetpack/modules/contact-form/grunion-contact-form.php512
-rw-r--r--plugins/jetpack/modules/contact-form/grunion-form-view.php26
-rw-r--r--plugins/jetpack/modules/contact-form/grunion-omnisearch.php21
-rw-r--r--plugins/jetpack/modules/contact-form/images/blank-screen-akismet.pngbin2383 -> 2270 bytes
-rw-r--r--plugins/jetpack/modules/contact-form/images/blank-screen-button.pngbin1936 -> 1823 bytes
-rw-r--r--plugins/jetpack/modules/contact-form/images/grunion-form.pngbin297 -> 188 bytes
-rw-r--r--plugins/jetpack/modules/contact-form/images/grunion-menu-2x.pngbin53439 -> 546 bytes
-rw-r--r--plugins/jetpack/modules/contact-form/images/grunion-menu-big-2x.pngbin414 -> 340 bytes
-rw-r--r--plugins/jetpack/modules/contact-form/images/grunion-menu-big.pngbin431 -> 352 bytes
-rw-r--r--plugins/jetpack/modules/contact-form/images/grunion-menu-hover-2x.pngbin51427 -> 611 bytes
-rw-r--r--plugins/jetpack/modules/contact-form/images/grunion-menu-hover.pngbin391 -> 278 bytes
-rw-r--r--plugins/jetpack/modules/contact-form/images/grunion-menu.pngbin268 -> 157 bytes
-rw-r--r--plugins/jetpack/modules/contact-form/images/grunion-remove-field-2x.pngbin47832 -> 201 bytes
-rw-r--r--plugins/jetpack/modules/contact-form/images/grunion-remove-field-hover-2x.pngbin47745 -> 207 bytes
-rw-r--r--plugins/jetpack/modules/contact-form/images/grunion-remove-option-2x.pngbin208 -> 99 bytes
-rw-r--r--plugins/jetpack/modules/contact-form/js/grunion-admin.js29
-rw-r--r--plugins/jetpack/modules/contact-form/js/grunion.js174
-rw-r--r--plugins/jetpack/modules/custom-content-types.php51
-rw-r--r--plugins/jetpack/modules/custom-css.php13
-rw-r--r--plugins/jetpack/modules/custom-css/csstidy/class.csstidy.php10
-rw-r--r--plugins/jetpack/modules/custom-css/csstidy/cssparse-rtl.css118
-rw-r--r--plugins/jetpack/modules/custom-css/csstidy/cssparse-rtl.min.css1
-rw-r--r--plugins/jetpack/modules/custom-css/csstidy/cssparse.min.css1
-rw-r--r--plugins/jetpack/modules/custom-css/csstidy/cssparsed-rtl.css29
-rw-r--r--plugins/jetpack/modules/custom-css/csstidy/cssparsed-rtl.min.css1
-rw-r--r--plugins/jetpack/modules/custom-css/csstidy/cssparsed.min.css1
-rw-r--r--plugins/jetpack/modules/custom-css/csstidy/data-wp.inc.php3
-rw-r--r--plugins/jetpack/modules/custom-css/csstidy/data.inc.php8
-rw-r--r--plugins/jetpack/modules/custom-css/csstidy/lang.inc.php21
-rw-r--r--plugins/jetpack/modules/custom-css/custom-css.php293
-rw-r--r--plugins/jetpack/modules/custom-css/custom-css/css/ace.css25
-rw-r--r--plugins/jetpack/modules/custom-css/custom-css/css/codemirror-rtl.css262
-rw-r--r--plugins/jetpack/modules/custom-css/custom-css/css/codemirror-rtl.min.css1
-rw-r--r--plugins/jetpack/modules/custom-css/custom-css/css/codemirror.css262
-rw-r--r--plugins/jetpack/modules/custom-css/custom-css/css/codemirror.min.css1
-rw-r--r--plugins/jetpack/modules/custom-css/custom-css/css/css-editor.css7
-rw-r--r--plugins/jetpack/modules/custom-css/custom-css/css/css-editor.min.css1
-rw-r--r--plugins/jetpack/modules/custom-css/custom-css/css/rtl/codemirror-rtl.css260
-rw-r--r--plugins/jetpack/modules/custom-css/custom-css/css/use-codemirror.css6
-rw-r--r--plugins/jetpack/modules/custom-css/custom-css/css/use-codemirror.min.css1
-rw-r--r--plugins/jetpack/modules/custom-css/custom-css/js/ace/ace.js10
-rw-r--r--plugins/jetpack/modules/custom-css/custom-css/js/ace/mode-css.js1
-rw-r--r--plugins/jetpack/modules/custom-css/custom-css/js/ace/mode-less.js1
-rw-r--r--plugins/jetpack/modules/custom-css/custom-css/js/ace/mode-scss.js1
-rw-r--r--plugins/jetpack/modules/custom-css/custom-css/js/ace/readme.txt1
-rw-r--r--plugins/jetpack/modules/custom-css/custom-css/js/ace/theme-textmate.js1
-rw-r--r--plugins/jetpack/modules/custom-css/custom-css/js/ace/worker-css.js7886
-rw-r--r--plugins/jetpack/modules/custom-css/custom-css/js/codemirror.min.js11
-rw-r--r--plugins/jetpack/modules/custom-css/custom-css/js/css-editor.js17
-rw-r--r--plugins/jetpack/modules/custom-css/custom-css/js/safecss-ace.js70
-rw-r--r--plugins/jetpack/modules/custom-css/custom-css/js/use-codemirror.js47
-rw-r--r--plugins/jetpack/modules/custom-css/custom-css/preprocessors/lessc.inc.php4
-rw-r--r--plugins/jetpack/modules/custom-css/custom-css/preprocessors/scss.inc.php114
-rw-r--r--plugins/jetpack/modules/custom-post-types/comics.php82
-rw-r--r--plugins/jetpack/modules/custom-post-types/comics/admin.css1
-rw-r--r--plugins/jetpack/modules/custom-post-types/comics/comics.js11
-rw-r--r--plugins/jetpack/modules/custom-post-types/css/edit-items.css24
-rw-r--r--plugins/jetpack/modules/custom-post-types/css/many-items.css14
-rw-r--r--plugins/jetpack/modules/custom-post-types/css/nova-font.css29
-rw-r--r--plugins/jetpack/modules/custom-post-types/css/nova.css110
-rw-r--r--plugins/jetpack/modules/custom-post-types/css/portfolio-shortcode.css131
-rw-r--r--plugins/jetpack/modules/custom-post-types/css/testimonial-shortcode.css101
-rw-r--r--plugins/jetpack/modules/custom-post-types/js/many-items.js112
-rw-r--r--plugins/jetpack/modules/custom-post-types/js/menu-checkboxes.js49
-rw-r--r--plugins/jetpack/modules/custom-post-types/js/nova-drag-drop.js49
-rw-r--r--plugins/jetpack/modules/custom-post-types/nova.php1162
-rw-r--r--plugins/jetpack/modules/custom-post-types/portfolios.php730
-rw-r--r--plugins/jetpack/modules/custom-post-types/testimonial.php467
-rw-r--r--plugins/jetpack/modules/enhanced-distribution.php25
-rw-r--r--plugins/jetpack/modules/featured-content/featured-content.php456
-rw-r--r--plugins/jetpack/modules/gplus-authorship.php208
-rw-r--r--plugins/jetpack/modules/gplus-authorship/admin/connect.js42
-rw-r--r--plugins/jetpack/modules/gplus-authorship/admin/listener.js57
-rw-r--r--plugins/jetpack/modules/gplus-authorship/admin/style.css51
-rw-r--r--plugins/jetpack/modules/gplus-authorship/admin/ui.php270
-rw-r--r--plugins/jetpack/modules/gplus-authorship/style.css17
-rw-r--r--plugins/jetpack/modules/gravatar-hovercards.php19
-rw-r--r--plugins/jetpack/modules/infinite-scroll.php50
-rw-r--r--plugins/jetpack/modules/infinite-scroll/infinity.css32
-rw-r--r--plugins/jetpack/modules/infinite-scroll/infinity.js271
-rw-r--r--plugins/jetpack/modules/infinite-scroll/infinity.php620
-rw-r--r--plugins/jetpack/modules/infinite-scroll/themes/twentyeleven.php29
-rw-r--r--plugins/jetpack/modules/infinite-scroll/themes/twentyfifteen-rtl.css216
-rw-r--r--plugins/jetpack/modules/infinite-scroll/themes/twentyfifteen.css216
-rw-r--r--plugins/jetpack/modules/infinite-scroll/themes/twentyfifteen.php26
-rw-r--r--plugins/jetpack/modules/infinite-scroll/themes/twentyfourteen.css111
-rw-r--r--plugins/jetpack/modules/infinite-scroll/themes/twentyfourteen.php47
-rw-r--r--plugins/jetpack/modules/json-api.php16
-rw-r--r--plugins/jetpack/modules/latex.php5
-rw-r--r--plugins/jetpack/modules/likes.php523
-rw-r--r--plugins/jetpack/modules/likes/post-count-jetpack.js2
-rw-r--r--plugins/jetpack/modules/likes/post-count.js11
-rw-r--r--plugins/jetpack/modules/likes/queuehandler.js242
-rw-r--r--plugins/jetpack/modules/likes/style.css145
-rw-r--r--plugins/jetpack/modules/manage.php16
-rw-r--r--plugins/jetpack/modules/markdown.php25
-rw-r--r--plugins/jetpack/modules/markdown/easy-markdown.php714
-rw-r--r--plugins/jetpack/modules/minileven.php41
-rw-r--r--plugins/jetpack/modules/minileven/images/wp-app-devices.pngbin1865 -> 1014 bytes
-rw-r--r--plugins/jetpack/modules/minileven/minileven.php40
-rw-r--r--plugins/jetpack/modules/minileven/theme/pub/minileven/content-gallery.php8
-rw-r--r--plugins/jetpack/modules/minileven/theme/pub/minileven/content.php14
-rw-r--r--plugins/jetpack/modules/minileven/theme/pub/minileven/footer.php27
-rw-r--r--plugins/jetpack/modules/minileven/theme/pub/minileven/functions.php75
-rw-r--r--plugins/jetpack/modules/minileven/theme/pub/minileven/header.php27
-rw-r--r--plugins/jetpack/modules/minileven/theme/pub/minileven/image.php6
-rw-r--r--plugins/jetpack/modules/minileven/theme/pub/minileven/inc/tweaks.php5
-rw-r--r--plugins/jetpack/modules/minileven/theme/pub/minileven/index.php4
-rw-r--r--plugins/jetpack/modules/minileven/theme/pub/minileven/js/small-menu.js13
-rw-r--r--plugins/jetpack/modules/minileven/theme/pub/minileven/screenshot.pngbin59059 -> 58138 bytes
-rw-r--r--plugins/jetpack/modules/minileven/theme/pub/minileven/style.css32
-rw-r--r--plugins/jetpack/modules/mobile-push.php15
-rw-r--r--plugins/jetpack/modules/module-extras.php21
-rw-r--r--plugins/jetpack/modules/module-headings.php240
-rw-r--r--plugins/jetpack/modules/module-info.php441
-rw-r--r--plugins/jetpack/modules/monitor.php156
-rw-r--r--plugins/jetpack/modules/notes.php14
-rw-r--r--plugins/jetpack/modules/omnisearch.php9
-rw-r--r--plugins/jetpack/modules/omnisearch/omnisearch-core.php9
-rw-r--r--plugins/jetpack/modules/omnisearch/omnisearch-jetpack-rtl.css10
-rw-r--r--plugins/jetpack/modules/omnisearch/omnisearch-jetpack-rtl.min.css1
-rw-r--r--plugins/jetpack/modules/omnisearch/omnisearch-jetpack.css25
-rw-r--r--plugins/jetpack/modules/omnisearch/omnisearch-jetpack.min.css1
-rw-r--r--plugins/jetpack/modules/omnisearch/omnisearch-posts.php14
-rw-r--r--plugins/jetpack/modules/omnisearch/omnisearch-rtl.css130
-rw-r--r--plugins/jetpack/modules/omnisearch/omnisearch-rtl.min.css1
-rw-r--r--plugins/jetpack/modules/omnisearch/omnisearch.css15
-rw-r--r--plugins/jetpack/modules/omnisearch/omnisearch.min.css1
-rw-r--r--plugins/jetpack/modules/omnisearch/rtl/omnisearch-jetpack-rtl.css28
-rw-r--r--plugins/jetpack/modules/omnisearch/rtl/omnisearch-rtl.css17
-rw-r--r--plugins/jetpack/modules/photon.php14
-rw-r--r--plugins/jetpack/modules/photon/photon.js25
-rw-r--r--plugins/jetpack/modules/post-by-email.php11
-rw-r--r--plugins/jetpack/modules/post-by-email/post-by-email.js13
-rw-r--r--plugins/jetpack/modules/post-by-email/post-by-email.min.css1
-rw-r--r--plugins/jetpack/modules/protect.php682
-rw-r--r--plugins/jetpack/modules/protect/config-ui.php57
-rw-r--r--plugins/jetpack/modules/protect/math-fallback.php113
-rw-r--r--plugins/jetpack/modules/protect/protect-dashboard-widget-rtl.css117
-rw-r--r--plugins/jetpack/modules/protect/protect-dashboard-widget-rtl.min.css1
-rw-r--r--plugins/jetpack/modules/protect/protect-dashboard-widget.css117
-rw-r--r--plugins/jetpack/modules/protect/protect-dashboard-widget.min.css1
-rw-r--r--plugins/jetpack/modules/protect/shared-functions.php183
-rw-r--r--plugins/jetpack/modules/protect/transient-cleanup.php56
-rw-r--r--plugins/jetpack/modules/publicize.php67
-rw-r--r--plugins/jetpack/modules/publicize/assets/linkedin-logo.pngbin6882 -> 6783 bytes
-rw-r--r--plugins/jetpack/modules/publicize/assets/path-logo.pngbin5708 -> 4605 bytes
-rw-r--r--plugins/jetpack/modules/publicize/assets/publicize-fb-2x.pngbin0 -> 2723 bytes
-rw-r--r--plugins/jetpack/modules/publicize/assets/publicize-google-2x.pngbin0 -> 1960 bytes
-rw-r--r--plugins/jetpack/modules/publicize/assets/publicize-linkedin-2x.pngbin0 -> 2281 bytes
-rw-r--r--plugins/jetpack/modules/publicize/assets/publicize-path-2x.pngbin0 -> 4912 bytes
-rw-r--r--plugins/jetpack/modules/publicize/assets/publicize-rtl.css214
-rw-r--r--plugins/jetpack/modules/publicize/assets/publicize-rtl.min.css1
-rw-r--r--plugins/jetpack/modules/publicize/assets/publicize-tumblr-2x.pngbin0 -> 2128 bytes
-rw-r--r--plugins/jetpack/modules/publicize/assets/publicize-twitter-2x.pngbin0 -> 3372 bytes
-rw-r--r--plugins/jetpack/modules/publicize/assets/publicize.css67
-rw-r--r--plugins/jetpack/modules/publicize/assets/publicize.js110
-rw-r--r--plugins/jetpack/modules/publicize/assets/publicize.min.css1
-rw-r--r--plugins/jetpack/modules/publicize/assets/rtl/publicize-rtl.css69
-rw-r--r--plugins/jetpack/modules/publicize/assets/tumblr-logo.pngbin9001 -> 8902 bytes
-rw-r--r--plugins/jetpack/modules/publicize/assets/twitter-logo.pngbin4623 -> 4524 bytes
-rw-r--r--plugins/jetpack/modules/publicize/enhanced-open-graph.php122
-rw-r--r--plugins/jetpack/modules/publicize/publicize-jetpack.php238
-rw-r--r--plugins/jetpack/modules/publicize/publicize.php76
-rw-r--r--plugins/jetpack/modules/publicize/ui.php162
-rw-r--r--plugins/jetpack/modules/random-redirect.php47
-rw-r--r--plugins/jetpack/modules/related-posts.php89
-rw-r--r--plugins/jetpack/modules/related-posts/jetpack-related-posts.php1126
-rw-r--r--plugins/jetpack/modules/related-posts/related-posts.css199
-rw-r--r--plugins/jetpack/modules/related-posts/related-posts.js192
-rw-r--r--plugins/jetpack/modules/related-posts/rtl/related-posts-rtl.css190
-rw-r--r--plugins/jetpack/modules/sharedaddy.php16
-rw-r--r--plugins/jetpack/modules/sharedaddy/admin-sharing-rtl.css402
-rw-r--r--plugins/jetpack/modules/sharedaddy/admin-sharing-rtl.min.css1
-rw-r--r--plugins/jetpack/modules/sharedaddy/admin-sharing.css542
-rw-r--r--plugins/jetpack/modules/sharedaddy/admin-sharing.js140
-rw-r--r--plugins/jetpack/modules/sharedaddy/admin-sharing.min.css1
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/after-the-deadline@2x.pngbin2384 -> 1068 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/comments@2x.pngbin1980 -> 763 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/contact-form@2x.pngbin1504 -> 539 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/custom.pngbin1364 -> 445 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/custom@2x.pngbin2068 -> 1147 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/designfloat.pngbin870 -> 833 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/digg.pngbin1449 -> 530 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/digg@2x.pngbin1793 -> 872 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/divider.pngbin945 -> 94 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/divider@2x.pngbin1037 -> 116 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/draggy.pngbin958 -> 107 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/draggy@2x.pngbin1030 -> 109 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/email.pngbin316 -> 209 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/email@2x.pngbin1848 -> 927 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/ember.pngbin570 -> 533 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/enhanced-distribution@2x.pngbin1307 -> 757 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/feed.pngbin805 -> 761 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/googleplus1.pngbin660 -> 602 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/googleplus1@2x.pngbin1187 -> 1134 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/icon-facebook-2x.pngbin1080 -> 1027 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/icon-facebook.pngbin634 -> 581 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/icon-googleplus-2x.pngbin0 -> 1333 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/icon-googleplus.pngbin0 -> 722 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/icon-twitter-2x.pngbin1451 -> 1414 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/icon-wordpress-2x.pngbin657 -> 592 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/icon-wordpress.pngbin775 -> 666 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/kindle.pngbin1843 -> 750 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/kindle@2x.pngbin1563 -> 1505 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/linkedin-horizontal.pngbin2245 -> 2115 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/linkedin-horizontal@2x.pngbin3828 -> 2975 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/linkedin-nocount.pngbin1694 -> 1564 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/linkedin-nocount@2x.pngbin2589 -> 1736 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/linkedin-smart.pngbin2245 -> 2115 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/linkedin-smart@2x.pngbin3828 -> 2975 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/linkedin-vertical.pngbin2404 -> 2274 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/linkedin-vertical@2x.pngbin3574 -> 2653 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/linkedin.pngbin381 -> 360 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/linkedin@2x.pngbin1865 -> 944 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/more.pngbin395 -> 285 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/more@2x.pngbin1719 -> 798 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/pinterest.pngbin6407 -> 624 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/pinterest@2x.pngbin2231 -> 1310 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/pocket.pngbin1288 -> 367 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/pocket@2x.pngbin1425 -> 504 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/print.pngbin316 -> 209 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/print@2x.pngbin1973 -> 1052 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/reddit.pngbin918 -> 881 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/reddit@2x.pngbin2421 -> 1500 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/rss.pngbin907 -> 870 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/rss@2x.pngbin2696 -> 1775 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/share-bg.pngbin933 -> 82 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/sharing-hidden.pngbin2929 -> 213 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/sharing-hidden@2x.pngbin1027 -> 106 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/smart-digg.pngbin1644 -> 793 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/smart-digg@2x.pngbin2068 -> 1147 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/smart-facebook.pngbin2278 -> 1427 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/smart-facebook@2x.pngbin1751 -> 830 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/smart-googleplus1.pngbin6719 -> 2323 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/smart-googleplus1@2x.pngbin7795 -> 3398 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/smart-like.pngbin1965 -> 1620 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/smart-like@2x.pngbin2278 -> 3800 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/smart-pinterest.pngbin7463 -> 1235 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/smart-pinterest@2x.pngbin3480 -> 2170 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/smart-pocket.pngbin1494 -> 641 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/smart-pocket@2x.pngbin2125 -> 1272 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/smart-reddit.pngbin2423 -> 1572 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/smart-reddit@2x.pngbin3522 -> 2601 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/smart-stumbleupon@2x.pngbin2993 -> 2072 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/smart-tumblr.pngbin1568 -> 1531 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/smart-tumblr@2x.pngbin5032 -> 4179 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/smart-twitter@2x.pngbin3179 -> 2258 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/stumbleupon@2x.pngbin2276 -> 1423 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/tumblr.pngbin1941 -> 742 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/tumblr@2x.pngbin1847 -> 926 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/twitter@2x.pngbin2223 -> 1302 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/wordpress.pngbin1586 -> 667 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/images/wordpress@2x.pngbin2265 -> 1344 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/screenshot-1.jpgbin58951 -> 48840 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/screenshot-2.jpgbin27511 -> 23781 bytes
-rw-r--r--plugins/jetpack/modules/sharedaddy/sharedaddy.php77
-rw-r--r--plugins/jetpack/modules/sharedaddy/sharing-service.php183
-rw-r--r--plugins/jetpack/modules/sharedaddy/sharing-sources.php404
-rw-r--r--plugins/jetpack/modules/sharedaddy/sharing.css870
-rw-r--r--plugins/jetpack/modules/sharedaddy/sharing.js356
-rw-r--r--plugins/jetpack/modules/sharedaddy/sharing.php313
-rw-r--r--plugins/jetpack/modules/shortcodes.php31
-rw-r--r--plugins/jetpack/modules/shortcodes/archives.php30
-rw-r--r--plugins/jetpack/modules/shortcodes/audio.php73
-rw-r--r--plugins/jetpack/modules/shortcodes/bandcamp.php93
-rw-r--r--plugins/jetpack/modules/shortcodes/cartodb.php18
-rw-r--r--plugins/jetpack/modules/shortcodes/css/recipes-print.css3
-rw-r--r--plugins/jetpack/modules/shortcodes/css/recipes.css33
-rw-r--r--plugins/jetpack/modules/shortcodes/css/rtl/recipes-rtl.css35
-rw-r--r--plugins/jetpack/modules/shortcodes/css/rtl/slideshow-shortcode-rtl.css35
-rw-r--r--plugins/jetpack/modules/shortcodes/css/slideshow-shortcode.css33
-rw-r--r--plugins/jetpack/modules/shortcodes/css/style.css3
-rw-r--r--plugins/jetpack/modules/shortcodes/dailymotion.php107
-rw-r--r--plugins/jetpack/modules/shortcodes/diggthis.php33
-rw-r--r--plugins/jetpack/modules/shortcodes/facebook.php36
-rw-r--r--plugins/jetpack/modules/shortcodes/flickr.php85
-rw-r--r--plugins/jetpack/modules/shortcodes/gist.php37
-rw-r--r--plugins/jetpack/modules/shortcodes/googlemaps.php50
-rw-r--r--plugins/jetpack/modules/shortcodes/googleplus.php9
-rw-r--r--plugins/jetpack/modules/shortcodes/images/collapse.pngbin4811 -> 2072 bytes
-rw-r--r--plugins/jetpack/modules/shortcodes/images/expand.pngbin4778 -> 2039 bytes
-rw-r--r--plugins/jetpack/modules/shortcodes/images/slide-nav.pngbin5741 -> 5704 bytes
-rw-r--r--plugins/jetpack/modules/shortcodes/instagram.php178
-rw-r--r--plugins/jetpack/modules/shortcodes/js/audio-shortcode.js11
-rw-r--r--plugins/jetpack/modules/shortcodes/js/jmpress.js2
-rw-r--r--plugins/jetpack/modules/shortcodes/js/main.js13
-rw-r--r--plugins/jetpack/modules/shortcodes/js/recipes-printthis.js170
-rw-r--r--plugins/jetpack/modules/shortcodes/js/recipes.js11
-rw-r--r--plugins/jetpack/modules/shortcodes/js/slideshow-shortcode.js102
-rw-r--r--plugins/jetpack/modules/shortcodes/medium.php66
-rw-r--r--plugins/jetpack/modules/shortcodes/mixcloud.php52
-rw-r--r--plugins/jetpack/modules/shortcodes/polldaddy.php11
-rw-r--r--plugins/jetpack/modules/shortcodes/presentations.php74
-rw-r--r--plugins/jetpack/modules/shortcodes/recipe.php147
-rw-r--r--plugins/jetpack/modules/shortcodes/scribd.php14
-rw-r--r--plugins/jetpack/modules/shortcodes/slideshare.php28
-rw-r--r--plugins/jetpack/modules/shortcodes/slideshow.php116
-rw-r--r--plugins/jetpack/modules/shortcodes/soundcloud.php295
-rw-r--r--plugins/jetpack/modules/shortcodes/ted.php8
-rw-r--r--plugins/jetpack/modules/shortcodes/twitter-timeline.php4
-rw-r--r--plugins/jetpack/modules/shortcodes/vimeo.php68
-rw-r--r--plugins/jetpack/modules/shortcodes/vine.php2
-rw-r--r--plugins/jetpack/modules/shortcodes/youtube.php163
-rw-r--r--plugins/jetpack/modules/shortlinks.php16
-rw-r--r--plugins/jetpack/modules/site-icon.php16
-rw-r--r--plugins/jetpack/modules/site-icon/browser.pngbin0 -> 47596 bytes
-rw-r--r--plugins/jetpack/modules/site-icon/css/site-icon-admin.css57
-rw-r--r--plugins/jetpack/modules/site-icon/jetpack-site-icon.php813
-rw-r--r--plugins/jetpack/modules/site-icon/js/site-icon-admin.js (renamed from plugins/jetpack/modules/custom-post-types/testimonials.php)0
-rw-r--r--plugins/jetpack/modules/site-icon/js/site-icon-crop.js55
-rw-r--r--plugins/jetpack/modules/site-icon/site-icon-functions.php73
-rw-r--r--plugins/jetpack/modules/site-icon/upload-site-icon.php31
-rw-r--r--plugins/jetpack/modules/social-links.php10
-rw-r--r--plugins/jetpack/modules/sso.php978
-rw-r--r--plugins/jetpack/modules/stats.php199
-rw-r--r--plugins/jetpack/modules/subscriptions.php215
-rw-r--r--plugins/jetpack/modules/subscriptions/subscriptions.css8
-rw-r--r--plugins/jetpack/modules/theme-tools.php85
-rw-r--r--plugins/jetpack/modules/theme-tools/compat/twentyfifteen-rtl.css752
-rw-r--r--plugins/jetpack/modules/theme-tools/compat/twentyfifteen.css752
-rw-r--r--plugins/jetpack/modules/theme-tools/compat/twentyfifteen.php28
-rw-r--r--plugins/jetpack/modules/theme-tools/compat/twentyfourteen-rtl.css367
-rw-r--r--plugins/jetpack/modules/theme-tools/compat/twentyfourteen.css367
-rw-r--r--plugins/jetpack/modules/theme-tools/compat/twentyfourteen.php71
-rw-r--r--plugins/jetpack/modules/theme-tools/featured-content.php581
-rw-r--r--plugins/jetpack/modules/theme-tools/infinite-scroll.php47
-rw-r--r--plugins/jetpack/modules/theme-tools/js/suggest.js10
-rw-r--r--plugins/jetpack/modules/theme-tools/random-redirect.php69
-rw-r--r--plugins/jetpack/modules/theme-tools/responsive-videos.php40
-rw-r--r--plugins/jetpack/modules/theme-tools/responsive-videos/responsive-videos.js93
-rw-r--r--plugins/jetpack/modules/theme-tools/responsive-videos/responsive-videos.min.js1
-rw-r--r--plugins/jetpack/modules/theme-tools/site-breadcrumbs.php37
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo.php33
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control-rtl.css12
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control-rtl.min.css1
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control.css49
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control.min.css1
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/inc/class-site-logo-control.php108
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/inc/class-site-logo.php354
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/inc/compat.php44
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/inc/functions.php116
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-control.js154
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-control.min.js1
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-header-text.js24
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-header-text.min.js1
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/js/site-logo.js43
-rw-r--r--plugins/jetpack/modules/theme-tools/site-logo/js/site-logo.min.js1
-rw-r--r--plugins/jetpack/modules/theme-tools/social-links.php (renamed from plugins/jetpack/modules/social-links/social-links.php)104
-rw-r--r--plugins/jetpack/modules/tiled-gallery.php8
-rw-r--r--plugins/jetpack/modules/tiled-gallery/tiled-gallery.php479
-rw-r--r--plugins/jetpack/modules/tiled-gallery/tiled-gallery/rtl/tiled-gallery-rtl.css3
-rw-r--r--plugins/jetpack/modules/tiled-gallery/tiled-gallery/templates/carousel-container.php18
-rw-r--r--plugins/jetpack/modules/tiled-gallery/tiled-gallery/templates/circle-layout.php3
-rw-r--r--plugins/jetpack/modules/tiled-gallery/tiled-gallery/templates/partials/carousel-image-args.php18
-rw-r--r--plugins/jetpack/modules/tiled-gallery/tiled-gallery/templates/partials/item.php49
-rw-r--r--plugins/jetpack/modules/tiled-gallery/tiled-gallery/templates/rectangular-layout.php23
-rw-r--r--plugins/jetpack/modules/tiled-gallery/tiled-gallery/templates/square-layout.php19
-rw-r--r--plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-circle.php8
-rw-r--r--plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-item.php74
-rw-r--r--plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-layout.php80
-rw-r--r--plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-rectangular.php221
-rw-r--r--plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-shape.php209
-rw-r--r--plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-square.php70
-rw-r--r--plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery.css1
-rw-r--r--plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery.js265
-rw-r--r--plugins/jetpack/modules/tonesque.php10
-rw-r--r--plugins/jetpack/modules/vaultpress.php4
-rw-r--r--plugins/jetpack/modules/verification-tools.php27
-rw-r--r--plugins/jetpack/modules/verification-tools/blog-verification-tools.php122
-rw-r--r--plugins/jetpack/modules/videopress.php9
-rw-r--r--plugins/jetpack/modules/videopress/class.videopress-player.php26
-rw-r--r--plugins/jetpack/modules/videopress/shortcode.php15
-rw-r--r--plugins/jetpack/modules/videopress/videopress-admin-rtl.css97
-rw-r--r--plugins/jetpack/modules/videopress/videopress-admin-rtl.min.css1
-rw-r--r--plugins/jetpack/modules/videopress/videopress-admin.js90
-rw-r--r--plugins/jetpack/modules/videopress/videopress-admin.min.css1
-rw-r--r--plugins/jetpack/modules/videopress/videopress.php8
-rw-r--r--plugins/jetpack/modules/widget-visibility.php4
-rw-r--r--plugins/jetpack/modules/widget-visibility/widget-conditions.php329
-rw-r--r--plugins/jetpack/modules/widget-visibility/widget-conditions/rtl/widget-conditions-rtl.css47
-rw-r--r--plugins/jetpack/modules/widget-visibility/widget-conditions/widget-conditions-rtl.css73
-rw-r--r--plugins/jetpack/modules/widget-visibility/widget-conditions/widget-conditions-rtl.min.css1
-rw-r--r--plugins/jetpack/modules/widget-visibility/widget-conditions/widget-conditions.css48
-rw-r--r--plugins/jetpack/modules/widget-visibility/widget-conditions/widget-conditions.js95
-rw-r--r--plugins/jetpack/modules/widget-visibility/widget-conditions/widget-conditions.min.css1
-rw-r--r--plugins/jetpack/modules/widgets.php23
-rw-r--r--plugins/jetpack/modules/widgets/contact-info.php266
-rw-r--r--plugins/jetpack/modules/widgets/contact-info/contact-info-map.css11
-rw-r--r--plugins/jetpack/modules/widgets/contact-info/contact-info-map.js23
-rw-r--r--plugins/jetpack/modules/widgets/facebook-likebox.php17
-rw-r--r--plugins/jetpack/modules/widgets/gallery.php88
-rw-r--r--plugins/jetpack/modules/widgets/gallery/css/admin-rtl.css11
-rw-r--r--plugins/jetpack/modules/widgets/gallery/css/admin-rtl.min.css1
-rw-r--r--plugins/jetpack/modules/widgets/gallery/css/admin.min.css1
-rw-r--r--plugins/jetpack/modules/widgets/gallery/js/admin.js93
-rw-r--r--plugins/jetpack/modules/widgets/gallery/templates/form.php16
-rw-r--r--plugins/jetpack/modules/widgets/goodreads.php144
-rw-r--r--plugins/jetpack/modules/widgets/goodreads/css/goodreads.css48
-rw-r--r--plugins/jetpack/modules/widgets/goodreads/css/rtl/goodreads-rtl.css50
-rw-r--r--plugins/jetpack/modules/widgets/gravatar-profile.css5
-rw-r--r--plugins/jetpack/modules/widgets/gravatar-profile.php29
-rw-r--r--plugins/jetpack/modules/widgets/image-widget.php152
-rw-r--r--plugins/jetpack/modules/widgets/image-widget/style.css (renamed from plugins/jetpack/modules/widgets/widgets.css)2
-rw-r--r--plugins/jetpack/modules/widgets/readmill.php138
-rw-r--r--plugins/jetpack/modules/widgets/rsslinks-widget.php125
-rw-r--r--plugins/jetpack/modules/widgets/top-posts.php62
-rw-r--r--plugins/jetpack/modules/widgets/top-posts/style.css (renamed from plugins/jetpack/modules/widgets/widget-grid-and-list.css)4
-rw-r--r--plugins/jetpack/modules/widgets/twitter-timeline.php71
-rw-r--r--plugins/jetpack/modules/widgets/wordpress-post-widget.php222
-rw-r--r--plugins/jetpack/modules/widgets/wordpress-post-widget/style.css24
-rw-r--r--plugins/jetpack/modules/wpcc.php24
-rw-r--r--plugins/jetpack/modules/wpcc/wpcc-sign-on.css11
-rw-r--r--plugins/jetpack/modules/wpcc/wpcc-sign-on.js4
-rw-r--r--plugins/jetpack/modules/wpcc/wpcc-sign-on.php437
-rw-r--r--plugins/jetpack/modules/wpgroho.js5
457 files changed, 29241 insertions, 15230 deletions
diff --git a/plugins/jetpack/modules/after-the-deadline.php b/plugins/jetpack/modules/after-the-deadline.php
index 61e32f01..b4e89036 100644
--- a/plugins/jetpack/modules/after-the-deadline.php
+++ b/plugins/jetpack/modules/after-the-deadline.php
@@ -1,47 +1,69 @@
<?php
/**
* Module Name: Spelling and Grammar
- * Module Description: Improve your spelling, style, and grammar with the <a href="http://www.afterthedeadline.com/">After&nbsp;the&nbsp;Deadline</a> Proofreading service.
+ * Module Description: Check your spelling, style, and grammar with the After the Deadline proofreading service.
* Sort Order: 6
* First Introduced: 1.1
* Requires Connection: Yes
* Auto Activate: Yes
+ * Module Tags: Writing
*/
-add_action( 'jetpack_modules_loaded', 'AtD_load' );
+if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
+ // This wpcom-specific code should eventually be moved elsewhere.
-function AtD_load() {
- Jetpack::enable_module_configurable( __FILE__ );
- Jetpack::module_configuration_load( __FILE__, 'AtD_configuration_load' );
-}
+ function AtD_http_post_timeout_action() {
+ return 5;
+ }
+ add_filter( 'atd_http_post_timeout', 'AtD_http_post_timeout_action' );
+ function AtD_http_post_error_action( $code ) {
+ bump_stats_extras( 'atd-remote-error', $code );
+ }
+ add_action( 'atd_http_post_error', 'AtD_http_post_error_action' );
+ function AtD_service_domain_action() {
+ return 'en.service.afterthedeadline.com';
+ }
+ add_filter( 'atd_service_domain', 'AtD_service_domain_action' );
+ function AtD_update_setting( $user_id, $name, $value ) {
+ update_user_attribute( $user_id, $name, $value );
+ }
+ function AtD_get_setting( $user_id, $name, $single = true ) {
+ return get_user_attribute( $user_id, $name );
+ }
+ function AtD_get_rpc_id() {
+ return get_bloginfo( 'wpurl' );
+ }
+} else {
+ // This code is used only in Jetpack.
-function AtD_configuration_load() {
- wp_safe_redirect( get_edit_profile_url( get_current_user_id() ) . '#atd' );
- exit;
+ add_action( 'jetpack_modules_loaded', 'AtD_load' );
+ function AtD_load() {
+ Jetpack::enable_module_configurable( __FILE__ );
+ Jetpack::module_configuration_load( __FILE__, 'AtD_configuration_load' );
+ }
+ function AtD_configuration_load() {
+ wp_safe_redirect( get_edit_profile_url( get_current_user_id() ) . '#atd' );
+ exit;
+ }
+ function AtD_update_setting( $user_id, $name, $value ) {
+ update_user_meta( $user_id, $name, $value );
+ }
+ function AtD_get_setting( $user_id, $name, $single = true ) {
+ return get_user_meta( $user_id, $name, $single );
+ }
+ function AtD_get_rpc_id() {
+ return 'WPORG-' . md5( get_bloginfo( 'wpurl ') );
+ }
}
/*
* Load necessary include files
*/
-include( 'after-the-deadline/config-options.php' );
-include( 'after-the-deadline/config-unignore.php' );
-include( 'after-the-deadline/proxy.php' );
+include( dirname( __FILE__ ) . '/after-the-deadline/config-options.php' );
+include( dirname( __FILE__ ) . '/after-the-deadline/config-unignore.php' );
+include( dirname( __FILE__ ) . '/after-the-deadline/proxy.php' );
-define('ATD_VERSION', '20120221');
-
-/**
- * Update a user's After the Deadline Setting
- */
-function AtD_update_setting( $user_id, $name, $value ) {
- update_user_meta( $user_id, $name, $value );
-}
-
-/**
- * Retrieve a user's After the Deadline Setting
- */
-function AtD_get_setting( $user_id, $name, $single = true ) {
- return get_user_meta( $user_id, $name, $single );
-}
+define( 'ATD_VERSION', '20140527' );
/*
* Display the AtD configuration options
@@ -59,6 +81,10 @@ function AtD_addbuttons() {
if ( ! AtD_is_allowed() )
return;
+ if ( ! defined( 'ATD_TINYMCE_4' ) ) {
+ define( 'ATD_TINYMCE_4', ( ! empty( $GLOBALS['tinymce_version'] ) && substr( $GLOBALS['tinymce_version'], 0, 1 ) >= 4 ) );
+ }
+
/* Add only in Rich Editor mode */
if ( get_user_option( 'rich_editing' ) == 'true' ) {
add_filter( 'mce_external_plugins', 'add_AtD_tinymce_plugin' );
@@ -74,6 +100,14 @@ function AtD_addbuttons() {
* Hook into the TinyMCE buttons and replace the current spellchecker
*/
function register_AtD_button( $buttons ) {
+ if ( ATD_TINYMCE_4 ) {
+ // Use the default icon in TinyMCE 4.0 (replaced by dashicons in editor.css)
+ if ( ! in_array( 'spellchecker', $buttons, true ) ) {
+ $buttons[] = 'spellchecker';
+ }
+
+ return $buttons;
+ }
/* kill the spellchecker.. don't need no steenkin PHP spell checker */
foreach ( $buttons as $key => $button ) {
@@ -89,10 +123,12 @@ function register_AtD_button( $buttons ) {
}
/*
- * Load the TinyMCE plugin : editor_plugin.js (wp2.5)
+ * Load the TinyMCE plugin : editor_plugin.js (TinyMCE 3.x) | plugin.js (TinyMCE 4.0)
*/
function add_AtD_tinymce_plugin( $plugin_array ) {
- $plugin_array['AtD'] = plugins_url( 'after-the-deadline/tinymce/editor_plugin.js?v=' . ATD_VERSION, __FILE__ );
+ $plugin = ATD_TINYMCE_4 ? 'plugin' : 'editor_plugin';
+
+ $plugin_array['AtD'] = plugins_url( 'after-the-deadline/tinymce/' . $plugin . '.js?v=' . ATD_VERSION, __FILE__ );
return $plugin_array;
}
@@ -103,11 +139,14 @@ function AtD_change_mce_settings( $init_array ) {
if ( ! AtD_is_allowed() )
return $init_array;
+ if ( ! is_array( $init_array ) )
+ $init_array = array();
+
$user = wp_get_current_user();
- $init_array['atd_rpc_url'] = admin_url( 'admin-ajax.php?action=proxy_atd&url=' );
- $init_array['atd_ignore_rpc_url'] = admin_url( 'admin-ajax.php?action=atd_ignore&phrase=' );
- $init_array['atd_rpc_id'] = 'WPORG-' . md5(get_bloginfo('wpurl'));
+ $init_array['atd_rpc_url'] = admin_url( 'admin-ajax.php?action=proxy_atd&_wpnonce=' . wp_create_nonce( 'proxy_atd' ) . '&url=' );
+ $init_array['atd_ignore_rpc_url'] = admin_url( 'admin-ajax.php?action=atd_ignore&_wpnonce=' . wp_create_nonce( 'atd_ignore' ) . '&phrase=' );
+ $init_array['atd_rpc_id'] = AtD_get_rpc_id();
$init_array['atd_theme'] = 'wordpress';
$init_array['atd_ignore_enable'] = 'true';
$init_array['atd_strip_on_get'] = 'true';
@@ -122,42 +161,70 @@ function AtD_change_mce_settings( $init_array ) {
* Sanitizes AtD AJAX data to acceptable chars, caller needs to make sure ' is escaped
*/
function AtD_sanitize( $untrusted ) {
- return preg_replace( '/[^a-zA-Z0-9\-\',_ ]/i', "", $untrusted );
+ return preg_replace( '/[^a-zA-Z0-9\-\',_ ]/i', "", $untrusted );
}
/*
* AtD HTML Editor Stuff
*/
function AtD_settings() {
- $user = wp_get_current_user();
+ $user = wp_get_current_user();
- header( 'Content-Type: text/javascript' );
+ header( 'Content-Type: text/javascript' );
/* set the RPC URL for AtD */
- echo "AtD.rpc = " . json_encode( esc_url_raw( admin_url( 'admin-ajax.php?action=proxy_atd&url=' ) ) ) . ";\n";
+ echo "AtD.rpc = " . json_encode( esc_url_raw( admin_url( 'admin-ajax.php?action=proxy_atd&_wpnonce=' . wp_create_nonce( 'proxy_atd' ) . '&url=' ) ) ) . ";\n";
/* set the API key for AtD */
- echo "AtD.api_key = " . json_encode( 'WPORG-' . md5( get_bloginfo( 'wpurl' ) ) ) . ";\n";
+ echo "AtD.api_key = " . json_encode( AtD_get_rpc_id() ) . ";\n";
- /* set the ignored phrases for AtD */
+ /* set the ignored phrases for AtD */
echo "AtD.setIgnoreStrings(" . json_encode( AtD_get_setting( $user->ID, 'AtD_ignored_phrases' ) ) . ");\n";
- /* honor the types we want to show */
- echo "AtD.showTypes(" . json_encode( AtD_get_setting( $user->ID, 'AtD_options' ) ) .");\n";
+ /* honor the types we want to show */
+ echo "AtD.showTypes(" . json_encode( AtD_get_setting( $user->ID, 'AtD_options' ) ) .");\n";
- /* this is not an AtD/jQuery setting but I'm putting it in AtD to make it easy for the non-viz plugin to find it */
- echo "AtD.rpc_ignore = " . json_encode( esc_url_raw( admin_url( 'admin-ajax.php?action=atd_ignore&phrase=' ) ) ) . ";\n";
+ /* this is not an AtD/jQuery setting but I'm putting it in AtD to make it easy for the non-viz plugin to find it */
+ $admin_ajax_url = admin_url( 'admin-ajax.php?action=atd_ignore&_wpnonce=' . wp_create_nonce( 'atd_ignore' ) . '&phrase=' );
+ echo "AtD.rpc_ignore = " . json_encode( esc_url_raw( $admin_ajax_url ) ) . ";\n";
- die;
+ die;
}
function AtD_load_javascripts() {
if ( AtD_should_load_on_page() ) {
wp_enqueue_script( 'AtD_core', plugins_url( '/after-the-deadline/atd.core.js', __FILE__ ), array(), ATD_VERSION );
- wp_enqueue_script( 'AtD_quicktags', plugins_url( '/after-the-deadline/atd-nonvis-editor-plugin.js', __FILE__ ), array('quicktags'), ATD_VERSION );
- wp_enqueue_script( 'AtD_jquery', plugins_url( '/after-the-deadline/jquery.atd.js', __FILE__ ), array('jquery'), ATD_VERSION );
- wp_enqueue_script( 'AtD_settings', admin_url() . 'admin-ajax.php?action=atd_settings', array('AtD_jquery'), ATD_VERSION );
+ wp_enqueue_script( 'AtD_quicktags', plugins_url( '/after-the-deadline/atd-nonvis-editor-plugin.js', __FILE__ ), array('quicktags'), ATD_VERSION );
+ wp_enqueue_script( 'AtD_jquery', plugins_url( '/after-the-deadline/jquery.atd.js', __FILE__ ), array('jquery'), ATD_VERSION );
+ wp_enqueue_script( 'AtD_settings', admin_url() . 'admin-ajax.php?action=atd_settings', array('AtD_jquery'), ATD_VERSION );
wp_enqueue_script( 'AtD_autoproofread', plugins_url( '/after-the-deadline/atd-autoproofread.js', __FILE__ ), array('AtD_jquery'), ATD_VERSION );
+
+ /* load localized strings for AtD */
+ wp_localize_script( 'AtD_core', 'AtD_l10n_r0ar', array (
+ 'menu_title_spelling' => __( 'Spelling', 'jetpack' ),
+ 'menu_title_repeated_word' => __( 'Repeated Word', 'jetpack' ),
+
+ 'menu_title_no_suggestions' => __( 'No suggestions', 'jetpack' ),
+
+ 'menu_option_explain' => __( 'Explain...', 'jetpack' ),
+ 'menu_option_ignore_once' => __( 'Ignore suggestion', 'jetpack' ),
+ 'menu_option_ignore_always' => __( 'Ignore always', 'jetpack' ),
+ 'menu_option_ignore_all' => __( 'Ignore all', 'jetpack' ),
+
+ 'menu_option_edit_selection' => __( 'Edit Selection...', 'jetpack' ),
+
+ 'button_proofread' => __( 'proofread', 'jetpack' ),
+ 'button_edit_text' => __( 'edit text', 'jetpack' ),
+ 'button_proofread_tooltip' => __( 'Proofread Writing', 'jetpack' ),
+
+ 'message_no_errors_found' => __( 'No writing errors were found.', 'jetpack' ),
+ 'message_server_error' => __( 'There was a problem communicating with the Proofreading service. Try again in one minute.', 'jetpack' ),
+ 'message_server_error_short' => __( 'There was an error communicating with the proofreading service.', 'jetpack' ),
+
+ 'dialog_replace_selection' => __( 'Replace selection with:', 'jetpack' ),
+ 'dialog_confirm_post_publish' => __( "The proofreader has suggestions for this post. Are you sure you want to publish it?\n\nPress OK to publish your post, or Cancel to view the suggestions and edit your post.", 'jetpack' ),
+ 'dialog_confirm_post_update' => __( "The proofreader has suggestions for this post. Are you sure you want to update it?\n\nPress OK to update your post, or Cancel to view the suggestions and edit your post.", 'jetpack' ),
+ ) );
}
}
@@ -189,19 +256,27 @@ function AtD_load_submit_check_javascripts() {
* Check if a user is allowed to use AtD
*/
function AtD_is_allowed() {
- $user = wp_get_current_user();
- if ( ! $user || $user->ID == 0 )
- return;
+ if ( ( defined( 'AtD_FORCED_ON' ) && AtD_FORCED_ON ) ) {
+ return true;
+ }
+ $user = wp_get_current_user();
+ if ( ! $user || $user->ID == 0 )
+ return;
- if ( ! current_user_can( 'edit_posts' ) && ! current_user_can( 'edit_pages' ) )
- return;
+ if ( ! current_user_can( 'edit_posts' ) && ! current_user_can( 'edit_pages' ) )
+ return;
- return 1;
+ return 1;
}
function AtD_load_css() {
- if ( AtD_should_load_on_page() )
- wp_enqueue_style( 'AtD_style', plugins_url( '/after-the-deadline/atd.css', __FILE__ ), null, ATD_VERSION, 'screen' );
+ if ( AtD_should_load_on_page() ) {
+ if( is_rtl() ) {
+ wp_enqueue_style( 'AtD_style', plugins_url( '/after-the-deadline/rtl/atd-rtl.css', __FILE__ ), null, ATD_VERSION, 'screen' );
+ } else {
+ wp_enqueue_style( 'AtD_style', plugins_url( '/after-the-deadline/atd.css', __FILE__ ), null, ATD_VERSION, 'screen' );
+ }
+ }
}
/* Helper used to check if javascript should be added to page. Helps avoid bloat in admin */
@@ -217,11 +292,22 @@ function AtD_should_load_on_page() {
return true;
}
+ /**
+ * Allows scripts to be loaded via AtD in admin.
+ *
+ * By default, AtD only enqueues JS on certain admin pages to reduce bloat. The filter allows additional pages to have AtD JS.
+ *
+ * @since 1.2.3
+ *
+ * @param bool false Boolean to load or not load AtD scripts in admin.
+ */
return apply_filters( 'atd_load_scripts', false );
}
// add button to DFW
-add_filter( 'wp_fullscreen_buttons', 'AtD_fullscreen' );
+if ( ! ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ) {
+ add_filter( 'wp_fullscreen_buttons', 'AtD_fullscreen' );
+}
function AtD_fullscreen($buttons) {
$buttons['spellchecker'] = array( 'title' => __( 'Proofread Writing', 'jetpack' ), 'onclick' => "tinyMCE.execCommand('mceWritingImprovementTool');", 'both' => false );
return $buttons;
@@ -231,9 +317,9 @@ function AtD_fullscreen($buttons) {
add_filter( 'tiny_mce_before_init', 'AtD_change_mce_settings' );
/* load some stuff for non-visual editor */
-add_action( 'admin_print_scripts', 'AtD_load_javascripts' );
-add_action( 'admin_print_scripts', 'AtD_load_submit_check_javascripts' );
-add_action( 'admin_print_styles', 'AtD_load_css' );
+add_action( 'admin_enqueue_scripts', 'AtD_load_javascripts' );
+add_action( 'admin_enqueue_scripts', 'AtD_load_submit_check_javascripts' );
+add_action( 'admin_enqueue_scripts', 'AtD_load_css' );
/* init process for button control */
add_action( 'init', 'AtD_addbuttons' );
@@ -242,6 +328,3 @@ add_action( 'init', 'AtD_addbuttons' );
add_action( 'wp_ajax_proxy_atd', 'AtD_redirect_call' );
add_action( 'wp_ajax_atd_ignore', 'AtD_ignore_call' );
add_action( 'wp_ajax_atd_settings', 'AtD_settings' );
-
-/* load and install the localization stuff */
-include( 'after-the-deadline/atd-l10n.php' );
diff --git a/plugins/jetpack/modules/after-the-deadline/atd-autoproofread.js b/plugins/jetpack/modules/after-the-deadline/atd-autoproofread.js
index 53ef766d..c56d55d9 100644
--- a/plugins/jetpack/modules/after-the-deadline/atd-autoproofread.js
+++ b/plugins/jetpack/modules/after-the-deadline/atd-autoproofread.js
@@ -1,18 +1,24 @@
+/* jshint devel: true, onevar: false */
+/* global tinyMCE, AtD_restore_if_proofreading, AtD_check, AtD_unbind_proofreader_listeners,
+ AtD, AtD_bind_proofreader_listeners, AtD_check_when
+ */
+
/* the AtD/jQuery and AtD/TinyMCE plugins check if this variable exists and increment it when a proofread check happens */
var AtD_proofread_click_count = 0;
/* This is function called when the publish/update button is pressed */
function AtD_submit_check( e ) {
/* User has already checked their document... no need to hold up their submit */
- if (AtD_proofread_click_count > 0)
+ if (AtD_proofread_click_count > 0) {
return;
+ }
/* Let's not submit the form, shall we? */
e.stopImmediatePropagation();
e.preventDefault();
/* We'll call the AtD function based on which editor is currently active */
- if ( typeof(tinyMCE) != 'undefined' && tinyMCE.activeEditor && !tinyMCE.activeEditor.isHidden() ) {
+ if ( typeof(tinyMCE) !== 'undefined' && tinyMCE.activeEditor && !tinyMCE.activeEditor.isHidden() ) {
/* Woo! We're running tinyMCE! */
tinyMCE.activeEditor.execCommand('mceWritingImprovementTool', AtD_submit_check_callback);
} else {
@@ -24,25 +30,26 @@ function AtD_submit_check( e ) {
/* This is the callback function that runs after the publish/update button is pressed */
function AtD_submit_check_callback(count) {
- count = count || 0;
+ count = Number( count || 0 );
AtD_unbind_proofreader_listeners();
- if ( 0 == count || 1 < AtD_proofread_click_count ) {
+ if ( 0 === count || 1 < AtD_proofread_click_count ) {
/* if no errors were found, submit form */
AtD_update_post();
- } else if ( -1 == count ) {
+ } else if ( -1 === count ) {
/* If there was an error, alert the user and submit form */
alert( AtD.getLang('message_server_error', 'There was a problem communicating with the Proofreading service. Try again in one minute.') );
AtD_update_post();
} else {
- var original_post_status = jQuery('#original_post_status').val()
+ var original_post_status = jQuery('#original_post_status').val();
/* Okay, the user has tried to publish/update already but there are still errors. Ask them what to do */
var message;
- if ( original_post_status == 'publish' )
+ if ( original_post_status === 'publish' ) {
message = AtD.getLang('dialog_confirm_post_publish', 'The proofreader has suggestions for this post. Are you sure you want to publish it?\n\nPress OK to publish your post, or Cancel to view the suggestions and edit your post.');
- else
+ } else {
message = AtD.getLang('dialog_confirm_post_update', 'The proofreader has suggestions for this post. Are you sure you want to update it?\n\nPress OK to update your post, or Cancel to view the suggestions and edit your post.');
+ }
if ( confirm( message ) ) {
AtD_update_post();
@@ -65,8 +72,9 @@ function AtD_kill_autoproofread() {
/* a function to force the post to be submitted */
function AtD_update_post() {
- if ( typeof(tinyMCE) == 'undefined' || !tinyMCE.activeEditor || tinyMCE.activeEditor.isHidden() )
+ if ( typeof(tinyMCE) === 'undefined' || !tinyMCE.activeEditor || tinyMCE.activeEditor.isHidden() ) {
AtD_restore_if_proofreading();
+ }
jQuery('#publish').unbind('click.AtD_submit_check').click();
}
@@ -76,9 +84,10 @@ jQuery( document ).ready( function($){
var orig_status = $('#original_post_status').val();
/* check if auto-check is enabled && if #content exists */
- if ( typeof AtD_check_when != 'undefined' && $('#content').length
- && ( ( orig_status != 'publish' && AtD_check_when.onpublish )
- || ( ( orig_status == 'publish' || orig_status == 'schedule' ) && AtD_check_when.onupdate ) ) )
+ if ( typeof AtD_check_when !== 'undefined' && $('#content').length &&
+ ( ( orig_status !== 'publish' && AtD_check_when.onpublish ) ||
+ ( ( orig_status === 'publish' || orig_status === 'schedule' ) && AtD_check_when.onupdate ) ) ) {
$('#publish').bind( 'click.AtD_submit_check', AtD_submit_check );
+ }
});
diff --git a/plugins/jetpack/modules/after-the-deadline/atd-l10n.php b/plugins/jetpack/modules/after-the-deadline/atd-l10n.php
deleted file mode 100644
index 628baa4d..00000000
--- a/plugins/jetpack/modules/after-the-deadline/atd-l10n.php
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-/*
- * loads AtD localization strings (shared between Visual and HTML Editors)
- */
-function AtD_init_l10n_js() {
- if ( !AtD_should_load_on_page() ) {
- return;
- }
-
- /* load localized strings for AtD */
- wp_localize_script( 'AtD_settings', 'AtD_l10n_r0ar', array (
- 'menu_title_spelling' => __( 'Spelling', 'jetpack' ),
- 'menu_title_repeated_word' => __( 'Repeated Word', 'jetpack' ),
-
- 'menu_title_no_suggestions' => __( 'No suggestions', 'jetpack' ),
-
- 'menu_option_explain' => __( 'Explain...', 'jetpack' ),
- 'menu_option_ignore_once' => __( 'Ignore suggestion', 'jetpack' ),
- 'menu_option_ignore_always' => __( 'Ignore always', 'jetpack' ),
- 'menu_option_ignore_all' => __( 'Ignore all', 'jetpack' ),
-
- 'menu_option_edit_selection' => __( 'Edit Selection...', 'jetpack' ),
-
- 'button_proofread' => __( 'proofread', 'jetpack' ),
- 'button_edit_text' => __( 'edit text', 'jetpack' ),
- 'button_proofread_tooltip' => __( 'Proofread Writing', 'jetpack' ),
-
- 'message_no_errors_found' => __( 'No writing errors were found.', 'jetpack' ),
- 'message_server_error' => __( 'There was a problem communicating with the Proofreading service. Try again in one minute.', 'jetpack' ),
- 'message_server_error_short' => __( 'There was an error communicating with the proofreading service.', 'jetpack' ),
-
- 'dialog_replace_selection' => __( 'Replace selection with:', 'jetpack' ),
- 'dialog_confirm_post_publish' => __( "The proofreader has suggestions for this post. Are you sure you want to publish it?\n\nPress OK to publish your post, or Cancel to view the suggestions and edit your post.", 'jetpack' ),
- 'dialog_confirm_post_update' => __( "The proofreader has suggestions for this post. Are you sure you want to update it?\n\nPress OK to update your post, or Cancel to view the suggestions and edit your post.", 'jetpack' ),
- ) );
-
- wp_enqueue_script( 'AtD_l10n', plugins_url( 'install_atd_l10n.js', __FILE__ ), array( 'AtD_settings', 'jquery' ), ATD_VERSION );
-}
-
-add_action( 'admin_print_scripts', 'AtD_init_l10n_js' );
diff --git a/plugins/jetpack/modules/after-the-deadline/atd-nonvis-editor-plugin.js b/plugins/jetpack/modules/after-the-deadline/atd-nonvis-editor-plugin.js
index 88f2d9c8..1e33a0c8 100644
--- a/plugins/jetpack/modules/after-the-deadline/atd-nonvis-editor-plugin.js
+++ b/plugins/jetpack/modules/after-the-deadline/atd-nonvis-editor-plugin.js
@@ -1,19 +1,30 @@
-var AtD_qtbutton;
+/* jshint devel: true, onevar: false, smarttabs: true */
+/* global AtD, QTags, AtD_l10n_r0ar, edButtons, edButton, switchEditors, AtD_unbind_proofreader_listeners */
+/* exported AtD_unbind_proofreader_listeners */
+
+var AtD_qtbutton, autosave;
/* convienence method to restore the text area from the preview div */
function AtD_restore_text_area()
{
- /* clear the error HTML out of the preview div */
- AtD.remove('content');
-
+ var content;
/* swap the preview div for the textarea, notice how I have to restore the appropriate class/id/style attributes */
- var content = jQuery('#content').html();
+ if( jQuery('#atd-content').get(0) ) {
+ AtD.remove('atd-content');
+ content = jQuery('#atd-content').html();
+ } else {
+ AtD.remove('content');
+ content = jQuery('#content').html();
+ }
- if ( navigator.appName == 'Microsoft Internet Explorer' )
- content = content.replace(/<BR.*?class.*?atd_remove_me.*?>/gi, "\n");
+ if ( navigator.appName === 'Microsoft Internet Explorer' ) {
+ content = content.replace(/<BR.*?class.*?atd_remove_me.*?>/gi, '\n');
+ }
- jQuery('#content').replaceWith( AtD.content_canvas );
- jQuery('#content').val( content.replace(/\&lt\;/g, '<').replace(/\&gt\;/g, '>').replace(/\&amp;/g, '&') );
- jQuery('#content').height(AtD.height);
+ // jQuery('#content').replaceWith( AtD.content_canvas );
+ jQuery('#content').val( content.replace(/\&lt\;/g, '<').replace(/\&gt\;/g, '>').replace(/\&amp;/g, '&') )
+ .height(AtD.height)
+ .show();
+ jQuery('#atd-content').remove();
if ( AtD_qtbutton ) {
/* change the link text back to its original label */
@@ -25,13 +36,19 @@ function AtD_restore_text_area()
}
/* restore autosave */
- if ( AtD.autosave != undefined )
- autosave = AtD.autosave;
-};
+ if ( AtD.autosave !== undefined ) {
+ if ( window.wp && window.wp.autosave && window.wp.autosave.server ) {
+ window.wp.autosave.local.resume && window.wp.autosave.local.resume();
+ window.wp.autosave.server.resume && window.wp.autosave.server.resume();
+ } else {
+ autosave = AtD.autosave;
+ }
+ }
+}
// add the AtD button properly to quicktags
-if ( typeof(QTags) != 'undefined' && QTags.addButton ) {
- jQuery(document).ready(function($){
+if ( typeof(QTags) !== 'undefined' && QTags.addButton ) {
+ jQuery(document).ready(function(){
QTags.addButton( 'AtD', AtD_l10n_r0ar.button_proofread, AtD_check );
});
} else {
@@ -42,8 +59,9 @@ if ( typeof(QTags) != 'undefined' && QTags.addButton ) {
}
function AtD_restore_if_proofreading() {
- if ( AtD_qtbutton && jQuery(AtD_qtbutton).val() == AtD.getLang('button_edit_text', 'edit text') )
+ if ( AtD_qtbutton && jQuery(AtD_qtbutton).val() === AtD.getLang('button_edit_text', 'edit text') ) {
AtD_restore_text_area();
+ }
}
function AtD_unbind_proofreader_listeners() {
@@ -60,7 +78,8 @@ function AtD_bind_proofreader_listeners() {
/* where the magic happens, checks the spelling or restores the form */
function AtD_check(button) {
- var callback;
+ var callback, divHeight;
+
if ( jQuery.isFunction( button ) ) {
callback = button;
@@ -68,8 +87,9 @@ function AtD_check(button) {
AtD_qtbutton = jQuery( '#qt_content_AtD, #ed_AtD' ).get( 0 );
}
} else {
- if ( !button.id )
+ if ( !button.id ) {
button = button[0];
+ }
AtD_qtbutton = button;
}
@@ -84,11 +104,19 @@ function AtD_check(button) {
/* If the text of the link says edit comment, then restore the textarea so the user can edit the text */
- if ( jQuery(AtD_qtbutton).val() == AtD.getLang('button_edit_text', 'edit text') ) {
+ if ( jQuery(AtD_qtbutton).val() === AtD.getLang('button_edit_text', 'edit text') ) {
AtD_restore_text_area();
} else {
+ // Disable editor expand/scroll
+ if ( window.editorExpand && jQuery( '#postdivrich' ).hasClass( 'wp-editor-expand' ) ) {
+ AtD.wpEditorExpand = true;
+ // window.editorExpand.off && window.editorExpand.off();
+ } else {
+ AtD.wpEditorExpand = false;
+ }
+
/* initialize some of the stuff related to this plugin */
- if ( !AtD.height ) {
+ if ( ! AtD.height ) {
AtD.height = jQuery('#content').height();
AtD_bind_proofreader_listeners();
@@ -106,6 +134,9 @@ function AtD_check(button) {
/* store the autosave, we're going to make it empty during spellcheck to prevent auto saved text from being
over written with empty text */
AtD.autosave = autosave;
+ } else {
+ // Update the height
+ AtD.height = jQuery('#content').height();
}
/* set the spell check link to a link that lets the user edit the text */
@@ -114,47 +145,77 @@ function AtD_check(button) {
jQuery(AtD_qtbutton).css({ 'color' : 'red' }).val( AtD.getLang('button_edit_text', 'edit text') ).attr('disabled', true);
/* replace the div */
- var text = jQuery('#content').val().replace(/\&/g, '&amp;').replace(/\</g, '&lt;').replace(/\>/g, '&gt;');
+ var $replacement,
+ $textarea = jQuery('#content'),
+ text = $textarea.val().replace( /\&/g, '&amp;' ).replace( /</g, '&lt;' ).replace( /\>/g, '&gt;' ),
+ fontFamily = $textarea.css('font-family'),
+ fontSize = $textarea.css('font-size'),
+ lineHeight = $textarea.css('line-height');
+
+ if ( navigator.appName === 'Microsoft Internet Explorer' ) {
+ text = text.replace( /[\n\r\f]/gm, '<BR class="atd_remove_me">' );
+ }
- if (navigator.appName == 'Microsoft Internet Explorer') {
- text = text.replace(/[\n\r\f]/gm, '<BR class="atd_remove_me">');
- var node = jQuery('<div class="input" id="content" style="height: 170px">' + text + '</div>');
- jQuery('#content').replaceWith(node);
- node.css( { 'overflow' : 'auto', 'background-color' : 'white', 'color' : 'black' } );
- } else {
- jQuery('#content').replaceWith('<div class="input" id="content">' + text + '</div>');
- jQuery('#content').css( { 'overflow' : 'auto', 'background-color' : 'white', 'color' : 'black', 'white-space' : 'pre-wrap' } );
- jQuery('#content').height(AtD.height);
+ $replacement = jQuery( '<div class="input" id="atd-content">' + text + '</div>' );
+ $textarea.after( $replacement ).hide();
+
+ divHeight = AtD.height;
+ // AtD disables resizing of the Text editor, normalize the size of the replacement div.
+ if ( divHeight < 200 ) {
+ divHeight = 200;
+ } else if ( divHeight > 1000 ) {
+ divHeight = 1000;
}
+ var toolBarHeight = jQuery('#ed_toolbar').height();
+ $replacement.css( {
+ overflow: 'auto',
+ 'background-color': 'white',
+ color: 'black',
+ 'white-space': 'pre-wrap',
+ padding: '10px',
+ 'font-family': fontFamily || 'Consolas, Monaco, monospace',
+ 'font-size': fontSize || '13px',
+ 'line-height': lineHeight || '1.5',
+ height: divHeight,
+ 'margin-top': toolBarHeight+7+'px'
+ } );
/* kill autosave... :) */
- autosave = function() { };
+ if ( window.wp && window.wp.autosave && window.wp.autosave.server ) {
+ window.wp.autosave.local.suspend && window.wp.autosave.local.suspend();
+ window.wp.autosave.server.suspend && window.wp.autosave.server.suspend();
+ } else {
+ autosave = function() { };
+ }
/* disable the toolbar buttons */
jQuery( AtD_qtbutton ).siblings('input').andSelf().attr( 'disabled', true ); // using .arrt instead of .prop so it's compat with older WP and jQuery
/* check the writing in the textarea */
- AtD.check('content', {
+ AtD.check('atd-content', {
success: function(errorCount) {
- if ( errorCount == 0 && typeof callback !== 'function' )
+ if ( Number( errorCount ) === 0 && typeof callback !== 'function' ) {
alert( AtD.getLang('message_no_errors_found', 'No writing errors were found') );
+ }
AtD_restore_if_proofreading();
},
ready: function(errorCount) {
jQuery(AtD_qtbutton).attr('disabled', false);
- if ( typeof callback === 'function' )
+ if ( typeof callback === 'function' ) {
callback( errorCount );
+ }
},
- error: function(reason) {
+ error: function() {
jQuery(AtD_qtbutton).attr('disabled', false);
- if ( typeof callback === 'function' )
+ if ( typeof callback === 'function' ) {
callback( -1 );
- else
+ } else {
alert( AtD.getLang('message_server_error', 'There was a problem communicating with the Proofreading service. Try again in one minute.') );
+ }
AtD_restore_if_proofreading();
},
@@ -162,8 +223,9 @@ function AtD_check(button) {
editSelection: function(element) {
var text = prompt( AtD.getLang('dialog_replace_selection', 'Replace selection with:'), element.text() );
- if ( text != null )
+ if ( text != null ) {
element.replaceWith( text );
+ }
},
explain: function(url) {
@@ -178,8 +240,9 @@ function AtD_check(button) {
url : AtD.rpc_ignore + encodeURI( word ).replace( /&/g, '%26'),
format : 'raw',
error : function(XHR, status, error) {
- if ( AtD.callback_f != undefined && AtD.callback_f.error != undefined )
- AtD.callback_f.error(status + ": " + error);
+ if ( AtD.callback_f !== undefined && AtD.callback_f.error !== undefined ) {
+ AtD.callback_f.error(status + ': ' + error);
+ }
}
});
}
diff --git a/plugins/jetpack/modules/after-the-deadline/atd-rtl.css b/plugins/jetpack/modules/after-the-deadline/atd-rtl.css
new file mode 100644
index 00000000..ec46b155
--- /dev/null
+++ b/plugins/jetpack/modules/after-the-deadline/atd-rtl.css
@@ -0,0 +1,122 @@
+/* AtD error styles */
+
+.hiddenSpellError
+{
+ border-bottom: 2px solid red;
+ cursor: default;
+}
+
+.hiddenGrammarError
+{
+ border-bottom: 2px solid green;
+ cursor: default;
+}
+
+.hiddenSuggestion
+{
+ border-bottom: 2px solid blue;
+ cursor: default;
+}
+
+/* Menu styles derived from:
+ * jquery.spellchecker.js - a simple jQuery Spell Checker
+ * Copyright (c) 2008 Richard Willis
+ * MIT license : http://www.opensource.org/licenses/mit-license.php
+ * Project : http://jquery-spellchecker.googlecode.com
+ */
+
+#suggestmenu
+{
+ min-width: 122px;
+ background: #ebeaeb;
+ position: absolute;
+ display: none;
+ z-index: 9999;
+ overflow: none;
+ margin-top: 1px;
+ text-align: right;
+ font-size: 11px;
+ font-family: Tahoma, Verdana, Arial, Helvetica;
+}
+
+#suggestmenu strong
+{
+ background: #cccccc;
+ font-weight: bold;
+ padding:3px 6px 3px 6px;
+ display:block;
+ border:1px solid #dddddd;
+ border-bottom: 1px solid #aaaaaa;
+ color: black;
+}
+
+#suggestmenu em
+{
+ text-align:center;
+ padding:3px 6px 3px 6px;
+ display:block;
+ border-top:1px solid #ccc;
+ border-right:1px solid #ccc;
+}
+
+#suggestmenu a, #suggestmenu a:visited
+{
+ background: #ebeaeb;
+ border-right:1px solid #dddddd;
+ border-left:1px solid #dddddd;
+ padding:3px 6px 3px 6px;
+ display:block;
+ margin:0px;
+ text-decoration:none;
+ color: black;
+ outline:none
+}
+
+#suggestmenu a.first, #suggestmenu a.first:visited
+{
+ border-top:1px solid #dddddd;
+}
+
+.spell_sep_bottom
+{
+ border-bottom: 1px solid #dddddd;
+}
+
+.spell_sep_top
+{
+ border-top: 1px solid #aaaaaa;
+}
+
+#suggestmenu a:hover
+{
+ color:#000;
+ background: #f5f5f5;
+}
+
+#suggestmenu .foot
+{
+ border-top:1px solid #aaaaaa;
+ background:#fff
+}
+
+#suggestmenu .foot a, #suggestmenu .foot a:visited
+{
+ outline:none
+}
+
+/* TinyMCE 4.0 */
+div.mce-atd-menu-title.mce-disabled {
+ padding: 3px 12px 0;
+}
+
+div.mce-atd-menu-title.mce-disabled:hover,
+div.mce-atd-menu-title.mce-disabled:hover span.mce-text {
+ background: none;
+ color: #888;
+ cursor: default;
+}
+
+div.mce-atd-menu-title.mce-disabled span.mce-text {
+ font-weight: bold;
+ color: #888;
+}
diff --git a/plugins/jetpack/modules/after-the-deadline/atd-rtl.min.css b/plugins/jetpack/modules/after-the-deadline/atd-rtl.min.css
new file mode 100644
index 00000000..6c896dd2
--- /dev/null
+++ b/plugins/jetpack/modules/after-the-deadline/atd-rtl.min.css
@@ -0,0 +1 @@
+.hiddenSpellError{border-bottom:2px solid red;cursor:default}.hiddenGrammarError{border-bottom:2px solid green;cursor:default}.hiddenSuggestion{border-bottom:2px solid #00f;cursor:default}#suggestmenu{min-width:122px;background:#ebeaeb;position:absolute;display:none;z-index:9999;overflow:none;margin-top:1px;text-align:right;font-size:11px;font-family:Tahoma,Verdana,Arial,Helvetica}#suggestmenu strong{background:#ccc;font-weight:700;padding:3px 6px;display:block;border:1px solid #ddd;border-bottom:1px solid #aaa;color:#000}#suggestmenu em{text-align:center;padding:3px 6px;display:block;border-top:1px solid #ccc;border-right:1px solid #ccc}#suggestmenu a,#suggestmenu a:visited{background:#ebeaeb;border-right:1px solid #ddd;border-left:1px solid #ddd;padding:3px 6px;display:block;margin:0;text-decoration:none;color:#000;outline:0}#suggestmenu a.first,#suggestmenu a.first:visited{border-top:1px solid #ddd}.spell_sep_bottom{border-bottom:1px solid #ddd}.spell_sep_top{border-top:1px solid #aaa}#suggestmenu a:hover{color:#000;background:#f5f5f5}#suggestmenu .foot{border-top:1px solid #aaa;background:#fff}#suggestmenu .foot a,#suggestmenu .foot a:visited{outline:0}div.mce-atd-menu-title.mce-disabled{padding:3px 12px 0}div.mce-atd-menu-title.mce-disabled:hover,div.mce-atd-menu-title.mce-disabled:hover span.mce-text{background:0 0;color:#888;cursor:default}div.mce-atd-menu-title.mce-disabled span.mce-text{font-weight:700;color:#888} \ No newline at end of file
diff --git a/plugins/jetpack/modules/after-the-deadline/atd.core.js b/plugins/jetpack/modules/after-the-deadline/atd.core.js
index 5d6efc91..099dd159 100644
--- a/plugins/jetpack/modules/after-the-deadline/atd.core.js
+++ b/plugins/jetpack/modules/after-the-deadline/atd.core.js
@@ -6,6 +6,9 @@
* Contact : raffi@automattic.com
*/
+/* jshint sub: true, devel: true, onevar: false, smarttabs: true */
+/* exported EXPORTED_SYMBOLS, atd_sprintf */
+
/* EXPORTED_SYMBOLS is set so this file can be a JavaScript Module */
var EXPORTED_SYMBOLS = ['AtDCore'];
@@ -17,22 +20,21 @@ function AtDCore() {
this.ignore_strings = {};
/* Localized strings */
+ // Back-compat, not used
this.i18n = {};
-};
+}
/*
* Internationalization Functions
*/
-AtDCore.prototype.getLang = function(key, defaultk) {
- if (this.i18n[key] == undefined)
- return defaultk;
-
- return this.i18n[key];
+AtDCore.prototype.getLang = function( key, defaultk ) {
+ return ( window.AtD_l10n_r0ar && window.AtD_l10n_r0ar[key] ) || defaultk;
};
-AtDCore.prototype.addI18n = function(localizations) {
- this.i18n = localizations;
+AtDCore.prototype.addI18n = function( obj ) {
+ // Back-compat
+ window.AtD_l10n_r0ar = obj;
};
/*
@@ -54,18 +56,18 @@ AtDCore.prototype.showTypes = function(string) {
/* set some default types that we want to make optional */
/* grammar checker options */
- types["Double Negatives"] = 1;
- types["Hidden Verbs"] = 1;
- types["Passive voice"] = 1;
- types["Bias Language"] = 1;
+ types['Double Negatives'] = 1;
+ types['Hidden Verbs'] = 1;
+ types['Passive voice'] = 1;
+ types['Bias Language'] = 1;
/* style checker options */
- types["Cliches"] = 1;
- types["Complex Expression"] = 1;
- types["Diacritical Marks"] = 1;
- types["Jargon Language"] = 1;
- types["Phrases to Avoid"] = 1;
- types["Redundant Expression"] = 1;
+ types['Cliches'] = 1;
+ types['Complex Expression'] = 1;
+ types['Diacritical Marks'] = 1;
+ types['Jargon Language'] = 1;
+ types['Phrases to Avoid'] = 1;
+ types['Redundant Expression'] = 1;
var ignore_types = [];
@@ -74,8 +76,9 @@ AtDCore.prototype.showTypes = function(string) {
});
this.map(this.ignore_types, function(string) {
- if (types[string] != undefined)
+ if (types[string] !== undefined) {
ignore_types.push(string);
+ }
});
this.ignore_types = ignore_types;
@@ -85,23 +88,23 @@ AtDCore.prototype.showTypes = function(string) {
* Error Parsing Code
*/
-AtDCore.prototype.makeError = function(error_s, tokens, type, seps, pre) {
- var struct = new Object();
+AtDCore.prototype.makeError = function(error_s, tokens, type, seps/*, pre*/) {
+ var struct = {};
struct.type = type;
struct.string = error_s;
struct.tokens = tokens;
- if (new RegExp("\\b" + error_s + "\\b").test(error_s)) {
- struct.regexp = new RegExp("(?!"+error_s+"<)\\b" + error_s.replace(/\s+/g, seps) + "\\b");
+ if (new RegExp('\\b' + error_s + '\\b').test(error_s)) {
+ struct.regexp = new RegExp('(?!'+error_s+'<)\\b' + error_s.replace(/\s+/g, seps) + '\\b');
}
- else if (new RegExp(error_s + "\\b").test(error_s)) {
- struct.regexp = new RegExp("(?!"+error_s+"<)" + error_s.replace(/\s+/g, seps) + "\\b");
+ else if (new RegExp(error_s + '\\b').test(error_s)) {
+ struct.regexp = new RegExp('(?!'+error_s+'<)' + error_s.replace(/\s+/g, seps) + '\\b');
}
- else if (new RegExp("\\b" + error_s).test(error_s)) {
- struct.regexp = new RegExp("(?!"+error_s+"<)\\b" + error_s.replace(/\s+/g, seps));
+ else if (new RegExp('\\b' + error_s).test(error_s)) {
+ struct.regexp = new RegExp('(?!'+error_s+'<)\\b' + error_s.replace(/\s+/g, seps));
}
else {
- struct.regexp = new RegExp("(?!"+error_s+"<)" + error_s.replace(/\s+/g, seps));
+ struct.regexp = new RegExp('(?!'+error_s+'<)' + error_s.replace(/\s+/g, seps));
}
struct.used = false; /* flag whether we've used this rule or not */
@@ -113,23 +116,24 @@ AtDCore.prototype.addToErrorStructure = function(errors, list, type, seps) {
var parent = this;
this.map(list, function(error) {
- var tokens = error["word"].split(/\s+/);
- var pre = error["pre"];
+ var tokens = error['word'].split(/\s+/);
+ var pre = error['pre'];
var first = tokens[0];
- if (errors['__' + first] == undefined) {
- errors['__' + first] = new Object();
+ if (errors['__' + first] === undefined) {
+ errors['__' + first] = {};
errors['__' + first].pretoks = {};
- errors['__' + first].defaults = new Array();
+ errors['__' + first].defaults = [];
}
- if (pre == "") {
- errors['__' + first].defaults.push(parent.makeError(error["word"], tokens, type, seps, pre));
+ if (pre === '') {
+ errors['__' + first].defaults.push(parent.makeError(error['word'], tokens, type, seps, pre));
} else {
- if (errors['__' + first].pretoks['__' + pre] == undefined)
- errors['__' + first].pretoks['__' + pre] = new Array();
+ if (errors['__' + first].pretoks['__' + pre] === undefined) {
+ errors['__' + first].pretoks['__' + pre] = [];
+ }
- errors['__' + first].pretoks['__' + pre].push(parent.makeError(error["word"], tokens, type, seps, pre));
+ errors['__' + first].pretoks['__' + pre].push(parent.makeError(error['word'], tokens, type, seps, pre));
}
});
};
@@ -138,21 +142,22 @@ AtDCore.prototype.buildErrorStructure = function(spellingList, enrichmentList, g
var seps = this._getSeparators();
var errors = {};
- this.addToErrorStructure(errors, spellingList, "hiddenSpellError", seps);
- this.addToErrorStructure(errors, grammarList, "hiddenGrammarError", seps);
- this.addToErrorStructure(errors, enrichmentList, "hiddenSuggestion", seps);
+ this.addToErrorStructure(errors, spellingList, 'hiddenSpellError', seps);
+ this.addToErrorStructure(errors, grammarList, 'hiddenGrammarError', seps);
+ this.addToErrorStructure(errors, enrichmentList, 'hiddenSuggestion', seps);
return errors;
};
AtDCore.prototype._getSeparators = function() {
var re = '', i;
- var str = '"s!#$%&()*+,./:;<=>?@[\]^_{|}';
+ var str = '"s!#$%&()*+,./:;<=>?@[\\]^_{|}';
// Build word separator regexp
- for (i=0; i<str.length; i++)
+ for (i=0; i<str.length; i++) {
re += '\\' + str.charAt(i);
+ }
- return "(?:(?:[\xa0" + re + "])|(?:\\-\\-))+";
+ return '(?:(?:[\xa0' + re + '])|(?:\\-\\-))+';
};
AtDCore.prototype.processXML = function(responseXML) {
@@ -176,69 +181,78 @@ AtDCore.prototype.processXML = function(responseXML) {
var enrichment = [];
for (var i = 0; i < errors.length; i++) {
- if (errors[i].getElementsByTagName('string').item(0).firstChild != null) {
+ if (errors[i].getElementsByTagName('string').item(0).firstChild !== null) {
var errorString = errors[i].getElementsByTagName('string').item(0).firstChild.data;
var errorType = errors[i].getElementsByTagName('type').item(0).firstChild.data;
var errorDescription = errors[i].getElementsByTagName('description').item(0).firstChild.data;
var errorContext;
- if (errors[i].getElementsByTagName('precontext').item(0).firstChild != null)
+ if (errors[i].getElementsByTagName('precontext').item(0).firstChild !== null) {
errorContext = errors[i].getElementsByTagName('precontext').item(0).firstChild.data;
- else
- errorContext = "";
+ } else {
+ errorContext = '';
+ }
/* create a hashtable with information about the error in the editor object, we will use this later
to populate a popup menu with information and suggestions about the error */
- if (this.ignore_strings[errorString] == undefined) {
+ if (this.ignore_strings[errorString] === undefined) {
var suggestion = {};
- suggestion["description"] = errorDescription;
- suggestion["suggestions"] = [];
+ suggestion['description'] = errorDescription;
+ suggestion['suggestions'] = [];
/* used to find suggestions when a highlighted error is clicked on */
- suggestion["matcher"] = new RegExp('^' + errorString.replace(/\s+/, this._getSeparators()) + '$');
+ suggestion['matcher'] = new RegExp('^' + errorString.replace(/\s+/, this._getSeparators()) + '$');
- suggestion["context"] = errorContext;
- suggestion["string"] = errorString;
- suggestion["type"] = errorType;
+ suggestion['context'] = errorContext;
+ suggestion['string'] = errorString;
+ suggestion['type'] = errorType;
this.suggestions.push(suggestion);
- if (errors[i].getElementsByTagName('suggestions').item(0) != undefined) {
+ if (errors[i].getElementsByTagName('suggestions').item(0) !== null) {
var suggestions = errors[i].getElementsByTagName('suggestions').item(0).getElementsByTagName('option');
- for (var j = 0; j < suggestions.length; j++)
- suggestion["suggestions"].push(suggestions[j].firstChild.data);
+ for (var j = 0; j < suggestions.length; j++) {
+ suggestion['suggestions'].push(suggestions[j].firstChild.data);
+ }
}
/* setup the more info url */
- if (errors[i].getElementsByTagName('url').item(0) != undefined) {
+ if (errors[i].getElementsByTagName('url').item(0) !== null) {
var errorUrl = errors[i].getElementsByTagName('url').item(0).firstChild.data;
- suggestion["moreinfo"] = errorUrl + '&theme=tinymce';
+ suggestion['moreinfo'] = errorUrl + '&theme=tinymce';
}
- if (types[errorDescription] == undefined) {
- if (errorType == "suggestion")
+ if (types[errorDescription] === undefined) {
+ if (errorType === 'suggestion') {
enrichment.push({ word: errorString, pre: errorContext });
+ }
- if (errorType == "grammar")
+ if (errorType === 'grammar') {
grammarErrors.push({ word: errorString, pre: errorContext });
+ }
}
- if (errorType == "spelling" || errorDescription == "Homophone")
+ if (errorType === 'spelling' || errorDescription === 'Homophone') {
spellingErrors.push({ word: errorString, pre: errorContext });
+ }
- if (errorDescription == 'Cliches')
- suggestion["description"] = 'Clich&eacute;s'; /* done here for backwards compatability with current user settings */
+ if (errorDescription === 'Cliches') {
+ suggestion['description'] = 'Clichés'; /* done here for backwards compatability with current user settings */
+ }
- if (errorDescription == "Spelling")
- suggestion["description"] = this.getLang('menu_title_spelling', 'Spelling');
+ if (errorDescription === 'Spelling') {
+ suggestion['description'] = this.getLang('menu_title_spelling', 'Spelling');
+ }
- if (errorDescription == "Repeated Word")
- suggestion["description"] = this.getLang('menu_title_repeated_word', 'Repeated Word');
+ if (errorDescription === 'Repeated Word') {
+ suggestion['description'] = this.getLang('menu_title_repeated_word', 'Repeated Word');
+ }
- if (errorDescription == "Did you mean...")
- suggestion["description"] = this.getLang('menu_title_confused_word', 'Did you mean...');
+ if (errorDescription === 'Did you mean...') {
+ suggestion['description'] = this.getLang('menu_title_confused_word', 'Did you mean...');
+ }
} // end if ignore[errorString] == undefined
} // end if
} // end for loop
@@ -246,10 +260,11 @@ AtDCore.prototype.processXML = function(responseXML) {
var errorStruct;
var ecount = spellingErrors.length + grammarErrors.length + enrichment.length;
- if (ecount > 0)
+ if (ecount > 0) {
errorStruct = this.buildErrorStructure(spellingErrors, enrichment, grammarErrors);
- else
+ } else {
errorStruct = undefined;
+ }
/* save some state in this object, for retrieving suggestions later */
return { errors: errorStruct, count: ecount, suggestions: this.suggestions };
@@ -257,19 +272,16 @@ AtDCore.prototype.processXML = function(responseXML) {
AtDCore.prototype.findSuggestion = function(element) {
var text = element.innerHTML;
- var context = ( this.getAttrib(element, 'pre') + "" ).replace(/[\\,!\\?\\."\s]/g, '');
- if (this.getAttrib(element, 'pre') == undefined)
- {
+ var context = ( this.getAttrib(element, 'pre') + '' ).replace(/[\\,!\\?\\."\s]/g, '');
+ if (this.getAttrib(element, 'pre') === undefined) {
alert(element.innerHTML);
}
- var errorDescription = undefined;
+ var errorDescription;
var len = this.suggestions.length;
for (var i = 0; i < len; i++) {
- var key = this.suggestions[i]["string"];
-
- if ((context == "" || context == this.suggestions[i]["context"]) && this.suggestions[i]["matcher"].test(text)) {
+ if ((context === '' || context === this.suggestions[i]['context']) && this.suggestions[i]['matcher'].test(text)) {
errorDescription = this.suggestions[i];
break;
}
@@ -286,7 +298,7 @@ function TokenIterator(tokens) {
this.index = 0;
this.count = 0;
this.last = 0;
-};
+}
TokenIterator.prototype.next = function() {
var current = this.tokens[this.index];
@@ -295,12 +307,14 @@ TokenIterator.prototype.next = function() {
this.index++;
/* strip single quotes from token, AtD does this when presenting errors */
- if (current != "") {
- if (current[0] == "'")
+ if (current !== '') {
+ if (current[0] === '\'') {
current = current.substring(1, current.length);
+ }
- if (current[current.length - 1] == "'")
+ if (current[current.length - 1] === '\'') {
current = current.substring(0, current.length - 1);
+ }
}
return current;
@@ -318,8 +332,9 @@ TokenIterator.prototype.skip = function(m, n) {
this.index += m;
this.last += n;
- if (this.index < this.tokens.length)
+ if (this.index < this.tokens.length) {
this.count = this.last - this.tokens[this.index].length;
+ }
};
TokenIterator.prototype.getCount = function() {
@@ -327,10 +342,11 @@ TokenIterator.prototype.getCount = function() {
};
TokenIterator.prototype.peek = function(n) {
- var peepers = new Array();
+ var peepers = [];
var end = this.index + n;
- for (var x = this.index; x < end; x++)
+ for (var x = this.index; x < end; x++) {
peepers.push(this.tokens[x]);
+ }
return peepers;
};
@@ -338,42 +354,45 @@ TokenIterator.prototype.peek = function(n) {
* code to manage highlighting of errors
*/
AtDCore.prototype.markMyWords = function(container_nodes, errors) {
- var seps = new RegExp(this._getSeparators());
- var nl = new Array();
- var ecount = 0; /* track number of highlighted errors */
- var parent = this;
+ var seps = new RegExp(this._getSeparators()),
+ nl = [],
+ ecount = 0, /* track number of highlighted errors */
+ parent = this,
+ bogus = this._isTinyMCE ? ' data-mce-bogus="1"' : '',
+ emptySpan = '<span class="mceItemHidden"' + bogus + '>&nbsp;</span>';
/* Collect all text nodes */
/* Our goal--ignore nodes that are already wrapped */
- this._walk(container_nodes, function(n) {
- if (n.nodeType == 3 && !parent.isMarkedNode(n))
- nl.push(n);
+ this._walk( container_nodes, function( n ) {
+ if ( n.nodeType === 3 && ! parent.isMarkedNode( n ) ) {
+ nl.push( n );
+ }
});
/* walk through the relevant nodes */
var iterator;
- this.map(nl, function(n) {
+ this.map( nl, function( n ) {
var v;
- if (n.nodeType == 3) {
+ if ( n.nodeType === 3 ) {
v = n.nodeValue; /* we don't want to mangle the HTML so use the actual encoded string */
- var tokens = n.nodeValue.split(seps); /* split on the unencoded string so we get access to quotes as " */
- var previous = "";
+ var tokens = n.nodeValue.split( seps ); /* split on the unencoded string so we get access to quotes as " */
+ var previous = '';
var doReplaces = [];
iterator = new TokenIterator(tokens);
- while (iterator.hasNext()) {
+ while ( iterator.hasNext() ) {
var token = iterator.next();
var current = errors['__' + token];
var defaults;
- if (current != undefined && current.pretoks != undefined) {
+ if ( current !== undefined && current.pretoks !== undefined ) {
defaults = current.defaults;
current = current.pretoks['__' + previous];
@@ -383,21 +402,19 @@ AtDCore.prototype.markMyWords = function(container_nodes, errors) {
prev = v.substr(0, iterator.getCount());
curr = v.substr(prev.length, v.length);
- var checkErrors = function(error) {
- if (error != undefined && !error.used && foundStrings['__' + error.string] == undefined && error.regexp.test(curr)) {
- var oldlen = curr.length;
-
- foundStrings['__' + error.string] = 1;
- doReplaces.push([error.regexp, '<span class="'+error.type+'" pre="'+previous+'">$&</span>']);
+ var checkErrors = function( error ) {
+ if ( error !== undefined && ! error.used && foundStrings[ '__' + error.string ] === undefined && error.regexp.test( curr ) ) {
+ foundStrings[ '__' + error.string ] = 1;
+ doReplaces.push([ error.regexp, '<span class="'+error.type+'" pre="'+previous+'"' + bogus + '>$&</span>' ]);
error.used = true;
done = true;
}
- };
+ }; // jshint ignore:line
var foundStrings = {};
- if (current != undefined) {
+ if (current !== undefined) {
previous = previous + ' ';
parent.map(current, checkErrors);
}
@@ -412,40 +429,42 @@ AtDCore.prototype.markMyWords = function(container_nodes, errors) {
} // end while
/* do the actual replacements on this span */
- if (doReplaces.length > 0) {
- newNode = n;
+ if ( doReplaces.length > 0 ) {
+ var newNode = n;
- for (var x = 0; x < doReplaces.length; x++) {
+ for ( var x = 0; x < doReplaces.length; x++ ) {
var regexp = doReplaces[x][0], result = doReplaces[x][1];
/* it's assumed that this function is only being called on text nodes (nodeType == 3), the iterating is necessary
because eventually the whole thing gets wrapped in an mceItemHidden span and from there it's necessary to
handle each node individually. */
- var bringTheHurt = function(node) {
- if (node.nodeType == 3) {
+ var bringTheHurt = function( node ) {
+ if ( node.nodeType === 3 ) {
ecount++;
/* sometimes IE likes to ignore the space between two spans, solution is to insert a placeholder span with
a non-breaking space. The markup removal code substitutes this span for a space later */
- if (parent.isIE() && node.nodeValue.length > 0 && node.nodeValue.substr(0, 1) == ' ')
- return parent.create('<span class="mceItemHidden">&nbsp;</span>' + node.nodeValue.substr(1, node.nodeValue.length - 1).replace(regexp, result), false);
- else
- return parent.create(node.nodeValue.replace(regexp, result), false);
+ if ( parent.isIE() && node.nodeValue.length > 0 && node.nodeValue.substr(0, 1) === ' ' ) {
+ return parent.create( emptySpan + node.nodeValue.substr( 1, node.nodeValue.length - 1 ).replace( regexp, result ), false );
+ } else {
+ return parent.create( node.nodeValue.replace( regexp, result ), false );
+ }
}
else {
var contents = parent.contents(node);
- for (var y = 0; y < contents.length; y++) {
- if (contents[y].nodeType == 3 && regexp.test(contents[y].nodeValue)) {
+ for ( var y = 0; y < contents.length; y++ ) {
+ if ( contents[y].nodeType === 3 && regexp.test( contents[y].nodeValue ) ) {
var nnode;
- if (parent.isIE() && contents[y].nodeValue.length > 0 && contents[y].nodeValue.substr(0, 1) == ' ')
- nnode = parent.create('<span class="mceItemHidden">&nbsp;</span>' + contents[y].nodeValue.substr(1, contents[y].nodeValue.length - 1).replace(regexp, result), true);
- else
- nnode = parent.create(contents[y].nodeValue.replace(regexp, result), true);
+ if ( parent.isIE() && contents[y].nodeValue.length > 0 && contents[y].nodeValue.substr(0, 1) === ' ') {
+ nnode = parent.create( emptySpan + contents[y].nodeValue.substr( 1, contents[y].nodeValue.length - 1 ).replace( regexp, result ), true );
+ } else {
+ nnode = parent.create( contents[y].nodeValue.replace( regexp, result ), true );
+ }
- parent.replaceWith(contents[y], nnode);
- parent.removeParent(nnode);
+ parent.replaceWith( contents[y], nnode );
+ parent.removeParent( nnode );
ecount++;
@@ -455,7 +474,7 @@ AtDCore.prototype.markMyWords = function(container_nodes, errors) {
return node;
}
- };
+ }; // jshint ignore:line
newNode = bringTheHurt(newNode);
}
@@ -482,11 +501,10 @@ AtDCore.prototype.removeWords = function(node, w) {
this.map(this.findSpans(node).reverse(), function(n) {
if (n && (parent.isMarkedNode(n) || parent.hasClass(n, 'mceItemHidden') || parent.isEmptySpan(n)) ) {
- if (n.innerHTML == '&nbsp;') {
+ if (n.innerHTML === '&nbsp;') {
var nnode = document.createTextNode(' '); /* hax0r */
parent.replaceWith(n, nnode);
- }
- else if (!w || n.innerHTML == w) {
+ } else if (!w || n.innerHTML === w) {
parent.removeParent(n);
count++;
}
@@ -497,7 +515,7 @@ AtDCore.prototype.removeWords = function(node, w) {
};
AtDCore.prototype.isEmptySpan = function(node) {
- return (this.getAttrib(node, 'class') == "" && this.getAttrib(node, 'style') == "" && this.getAttrib(node, 'id') == "" && !this.hasClass(node, 'Apple-style-span') && this.getAttrib(node, 'mce_name') == "");
+ return (this.getAttrib(node, 'class') === '' && this.getAttrib(node, 'style') === '' && this.getAttrib(node, 'id') === '' && !this.hasClass(node, 'Apple-style-span') && this.getAttrib(node, 'mce_name') === '');
};
AtDCore.prototype.isMarkedNode = function(node) {
@@ -508,7 +526,7 @@ AtDCore.prototype.isMarkedNode = function(node) {
* Context Menu Helpers
*/
AtDCore.prototype.applySuggestion = function(element, suggestion) {
- if (suggestion == '(omit)') {
+ if (suggestion === '(omit)') {
this.remove(element);
}
else {
@@ -522,7 +540,7 @@ AtDCore.prototype.applySuggestion = function(element, suggestion) {
* Check for an error
*/
AtDCore.prototype.hasErrorMessage = function(xmlr) {
- return (xmlr != undefined && xmlr.getElementsByTagName('message').item(0) != null);
+ return (xmlr !== undefined && xmlr.getElementsByTagName('message').item(0) !== null);
};
AtDCore.prototype.getErrorMessage = function(xmlr) {
@@ -531,5 +549,15 @@ AtDCore.prototype.getErrorMessage = function(xmlr) {
/* this should always be an error, alas... not practical */
AtDCore.prototype.isIE = function() {
- return navigator.appName == 'Microsoft Internet Explorer';
+ return navigator.appName === 'Microsoft Internet Explorer';
};
+
+// TODO: this doesn't seem used anywhere in AtD, moved here from install_atd_l10n.js for eventual back-compat
+/* a quick poor man's sprintf */
+function atd_sprintf(format, values) {
+ var result = format;
+ for (var x = 0; x < values.length; x++) {
+ result = result.replace(new RegExp('%' + (x + 1) + '\\$', 'g'), values[x]);
+ }
+ return result;
+}
diff --git a/plugins/jetpack/modules/after-the-deadline/atd.css b/plugins/jetpack/modules/after-the-deadline/atd.css
index 2f59bd21..756bd105 100644
--- a/plugins/jetpack/modules/after-the-deadline/atd.css
+++ b/plugins/jetpack/modules/after-the-deadline/atd.css
@@ -103,3 +103,20 @@
{
outline:none
}
+
+/* TinyMCE 4.0 */
+div.mce-atd-menu-title.mce-disabled {
+ padding: 3px 12px 0;
+}
+
+div.mce-atd-menu-title.mce-disabled:hover,
+div.mce-atd-menu-title.mce-disabled:hover span.mce-text {
+ background: none;
+ color: #888;
+ cursor: default;
+}
+
+div.mce-atd-menu-title.mce-disabled span.mce-text {
+ font-weight: bold;
+ color: #888;
+}
diff --git a/plugins/jetpack/modules/after-the-deadline/atd.min.css b/plugins/jetpack/modules/after-the-deadline/atd.min.css
new file mode 100644
index 00000000..39f86c72
--- /dev/null
+++ b/plugins/jetpack/modules/after-the-deadline/atd.min.css
@@ -0,0 +1 @@
+.hiddenSpellError{border-bottom:2px solid red;cursor:default}.hiddenGrammarError{border-bottom:2px solid green;cursor:default}.hiddenSuggestion{border-bottom:2px solid #00f;cursor:default}#suggestmenu{min-width:122px;background:#ebeaeb;position:absolute;display:none;z-index:9999;overflow:none;margin-top:1px;text-align:left;font-size:11px;font-family:Tahoma,Verdana,Arial,Helvetica}#suggestmenu strong{background:#ccc;font-weight:700;padding:3px 6px;display:block;border:1px solid #ddd;border-bottom:1px solid #aaa;color:#000}#suggestmenu em{text-align:center;padding:3px 6px;display:block;border-top:1px solid #ccc;border-left:1px solid #ccc}#suggestmenu a,#suggestmenu a:visited{background:#ebeaeb;border-left:1px solid #ddd;border-right:1px solid #ddd;padding:3px 6px;display:block;margin:0;text-decoration:none;color:#000;outline:0}#suggestmenu a.first,#suggestmenu a.first:visited{border-top:1px solid #ddd}.spell_sep_bottom{border-bottom:1px solid #ddd}.spell_sep_top{border-top:1px solid #aaa}#suggestmenu a:hover{color:#000;background:#f5f5f5}#suggestmenu .foot{border-top:1px solid #aaa;background:#fff}#suggestmenu .foot a,#suggestmenu .foot a:visited{outline:0}div.mce-atd-menu-title.mce-disabled{padding:3px 12px 0}div.mce-atd-menu-title.mce-disabled:hover,div.mce-atd-menu-title.mce-disabled:hover span.mce-text{background:0 0;color:#888;cursor:default}div.mce-atd-menu-title.mce-disabled span.mce-text{font-weight:700;color:#888} \ No newline at end of file
diff --git a/plugins/jetpack/modules/after-the-deadline/config-options.php b/plugins/jetpack/modules/after-the-deadline/config-options.php
index db4a49c7..10ca96c6 100644
--- a/plugins/jetpack/modules/after-the-deadline/config-options.php
+++ b/plugins/jetpack/modules/after-the-deadline/config-options.php
@@ -10,7 +10,7 @@ function AtD_print_option( $name, $value, $options ) {
// Attribute-safe version of $name
$attr_name = sanitize_title($name); // Using sanitize_title since there's no comparable function for attributes
?>
- <input type="checkbox" id="atd_<?php echo ($attr_name) ?>" name="<?php echo $options['name'] ?>[<?php echo $name; ?>]" value="1" <?php checked( '1', isset( $options[$name] ) ? $options[$name] : false ); ?>> <label for="atd_<?php echo $attr_name ?>"><?php echo $value; ?></label>
+ <input type="checkbox" id="atd_<?php echo esc_attr( $attr_name ) ?>" name="<?php echo esc_attr( $options['name'] ); ?>[<?php echo esc_attr( $name ); ?>]" value="1" <?php checked( '1', isset( $options[$name] ) ? $options[$name] : false ); ?>> <label for="atd_<?php echo esc_attr( $attr_name ); ?>"><?php echo esc_html( $value ); ?></label>
<?php
}
@@ -85,11 +85,9 @@ function AtD_display_options_form() {
<p style="font-weight: bold"><?php _e( 'Language', 'jetpack' ); ?></font>
- <p><?php printf(
- _x( 'The proofreader supports English, French, German, Portuguese, and Spanish. Your <a href="%1$s">%2$s</a> value is the default proofreading language.', '%1$s = http://codex.wordpress.org/Installing_WordPress_in_Your_Language, %2$s = WPLANG', 'jetpack' ),
- 'http://codex.wordpress.org/Installing_WordPress_in_Your_Language',
- 'WPLANG'
- ); ?></p>
+ <p><?php
+ _e( 'The proofreader supports English, French, German, Portuguese, and Spanish. Your user interface language (see above) is the default proofreading language.', 'jetpack' );
+ ?></p>
<p><?php
AtD_print_option( 'true', __('Use automatically detected language to proofread posts and pages', 'jetpack' ), $options_guess_lang );
diff --git a/plugins/jetpack/modules/after-the-deadline/config-unignore.php b/plugins/jetpack/modules/after-the-deadline/config-unignore.php
index d8394d7b..43c36a72 100644
--- a/plugins/jetpack/modules/after-the-deadline/config-unignore.php
+++ b/plugins/jetpack/modules/after-the-deadline/config-unignore.php
@@ -12,6 +12,8 @@ function AtD_ignore_call() {
if ( ! $user || $user->ID == 0 )
return;
+ check_admin_referer( 'atd_ignore' );
+
$ignores = explode( ',', AtD_get_setting( $user->ID, 'AtD_ignored_phrases') );
array_push( $ignores, $_GET['phrase'] );
@@ -111,7 +113,7 @@ function atd_ignore () {
function atd_ignore_init() {
jQuery( '#AtD_message' ).hide();
- jQuery( '#atd_ignores' ).delegate( 'a', 'click', function() {
+ jQuery( '#atd_ignores' ).on( 'click', 'a', function() {
atd_unignore( jQuery(this).data( 'ignored' ) );
return false;
} );
diff --git a/plugins/jetpack/modules/after-the-deadline/install_atd_l10n.js b/plugins/jetpack/modules/after-the-deadline/install_atd_l10n.js
deleted file mode 100644
index 3215de66..00000000
--- a/plugins/jetpack/modules/after-the-deadline/install_atd_l10n.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/* a quick poor man's sprintf */
-function atd_sprintf(format, values) {
- var result = format;
- for (var x = 0; x < values.length; x++)
- result = result.replace(new RegExp('%' + (x + 1) + '\\$', 'g'), values[x]);
- return result;
-}
-
-/* init the autoproofread options */
-function install_atd_l10n() {
- /* install L10n strings into TinyMCE if it's present */
- if ( typeof( tinyMCE ) != 'undefined' && typeof( tinyMCEPreInit ) != 'undefined' )
- tinyMCE.addI18n(tinyMCEPreInit.mceInit.language + '.AtD', AtD_l10n_r0ar);
-
- /* set the AtD l10n instance */
- AtD.addI18n(AtD_l10n_r0ar);
-}
-
-/* document.ready() does not execute in IE6 unless it's at the bottom of the page. oi! */
-if (navigator.appName == 'Microsoft Internet Explorer')
- setTimeout( install_atd_l10n, 2500 );
-else
- jQuery( document ).ready( install_atd_l10n );
-
diff --git a/plugins/jetpack/modules/after-the-deadline/jquery.atd.js b/plugins/jetpack/modules/after-the-deadline/jquery.atd.js
index ee2ef6be..7d7e7682 100644
--- a/plugins/jetpack/modules/after-the-deadline/jquery.atd.js
+++ b/plugins/jetpack/modules/after-the-deadline/jquery.atd.js
@@ -14,26 +14,26 @@
* Contact : willis.rh@gmail.com
*/
+/* jshint onevar: false, sub: true, smarttabs: true */
+/* global AtDCore, AtD_proofread_click_count, CSSHttpRequest, ActiveXObject */
+
var AtD =
{
rpc : '', /* see the proxy.php that came with the AtD/TinyMCE plugin */
rpc_css : 'http://www.polishmywriting.com/atd-jquery/server/proxycss.php?data=', /* you may use this, but be nice! */
rpc_css_lang : 'en',
api_key : '',
- i18n : {},
+ i18n : {}, // Back-compat
listener : {}
};
-AtD.getLang = function(key, defaultk) {
- if (AtD.i18n[key] == undefined)
- return defaultk;
-
- return AtD.i18n[key];
+AtD.getLang = function( key, defaultk ) {
+ return ( window.AtD_l10n_r0ar && window.AtD_l10n_r0ar[key] ) || defaultk;
};
-AtD.addI18n = function(localizations) {
- AtD.i18n = localizations;
- AtD.core.addI18n(localizations);
+AtD.addI18n = function( obj ) {
+ // Back-compat
+ window.AtD_l10n_r0ar = obj;
};
AtD.setIgnoreStrings = function(string) {
@@ -46,43 +46,44 @@ AtD.showTypes = function(string) {
AtD.checkCrossAJAX = function(container_id, callback_f) {
/* checks if a global var for click stats exists and increments it if it does... */
- if (typeof AtD_proofread_click_count != "undefined")
+ if (typeof AtD_proofread_click_count !== 'undefined') {
AtD_proofread_click_count++;
+ }
AtD.callback_f = callback_f; /* remember the callback for later */
AtD.remove(container_id);
var container = jQuery('#' + container_id);
- var html = container.html();
- text = jQuery.trim(container.html());
+ var text = jQuery.trim(container.html());
text = text.replace(/\&lt;/g, '<').replace(/\&gt;/g, '>').replace(/\&amp;/g, '&');
text = encodeURIComponent( text.replace( /\%/g, '%25' ) ); /* % not being escaped here creates problems, I don't know why. */
/* do some sanity checks based on the browser */
- if ((text.length > 2000 && navigator.appName == 'Microsoft Internet Explorer') || text.length > 7800) {
- if (callback_f != undefined && callback_f.error != undefined)
- callback_f.error("Maximum text length for this browser exceeded");
+ if ((text.length > 2000 && navigator.appName === 'Microsoft Internet Explorer') || text.length > 7800) {
+ if (callback_f !== undefined && callback_f.error !== undefined) {
+ callback_f.error('Maximum text length for this browser exceeded');
+ }
return;
}
/* do some cross-domain AJAX action with CSSHttpRequest */
- CSSHttpRequest.get(AtD.rpc_css + text + "&lang=" + AtD.rpc_css_lang + "&nocache=" + (new Date().getTime()), function(response) {
+ CSSHttpRequest.get(AtD.rpc_css + text + '&lang=' + AtD.rpc_css_lang + '&nocache=' + (new Date().getTime()), function(response) {
/* do some magic to convert the response into an XML document */
var xml;
- if (navigator.appName == 'Microsoft Internet Explorer') {
- xml = new ActiveXObject("Microsoft.XMLDOM");
+ if (navigator.appName === 'Microsoft Internet Explorer') {
+ xml = new ActiveXObject('Microsoft.XMLDOM');
xml.async = false;
xml.loadXML(response);
- }
- else {
+ } else {
xml = (new DOMParser()).parseFromString(response, 'text/xml');
}
/* check for and display error messages from the server */
if (AtD.core.hasErrorMessage(xml)) {
- if (AtD.callback_f != undefined && AtD.callback_f.error != undefined)
+ if (AtD.callback_f !== undefined && AtD.callback_f.error !== undefined) {
AtD.callback_f.error(AtD.core.getErrorMessage(xml));
+ }
return;
}
@@ -90,13 +91,15 @@ AtD.checkCrossAJAX = function(container_id, callback_f) {
/* highlight the errors */
AtD.container = container_id;
- var count = AtD.processXML(container_id, xml);
+ var count = Number( AtD.processXML(container_id, xml) );
- if (AtD.callback_f != undefined && AtD.callback_f.ready != undefined)
+ if (AtD.callback_f !== undefined && AtD.callback_f.ready !== undefined) {
AtD.callback_f.ready(count);
+ }
- if (count == 0 && AtD.callback_f != undefined && AtD.callback_f.success != undefined)
+ if (count === 0 && AtD.callback_f !== undefined && AtD.callback_f.success !== undefined) {
AtD.callback_f.success(count);
+ }
AtD.counter = count;
AtD.count = count;
@@ -106,8 +109,9 @@ AtD.checkCrossAJAX = function(container_id, callback_f) {
/* check a div for any incorrectly spelled words */
AtD.check = function(container_id, callback_f) {
/* checks if a global var for click stats exists and increments it if it does... */
- if (typeof AtD_proofread_click_count != "undefined")
+ if (typeof AtD_proofread_click_count !== 'undefined') {
AtD_proofread_click_count++;
+ }
AtD.callback_f = callback_f; /* remember the callback for later */
@@ -115,21 +119,21 @@ AtD.check = function(container_id, callback_f) {
var container = jQuery('#' + container_id);
- var html = container.html();
- text = jQuery.trim(container.html());
+ var text = jQuery.trim(container.html());
text = text.replace(/\&lt;/g, '<').replace(/\&gt;/g, '>').replace(/\&amp;/g, '&');
text = encodeURIComponent( text ); /* re-escaping % is not necessary here. don't do it */
jQuery.ajax({
- type : "POST",
+ type : 'POST',
url : AtD.rpc + '/checkDocument',
data : 'key=' + AtD.api_key + '&data=' + text,
format : 'raw',
- dataType : (jQuery.browser.msie) ? "text" : "xml",
+ dataType : (jQuery.browser.msie) ? 'text' : 'xml',
error : function(XHR, status, error) {
- if (AtD.callback_f != undefined && AtD.callback_f.error != undefined)
- AtD.callback_f.error(status + ": " + error);
+ if (AtD.callback_f !== undefined && AtD.callback_f.error !== undefined) {
+ AtD.callback_f.error(status + ': ' + error);
+ }
},
success : function(data) {
@@ -137,8 +141,8 @@ AtD.check = function(container_id, callback_f) {
http://docs.jquery.com/Specifying_the_Data_Type_for_AJAX_Requests */
var xml;
- if (typeof data == "string") {
- xml = new ActiveXObject("Microsoft.XMLDOM");
+ if (typeof data === 'string') {
+ xml = new ActiveXObject('Microsoft.XMLDOM');
xml.async = false;
xml.loadXML(data);
}
@@ -147,8 +151,9 @@ AtD.check = function(container_id, callback_f) {
}
if (AtD.core.hasErrorMessage(xml)) {
- if (AtD.callback_f != undefined && AtD.callback_f.error != undefined)
+ if (AtD.callback_f !== undefined && AtD.callback_f.error !== undefined) {
AtD.callback_f.error(AtD.core.getErrorMessage(xml));
+ }
return;
}
@@ -156,13 +161,15 @@ AtD.check = function(container_id, callback_f) {
/* on with the task of processing and highlighting errors */
AtD.container = container_id;
- var count = AtD.processXML(container_id, xml);
+ var count = Number( AtD.processXML(container_id, xml) );
- if (AtD.callback_f != undefined && AtD.callback_f.ready != undefined)
+ if (AtD.callback_f !== undefined && AtD.callback_f.ready !== undefined) {
AtD.callback_f.ready(count);
+ }
- if (count == 0 && AtD.callback_f != undefined && AtD.callback_f.success != undefined)
+ if (count === 0 && AtD.callback_f !== undefined && AtD.callback_f.success !== undefined) {
AtD.callback_f.success(count);
+ }
AtD.counter = count;
AtD.count = count;
@@ -175,16 +182,18 @@ AtD.remove = function(container_id) {
};
AtD.clickListener = function(event) {
- if (AtD.core.isMarkedNode(event.target))
+ if (AtD.core.isMarkedNode(event.target)) {
AtD.suggest(event.target);
+ }
};
AtD.processXML = function(container_id, responseXML) {
var results = AtD.core.processXML(responseXML);
- if (results.count > 0)
+ if (results.count > 0) {
results.count = AtD.core.markMyWords(jQuery('#' + container_id).contents(), results.errors);
+ }
jQuery('#' + container_id).unbind('click', AtD.clickListener);
jQuery('#' + container_id).click(AtD.clickListener);
@@ -196,20 +205,23 @@ AtD.useSuggestion = function(word) {
this.core.applySuggestion(AtD.errorElement, word);
AtD.counter --;
- if (AtD.counter == 0 && AtD.callback_f != undefined && AtD.callback_f.success != undefined)
+ if (AtD.counter === 0 && AtD.callback_f !== undefined && AtD.callback_f.success !== undefined) {
AtD.callback_f.success(AtD.count);
+ }
};
AtD.editSelection = function() {
var parent = AtD.errorElement.parent();
- if (AtD.callback_f != undefined && AtD.callback_f.editSelection != undefined)
+ if (AtD.callback_f !== undefined && AtD.callback_f.editSelection !== undefined) {
AtD.callback_f.editSelection(AtD.errorElement);
+ }
- if (AtD.errorElement.parent() != parent) {
+ if (AtD.errorElement.parent() !== parent) {
AtD.counter --;
- if (AtD.counter == 0 && AtD.callback_f != undefined && AtD.callback_f.success != undefined)
+ if (AtD.counter === 0 && AtD.callback_f !== undefined && AtD.callback_f.success !== undefined) {
AtD.callback_f.success(AtD.count);
+ }
}
};
@@ -217,8 +229,9 @@ AtD.ignoreSuggestion = function() {
AtD.core.removeParent(AtD.errorElement);
AtD.counter --;
- if (AtD.counter == 0 && AtD.callback_f != undefined && AtD.callback_f.success != undefined)
+ if (AtD.counter === 0 && AtD.callback_f !== undefined && AtD.callback_f.success !== undefined) {
AtD.callback_f.success(AtD.count);
+ }
};
AtD.ignoreAll = function(container_id) {
@@ -227,35 +240,37 @@ AtD.ignoreAll = function(container_id) {
AtD.counter -= removed;
- if (AtD.counter == 0 && AtD.callback_f != undefined && AtD.callback_f.success != undefined)
+ if (AtD.counter === 0 && AtD.callback_f !== undefined && AtD.callback_f.success !== undefined) {
AtD.callback_f.success(AtD.count);
+ }
- if (AtD.callback_f != undefined && AtD.callback_f.ignore != undefined) {
+ if (AtD.callback_f !== undefined && AtD.callback_f.ignore !== undefined) {
AtD.callback_f.ignore(target);
AtD.core.setIgnoreStrings(target);
}
};
AtD.explainError = function() {
- if (AtD.callback_f != undefined && AtD.callback_f.explain != undefined)
+ if (AtD.callback_f !== undefined && AtD.callback_f.explain !== undefined) {
AtD.callback_f.explain(AtD.explainURL);
+ }
};
AtD.suggest = function(element) {
/* construct the menu if it doesn't already exist */
+ var suggest;
- if (jQuery('#suggestmenu').length == 0) {
- var suggest = jQuery('<div id="suggestmenu"></div>');
+ if (jQuery('#suggestmenu').length === 0) {
+ suggest = jQuery('<div id="suggestmenu"></div>');
suggest.prependTo('body');
- }
- else {
- var suggest = jQuery('#suggestmenu');
+ } else {
+ suggest = jQuery('#suggestmenu');
suggest.hide();
}
/* find the correct suggestions object */
- errorDescription = AtD.core.findSuggestion(element);
+ var errorDescription = AtD.core.findSuggestion(element);
/* build up the menu y0 */
@@ -263,25 +278,23 @@ AtD.suggest = function(element) {
suggest.empty();
- if (errorDescription == undefined) {
+ if (errorDescription === undefined) {
suggest.append('<strong>' + AtD.getLang('menu_title_no_suggestions', 'No suggestions') + '</strong>');
- }
- else if (errorDescription["suggestions"].length == 0) {
+ } else if (errorDescription['suggestions'].length === 0) {
suggest.append('<strong>' + errorDescription['description'] + '</strong>');
- }
- else {
+ } else {
suggest.append('<strong>' + errorDescription['description'] + '</strong>');
- for (var i = 0; i < errorDescription["suggestions"].length; i++) {
+ for (var i = 0; i < errorDescription['suggestions'].length; i++) {
(function(sugg) {
suggest.append('<a href="javascript:AtD.useSuggestion(\'' + sugg.replace(/'/, '\\\'') + '\')">' + sugg + '</a>');
- })(errorDescription["suggestions"][i]);
+ })(errorDescription['suggestions'][i]); // jshint ignore:line
}
}
/* do the explain menu if configured */
- if (AtD.callback_f != undefined && AtD.callback_f.explain != undefined && errorDescription['moreinfo'] != undefined) {
+ if (AtD.callback_f !== undefined && AtD.callback_f.explain !== undefined && errorDescription['moreinfo'] !== undefined) {
suggest.append('<a href="javascript:AtD.explainError()" class="spell_sep_top">' + AtD.getLang('menu_option_explain', 'Explain...') + '</a>');
AtD.explainURL = errorDescription['moreinfo'];
}
@@ -292,19 +305,21 @@ AtD.suggest = function(element) {
/* add the edit in place and ignore always option */
- if (AtD.callback_f != undefined && AtD.callback_f.editSelection != undefined) {
- if (AtD.callback_f != undefined && AtD.callback_f.ignore != undefined)
+ if (AtD.callback_f !== undefined && AtD.callback_f.editSelection !== undefined) {
+ if (AtD.callback_f !== undefined && AtD.callback_f.ignore !== undefined) {
suggest.append('<a href="javascript:AtD.ignoreAll(\'' + AtD.container + '\')">' + AtD.getLang('menu_option_ignore_always', 'Ignore always') + '</a>');
- else
+ } else {
suggest.append('<a href="javascript:AtD.ignoreAll(\'' + AtD.container + '\')">' + AtD.getLang('menu_option_ignore_all', 'Ignore all') + '</a>');
+ }
suggest.append('<a href="javascript:AtD.editSelection(\'' + AtD.container + '\')" class="spell_sep_bottom spell_sep_top">' + AtD.getLang('menu_option_edit_selection', 'Edit Selection...') + '</a>');
}
else {
- if (AtD.callback_f != undefined && AtD.callback_f.ignore != undefined)
+ if (AtD.callback_f !== undefined && AtD.callback_f.ignore !== undefined) {
suggest.append('<a href="javascript:AtD.ignoreAll(\'' + AtD.container + '\')" class="spell_sep_bottom">' + AtD.getLang('menu_option_ignore_always', 'Ignore always') + '</a>');
- else
+ } else {
suggest.append('<a href="javascript:AtD.ignoreAll(\'' + AtD.container + '\')" class="spell_sep_bottom">' + AtD.getLang('menu_option_ignore_all', 'Ignore all') + '</a>');
+ }
}
/* show the menu */
@@ -313,8 +328,9 @@ AtD.suggest = function(element) {
var width = jQuery(element).width();
/* a sanity check for Internet Explorer--my favorite browser in every possible way */
- if (width > 100)
- width = 50;
+ if (width > 100) {
+ width = 50;
+ }
jQuery(suggest).css({ left: (pos.left + width) + 'px', top: pos.top + 'px' });
@@ -325,9 +341,10 @@ AtD.suggest = function(element) {
AtD.suggestShow = true;
setTimeout(function() {
- jQuery("body").bind("click", function() {
- if (!AtD.suggestShow)
+ jQuery('body').bind('click', function() {
+ if (!AtD.suggestShow) {
jQuery('#suggestmenu').fadeOut(200);
+ }
});
}, 1);
@@ -361,22 +378,23 @@ AtD.initCoreModule = function() {
};
core.findSpans = function(parent) {
- return jQuery.makeArray(parent.find('span'));
+ return jQuery.makeArray(parent.find('span'));
};
- core.create = function(string, isTextNode) {
+ core.create = function(string/*, isTextNode*/) {
// replace out all tags with &-equivalents so that we preserve tag text.
string = string.replace(/\&/g, '&amp;');
- string = string.replace(/\</g, '&lt;').replace(/\>/g, '&gt;');
+ string = string.replace(/</g, '&lt;').replace(/\>/g, '&gt;');
// find all instances of AtD-created spans
var matches = string.match(/\&lt;span class="hidden\w+?" pre="[^"]*"\&gt;.*?\&lt;\/span\&gt;/g);
+ var x;
// ... and fix the tags in those substrings.
if (matches) {
- for (var x = 0; x < matches.length; x++) {
+ for (x = 0; x < matches.length; x++) {
string = string.replace(matches[x], matches[x].replace(/\&lt;/gi, '<').replace(/\&gt;/gi, '>'));
- };
+ }
}
if (core.isIE()) {
@@ -384,13 +402,13 @@ AtD.initCoreModule = function() {
matches = string.match(/\&lt;span class="mceItemHidden"\&gt;\&amp;nbsp;\&lt;\/span&gt;/g, string);
//|&lt;BR.*?class.*?atd_remove_me.*?\&gt;/gi, string);
if (matches) {
- for (var x = 0; x < matches.length; x++) {
+ for (x = 0; x < matches.length; x++) {
string = string.replace(matches[x], matches[x].replace(/\&lt;/gi, '<').replace(/\&gt;/gi, '>').replace(/\&amp;/gi, '&'));
- };
+ }
}
}
- node = jQuery('<span class="mceItemHidden"></span>');
+ var node = jQuery('<span class="mceItemHidden"></span>');
node.html(string);
return node;
};
@@ -401,10 +419,11 @@ AtD.initCoreModule = function() {
core.removeParent = function(node) {
/* unwrap exists in jQuery 1.4+ only. Thankfully because replaceWith as-used here won't work in 1.4 */
- if (jQuery(node).unwrap)
+ if (jQuery(node).unwrap) {
return jQuery(node).contents().unwrap();
- else
+ } else {
return jQuery(node).replaceWith(jQuery(node).html());
+ }
};
core.getAttrib = function(node, name) {
diff --git a/plugins/jetpack/modules/after-the-deadline/proxy.php b/plugins/jetpack/modules/after-the-deadline/proxy.php
index 3d5ef3b6..c0299da1 100644
--- a/plugins/jetpack/modules/after-the-deadline/proxy.php
+++ b/plugins/jetpack/modules/after-the-deadline/proxy.php
@@ -16,16 +16,38 @@ function AtD_http_post( $request, $host, $path, $port = 80 ) {
'User-Agent' => 'AtD/0.1'
),
'httpversion' => '1.0',
+ /**
+ * Change the timeout time for AtD post.
+ *
+ * @since 1.2.3
+ *
+ * @param int $var Timeout time in seconds, default 15.
+ */
'timeout' => apply_filters( 'atd_http_post_timeout', 15 ),
);
- $AtD_url = "http://{$host}{$path}";
+
+ // Handle non-standard ports being passed in.
+ if ( ( 80 !== $port ) && is_numeric( $port ) && ( intval( $port ) > 0 ) ) {
+ $host .= ':' . intval( $port );
+ }
+ // Strip any / off the begining so we can add it back and protect against SSRF
+ $path = ltrim( $path, '/' );
+ $AtD_url = set_url_scheme( "http://{$host}/{$path}" );
$response = wp_remote_post( $AtD_url, $http_args );
- $code = (int) wp_remote_retrieve_response_code( $response );
+ $code = (int) wp_remote_retrieve_response_code( $response );
if ( is_wp_error( $response ) ) {
+ /**
+ * Fires when there is a post error to AtD.
+ *
+ * @since 1.2.3
+ *
+ * @param int|string http-error The error that AtD runs into.
+ */
do_action( 'atd_http_post_error', 'http-error' );
return array();
} elseif ( 200 != $code ) {
+ /** This action is documented in modules/after-the-deadline/proxy.php */
do_action( 'atd_http_post_error', $code );
}
@@ -39,31 +61,49 @@ function AtD_http_post( $request, $host, $path, $port = 80 ) {
* This function is called as an action handler to admin-ajax.php
*/
function AtD_redirect_call() {
- if ( $_SERVER['REQUEST_METHOD'] === 'POST' )
- $postText = trim( file_get_contents( 'php://input' ) );
+ if ( $_SERVER['REQUEST_METHOD'] === 'POST' )
+ $postText = trim( file_get_contents( 'php://input' ) );
- $url = $_GET['url'];
+ check_admin_referer( 'proxy_atd' );
+ $url = $_GET['url'];
+ /**
+ * Change the AtD service domain.
+ *
+ * @since 1.2.3
+ *
+ * @param string $var The URL for AtD service domain, default is service.afterthedeadline.com.
+ */
$service = apply_filters( 'atd_service_domain', 'service.afterthedeadline.com' );
- if ( defined('WPLANG') ) {
- if ( strpos(WPLANG, 'pt') !== false )
+
+ $user = wp_get_current_user();
+
+ $atd_lang = get_locale();
+
+ // If we're on WPCOM, this function should be available.
+ if ( function_exists( 'get_user_lang_code' ) ) {
+ $atd_lang = get_user_lang_code( $user->ID );
+ }
+
+ if ( ! empty( $atd_lang ) ) {
+ if ( strpos($atd_lang, 'pt') !== false )
$service = 'pt.service.afterthedeadline.com';
- else if ( strpos(WPLANG, 'de') !== false )
+ else if ( strpos($atd_lang, 'de') !== false )
$service = 'de.service.afterthedeadline.com';
- else if ( strpos(WPLANG, 'es') !== false )
+ else if ( strpos($atd_lang, 'es') !== false )
$service = 'es.service.afterthedeadline.com';
- else if ( strpos(WPLANG, 'fr') !== false )
+ else if ( strpos($atd_lang, 'fr') !== false )
$service = 'fr.service.afterthedeadline.com';
}
- $user = wp_get_current_user();
+
$guess = strcmp( AtD_get_setting( $user->ID, 'AtD_guess_lang' ), "true" ) == 0 ? "true" : "false";
- $data = AtD_http_post( $postText . "&guess=$guess", defined('ATD_HOST') ? ATD_HOST : $service, $url, defined('ATD_PORT') ? ATD_PORT : 80 );
+ $data = AtD_http_post( $postText . "&guess=$guess", defined('ATD_HOST') ? ATD_HOST : $service, $url, defined('ATD_PORT') ? ATD_PORT : 80 );
- header( 'Content-Type: text/xml' );
+ header( 'Content-Type: text/xml' );
- if ( !empty($data[1]) )
- echo $data[1];
+ if ( ! empty( $data[1] ) )
+ echo $data[1];
- die();
+ die();
}
diff --git a/plugins/jetpack/modules/after-the-deadline/rtl/atd-rtl.css b/plugins/jetpack/modules/after-the-deadline/rtl/atd-rtl.css
new file mode 100644
index 00000000..d4f19d3c
--- /dev/null
+++ b/plugins/jetpack/modules/after-the-deadline/rtl/atd-rtl.css
@@ -0,0 +1,124 @@
+/* This file was automatically generated on Mar 20 2014 23:59:38 */
+
+/* AtD error styles */
+
+.hiddenSpellError
+{
+ border-bottom: 2px solid red;
+ cursor: default;
+}
+
+.hiddenGrammarError
+{
+ border-bottom: 2px solid green;
+ cursor: default;
+}
+
+.hiddenSuggestion
+{
+ border-bottom: 2px solid blue;
+ cursor: default;
+}
+
+/* Menu styles derived from:
+ * jquery.spellchecker.js - a simple jQuery Spell Checker
+ * Copyright (c) 2008 Richard Willis
+ * MIT license : http://www.opensource.org/licenses/mit-license.php
+ * Project : http://jquery-spellchecker.googlecode.com
+ */
+
+#suggestmenu
+{
+ min-width: 122px;
+ background: #ebeaeb;
+ position: absolute;
+ display: none;
+ z-index: 9999;
+ overflow: none;
+ margin-top: 1px;
+ text-align: right;
+ font-size: 11px;
+ font-family: Tahoma, Verdana, Arial, Helvetica;
+}
+
+#suggestmenu strong
+{
+ background: #cccccc;
+ font-weight: bold;
+ padding:3px 6px 3px 6px;
+ display:block;
+ border:1px solid #dddddd;
+ border-bottom: 1px solid #aaaaaa;
+ color: black;
+}
+
+#suggestmenu em
+{
+ text-align:center;
+ padding:3px 6px 3px 6px;
+ display:block;
+ border-top:1px solid #ccc;
+ border-right:1px solid #ccc;
+}
+
+#suggestmenu a, #suggestmenu a:visited
+{
+ background: #ebeaeb;
+ border-right:1px solid #dddddd;
+ border-left:1px solid #dddddd;
+ padding:3px 6px 3px 6px;
+ display:block;
+ margin:0px;
+ text-decoration:none;
+ color: black;
+ outline:none
+}
+
+#suggestmenu a.first, #suggestmenu a.first:visited
+{
+ border-top:1px solid #dddddd;
+}
+
+.spell_sep_bottom
+{
+ border-bottom: 1px solid #dddddd;
+}
+
+.spell_sep_top
+{
+ border-top: 1px solid #aaaaaa;
+}
+
+#suggestmenu a:hover
+{
+ color:#000;
+ background: #f5f5f5;
+}
+
+#suggestmenu .foot
+{
+ border-top:1px solid #aaaaaa;
+ background:#fff
+}
+
+#suggestmenu .foot a, #suggestmenu .foot a:visited
+{
+ outline:none
+}
+
+/* TinyMCE 4.0 */
+div.mce-atd-menu-title.mce-disabled {
+ padding: 3px 12px 0;
+}
+
+div.mce-atd-menu-title.mce-disabled:hover,
+div.mce-atd-menu-title.mce-disabled:hover span.mce-text {
+ background: none;
+ color: #888;
+ cursor: default;
+}
+
+div.mce-atd-menu-title.mce-disabled span.mce-text {
+ font-weight: bold;
+ color: #888;
+}
diff --git a/plugins/jetpack/modules/after-the-deadline/tinymce/css/content.min.css b/plugins/jetpack/modules/after-the-deadline/tinymce/css/content.min.css
new file mode 100644
index 00000000..fc5165ca
--- /dev/null
+++ b/plugins/jetpack/modules/after-the-deadline/tinymce/css/content.min.css
@@ -0,0 +1 @@
+.hiddenSpellError{border-bottom:2px solid red;cursor:default}.hiddenGrammarError{border-bottom:2px solid green;cursor:default}.hiddenSuggestion{border-bottom:2px solid #00f;cursor:default} \ No newline at end of file
diff --git a/plugins/jetpack/modules/after-the-deadline/tinymce/editor_plugin.js b/plugins/jetpack/modules/after-the-deadline/tinymce/editor_plugin.js
index f9251cd9..90f4aec2 100644
--- a/plugins/jetpack/modules/after-the-deadline/tinymce/editor_plugin.js
+++ b/plugins/jetpack/modules/after-the-deadline/tinymce/editor_plugin.js
@@ -15,26 +15,32 @@
* Moxiecode Spell Checker plugin released under the LGPL with TinyMCE
*/
+/* jshint onevar: false, sub: true, devel: true */
+/* global tinymce, AtDCore, AtD_proofread_click_count */
+
(function()
{
- var JSONRequest = tinymce.util.JSONRequest, each = tinymce.each, DOM = tinymce.DOM;
+ var each = tinymce.each, DOM = tinymce.DOM, core;
+
+ function getLang( key, defaultStr ) {
+ return ( window.AtD_l10n_r0ar && window.AtD_l10n_r0ar[key] ) || defaultStr;
+ }
tinymce.create('tinymce.plugins.AfterTheDeadlinePlugin',
{
getInfo : function()
{
- return
- ({
- longname : 'After The Deadline',
- author : 'Raphael Mudge',
- authorurl : 'http://blog.afterthedeadline.com',
- infourl : 'http://www.afterthedeadline.com',
- version : tinymce.majorVersion + "." + tinymce.minorVersion
- });
+ return {
+ longname : 'After The Deadline',
+ author : 'Raphael Mudge',
+ authorurl : 'http://blog.afterthedeadline.com',
+ infourl : 'http://www.afterthedeadline.com',
+ version : tinymce.majorVersion + '.' + tinymce.minorVersion
+ };
},
/* initializes the functions used by the AtD Core UI Module */
- initAtDCore : function(editor, plugin)
+ initAtDCore : function(editor/*, plugin*/)
{
var core = new AtDCore();
@@ -45,12 +51,13 @@
return editor.dom.getAttrib(node, key);
};
- core.findSpans = function(parent)
+ core.findSpans = function(parent)
{
- if (parent == undefined)
+ if (!parent) {
return editor.dom.select('span');
- else
+ } else {
return editor.dom.select('span', parent);
+ }
};
core.hasClass = function(node, className)
@@ -75,7 +82,7 @@
core.removeParent = function(node)
{
- editor.dom.remove(node, 1);
+ editor.dom.remove(node, 1);
return node;
};
@@ -84,36 +91,29 @@
editor.dom.remove(node);
};
- core.getLang = function(key, defaultk)
- {
- return editor.getLang("AtD." + key, defaultk);
- };
-
- core.setIgnoreStrings(editor.getParam("atd_ignore_strings", [] ).join(','));
- core.showTypes(editor.getParam("atd_show_types", ""));
+ core.setIgnoreStrings(editor.getParam('atd_ignore_strings', [] ).join(','));
+ core.showTypes(editor.getParam('atd_show_types', ''));
return core;
},
/* called when the plugin is initialized */
init : function(ed, url)
{
- if ( typeof(AtDCore) == 'undefined' )
- return;
+ if ( typeof(AtDCore) === 'undefined' ) {
+ return;
+ }
- var t = this;
var plugin = this;
var editor = ed;
- var core = this.initAtDCore(editor, plugin);
-
this.url = url;
this.editor = ed;
- ed.core = core;
+
+ core = ed.core = this.initAtDCore(editor, plugin);
/* look at the atd_ignore variable and put that stuff into a hash */
var ignore = tinymce.util.Cookie.getHash('atd_ignore');
- if (ignore == undefined)
- {
+ if (!ignore) {
ignore = {};
}
@@ -121,8 +121,9 @@
editor.addCommand('mceWritingImprovementTool', function(callback)
{
/* checks if a global var for click stats exists and increments it if it does... */
- if (typeof AtD_proofread_click_count != "undefined")
+ if (typeof AtD_proofread_click_count !== 'undefined') {
AtD_proofread_click_count++;
+ }
/* create the nifty spinny thing that says "hizzo, I'm doing something fo realz" */
plugin.editor.setProgressState(1);
@@ -131,16 +132,16 @@
plugin._removeWords();
/* send request to our service */
- plugin.sendRequest('checkDocument', ed.getContent({ format: 'raw' }), function(data, request, someObject)
+ plugin.sendRequest('checkDocument', ed.getContent({ format: 'raw' }), function(data, request/*, someObject*/)
{
/* turn off the spinning thingie */
plugin.editor.setProgressState(0);
/* if the server is not accepting requests, let the user know */
- if ( request.status != 200 || request.responseText.substr(1, 4) == 'html' || !request.responseXML )
+ if ( request.status !== 200 || request.responseText.substr(1, 4) === 'html' || !request.responseXML )
{
ed.windowManager.alert(
- plugin.editor.getLang('AtD.message_server_error', 'There was a problem communicating with the Proofreading service. Try again in one minute.'),
+ getLang( 'message_server_error', 'There was a problem communicating with the Proofreading service. Try again in one minute.' ),
callback ? function() { callback( 0 ); } : function() {}
);
return;
@@ -165,28 +166,29 @@
ed.suggestions = results.suggestions;
}
- if (ecount == 0 && (!callback || callback == undefined))
- ed.windowManager.alert(plugin.editor.getLang('AtD.message_no_errors_found', 'No writing errors were found.'));
- else if (callback)
+ if (ecount === 0 && (!callback || callback === undefined)) {
+ ed.windowManager.alert( getLang('message_no_errors_found', 'No writing errors were found.') );
+ } else if (callback) {
callback(ecount);
+ }
});
});
/* load cascading style sheet for this plugin */
- editor.onInit.add(function()
+ editor.onInit.add(function()
{
/* loading the content.css file, why? I have no clue */
if (editor.settings.content_css !== false)
{
- editor.dom.loadCSS(editor.getParam("atd_css_url", url + '/css/content.css'));
+ editor.dom.loadCSS(editor.getParam('atd_css_url', url + '/css/content.css'));
}
- });
+ });
/* again showing a menu, I have no clue what */
- editor.onClick.add(plugin._showMenu, plugin);
+ editor.onClick.add(plugin._showMenu, plugin);
/* we're showing some sort of menu, no idea what */
- editor.onContextMenu.add(plugin._showMenu, plugin);
+ editor.onContextMenu.add(plugin._showMenu, plugin);
/* strip out the markup before the contents is serialized (and do it on a copy of the markup so we don't affect the user experience) */
editor.onPreProcess.add(function(sender, object)
@@ -195,7 +197,7 @@
each(dom.select('span', object.node).reverse(), function(n)
{
- if (n && (dom.hasClass(n, 'hiddenGrammarError') || dom.hasClass(n, 'hiddenSpellError') || dom.hasClass(n, 'hiddenSuggestion') || dom.hasClass(n, 'mceItemHidden') || (dom.getAttrib(n, 'class') == "" && dom.getAttrib(n, 'style') == "" && dom.getAttrib(n, 'id') == "" && !dom.hasClass(n, 'Apple-style-span') && dom.getAttrib(n, 'mce_name') == "")))
+ if (n && (dom.hasClass(n, 'hiddenGrammarError') || dom.hasClass(n, 'hiddenSpellError') || dom.hasClass(n, 'hiddenSuggestion') || dom.hasClass(n, 'mceItemHidden') || (!dom.getAttrib(n, 'class') && !dom.getAttrib(n, 'style') && !dom.getAttrib(n, 'id') && !dom.hasClass(n, 'Apple-style-span') && !dom.getAttrib(n, 'mce_name'))))
{
dom.remove(n, 1);
}
@@ -203,23 +205,23 @@
});
/* cleanup the HTML before executing certain commands */
- editor.onBeforeExecCommand.add(function(editor, command)
+ editor.onBeforeExecCommand.add(function(editor, command)
{
- if (command == 'mceCodeEditor')
+ if (command === 'mceCodeEditor')
{
plugin._removeWords();
}
- else if (command == 'mceFullScreen')
+ else if (command === 'mceFullScreen')
{
plugin._done();
}
});
- ed.addButton('AtD', {
- title: ed.getLang('AtD.button_proofread_tooltip', 'Proofread Writing'),
- image: ed.getParam('atd_button_url', url + '/atdbuttontr.gif'),
- cmd: 'mceWritingImprovementTool'
- });
+ ed.addButton('AtD', {
+ title: getLang( 'button_proofread_tooltip', 'Proofread Writing' ),
+ image: ed.getParam('atd_button_url', url + '/atdbuttontr.gif'),
+ cmd: 'mceWritingImprovementTool'
+ });
},
_removeWords : function(w)
@@ -249,8 +251,9 @@
_showMenu : function(ed, e)
{
- var t = this, ed = t.editor, m = t._menu, p1, dom = ed.dom, vp = dom.getViewPort(ed.getWin());
- var plugin = this;
+ var t = this;
+ ed = t.editor; // not clear why this overwrites the function parameter
+ var m = t._menu, p1, dom = ed.dom, vp = dom.getViewPort(ed.getWin());
if (!m)
{
@@ -275,19 +278,19 @@
/* find the correct suggestions object */
var errorDescription = ed.core.findSuggestion(e.target);
- if (errorDescription == undefined)
+ if (!errorDescription)
{
- m.add({title : plugin.editor.getLang('AtD.menu_title_no_suggestions', 'No suggestions'), 'class' : 'mceMenuItemTitle'}).setDisabled(1);
+ m.add({ title: getLang( 'menu_title_no_suggestions', 'No suggestions' ), 'class': 'mceMenuItemTitle' }).setDisabled(1);
}
- else if (errorDescription["suggestions"].length == 0)
+ else if (errorDescription['suggestions'].length === 0)
{
- m.add({title : errorDescription["description"], 'class' : 'mceMenuItemTitle'}).setDisabled(1);
+ m.add({ title: errorDescription['description'], 'class' : 'mceMenuItemTitle' }).setDisabled(1);
}
else
{
- m.add({ title : errorDescription["description"], 'class' : 'mceMenuItemTitle' }).setDisabled(1);
+ m.add({ title : errorDescription['description'], 'class' : 'mceMenuItemTitle' }).setDisabled(1);
- for (var i = 0; i < errorDescription["suggestions"].length; i++)
+ for (var i = 0; i < errorDescription['suggestions'].length; i++)
{
(function(sugg)
{
@@ -299,18 +302,18 @@
t._checkDone();
}
});
- })(errorDescription["suggestions"][i]);
+ })(errorDescription['suggestions'][i]); // jshint ignore:line
}
m.addSeparator();
}
- if (errorDescription != undefined && errorDescription["moreinfo"] != null)
+ if (errorDescription && errorDescription['moreinfo'])
{
(function(url)
{
m.add({
- title : plugin.editor.getLang('AtD.menu_option_explain', 'Explain...'),
+ title : getLang( 'menu_option_explain', 'Explain...' ),
onclick : function()
{
ed.windowManager.open({
@@ -319,36 +322,36 @@
height : 380,
inline : true
}, { theme_url : this.url });
- }
+ }
});
- })(errorDescription["moreinfo"]);
+ })(errorDescription['moreinfo']);
m.addSeparator();
}
m.add({
- title : plugin.editor.getLang('AtD.menu_option_ignore_once', 'Ignore suggestion'),
+ title : getLang( 'menu_option_ignore_once', 'Ignore suggestion' ),
onclick : function()
{
dom.remove(e.target, 1);
t._checkDone();
- }
+ }
});
- if (String(this.editor.getParam("atd_ignore_enable", "false")) == "true")
+ if (String(this.editor.getParam('atd_ignore_enable', 'false')) === 'true')
{
m.add({
- title : plugin.editor.getLang('AtD.menu_option_ignore_always', 'Ignore always'),
+ title : getLang( 'menu_option_ignore_always', 'Ignore always' ),
onclick : function()
{
var url = t.editor.getParam('atd_ignore_rpc_url', '{backend}');
- if (url == '{backend}')
+ if (url === '{backend}')
{
/* Default scheme is to save ignore preferences in a cookie */
var ignore = tinymce.util.Cookie.getHash('atd_ignore');
- if (ignore == undefined) { ignore = {}; }
+ if (!ignore) { ignore = {}; }
ignore[e.target.innerHTML] = 1;
tinymce.util.Cookie.setHash('atd_ignore', ignore, new Date( (new Date().getTime()) + 157680000000) );
@@ -357,20 +360,20 @@
{
/* Plugin is configured to send ignore preferences to server, do that */
- var id = t.editor.getParam("atd_rpc_id", "12345678");
+ var id = t.editor.getParam('atd_rpc_id', '12345678');
tinymce.util.XHR.send({
- url : url + encodeURI(e.target.innerHTML).replace(/&/g, '%26') + "&key=" + id,
+ url : url + encodeURI(e.target.innerHTML).replace(/&/g, '%26') + '&key=' + id,
content_type : 'text/xml',
async : true,
type : 'GET',
- success : function( type, req, o )
+ success : function(/* type, req, o */)
{
/* do nothing */
},
error : function( type, req, o )
{
- alert( "Ignore preference save failed\n" + type + "\n" + req.status + "\nAt: " + o.url );
+ alert( 'Ignore preference save failed\n' + type + '\n' + req.status + '\nAt: ' + o.url );
}
});
@@ -386,7 +389,7 @@
else
{
m.add({
- title : plugin.editor.getLang('menu_option_ignore_all', 'Ignore all'),
+ title : getLang( 'menu_option_ignore_all', 'Ignore all' ),
onclick : function()
{
t._removeWords(e.target.innerHTML);
@@ -444,11 +447,11 @@
sendRequest : function(file, data, success)
{
- var id = this.editor.getParam("atd_rpc_id", "12345678");
- var url = this.editor.getParam("atd_rpc_url", "{backend}");
+ var id = this.editor.getParam('atd_rpc_id', '12345678');
+ var url = this.editor.getParam('atd_rpc_url', '{backend}');
var plugin = this;
- if (url == '{backend}' || id == '12345678')
+ if (url === '{backend}' || id === '12345678')
{
this.editor.setProgressState(0);
alert('Please specify: atd_rpc_url and atd_rpc_id');
@@ -456,16 +459,16 @@
}
tinymce.util.XHR.send({
- url : url + "/" + file,
+ url : url + '/' + file,
content_type : 'text/xml',
- type : "POST",
- data : "data=" + encodeURI(data).replace(/&/g, '%26') + "&key=" + id,
+ type : 'POST',
+ data : 'data=' + encodeURI(data).replace(/&/g, '%26') + '&key=' + id,
async : true,
success : success,
error : function( type, req, o )
{
- plugin.editor.setProgressState(0);
- alert( type + "\n" + req.status + "\nAt: " + o.url );
+ plugin.editor.setProgressState(0);
+ alert( type + '\n' + req.status + '\nAt: ' + o.url );
}
});
}
diff --git a/plugins/jetpack/modules/after-the-deadline/tinymce/plugin.js b/plugins/jetpack/modules/after-the-deadline/tinymce/plugin.js
new file mode 100644
index 00000000..1a71ce8b
--- /dev/null
+++ b/plugins/jetpack/modules/after-the-deadline/tinymce/plugin.js
@@ -0,0 +1,427 @@
+/* global tinymce */
+/*
+ * TinyMCE Writing Improvement Tool Plugin
+ * Author: Raphael Mudge (raffi@automattic.com)
+ *
+ * Updated for TinyMCE 4.0
+ *
+ * http://www.afterthedeadline.com
+ *
+ * Distributed under the LGPL
+ *
+ * Derived from:
+ * $Id: editor_plugin_src.js 425 2007-11-21 15:17:39Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright (C) 2004-2008, Moxiecode Systems AB, All rights reserved.
+ *
+ * Moxiecode Spell Checker plugin released under the LGPL with TinyMCE
+ */
+tinymce.PluginManager.add( 'AtD', function( editor ) {
+ var suggestionsMenu, started, atdCore, dom,
+ each = tinymce.each;
+
+ /* initializes the functions used by the AtD Core UI Module */
+ function initAtDCore() {
+
+ atdCore = new window.AtDCore();
+ atdCore.map = each;
+ atdCore._isTinyMCE = true;
+
+ atdCore.getAttrib = function( node, key ) {
+ return dom.getAttrib( node, key );
+ };
+
+ atdCore.findSpans = function( parent ) {
+ if ( parent === undefined ) {
+ return dom.select('span');
+ } else {
+ return dom.select( 'span', parent );
+ }
+ };
+
+ atdCore.hasClass = function( node, className ) {
+ return dom.hasClass( node, className );
+ };
+
+ atdCore.contents = function( node ) {
+ return node.childNodes;
+ };
+
+ atdCore.replaceWith = function( old_node, new_node ) {
+ return dom.replace( new_node, old_node );
+ };
+
+ atdCore.create = function( node_html ) {
+ return dom.create( 'span', { 'class': 'mceItemHidden', 'data-mce-bogus': 1 }, node_html );
+ };
+
+ atdCore.removeParent = function( node ) {
+ dom.remove( node, true );
+ return node;
+ };
+
+ atdCore.remove = function( node ) {
+ dom.remove( node );
+ };
+
+ atdCore.setIgnoreStrings( editor.getParam( 'atd_ignore_strings', [] ).join(',') );
+ atdCore.showTypes( editor.getParam( 'atd_show_types', '' ) );
+ }
+
+ function getLang( key, defaultStr ) {
+ return ( window.AtD_l10n_r0ar && window.AtD_l10n_r0ar[key] ) || defaultStr;
+ }
+
+ function isMarkedNode( node ) {
+ return ( node.className && /\bhidden(GrammarError|SpellError|Suggestion)\b/.test( node.className ) );
+ }
+
+ function markMyWords( errors ) {
+ return atdCore.markMyWords( atdCore.contents( editor.getBody() ), errors );
+ }
+
+ // If no more suggestions, finish.
+ function checkIfFinished() {
+ if ( ! editor.dom.select('span.hiddenSpellError, span.hiddenGrammarError, span.hiddenSuggestion').length ) {
+ if ( suggestionsMenu ) {
+ suggestionsMenu.hideMenu();
+ }
+
+ finish();
+ }
+ }
+
+ function ignoreWord( target, word, all ) {
+ var dom = editor.dom;
+
+ if ( all ) {
+ each( editor.dom.select( 'span.hiddenSpellError, span.hiddenGrammarError, span.hiddenSuggestion' ), function( node ) {
+ var text = node.innerText || node.textContent;
+
+ if ( text === word ) {
+ dom.remove( node, true );
+ }
+ });
+ } else {
+ dom.remove( target, true );
+ }
+
+ checkIfFinished();
+ }
+
+ // Called when the user clicks "Finish" or when no more suggestions left.
+ // Removes all remaining spans and fires custom event.
+ function finish() {
+ var node,
+ dom = editor.dom,
+ regex = new RegExp( 'mceItemHidden|hidden(((Grammar|Spell)Error)|Suggestion)' ),
+ nodes = dom.select('span'),
+ i = nodes.length;
+
+ while ( i-- ) { // reversed
+ node = nodes[i];
+
+ if ( node.className && regex.test( node.className ) ) {
+ dom.remove( node, true );
+ }
+ }
+
+ // Rebuild the DOM so AtD core can find the text nodes
+ editor.setContent( editor.getContent({ format: 'raw' }), { format: 'raw' } );
+
+ started = false;
+ editor.nodeChanged();
+ editor.fire('SpellcheckEnd');
+ }
+
+ function sendRequest( file, data, success ) {
+ var id = editor.getParam( 'atd_rpc_id', '12345678' ),
+ url = editor.getParam( 'atd_rpc_url', '{backend}' );
+
+ if ( url === '{backend}' || id === '12345678' ) {
+ window.alert( 'Please specify: atd_rpc_url and atd_rpc_id' );
+ return;
+ }
+
+ // create the nifty spinny thing that says "hizzo, I'm doing something fo realz"
+ editor.setProgressState( true );
+
+ tinymce.util.XHR.send({
+ url: url + '/' + file,
+ content_type: 'text/xml',
+ type: 'POST',
+ data: 'data=' + encodeURI( data ).replace( /&/g, '%26' ) + '&key=' + id,
+ success: success,
+ error: function( type, req, o ) {
+ editor.setProgressState();
+ window.alert( type + '\n' + req.status + '\nAt: ' + o.url );
+ }
+ });
+ }
+
+ function storeIgnoredStrings( /*text*/ ) {
+ // Store in sessionStorage?
+ }
+
+ function setAlwaysIgnore( text ) {
+ var url = editor.getParam( 'atd_ignore_rpc_url' );
+
+ if ( ! url || url === '{backend}' ) {
+ // Store ignored words for this session only
+ storeIgnoredStrings( text );
+ } else {
+ // Plugin is configured to send ignore preferences to server, do that
+ tinymce.util.XHR.send({
+ url: url + encodeURIComponent( text ) + '&key=' + editor.getParam( 'atd_rpc_id', '12345678' ),
+ content_type: 'text/xml',
+ type: 'GET',
+ error: function() {
+ storeIgnoredStrings( text );
+ }
+ });
+ }
+
+ // Update atd_ignore_strings with the new value
+ atdCore.setIgnoreStrings( text );
+ }
+
+ // Create the suggestions menu
+ function showSuggestions( target ) {
+ var pos, root, targetPos,
+ items = [],
+ text = target.innerText || target.textContent,
+ errorDescription = atdCore.findSuggestion( target );
+
+ if ( ! errorDescription ) {
+ items.push({
+ text: getLang( 'menu_title_no_suggestions', 'No suggestions' ),
+ classes: 'atd-menu-title',
+ disabled: true
+ });
+ } else {
+ items.push({
+ text: errorDescription.description,
+ classes: 'atd-menu-title',
+ disabled: true
+ });
+
+ if ( errorDescription.suggestions.length ) {
+ items.push({ text: '-' }); // separator
+
+ each( errorDescription.suggestions, function( suggestion ) {
+ items.push({
+ text: suggestion,
+ onclick: function() {
+ atdCore.applySuggestion( target, suggestion );
+ checkIfFinished();
+ }
+ });
+ });
+ }
+ }
+
+ if ( errorDescription && errorDescription.moreinfo ) {
+ items.push({ text: '-' }); // separator
+
+ items.push({
+ text: getLang( 'menu_option_explain', 'Explain...' ),
+ onclick : function() {
+ editor.windowManager.open({
+ title: getLang( 'menu_option_explain', 'Explain...' ),
+ url: errorDescription.moreinfo,
+ width: 480,
+ height: 380,
+ inline: true
+ });
+ }
+ });
+ }
+
+ items.push.apply( items, [
+ { text: '-' }, // separator
+
+ { text: getLang( 'menu_option_ignore_once', 'Ignore suggestion' ), onclick: function() {
+ ignoreWord( target, text );
+ }}
+ ]);
+
+ if ( editor.getParam( 'atd_ignore_enable' ) ) {
+ items.push({
+ text: getLang( 'menu_option_ignore_always', 'Ignore always' ),
+ onclick: function() {
+ setAlwaysIgnore( text );
+ ignoreWord( target, text, true );
+ }
+ });
+ } else {
+ items.push({
+ text: getLang( 'menu_option_ignore_all', 'Ignore all' ),
+ onclick: function() {
+ ignoreWord( target, text, true );
+ }
+ });
+ }
+
+ // Render menu
+ suggestionsMenu = new tinymce.ui.Menu({
+ items: items,
+ context: 'contextmenu',
+ onautohide: function( event ) {
+ if ( isMarkedNode( event.target ) ) {
+ event.preventDefault();
+ }
+ },
+ onhide: function() {
+ suggestionsMenu.remove();
+ suggestionsMenu = null;
+ }
+ });
+
+ suggestionsMenu.renderTo( document.body );
+
+ // Position menu
+ pos = tinymce.DOM.getPos( editor.getContentAreaContainer() );
+ targetPos = editor.dom.getPos( target );
+ root = editor.dom.getRoot();
+
+ // Adjust targetPos for scrolling in the editor
+ if ( root.nodeName === 'BODY' ) {
+ targetPos.x -= root.ownerDocument.documentElement.scrollLeft || root.scrollLeft;
+ targetPos.y -= root.ownerDocument.documentElement.scrollTop || root.scrollTop;
+ } else {
+ targetPos.x -= root.scrollLeft;
+ targetPos.y -= root.scrollTop;
+ }
+
+ pos.x += targetPos.x;
+ pos.y += targetPos.y;
+
+ suggestionsMenu.moveTo( pos.x, pos.y + target.offsetHeight );
+ }
+
+ // Init everything
+ editor.on( 'init', function() {
+ if ( typeof window.AtDCore === 'undefined' ) {
+ return;
+ }
+
+ // Set dom and atdCore
+ dom = editor.dom;
+ initAtDCore();
+
+ // add a command to request a document check and process the results.
+ editor.addCommand( 'mceWritingImprovementTool', function( callback ) {
+ var results,
+ errorCount = 0;
+
+ if ( typeof callback !== 'function' ) {
+ callback = function(){};
+ }
+
+ // checks if a global var for click stats exists and increments it if it does...
+ if ( typeof window.AtD_proofread_click_count !== 'undefined' ) {
+ window.AtD_proofread_click_count++;
+ }
+
+ // remove the previous errors
+ if ( started ) {
+ finish();
+ return;
+ }
+
+ // send request to our service
+ sendRequest( 'checkDocument', editor.getContent({ format: 'raw' }), function( data, request ) {
+ // turn off the spinning thingie
+ editor.setProgressState();
+
+ // if the server is not accepting requests, let the user know
+ if ( request.status !== 200 || request.responseText.substr( 1, 4 ) === 'html' || ! request.responseXML ) {
+ editor.windowManager.alert(
+ getLang( 'message_server_error', 'There was a problem communicating with the Proofreading service. Try again in one minute.' ),
+ callback(0)
+ );
+
+ return;
+ }
+
+ // check to see if things are broken first and foremost
+ if ( request.responseXML.getElementsByTagName('message').item(0) !== null ) {
+ editor.windowManager.alert(
+ request.responseXML.getElementsByTagName('message').item(0).firstChild.data,
+ callback(0)
+ );
+
+ return;
+ }
+
+ results = atdCore.processXML( request.responseXML );
+
+ if ( results.count > 0 ) {
+ errorCount = markMyWords( results.errors );
+ }
+
+ if ( ! errorCount ) {
+ editor.windowManager.alert( getLang( 'message_no_errors_found', 'No writing errors were found.' ) );
+ } else {
+ started = true;
+ editor.fire('SpellcheckStart');
+ }
+
+ callback( errorCount );
+ });
+ });
+
+ if ( editor.settings.content_css !== false ) {
+ // CSS for underlining suggestions
+ dom.addStyle( '.hiddenSpellError{border-bottom:2px solid red;cursor:default;}' +
+ '.hiddenGrammarError{border-bottom:2px solid green;cursor:default;}' +
+ '.hiddenSuggestion{border-bottom:2px solid blue;cursor:default;}' );
+ }
+
+ // Menu z-index > DFW
+ tinymce.DOM.addStyle( 'div.mce-floatpanel{z-index:150100 !important;}' );
+
+ // Click on misspelled word
+ editor.on( 'click', function( event ) {
+ if ( isMarkedNode( event.target ) ) {
+ event.preventDefault();
+ editor.selection.select( event.target );
+ // Create the suggestions menu
+ showSuggestions( event.target );
+ }
+ });
+ });
+
+ editor.addMenuItem( 'spellchecker', {
+ text: getLang( 'button_proofread_tooltip', 'Proofread Writing' ),
+ context: 'tools',
+ cmd: 'mceWritingImprovementTool',
+ onPostRender: function() {
+ var self = this;
+
+ editor.on('SpellcheckStart SpellcheckEnd', function() {
+ self.active( started );
+ });
+ }
+ });
+
+ editor.addButton( 'spellchecker', {
+ tooltip: getLang( 'button_proofread_tooltip', 'Proofread Writing' ),
+ cmd: 'mceWritingImprovementTool',
+ onPostRender: function() {
+ var self = this;
+
+ editor.on( 'SpellcheckStart SpellcheckEnd', function() {
+ self.active( started );
+ });
+ }
+ });
+
+ editor.on( 'remove', function() {
+ if ( suggestionsMenu ) {
+ suggestionsMenu.remove();
+ suggestionsMenu = null;
+ }
+ });
+});
diff --git a/plugins/jetpack/modules/carousel.php b/plugins/jetpack/modules/carousel.php
index 77f186b7..75302cc5 100644
--- a/plugins/jetpack/modules/carousel.php
+++ b/plugins/jetpack/modules/carousel.php
@@ -2,11 +2,15 @@
/**
* Module Name: Carousel
- * Module Description: Transform your standard image galleries into an immersive full-screen experience.
- * Sort Order: 4
+ * Module Description: Transform standard image galleries into full-screen slideshows.
+ * Jumpstart Description: brings your photos and images to life as full-size, easily navigable galleries.
+ * Sort Order: 22
+ * Recommendation Order: 12
* First Introduced: 1.5
* Requires Connection: No
* Auto Activate: No
+ * Module Tags: Photos and Videos
+ * Feature: Jumpstart
*/
include dirname( __FILE__ ) . '/carousel/jetpack-carousel.php';
diff --git a/plugins/jetpack/modules/carousel/README b/plugins/jetpack/modules/carousel/README
deleted file mode 100644
index 9cc24a05..00000000
--- a/plugins/jetpack/modules/carousel/README
+++ /dev/null
@@ -1 +0,0 @@
-Team Carousel will rock your world! \ No newline at end of file
diff --git a/plugins/jetpack/modules/carousel/images/arrows-2x.png b/plugins/jetpack/modules/carousel/images/arrows-2x.png
index 12a0bd97..01214f2e 100644
--- a/plugins/jetpack/modules/carousel/images/arrows-2x.png
+++ b/plugins/jetpack/modules/carousel/images/arrows-2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/carousel/images/arrows.png b/plugins/jetpack/modules/carousel/images/arrows.png
index 45d3ef66..9251dce1 100644
--- a/plugins/jetpack/modules/carousel/images/arrows.png
+++ b/plugins/jetpack/modules/carousel/images/arrows.png
Binary files differ
diff --git a/plugins/jetpack/modules/carousel/images/carousel-sprite-2x.png b/plugins/jetpack/modules/carousel/images/carousel-sprite-2x.png
index f3630a11..85d0e3f3 100644
--- a/plugins/jetpack/modules/carousel/images/carousel-sprite-2x.png
+++ b/plugins/jetpack/modules/carousel/images/carousel-sprite-2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/carousel/images/carousel-sprite.png b/plugins/jetpack/modules/carousel/images/carousel-sprite.png
index 65df60e8..41ad9c8d 100644
--- a/plugins/jetpack/modules/carousel/images/carousel-sprite.png
+++ b/plugins/jetpack/modules/carousel/images/carousel-sprite.png
Binary files differ
diff --git a/plugins/jetpack/modules/carousel/jetpack-carousel-ie8fix.css b/plugins/jetpack/modules/carousel/jetpack-carousel-ie8fix.css
index 9f2f6cff..0c41d553 100644
--- a/plugins/jetpack/modules/carousel/jetpack-carousel-ie8fix.css
+++ b/plugins/jetpack/modules/carousel/jetpack-carousel-ie8fix.css
@@ -1,8 +1,13 @@
.jp-carousel .jp-carousel-slide {
- display: none !important;
+ display: none !important;
}
-
-.jp-carousel .selected {
- margin: 0 auto;
- display: block !important;
+.jp-carousel {
+ text-align: center!important;
+ width:100%!important;
}
+.jp-carousel .selected {
+ margin: 0 auto;
+ display: block !important;
+ width: auto;
+ position: relative!important;
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/carousel/jetpack-carousel.css b/plugins/jetpack/modules/carousel/jetpack-carousel.css
index 05854495..7d99a68f 100644
--- a/plugins/jetpack/modules/carousel/jetpack-carousel.css
+++ b/plugins/jetpack/modules/carousel/jetpack-carousel.css
@@ -1,4 +1,4 @@
-* {
+.jp-carousel-wrap * {
line-height:inherit; /* prevent declarations of line-height in the universal selector */
}
@@ -56,12 +56,15 @@ only screen and (min-device-pixel-ratio: 1.5) {
.jp-carousel-photo-info {
position: relative;
+ left: 25%;
+ width: 50%;
+}
+
+.jp-carousel-transitions .jp-carousel-photo-info {
-webkit-transition: 400ms ease-out;
-moz-transition: 400ms ease-out;
-o-transition: 400ms ease-out;
transition: 400ms ease-out;
- left: 25%;
- width: 50%;
}
.jp-carousel-info h2 {
@@ -96,6 +99,10 @@ only screen and (min-device-pixel-ratio: 1.5) {
zoom: 1;
filter: alpha(opacity=20);
opacity: 0.2;
+}
+
+.jp-carousel-transitions .jp-carousel-next-button span,
+.jp-carousel-transitions .jp-carousel-previous-button span {
-webkit-transition: 500ms opacity ease-out;
-moz-transition: 500ms opacity ease-out;
-o-transition: 500ms opacity ease-out;
@@ -140,6 +147,9 @@ div.jp-carousel-buttons a {
div.jp-carousel-buttons a:hover {
color: #68c9e8;
border: none !important;
+}
+
+.jp-carousel-transitions div.jp-carousel-buttons a:hover {
-webkit-transition: none !important;
-moz-transition: none !important;
-o-transition: none !important;
@@ -155,7 +165,7 @@ div.jp-carousel-buttons a:hover {
}
.jp-carousel-slide {
- position:absolute;
+ position:fixed;
width:0;
bottom:0;
background-color:#000;
@@ -164,10 +174,24 @@ div.jp-carousel-buttons a:hover {
-moz-border-radius:2px;
-ms-border-radius:2px;
-o-border-radius:2px;
- -webkit-transition: 400ms ease-out;
- -moz-transition: 400ms ease-out;
- -o-transition: 400ms ease-out;
- transition: 400ms ease-out;
+}
+
+.jp-carousel-transitions .jp-carousel-slide {
+ -webkit-transition: 300ms ease-out;
+ -moz-transition: 300ms ease-out;
+ -o-transition: 300ms ease-out;
+ transition: 300ms ease-out;
+}
+
+.jp-carousel-slide.selected {
+ position: absolute !important;
+ filter: alpha(opacity=100);
+ opacity: 1;
+}
+
+.jp-carousel-slide {
+ filter: alpha(opacity=25);
+ opacity: 0.25;
}
.jp-carousel-slide img {
@@ -183,19 +207,15 @@ div.jp-carousel-buttons a:hover {
-moz-box-shadow: 0 2px 8px rgba(0,0,0,0.1);
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
zoom: 1;
- filter: alpha(opacity=25);
- opacity: 0.25;
+}
+
+.jp-carousel-transitions .jp-carousel-slide {
-webkit-transition: opacity 400ms linear;
-moz-transition: opacity 400ms linear;
-o-transition: opacity 400ms linear;
transition: opacity 400ms linear;
}
-.jp-carousel-slide.selected img {
- filter: alpha(opacity=100);
- opacity: 1;
-}
-
.jp-carousel-close-hint {
color: #999;
cursor: default;
@@ -204,6 +224,9 @@ div.jp-carousel-buttons a:hover {
position: absolute;
text-align: left;
width: 90%;
+}
+
+.jp-carousel-transitions .jp-carousel-close-hint {
-webkit-transition: color 200ms linear;
-moz-transition: color 200ms linear;
-o-transition: color 200ms linear;
@@ -225,6 +248,9 @@ div.jp-carousel-buttons a:hover {
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
+}
+
+.jp-carousel-transitions .jp-carousel-close-hint span {
-webkit-transition: border-color 200ms linear;
-moz-transition: border-color 200ms linear;
-o-transition: border-color 200ms linear;
@@ -244,13 +270,13 @@ div.jp-carousel-buttons a.jp-carousel-like,
div.jp-carousel-buttons a.jp-carousel-reblog,
div.jp-carousel-buttons a.jp-carousel-commentlink,
a.jp-carousel-image-download {
- background: url(./images/carousel-sprite.png?4) no-repeat;
- background-size: 16px 160px;
+ background: url(./images/carousel-sprite.png?5) no-repeat;
+ background-size: 16px 200px;
}
div.jp-carousel-buttons a.jp-carousel-reblog,
div.jp-carousel-buttons a.jp-carousel-commentlink {
- margin:0 14px 0 0 !important;
+ margin: 0 14px 0 0 !important;
}
div.jp-carousel-buttons a.jp-carousel-reblog.reblogged,
@@ -258,7 +284,7 @@ div.jp-carousel-buttons a.jp-carousel-like.liked {
background-color: #303030;
padding-right: 8px !important;
border-radius: 2px;
- border-radius:2px;
+ border-radius: 2px;
-webkit-border-radius:2px;
-moz-border-radius:2px;
-ms-border-radius:2px;
@@ -266,19 +292,19 @@ div.jp-carousel-buttons a.jp-carousel-like.liked {
}
div.jp-carousel-buttons a.jp-carousel-reblog.reblogged {
- margin:0 2px 0 -12px !important;
+ margin: 0 2px 0 -12px !important;
}
-
div.jp-carousel-buttons a.jp-carousel-reblog,
div.jp-carousel-buttons a.jp-carousel-reblog.reblogged:hover {
background-position: 6px -36px;
+ padding-right: auto !important;
padding-left: 26px !important;
color: #999;
}
div.jp-carousel-buttons a.jp-carousel-commentlink {
- background-position: 0px -116px;
+ background-position: 0px -156px;
padding-left: 19px !important;
}
@@ -309,7 +335,7 @@ only screen and (min-device-pixel-ratio: 1.5) {
div.jp-carousel-buttons a.jp-carousel-reblog,
div.jp-carousel-buttons a.jp-carousel-commentlink,
a.jp-carousel-image-download {
- background-image: url(./images/carousel-sprite-2x.png?4);
+ background-image: url(./images/carousel-sprite-2x.png?5);
}
}
@@ -561,7 +587,7 @@ a.jp-carousel-image-download span.photo-size-times {
}
a.jp-carousel-image-download:hover {
- background-position: 0 -102px;
+ background-position: 0 -122px;
color: #68c9e8;
border: none !important;
}
@@ -808,8 +834,8 @@ textarea#jp-carousel-comment-form-comment-field:focus::-webkit-input-placeholder
border-radius: 2px;
font: 13px/1.4 "Helvetica Neue", sans-serif !important;
border: 1px solid rgba( 255, 255, 255, 0.17 );
- -webkit-box-shadow: inset 0px 0px 5px 5px rgba(0, 0, 0, 1);
- box-shadow: inset 0px 0px 5px 5px rgba(0, 0, 0, 1);
+ -webkit-box-shadow: inset 0px 0px 5px 5px rgba(0, 0, 0, 1);
+ box-shadow: inset 0px 0px 5px 5px rgba(0, 0, 0, 1);
}
.jp-carousel-comment-post-error {
@@ -826,7 +852,7 @@ textarea#jp-carousel-comment-form-comment-field:focus::-webkit-input-placeholder
}
#jp-carousel-comments-loading {
- font: 444 15px/1.7 "Helvetica Neue", sans-serif !important;
+ font: 400 15px/1.7 "Helvetica Neue", sans-serif !important;
display: none;
color: #999;
text-align: left;
@@ -904,7 +930,7 @@ textarea#jp-carousel-comment-form-comment-field:focus::-webkit-input-placeholder
}
.jp-carousel-light div.jp-carousel-buttons a.jp-carousel-commentlink {
- background-position: 0px -136px;
+ background-position: 0px -176px;
}
.jp-carousel-light div.jp-carousel-buttons a.jp-carousel-like,
@@ -994,11 +1020,11 @@ textarea#jp-carousel-comment-form-comment-field:focus::-webkit-input-placeholder
}
.jp-carousel-light a.jp-carousel-image-download {
- background-position: 0 -102px;
+ background-position: 0 -122px;
}
.jp-carousel-light a.jp-carousel-image-download:hover {
- background-position: 0 -102px;
+ background-position: 0 -122px;
color: #f1831e;
}
@@ -1026,8 +1052,8 @@ textarea#jp-carousel-comment-form-comment-field:focus::-webkit-input-placeholder
.jp-carousel-light #jp-carousel-comment-post-results span {
background: #f7f7f7;
border:1px solid #dfdfdf;
- -webkit-box-shadow: inset 0px 0px 5px rgba(0, 0, 0, 0.05);
- box-shadow: inset 0px 0px 5px rgba(0, 0, 0, 0.05);
+ -webkit-box-shadow: inset 0px 0px 5px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0px 0px 5px rgba(0, 0, 0, 0.05);
}
.jp-carousel-light .jp-carousel-slide {
@@ -1100,5 +1126,11 @@ textarea#jp-carousel-comment-form-comment-field:focus::-webkit-input-placeholder
.jp-carousel-left-column-wrapper {
padding: 0;
+ width: 100% !important;
+ }
+
+ .jp-carousel-photo-info {
+ left: 0 !important;
+ width: 100% !important;
}
}
diff --git a/plugins/jetpack/modules/carousel/jetpack-carousel.js b/plugins/jetpack/modules/carousel/jetpack-carousel.js
index 2b334fac..a7e27c74 100644
--- a/plugins/jetpack/modules/carousel/jetpack-carousel.js
+++ b/plugins/jetpack/modules/carousel/jetpack-carousel.js
@@ -1,15 +1,22 @@
+/* jshint sub: true, onevar: false, multistr: true, devel: true, smarttabs: true */
+/* global jetpackCarouselStrings, DocumentTouch, jetpackLikesWidgetQueue */
+
jQuery(document).ready(function($) {
// gallery faded layer and container elements
- var overlay, comments, gallery, container, nextButton, previousButton, info, title,
- caption, resizeTimeout, mouseTimeout, photo_info, close_hint, commentInterval, buttons,
- screenPadding = 110, originalOverflow = $('body').css('overflow'), originalHOverflow = $('html').css('overflow'), proportion = 85, isMobile;
+ var overlay, comments, gallery, container, nextButton, previousButton, info, transitionBegin,
+ caption, resizeTimeout, photo_info, close_hint, commentInterval, lastSelectedSlide,
+ screenPadding = 110, originalOverflow = $('body').css('overflow'), originalHOverflow = $('html').css('overflow'), proportion = 85,
+ last_known_location_hash = '', imageMeta, titleAndDescription, commentForm, leftColWrapper;
- isMobile = /Android|iPhone|iPod/i.test(navigator.userAgent);
+ if ( window.innerWidth <= 760 ) {
+ screenPadding = Math.round( ( window.innerWidth / 760 ) * 110 );
- if (isMobile)
- screenPadding = 0;
+ if ( screenPadding < 40 && ( ( 'ontouchstart' in window ) || window.DocumentTouch && document instanceof DocumentTouch ) ) {
+ screenPadding = 0;
+ }
+ }
var keyListener = function(e){
switch(e.which){
@@ -27,6 +34,7 @@ jQuery(document).ready(function($) {
gallery.jp_carousel('next');
break;
case 37: // left
+ case 8: // backspace
e.preventDefault();
gallery.jp_carousel('clearCommentTextAreaValue');
gallery.jp_carousel('previous');
@@ -42,80 +50,18 @@ jQuery(document).ready(function($) {
}
};
- var resizeListener = function(e){
+ var resizeListener = function(/*e*/){
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(function(){
gallery
.jp_carousel('slides')
.jp_carousel('fitSlide', true);
- gallery
- .jp_carousel('fitInfo', true)
- .jp_carousel('fitMeta', true);
+ gallery.jp_carousel('updateSlidePositions', true);
+ gallery.jp_carousel('fitMeta', true);
}, 200);
};
- // For each image in the carousel, emit likes widget markup
- var getCarouselLikeWidgets = function( dataCarouselExtra ) {
-
- // Only do this if likes is enabled
- if ( "undefined" === typeof jetpackLikesWidgetQueue )
- return "";
-
- var blogId = dataCarouselExtra.likes_blog_id;
- var attachmentId = 0;
- var protocol = 'http';
- var originDomain = 'http://wordpress.com';
-
- if ( dataCarouselExtra.permalink.length ) {
- var parts = dataCarouselExtra.permalink.split( ':' );
- var protocol = parts[0];
- if ( ( protocol != 'http' ) && ( protocol != 'https' ) ) {
- protocol = 'http';
- }
-
- parts = dataCarouselExtra.permalink.split( '/' );
- if ( parts.length >= 2 ) {
- originDomain = protocol + "://" + parts[2];
- }
- }
-
- var likesWidgetContainer = $("<div class='likes-widget-container'></div>");
-
- $( 'div.gallery, div.tiled-gallery' ).find( 'img' ).each( function() {
-
- attachmentId = $( this ).attr( "data-attachment-id" );
- var dataSource = protocol + "://widgets.wp.com/likes/#blog_id=" + blogId + "&amp;post_id=" + attachmentId + "&amp;slim=1&amp;origin=" + originDomain;
-
- if ( 'en' !== jetpackCarouselStrings.lang ) {
- dataSource += "&amp;lang=" + jetpackCarouselStrings.lang;
- }
-
- var likesWidgetWrapper = $( "<div></div>" );
- likesWidgetWrapper.addClass( "jetpack-likes-widget-wrapper" )
- .addClass( "jetpack-likes-widget-unloaded" )
- .addClass( "slim-likes-widget" )
- .attr( "id", "like-post-wrapper-" + blogId + "-" + attachmentId )
- .attr( "data-src", dataSource )
- .attr( "data-name", "like-post-frame-" + blogId + "-" + attachmentId )
- .attr( "data-attachment-id", attachmentId )
- .css( "display", "none" )
- .css( "vertical-align", "middle" );
-
- var likesWidget = $( "<iframe class='post-likes-widget jetpack-likes-widget jetpack-resizeable'></iframe>" );
- likesWidget.attr( "name", "like-post-frame-" + blogId + "-" + attachmentId )
- .attr( "src", dataSource );
- likesWidget.css( "display", "inline-block" );
- likesWidgetWrapper.append( likesWidget );
-
- likesWidgetWrapper.append( "<div class='post-likes-widget-placeholder'></div>" );
-
- likesWidgetContainer.append( likesWidgetWrapper );
- });
-
- return likesWidgetContainer.html();
- };
-
- var prepareGallery = function( dataCarouselExtra ){
+ var prepareGallery = function( /*dataCarouselExtra*/ ){
if (!overlay) {
overlay = $('<div></div>')
.addClass('jp-carousel-overlay')
@@ -127,10 +73,10 @@ jQuery(document).ready(function($) {
'left' : 0
});
- buttons = '<a class="jp-carousel-commentlink" href="#">' + jetpackCarouselStrings.comment + '</a>';
- if ( 1 == jetpackCarouselStrings.is_logged_in ) {
+ var buttons = '<a class="jp-carousel-commentlink" href="#">' + jetpackCarouselStrings.comment + '</a>';
+ if ( 1 === Number( jetpackCarouselStrings.is_logged_in ) ) {
}
- buttons += getCarouselLikeWidgets( dataCarouselExtra );
+
buttons = $('<div class="jp-carousel-buttons">' + buttons + '</div>');
caption = $('<h2></h2>');
@@ -144,10 +90,11 @@ jQuery(document).ready(function($) {
'width' : '250px'
});
- imageMeta.append( buttons );
- imageMeta.append( "<ul class='jp-carousel-image-exif' style='display:none;'></ul>" );
- imageMeta.append( "<a class='jp-carousel-image-download' style='display:none;'></a>" );
- imageMeta.append( "<div class='jp-carousel-image-map' style='display:none;'></div>" );
+ imageMeta
+ .append( buttons )
+ .append( '<ul class=\'jp-carousel-image-exif\' style=\'display:none;\'></ul>' )
+ .append( '<a class=\'jp-carousel-image-download\' style=\'display:none;\'></a>' )
+ .append( '<div class=\'jp-carousel-image-map\' style=\'display:none;\'></div>' );
titleAndDescription = $('<div></div>')
.addClass('jp-carousel-titleanddesc')
@@ -156,23 +103,16 @@ jQuery(document).ready(function($) {
'margin-top' : imageMeta.css('margin-top')
});
- var commentFormMarkup = '';
- var iframeSrc = '';
+ var commentFormMarkup = '<div id="jp-carousel-comment-form-container">';
- commentFormMarkup = '<div id="jp-carousel-comment-form-container">';
- if (iframeSrc && iframeSrc.length) {
- // We're using Jetpack comments!
- var iframeHeight = (jetpackCarouselStrings.is_logged_in || iframeSrc.match('comment_registration=1')) ? 220 : 340;
- iframeSrc = iframeSrc.replace(/(blogid=\d+)/, '$1&postid='+window.location.hash.replace(/#jp-carousel-/,'')); // get initial attachment id from URL hash
- commentFormMarkup += '<iframe src="'+iframeSrc+'" width="100%" height="'+iframeHeight+'" style="width:100%;height:'+iframeHeight+'px;" allowtransparency="true" frameBorder="0" scrolling="no" name="jp-carousel-comment-iframe" id="jp-carousel-comment-iframe"></iframe>';
- } else if ( jetpackCarouselStrings.local_comments_commenting_as && jetpackCarouselStrings.local_comments_commenting_as.length ) {
+ if ( jetpackCarouselStrings.local_comments_commenting_as && jetpackCarouselStrings.local_comments_commenting_as.length ) {
// Jetpack comments not enabled, fallback to local comments
- if ( 1 != jetpackCarouselStrings.is_logged_in && 1 == jetpackCarouselStrings.comment_registration ) {
+ if ( 1 !== Number( jetpackCarouselStrings.is_logged_in ) && 1 === Number( jetpackCarouselStrings.comment_registration ) ) {
commentFormMarkup += '<div id="jp-carousel-comment-form-commenting-as">' + jetpackCarouselStrings.local_comments_commenting_as + '</div>';
} else {
commentFormMarkup += '<form id="jp-carousel-comment-form">';
- commentFormMarkup += '<textarea name="comment" class="jp-carousel-comment-form-field jp-carousel-comment-form-textarea" id="jp-carousel-comment-form-comment-field" placeholder="Write a comment&hellip;"></textarea>';
+ commentFormMarkup += '<textarea name="comment" class="jp-carousel-comment-form-field jp-carousel-comment-form-textarea" id="jp-carousel-comment-form-comment-field" placeholder="' + jetpackCarouselStrings.write_comment + '"></textarea>';
commentFormMarkup += '<div id="jp-carousel-comment-form-submit-and-info-wrapper">';
commentFormMarkup += '<div id="jp-carousel-comment-form-commenting-as">' + jetpackCarouselStrings.local_comments_commenting_as + '</div>';
commentFormMarkup += '<input type="submit" name="submit" class="jp-carousel-comment-form-button" id="jp-carousel-comment-form-button-submit" value="'+jetpackCarouselStrings.post_comment+'" />';
@@ -199,79 +139,67 @@ jQuery(document).ready(function($) {
'margin-top' : '20px'
});
- commentsLoading = $('<div id="jp-carousel-comments-loading"><span>'+jetpackCarouselStrings.loading_comments+'</span></div>')
+ var commentsLoading = $('<div id="jp-carousel-comments-loading"><span>'+jetpackCarouselStrings.loading_comments+'</span></div>')
.css({
'width' : '100%',
'bottom' : '10px',
'margin-top' : '20px'
});
- leftWidth = ( $(window).width() - ( screenPadding * 2 ) ) - (imageMeta.width() + 40);
+ var leftWidth = ( $(window).width() - ( screenPadding * 2 ) ) - (imageMeta.width() + 40);
leftWidth += 'px';
- if (isMobile)
- leftWidth = '100%';
-
leftColWrapper = $('<div></div>')
.addClass('jp-carousel-left-column-wrapper')
.css({
- 'width' : leftWidth
+ 'width' : Math.floor( leftWidth )
})
.append(titleAndDescription)
.append(commentForm)
.append(comments)
.append(commentsLoading);
- fadeaway = $('<div></div>')
+ var fadeaway = $('<div></div>')
.addClass('jp-carousel-fadeaway');
info = $('<div></div>')
.addClass('jp-carousel-info')
.css({
- 'top' : ($(window).height() / 100) * proportion,
+ 'top' : Math.floor( ($(window).height() / 100) * proportion ),
'left' : screenPadding,
'right' : screenPadding
})
.append(photo_info)
- .append(imageMeta)
- .append(leftColWrapper);
+ .append(imageMeta);
- if (isMobile)
- info.prepend(leftColWrapper);
- else
- info.append(leftColWrapper);
+ if ( window.innerWidth <= 760 ) {
+ photo_info.remove().insertAfter( titleAndDescription );
+ info.prepend( leftColWrapper );
+ }
+ else {
+ info.append( leftColWrapper );
+ }
- targetBottomPos = ( $(window).height() - parseInt( info.css('top'), 10 ) ) + 'px';
+ var targetBottomPos = ( $(window).height() - parseInt( info.css('top'), 10 ) ) + 'px';
- nextButton = $("<div><span></span></div>")
+ nextButton = $('<div><span></span></div>')
.addClass('jp-carousel-next-button')
.css({
- 'position' : 'fixed',
- 'top' : 0,
- 'right' : '15px',
- 'bottom' : 0,
- 'width' : screenPadding
+ 'right' : '15px'
});
- $('span', nextButton).css({
- 'top' : '40px',
- 'bottom' : targetBottomPos
- });
-
- previousButton = $("<div><span></span></div>")
+ previousButton = $('<div><span></span></div>')
.addClass('jp-carousel-previous-button')
.css({
- 'position' : 'fixed',
- 'top' : 0,
- 'left' : 0,
- 'bottom' : 0,
- 'width' : screenPadding
+ 'left' : 0
});
- $('span', previousButton).css({
- 'top' : '40px',
- 'bottom' : targetBottomPos
- });
+ nextButton.add( previousButton ).css( {
+ 'position' : 'fixed',
+ 'top' : '40px',
+ 'bottom' : targetBottomPos,
+ 'width' : screenPadding
+ } );
gallery = $('<div></div>')
.addClass('jp-carousel')
@@ -288,11 +216,13 @@ jQuery(document).ready(function($) {
position : 'fixed'
});
- container = $("<div></div>")
- .addClass('jp-carousel-wrap');
+ container = $('<div></div>')
+ .addClass('jp-carousel-wrap')
+ .addClass( 'jp-carousel-transitions' );
- if ( 'white' == jetpackCarouselStrings.background_color )
+ if ( 'white' === jetpackCarouselStrings.background_color ) {
container.addClass('jp-carousel-light');
+ }
container.css({
'position' : 'fixed',
@@ -331,7 +261,7 @@ jQuery(document).ready(function($) {
} else if ( target.hasClass('jp-carousel-comment-login') ) {
var url = jetpackCarouselStrings.login_url + '%23jp-carousel-' + attachment_id;
- document.location.href = url;
+ window.location.href = url;
} else if ( target.parents('#jp-carousel-comment-form-container').length ) {
var textarea = $('#jp-carousel-comment-form-comment-field')
.blur(function(){
@@ -365,7 +295,7 @@ jQuery(document).ready(function($) {
$(window).unbind('keydown', keyListener);
});
- if ( textarea && textarea.attr('id') == target.attr('id')) {
+ if ( textarea && textarea.attr('id') === target.attr('id')) {
// For first page load
$(window).unbind('keydown', keyListener);
$('#jp-carousel-comment-form-submit-and-info-wrapper').slideDown('fast');
@@ -388,12 +318,12 @@ jQuery(document).ready(function($) {
return;
}
- if ( 1 != jetpackCarouselStrings.is_logged_in ) {
+ if ( 1 !== Number( jetpackCarouselStrings.is_logged_in ) ) {
ajaxData['email'] = emailField.val();
ajaxData['author'] = authorField.val();
ajaxData['url'] = urlField.val();
- if ( 1 == jetpackCarouselStrings.require_name_email ) {
+ if ( 1 === Number( jetpackCarouselStrings.require_name_email ) ) {
if ( ! ajaxData['email'].length || ! ajaxData['email'].match('@') ) {
gallery.jp_carousel('postCommentError', {'field': 'jp-carousel-comment-form-email-field', 'error': jetpackCarouselStrings.no_comment_email});
return;
@@ -409,10 +339,10 @@ jQuery(document).ready(function($) {
url: jetpackCarouselStrings.ajaxurl,
data: ajaxData,
dataType: 'json',
- success: function(response, status, xhr) {
- if ( 'approved' == response.comment_status ) {
+ success: function(response/*, status, xhr*/) {
+ if ( 'approved' === response.comment_status ) {
$('#jp-carousel-comment-post-results').slideUp('fast').html('<span class="jp-carousel-comment-post-success">' + jetpackCarouselStrings.comment_approved + '</span>').slideDown('fast');
- } else if ( 'unapproved' == response.comment_status ) {
+ } else if ( 'unapproved' === response.comment_status ) {
$('#jp-carousel-comment-post-results').slideUp('fast').html('<span class="jp-carousel-comment-post-success">' + jetpackCarouselStrings.comment_unapproved + '</span>').slideDown('fast');
} else {
// 'deleted', 'spam', false
@@ -423,7 +353,7 @@ jQuery(document).ready(function($) {
$('#jp-carousel-comment-form-button-submit').val(jetpackCarouselStrings.post_comment);
$('#jp-carousel-comment-form-spinner').spin(false);
},
- error: function(xhr, status, error) {
+ error: function(/*xhr, status, error*/) {
// TODO: Add error handling and display here
gallery.jp_carousel('postCommentError', {'field': 'jp-carousel-comment-form-comment-field', 'error': jetpackCarouselStrings.comment_post_error});
return;
@@ -438,6 +368,8 @@ jQuery(document).ready(function($) {
$(window).bind('keydown', keyListener);
$(window).bind('resize', resizeListener);
gallery.opened = true;
+
+ resizeListener();
})
.bind('jp_carousel.beforeClose', function(){
var scroll = $(window).scrollTop();
@@ -448,20 +380,39 @@ jQuery(document).ready(function($) {
})
.bind('jp_carousel.afterClose', function(){
if ( history.pushState ) {
- history.pushState("", document.title, window.location.pathname + window.location.search);
+ history.pushState('', document.title, window.location.pathname + window.location.search);
} else {
- document.location.hash = '';
+ last_known_location_hash = '';
+ window.location.hash = '';
}
gallery.opened = false;
- });
+ })
+ .on( 'transitionend.jp-carousel ', '.jp-carousel-slide', function ( e ) {
+ // If the movement transitions take more than twice the allotted time, disable them.
+ // There is some wiggle room in the 2x, since some of that time is taken up in
+ // JavaScript, setting up the transition and calling the events.
+ if ( 'transform' === e.originalEvent.propertyName ) {
+ var transitionMultiplier = ( ( Date.now() - transitionBegin ) / 1000 ) / e.originalEvent.elapsedTime;
- $('.jp-carousel').touchwipe({
- wipeLeft: function() { gallery.jp_carousel('next'); },
- wipeRight: function() { gallery.jp_carousel('previous'); },
- min_move_x: 20,
- min_move_y: 20,
- preventDefaultEvents: true
- });
+ container.off( 'transitionend.jp-carousel' );
+
+ if ( transitionMultiplier >= 2 ) {
+ $( '.jp-carousel-transitions' ).removeClass( 'jp-carousel-transitions' );
+ }
+ }
+ } );
+
+ $( '.jp-carousel-wrap' ).touchwipe( {
+ wipeLeft : function ( e ) {
+ e.preventDefault();
+ gallery.jp_carousel( 'next' );
+ },
+ wipeRight : function ( e ) {
+ e.preventDefault();
+ gallery.jp_carousel( 'previous' );
+ },
+ preventDefaultEvents : false
+ } );
$( '.jetpack-likes-widget-unloaded' ).each( function() {
jetpackLikesWidgetQueue.push( this.id );
@@ -482,32 +433,43 @@ jQuery(document).ready(function($) {
var methods = {
testForData: function(gallery) {
gallery = $( gallery ); // make sure we have it as a jQuery object.
- if ( ! gallery.length || undefined == gallery.data( 'carousel-extra' ) ) {
- return false;
- }
- return true;
+ return !( ! gallery.length || ! gallery.data( 'carousel-extra' ) );
},
testIfOpened: function() {
- if ( 'undefined' != typeof(gallery) && 'undefined' != typeof(gallery.opened) && true == gallery.opened )
- return true;
- return false;
+ return !!( 'undefined' !== typeof(gallery) && 'undefined' !== typeof(gallery.opened) && gallery.opened );
+ },
+
+ openOrSelectSlide: function( index ) {
+ // The `open` method triggers an asynchronous effect, so we will get an
+ // error if we try to use `open` then `selectSlideAtIndex` immediately
+ // after it. We can only use `selectSlideAtIndex` if the carousel is
+ // already open.
+ if ( ! $( this ).jp_carousel( 'testIfOpened' ) ) {
+ // The `open` method selects the correct slide during the
+ // initialization.
+ $( this ).jp_carousel( 'open', { start_index: index } );
+ } else {
+ gallery.jp_carousel( 'selectSlideAtIndex', index );
+ }
},
open: function(options) {
var settings = {
- 'items_selector' : ".gallery-item [data-attachment-id], .tiled-gallery-item [data-attachment-id]",
+ 'items_selector' : '.gallery-item [data-attachment-id], .tiled-gallery-item [data-attachment-id]',
'start_index': 0
},
data = $(this).data('carousel-extra');
- if ( !data )
+ if ( !data ) {
return; // don't run if the default gallery functions weren't used
+ }
prepareGallery( data );
- if ( gallery.jp_carousel( 'testIfOpened' ) )
+ if ( gallery.jp_carousel( 'testIfOpened' ) ) {
return; // don't open if already opened
+ }
// make sure to stop the page from scrolling behind the carousel overlay, so we don't trigger
// infiniscroll for it when enabled (Reader, theme infiniscroll, etc).
@@ -529,26 +491,29 @@ jQuery(document).ready(function($) {
// with our default settings
var $this = $(this);
- if ( options )
+ if ( options ) {
$.extend( settings, options );
- if ( -1 == settings.start_index )
+ }
+ if ( -1 === settings.start_index ) {
settings.start_index = 0; //-1 returned if can't find index, so start from beginning
+ }
container.trigger('jp_carousel.beforeOpen').fadeIn('fast',function(){
container.trigger('jp_carousel.afterOpen');
gallery
.jp_carousel('initSlides', $this.find(settings.items_selector), settings.start_index)
- .jp_carousel('start', settings.start_index);
+ .jp_carousel('selectSlideAtIndex', settings.start_index);
});
gallery.html('');
});
},
- start : function(start_index){
- var slides = this.jp_carousel('slides'), selected = slides.eq(start_index);
+ selectSlideAtIndex : function(index){
+ var slides = this.jp_carousel('slides'), selected = slides.eq(index);
- if ( 0 === selected.length )
+ if ( 0 === selected.length ) {
selected = slides.eq(0);
+ }
gallery.jp_carousel('selectSlide', selected, false);
return this;
@@ -567,70 +532,28 @@ jQuery(document).ready(function($) {
},
next : function(){
- var selected = this.jp_carousel('selectedSlide'), slide;
+ var slide = gallery.jp_carousel( 'nextSlide' );
container.animate({scrollTop:0}, 'fast');
- if ( 0 === selected.length ) { // no selection return first item
- slide = this.jp_carousel('slides').first(0);
- } else if( selected.is( this.jp_carousel('slides').last() ) ) {
- gallery.jp_carousel('loopSlides');
- } else {
- slide = selected.next();
- }
- if (!slide) {
- return this;
- } else {
- return this.jp_carousel('selectSlide', slide);
+
+ if ( slide ) {
+ this.jp_carousel('selectSlide', slide);
}
},
previous : function(){
- var selected = this.jp_carousel('selectedSlide'), slide;
+ var slide = gallery.jp_carousel( 'prevSlide' );
container.animate({scrollTop:0}, 'fast');
- if ( 0 === selected.length ) { // no selection return first item
- slide = this.jp_carousel('slides').first();
- } else if ( selected.is( this.jp_carousel('slides').first() ) ) { // if it's the last slide
- gallery.jp_carousel('loopSlides', true);
- } else {
- slide = selected.prev();
- }
- if (!slide) {
- return this;
- } else {
- return this.jp_carousel('selectSlide', slide);
+
+ if ( slide ) {
+ this.jp_carousel('selectSlide', slide);
}
},
resetButtons : function(current) {
- if ( current.data('liked') )
+ if ( current.data('liked') ) {
$('.jp-carousel-buttons a.jp-carousel-like').addClass('liked').text(jetpackCarouselStrings.unlike);
- else
- $('.jp-carousel-buttons a.jp-carousel-like').removeClass('liked').text(jetpackCarouselStrings.like);
- },
-
- loopSlides : function(reverse){
- var slides = gallery.jp_carousel('slides'), last, first;
- gallery.jp_carousel('selectedSlide').removeClass('selected').css({'position': 'fixed'});
- if (reverse !== true ) {
- last = slides.last();
- slides.first().nextAll().not(last).jp_carousel('setSlidePosition', gallery.width()+slides.first().width()).hide();
- last.jp_carousel('setSlidePosition', -last.width());
- last.prev().jp_carousel('setSlidePosition', -last.width() - last.prev().width());
- slides.first().jp_carousel('setSlidePosition', gallery.width());
- setTimeout(function(){
- gallery.jp_carousel('selectSlide', slides.show().first());
- }, 400);
-
} else {
- first = slides.first();
- first.jp_carousel('setSlidePosition', gallery.width());
- first.next().jp_carousel('setSlidePosition', gallery.width() + first.width());
- first.next().nextAll().hide().jp_carousel('setSlidePosition', -slides.last().width());
- slides.last().jp_carousel('setSlidePosition', -slides.last().width());
- slides.last().prevAll().not(first, first.next()).hide().jp_carousel('setSlidePosition', -slides.last().width()-slides.last().prev().width());
- setTimeout(function(){
- gallery.jp_carousel('selectSlide', slides.show().last());
- }, 400);
-
+ $('.jp-carousel-buttons a.jp-carousel-like').removeClass('liked').text(jetpackCarouselStrings.like);
}
},
@@ -639,6 +562,8 @@ jQuery(document).ready(function($) {
},
setSlidePosition : function(x) {
+ transitionBegin = Date.now();
+
return this.css({
'-webkit-transform':'translate3d(' + x + 'px,0,0)',
'-moz-transform':'translate3d(' + x + 'px,0,0)',
@@ -648,78 +573,150 @@ jQuery(document).ready(function($) {
});
},
+ updateSlidePositions : function(animate) {
+ var current = this.jp_carousel( 'selectedSlide' ),
+ galleryWidth = gallery.width(),
+ currentWidth = current.width(),
+ previous = gallery.jp_carousel( 'prevSlide' ),
+ next = gallery.jp_carousel( 'nextSlide' ),
+ previousPrevious = previous.prev(),
+ nextNext = next.next(),
+ left = Math.floor( ( galleryWidth - currentWidth ) * 0.5 );
+
+ current.jp_carousel( 'setSlidePosition', left ).show();
+
+ // minimum width
+ gallery.jp_carousel( 'fitInfo', animate );
+
+ // prep the slides
+ var direction = lastSelectedSlide.is( current.prevAll() ) ? 1 : -1;
+
+ // Since we preload the `previousPrevious` and `nextNext` slides, we need
+ // to make sure they technically visible in the DOM, but invisible to the
+ // user. To hide them from the user, we position them outside the edges
+ // of the window.
+ //
+ // This section of code only applies when there are more than three
+ // slides. Otherwise, the `previousPrevious` and `nextNext` slides will
+ // overlap with the `previous` and `next` slides which must be visible
+ // regardless.
+ if ( 1 === direction ) {
+ if ( ! nextNext.is( previous ) ) {
+ nextNext.jp_carousel( 'setSlidePosition', galleryWidth + next.width() ).show();
+ }
+
+ if ( ! previousPrevious.is( next ) ) {
+ previousPrevious.jp_carousel( 'setSlidePosition', -previousPrevious.width() - currentWidth ).show();
+ }
+ } else {
+ if ( ! nextNext.is( previous ) ) {
+ nextNext.jp_carousel( 'setSlidePosition', galleryWidth + currentWidth ).show();
+ }
+ }
+
+ previous.jp_carousel( 'setSlidePosition', Math.floor( -previous.width() + ( screenPadding * 0.75 ) ) ).show();
+ next.jp_carousel( 'setSlidePosition', Math.ceil( galleryWidth - ( screenPadding * 0.75 ) ) ).show();
+ },
+
selectSlide : function(slide, animate){
- var last = this.find('.selected').removeClass('selected'),
- slides = gallery.jp_carousel('slides').css({'position': 'fixed'}),
- current = $(slide).addClass('selected').css({'position': 'relative'}),
- previous = current.prev(),
- next = current.next(),
- width = $(window).width(),
- previous_previous = previous.prev(),
- next_next = next.next(),
- left = (gallery.width() - current.width()) * 0.5,
- info_left,
+ lastSelectedSlide = this.find( '.selected' ).removeClass( 'selected' );
+
+ var slides = gallery.jp_carousel( 'slides' ).css({ 'position': 'fixed' }),
+ current = $( slide ).addClass( 'selected' ).css({ 'position': 'relative' }),
+ attachmentId = current.data( 'attachment-id' ),
+ previous = gallery.jp_carousel( 'prevSlide' ),
+ next = gallery.jp_carousel( 'nextSlide' ),
+ previousPrevious = previous.prev(),
+ nextNext = next.next(),
animated,
- info_min;
+ captionHtml;
+
// center the main image
+ gallery.jp_carousel( 'loadFullImage', current );
caption.hide();
- method = 'css';
+ if ( next.length === 0 && slides.length <= 2 ) {
+ $( '.jp-carousel-next-button' ).hide();
+ } else {
+ $( '.jp-carousel-next-button' ).show();
+ }
+
+ if ( previous.length === 0 && slides.length <= 2 ) {
+ $( '.jp-carousel-previous-button' ).hide();
+ } else {
+ $( '.jp-carousel-previous-button' ).show();
+ }
+
animated = current
- .add(previous)
- .add(previous.prev())
- .add(next)
- .add(next.next())
- .jp_carousel('loadSlide');
+ .add( previous )
+ .add( previousPrevious )
+ .add( next )
+ .add( nextNext )
+ .jp_carousel( 'loadSlide' );
+
// slide the whole view to the x we want
- slides.not(animated).hide();
+ slides.not( animated ).hide();
- current.jp_carousel('setSlidePosition', left).show();
+ gallery.jp_carousel( 'updateSlidePositions', animate );
- // minimum width
- gallery.jp_carousel('fitInfo', animate);
+ gallery.jp_carousel( 'resetButtons', current );
+ container.trigger( 'jp_carousel.selectSlide', [current] );
- // prep the slides
- var direction = last.is(current.prevAll()) ? 1 : -1;
- if ( 1 == direction ) {
- next_next.jp_carousel('setSlidePosition', gallery.width() + next.width()).show();
- next.hide().jp_carousel('setSlidePosition', gallery.width() + current.width()).show();
- previous_previous.jp_carousel('setSlidePosition', -previous_previous.width() - current.width()).show();
- } else {
- previous.jp_carousel('setSlidePosition', -previous.width() - current.width()).show();
- next_next.jp_carousel('setSlidePosition', gallery.width() + current.width()).show();
+ gallery.jp_carousel( 'getTitleDesc', {
+ title: current.data( 'title' ),
+ desc: current.data( 'desc' )
+ });
+
+ // Lazy-load the Likes iframe for the current, next, and previous slides.
+ gallery.jp_carousel( 'loadLikes', attachmentId );
+ gallery.jp_carousel( 'updateLikesWidgetVisibility', attachmentId );
+
+ if ( next.length > 0 ) {
+ gallery.jp_carousel( 'loadLikes', next.data( 'attachment-id' ) );
+ }
+
+ if ( previous.length > 0 ) {
+ gallery.jp_carousel( 'loadLikes', previous.data( 'attachment-id' ) );
}
- // if advancing prepare the slide that will enter the screen
- previous.jp_carousel('setSlidePosition', -previous.width() + (screenPadding * 0.75)).show();
- next.jp_carousel('setSlidePosition', gallery.width() - (screenPadding * 0.75)).show();
- next.css({'position': ''});
- document.location.href = document.location.href.replace(/#.*/, '') + '#jp-carousel-' + current.data('attachment-id');
- gallery.jp_carousel('resetButtons', current);
- container.trigger('jp_carousel.selectSlide', [current]);
-
- gallery.jp_carousel( 'getTitleDesc', { title: current.data( 'title' ), desc: current.data( 'desc' ) } );
- gallery.jp_carousel( 'updateLikesWidgetVisibility', current.data( 'attachment-id' ) )
- gallery.jp_carousel( 'updateExif', current.data( 'image-meta' ) );
+ var imageMeta = current.data( 'image-meta' );
+ gallery.jp_carousel( 'updateExif', imageMeta );
gallery.jp_carousel( 'updateFullSizeLink', current );
- gallery.jp_carousel( 'updateMap', current.data( 'image-meta' ) );
+ gallery.jp_carousel( 'updateMap', imageMeta );
gallery.jp_carousel( 'testCommentsOpened', current.data( 'comments-opened' ) );
- gallery.jp_carousel( 'getComments', { 'attachment_id': current.data( 'attachment-id' ), 'offset': 0, 'clear': true } );
+ gallery.jp_carousel( 'getComments', {
+ 'attachment_id': attachmentId,
+ 'offset': 0,
+ 'clear': true
+ });
+ $( '#jp-carousel-comment-post-results' ).slideUp();
+
+ // $('<div />').text(sometext).html() is a trick to go to HTML to plain
+ // text (including HTML entities decode, etc)
+ if ( current.data( 'caption' ) ) {
+ captionHtml = $( '<div />' ).text( current.data( 'caption' ) ).html();
- $('#jp-carousel-comment-post-results').slideUp();
+ if ( captionHtml === $( '<div />' ).text( current.data( 'title' ) ).html() ) {
+ $( '.jp-carousel-titleanddesc-title' ).fadeOut( 'fast' ).empty();
+ }
- // $('<div />').text(sometext).html() is a trick to go to HTML to plain text (including HTML entities decode, etc)
- if ( current.data('caption') ) {
- if ( $('<div />').text(current.data('caption')).html() == $('<div />').text(current.data('title')).html() )
- $('.jp-carousel-titleanddesc-title').fadeOut('fast').empty();
- if ( $('<div />').text(current.data('caption')).html() == $('<div />').text(current.data('desc')).html() )
- $('.jp-carousel-titleanddesc-desc').fadeOut('fast').empty();
- caption.html( current.data('caption') ).fadeIn('slow');
+ if ( captionHtml === $( '<div />' ).text( current.data( 'desc' ) ).html() ) {
+ $( '.jp-carousel-titleanddesc-desc' ).fadeOut( 'fast' ).empty();
+ }
+
+ caption.html( current.data( 'caption' ) ).fadeIn( 'slow' );
} else {
- caption.fadeOut('fast').empty();
+ caption.fadeOut( 'fast' ).empty();
}
+
+ // Load the images for the next and previous slides.
+ $( next ).add( previous ).each( function() {
+ gallery.jp_carousel( 'loadFullImage', $( this ) );
+ });
+
+ window.location.hash = last_known_location_hash = '#jp-carousel-' + attachmentId;
},
slides : function(){
@@ -729,7 +726,7 @@ jQuery(document).ready(function($) {
slideDimensions : function(){
return {
width: $(window).width() - (screenPadding * 2),
- height: $(window).height() / 100 * proportion - 60
+ height: Math.floor( $(window).height() / 100 * proportion - 60 )
};
},
@@ -750,19 +747,22 @@ jQuery(document).ready(function($) {
orig = this.jp_carousel('originalDimensions'),
orig_ratio = orig.width / orig.height,
w_ratio = 1,
- h_ratio = 1;
+ h_ratio = 1,
+ width, height;
- if ( orig.width > max.width )
+ if ( orig.width > max.width ) {
w_ratio = max.width / orig.width;
- if ( orig.height > max.height )
+ }
+ if ( orig.height > max.height ) {
h_ratio = max.height / orig.height;
+ }
if ( w_ratio < h_ratio ) {
width = max.width;
- height = width / orig_ratio;
+ height = Math.floor( width / orig_ratio );
} else if ( h_ratio < w_ratio ) {
height = max.height;
- width = height * orig_ratio;
+ width = Math.floor( height * orig_ratio );
} else {
width = orig.width;
height = orig.height;
@@ -774,25 +774,20 @@ jQuery(document).ready(function($) {
};
},
- fitInfo : function(animated){
+ fitInfo : function(/*animated*/){
var current = this.jp_carousel('selectedSlide'),
size = current.jp_carousel('bestFit');
photo_info.css({
- 'left' : (info.width() - size.width) * 0.5,
- 'width' : size.width
+ 'left' : Math.floor( (info.width() - size.width) * 0.5 ),
+ 'width' : Math.floor( size.width )
});
- if (isMobile){
- photo_info.css('left', '0px');
- photo_info.css('top', '-20px');
- }
-
return this;
},
fitMeta : function(animated){
- var newInfoTop = { top: ( $(window).height() / 100 * proportion + 5 ) + 'px' };
+ var newInfoTop = { top: Math.floor( $(window).height() / 100 * proportion + 5 ) + 'px' };
var newLeftWidth = { width: ( info.width() - (imageMeta.width() + 80) ) + 'px' };
if (animated) {
@@ -804,22 +799,21 @@ jQuery(document).ready(function($) {
}
},
- fitSlide : function(animated){
+ fitSlide : function(/*animated*/){
return this.each(function(){
- var selected = gallery.jp_carousel('selectedSlide'),
- $this = $(this),
+ var $this = $(this),
dimensions = $this.jp_carousel('bestFit'),
method = 'css',
max = gallery.jp_carousel('slideDimensions');
dimensions.left = 0;
- dimensions.top = ( (max.height - dimensions.height) * 0.5 ) + 40;
+ dimensions.top = Math.floor( (max.height - dimensions.height) * 0.5 ) + 40;
$this[method](dimensions);
});
},
texturize : function(text) {
- text = new String(text); // make sure we get a string. Title "1" came in as int 1, for example, which did not support .replace().
+ text = '' + text; // make sure we get a string. Title "1" came in as int 1, for example, which did not support .replace().
text = text.replace(/'/g, '&#8217;').replace(/&#039;/g, '&#8217;').replace(/[\u2019]/g, '&#8217;');
text = text.replace(/"/g, '&#8221;').replace(/&#034;/g, '&#8221;').replace(/&quot;/g, '&#8221;').replace(/[\u201D]/g, '&#8221;');
text = text.replace(/([\w]+)=&#[\d]+;(.+?)&#[\d]+;/g, '$1="$2"'); // untexturize allowed HTML tags params double-quotes
@@ -827,18 +821,22 @@ jQuery(document).ready(function($) {
},
initSlides : function(items, start_index){
- var width = this.jp_carousel('slideDimensions').width,
- x = 0;
+ if ( items.length < 2 ) {
+ $( '.jp-carousel-next-button, .jp-carousel-previous-button' ).hide();
+ } else {
+ $( '.jp-carousel-next-button, .jp-carousel-previous-button' ).show();
+ }
// Calculate the new src.
- items.each(function(i){
+ items.each(function(/*i*/){
var src_item = $(this),
orig_size = src_item.data('orig-size') || '',
max = gallery.jp_carousel('slideDimensions'),
- parts = orig_size.split(',');
- orig_size = {width: parseInt(parts[0], 10), height: parseInt(parts[1], 10)},
+ parts = orig_size.split(','),
medium_file = src_item.data('medium-file') || '',
- large_file = src_item.data('large-file') || '';
+ large_file = src_item.data('large-file') || '',
+ src;
+ orig_size = {width: parseInt(parts[0], 10), height: parseInt(parts[1], 10)};
src = src_item.data('orig-file');
@@ -857,8 +855,11 @@ jQuery(document).ready(function($) {
});
// If the start_index is not 0 then preload the clicked image first.
- if ( 0 !== start_index )
+ if ( 0 !== start_index ) {
$('<img/>')[0].src = $(items[start_index]).data('gallery-src');
+ }
+
+ var useInPageThumbnails = items.first().closest( '.tiled-gallery.type-rectangular' ).length > 0;
// create the 'slide'
items.each(function(i){
@@ -867,6 +868,7 @@ jQuery(document).ready(function($) {
comments_opened = src_item.data('comments-opened') || 0,
image_meta = src_item.data('image-meta') || {},
orig_size = src_item.data('orig-size') || '',
+ thumb_size = { width : src_item[0].naturalWidth, height : src_item[0].naturalHeight },
title = src_item.data('image-title') || '',
description = src_item.data('image-description') || '',
caption = src_item.parents('dl').find('dd.gallery-caption').html() || '',
@@ -876,21 +878,28 @@ jQuery(document).ready(function($) {
orig_file = src_item.data('orig-file') || '';
var tiledCaption = src_item.parents('div.tiled-gallery-item').find('div.tiled-gallery-caption').html();
- if ( tiledCaption )
+ if ( tiledCaption ) {
caption = tiledCaption;
+ }
if ( attachment_id && orig_size.length ) {
title = gallery.jp_carousel('texturize', title);
description = gallery.jp_carousel('texturize', description);
caption = gallery.jp_carousel('texturize', caption);
+ // Initially, the image is a 1x1 transparent gif. The preview is shown as a background image on the slide itself.
+ var image = $( '<img/>' )
+ .attr( 'src', 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' )
+ .css( 'width', '100%' )
+ .css( 'height', '100%' );
+
var slide = $('<div class="jp-carousel-slide"></div>')
.hide()
.css({
//'position' : 'fixed',
'left' : i < start_index ? -1000 : gallery.width()
})
- .append($('<img>'))
+ .append( image )
.appendTo(gallery)
.data('src', src )
.data('title', title)
@@ -904,80 +913,101 @@ jQuery(document).ready(function($) {
.data('medium-file', medium_file)
.data('large-file', large_file)
.data('orig-file', orig_file)
- .jp_carousel('fitSlide', false);
+ .data('thumb-size', thumb_size)
+ ;
+
+ if ( useInPageThumbnails ) {
+ // Use the image already loaded in the gallery as a preview.
+ slide
+ .data( 'preview-image', src_item.attr( 'src' ) )
+ .css( {
+ 'background-image' : 'url("' + src_item.attr( 'src' ) + '")',
+ 'background-size' : '100% 100%',
+ 'background-position' : 'center center'
+ } );
+ }
- // Preloading all images
- slide.find('img').first().attr('src', src );
+ slide.jp_carousel( 'fitSlide', false );
}
});
return this;
},
selectBestImageSize: function(args) {
- if ( 'object' != typeof args )
+ if ( 'object' !== typeof args ) {
args = {};
+ }
- if ( 'undefined' == typeof args.orig_file )
+ if ( 'undefined' === typeof args.orig_file ) {
return '';
+ }
- if ( 'undefined' == typeof args.orig_width || 'undefined' == typeof args.max_width )
+ if ( 'undefined' === typeof args.orig_width || 'undefined' === typeof args.max_width ) {
return args.orig_file;
+ }
- if ( 'undefined' == typeof args.medium_file || 'undefined' == typeof args.large_file )
+ if ( 'undefined' === typeof args.medium_file || 'undefined' === typeof args.large_file ) {
return args.orig_file;
+ }
var medium_size = args.medium_file.replace(/-([\d]+x[\d]+)\..+$/, '$1'),
- medium_size_parts = (medium_size != args.medium_file) ? medium_size.split('x') : [args.orig_width, 0],
+ medium_size_parts = (medium_size !== args.medium_file) ? medium_size.split('x') : [args.orig_width, 0],
medium_width = parseInt( medium_size_parts[0], 10 ),
medium_height = parseInt( medium_size_parts[1], 10 ),
large_size = args.large_file.replace(/-([\d]+x[\d]+)\..+$/, '$1'),
- large_size_parts = (large_size != args.large_file) ? large_size.split('x') : [args.orig_width, 0],
+ large_size_parts = (large_size !== args.large_file) ? large_size.split('x') : [args.orig_width, 0],
large_width = parseInt( large_size_parts[0], 10 ),
large_height = parseInt( large_size_parts[1], 10 );
// Give devices with a higher devicePixelRatio higher-res images (Retina display = 2, Android phones = 1.5, etc)
- if ('undefined' != typeof window.devicePixelRatio && window.devicePixelRatio > 1) {
+ if ( 'undefined' !== typeof window.devicePixelRatio && window.devicePixelRatio > 1 ) {
args.max_width = args.max_width * window.devicePixelRatio;
args.max_height = args.max_height * window.devicePixelRatio;
}
- if ( large_width >= args.max_width || large_height >= args.max_height )
+ if ( large_width >= args.max_width || large_height >= args.max_height ) {
return args.large_file;
+ }
- if ( medium_width >= args.max_width || medium_height >= args.max_height )
+ if ( medium_width >= args.max_width || medium_height >= args.max_height ) {
return args.medium_file;
+ }
return args.orig_file;
},
-
originalDimensions: function() {
var splitted = $(this).data('orig-size').split(',');
return {width: parseInt(splitted[0], 10), height: parseInt(splitted[1], 10)};
},
format: function( args ) {
- if ( 'object' != typeof args )
+ if ( 'object' !== typeof args ) {
args = {};
- if ( ! args.text || 'undefined' == typeof args.text )
+ }
+ if ( ! args.text || 'undefined' === typeof args.text ) {
return;
- if ( ! args.replacements || 'undefined' == typeof args.replacements )
+ }
+ if ( ! args.replacements || 'undefined' === typeof args.replacements ) {
return args.text;
- return args.text.replace(/{(\d+)}/g, function(match, number) {
- return typeof args.replacements[number] != 'undefined' ? args.replacements[number] : match;
+ }
+ return args.text.replace(/{(\d+)}/g, function( match, number ) {
+ return typeof args.replacements[number] !== 'undefined' ? args.replacements[number] : match;
});
},
shutterSpeed: function(d) {
- if (d >= 1)
- return Math.round(d) + 's';
+ if (d >= 1) {
+ return Math.round(d*10)/10 + 's'; // round to one decimal if value > 1s by multiplying it by 10, rounding, then dividing by 10 again
+ }
var df = 1, top = 1, bot = 1;
- var limit = 1e5; //Increase for greater precision.
- while (df != d && limit-- > 0) {
+ var tol = 1e-8;
+ // iterate while value not reached and difference (positive or negative, hence the Math.abs) between value
+ // and approximated value greater than given tolerance
+ while (df !== d && Math.abs(df-d) > tol) {
if (df < d) {
top += 1;
- }
- else {
+ } else {
bot += 1;
top = parseInt(d * bot, 10);
}
@@ -987,16 +1017,18 @@ jQuery(document).ready(function($) {
bot = Math.round(bot / top);
top = 1;
}
- if (bot <= 1)
+ if (bot <= 1) {
return '1s';
+ }
return top + '/' + bot + 's';
},
parseTitleDesc: function( value ) {
- if ( !value.match(' ') && value.match('_') )
+ if ( !value.match(' ') && value.match('_') ) {
return '';
+ }
// Prefix list originally based on http://commons.wikimedia.org/wiki/MediaWiki:Filename-prefix-blacklist
- var prefixes = $([
+ $([
'CIMG', // Casio
'DSC_', // Nikon
'DSCF', // Fuji
@@ -1016,7 +1048,7 @@ jQuery(document).ready(function($) {
'Screen Shot [0-9]+' // Mac screenshots
])
.each(function(key, val){
- regex = new RegExp('^' + val);
+ var regex = new RegExp('^' + val);
if ( regex.test(value) ) {
value = '';
return;
@@ -1026,7 +1058,7 @@ jQuery(document).ready(function($) {
},
getTitleDesc: function( data ) {
- var title ='', desc = '', markup = '', target, commentWrappere;
+ var title ='', desc = '', markup = '', target;
target = $( 'div.jp-carousel-titleanddesc', 'div.jp-carousel-wrap' );
target.hide();
@@ -1036,8 +1068,9 @@ jQuery(document).ready(function($) {
if ( title.length || desc.length ) {
// $('<div />').text(sometext).html() is a trick to go to HTML to plain text (including HTML entities decode, etc)
- if ( $('<div />').text(title).html() == $('<div />').text(desc).html() )
+ if ( $('<div />').text(title).html() === $('<div />').text(desc).html() ) {
title = '';
+ }
markup = ( title.length ) ? '<div class="jp-carousel-titleanddesc-title">' + title + '</div>' : '';
markup += ( desc.length ) ? '<div class="jp-carousel-titleanddesc-desc">' + desc + '</div>' : '';
@@ -1049,28 +1082,86 @@ jQuery(document).ready(function($) {
$( 'div#jp-carousel-comments-loading' ).css('margin-top', '20px');
},
- updateLikesWidgetVisibility: function( attachmentId ) {
- // Hide all likes widgets except for the one for the attachmentId passed in
+ updateLikesWidgetVisibility: function ( attachmentId ) {
+ // Only do this if likes is enabled
+ if ( 'undefined' === typeof jetpackLikesWidgetQueue ) {
+ return;
+ }
- $( '.jp-carousel-buttons' ).find( '.jetpack-likes-widget-wrapper' ).each( function() {
+ // Hide all likes widgets except for the one for the attachmentId passed in
+ $( '.jp-carousel-buttons .jetpack-likes-widget-wrapper' ).css( 'display', 'none' ).each( function () {
var widgetWrapper = $( this );
- if ( widgetWrapper.attr('data-attachment-id') == attachmentId ) {
+ if ( widgetWrapper.attr( 'data-attachment-id' ) == attachmentId ) { // jshint ignore:line
widgetWrapper.css( 'display', 'inline-block' );
- } else {
- widgetWrapper.css( 'display', 'none' );
+ return false;
}
- });
+ });
+ },
+
+ loadLikes : function ( attachmentId ) {
+ var dataCarouselExtra = $( '.jp-carousel-wrap' ).data( 'carousel-extra' );
+ var blogId = dataCarouselExtra.likes_blog_id;
+
+ if ( $( '#like-post-wrapper-' + blogId + '-' + attachmentId ).length === 0 ) {
+ // Add the iframe the first time the slide is shown.
+ var protocol = 'http';
+ var originDomain = 'http://wordpress.com';
+
+ if ( dataCarouselExtra.permalink.length ) {
+ protocol = dataCarouselExtra.permalink.split( ':' )[0];
+
+ if ( ( protocol !== 'http' ) && ( protocol !== 'https' ) ) {
+ protocol = 'http';
+ }
+
+ var parts = dataCarouselExtra.permalink.split( '/' );
+
+ if ( parts.length >= 2 ) {
+ originDomain = protocol + '://' + parts[2];
+ }
+ }
+
+ var dataSource = protocol + '://widgets.wp.com/likes/#blog_id=' + encodeURIComponent( blogId ) +
+ '&post_id=' + encodeURIComponent( attachmentId ) +
+ '&slim=1&origin=' + encodeURIComponent( originDomain );
+
+ if ( 'en' !== jetpackCarouselStrings.lang ) {
+ dataSource += '&lang=' + encodeURIComponent( jetpackCarouselStrings.lang );
+ }
+
+ var likesWidget = $( '<iframe class=\'post-likes-widget jetpack-likes-widget jetpack-resizeable\'></iframe>' )
+ .attr( 'name', 'like-post-frame-' + blogId + '-' + attachmentId )
+ .attr( 'src', dataSource )
+ .css( 'display', 'inline-block' );
+
+ var likesWidgetWrapper = $( '<div/>' )
+ .addClass( 'jetpack-likes-widget-wrapper jetpack-likes-widget-unloaded slim-likes-widget' )
+ .attr( 'id', 'like-post-wrapper-' + blogId + '-' + attachmentId )
+ .attr( 'data-src', dataSource )
+ .attr( 'data-name', 'like-post-frame-' + blogId + '-' + attachmentId )
+ .attr( 'data-attachment-id', attachmentId )
+ .css( 'display', 'none' )
+ .css( 'vertical-align', 'middle' )
+ .append( likesWidget )
+ .append( '<div class=\'post-likes-widget-placeholder\'></div>' );
+
+ $( '.jp-carousel-buttons' ).append( likesWidgetWrapper );
+ }
+
},
// updateExif updates the contents of the exif UL (.jp-carousel-image-exif)
updateExif: function( meta ) {
- if ( !meta || 1 != jetpackCarouselStrings.display_exif )
+ if ( !meta || 1 !== Number( jetpackCarouselStrings.display_exif ) ) {
return false;
+ }
+
+ var $ul = $( '<ul class=\'jp-carousel-image-exif\'></ul>' );
- var $ul = $( "<ul class='jp-carousel-image-exif'></ul>" );
$.each( meta, function( key, val ) {
- if ( 0 === parseFloat(val) || !val.length || -1 === $.inArray( key, [ 'camera', 'aperture', 'shutter_speed', 'focal_length' ] ) )
+ if ( 0 === parseFloat(val) || !val.length || -1 === $.inArray( key, [ 'camera', 'aperture', 'shutter_speed', 'focal_length' ] ) ) {
return;
+ }
switch( key ) {
case 'focal_length':
@@ -1082,9 +1173,6 @@ jQuery(document).ready(function($) {
case 'aperture':
val = 'f/' + val;
break;
- default:
- // making jslint happy
- break;
}
$ul.append( '<li><h5>' + jetpackCarouselStrings[key] + '</h5>' + val + '</li>' );
@@ -1096,8 +1184,9 @@ jQuery(document).ready(function($) {
// updateFullSizeLink updates the contents of the jp-carousel-image-download link
updateFullSizeLink: function(current) {
- if(!current || !current.data)
+ if(!current || !current.data) {
return false;
+ }
var original = current.data('orig-file').replace(/\?.+$/, ''),
origSize = current.data('orig-size').split(','),
permalink = $( '<a>'+gallery.jp_carousel('format', {'text': jetpackCarouselStrings.download_original, 'replacements': origSize})+'</a>' )
@@ -1110,8 +1199,9 @@ jQuery(document).ready(function($) {
},
updateMap: function( meta ) {
- if ( !meta.latitude || !meta.longitude || 1 != jetpackCarouselStrings.display_geo )
+ if ( !meta.latitude || !meta.longitude || 1 !== Number( jetpackCarouselStrings.display_geo ) ) {
return;
+ }
var latitude = meta.latitude,
longitude = meta.longitude,
@@ -1140,7 +1230,7 @@ jQuery(document).ready(function($) {
},
testCommentsOpened: function( opened ) {
- if ( 1 == parseInt( opened, 10 ) ) {
+ if ( 1 === parseInt( opened, 10 ) ) {
$('.jp-carousel-buttons').fadeIn('fast');
commentForm.fadeIn('fast');
} else {
@@ -1150,23 +1240,25 @@ jQuery(document).ready(function($) {
},
getComments: function( args ) {
- if ( 'object' != typeof args )
- args = {};
+ clearInterval( commentInterval );
- if ( ! args.attachment_id || 'undefined' == typeof args.attachment_id )
+ if ( 'object' !== typeof args ) {
return;
+ }
+
+ if ( 'undefined' === typeof args.attachment_id || ! args.attachment_id ) {
+ return;
+ }
- if ( ! args.offset || 'undefined' == typeof args.offset || args.offset < 1 )
+ if ( ! args.offset || 'undefined' === typeof args.offset || args.offset < 1 ) {
args.offset = 0;
+ }
var comments = $('.jp-carousel-comments'),
- commentsLoading = $('#jp-carousel-comments-loading');
-
- commentsLoading.show();
+ commentsLoading = $('#jp-carousel-comments-loading').show();
if ( args.clear ) {
- comments.hide();
- comments.empty();
+ comments.hide().empty();
}
$.ajax({
@@ -1179,30 +1271,28 @@ jQuery(document).ready(function($) {
id: args.attachment_id,
offset: args.offset
},
- success: function(data, status, xhr) {
+ success: function(data/*, status, xhr*/) {
if ( args.clear ) {
- comments.fadeOut('fast');
- comments.empty();
+ comments.fadeOut('fast').empty();
}
$( data ).each(function(){
var comment = $('<div></div>')
.addClass('jp-carousel-comment')
.attr('id', 'jp-carousel-comment-' + this['id'])
- .css({})
.html(
- '<div class="comment-gravatar">'
- + this['gravatar_markup']
- + '</div>'
- + '<div class="comment-author">'
- + this['author_markup']
- + '</div>'
- + '<div class="comment-date">'
- + this['date_gmt']
- + '</div>'
- + '<div class="comment-content">'
- + this['content']
- + '</div>'
+ '<div class="comment-gravatar">' +
+ this['gravatar_markup'] +
+ '</div>' +
+ '<div class="comment-author">' +
+ this['author_markup'] +
+ '</div>' +
+ '<div class="comment-date">' +
+ this['date_gmt'] +
+ '</div>' +
+ '<div class="comment-content">' +
+ this['content'] +
+ '</div>'
);
comments.append(comment);
@@ -1213,14 +1303,14 @@ jQuery(document).ready(function($) {
gallery.jp_carousel('getComments',{ attachment_id: args.attachment_id, offset: args.offset + 10, clear: false });
clearInterval( commentInterval );
}
- }, 150 );
+ }, 300 );
});
// Verify (late) that the user didn't repeatldy click the arrows really fast, in which case the requested
// attachment id might no longer match the current attachment id by the time we get the data back or a now
// registered infiniscroll event kicks in, so we don't ever display comments for the wrong image by mistake.
var current = $('.jp-carousel div.selected');
- if ( current && current.data && current.data('attachment-id') != args.attachment_id ) {
+ if ( current && current.data && current.data('attachment-id') != args.attachment_id ) { // jshint ignore:line
comments.fadeOut('fast');
comments.empty();
return;
@@ -1242,10 +1332,12 @@ jQuery(document).ready(function($) {
},
postCommentError: function(args) {
- if ( 'object' != typeof args )
+ if ( 'object' !== typeof args ) {
args = {};
- if ( ! args.field || 'undefined' == typeof args.field || ! args.error || 'undefined' == typeof args.error )
+ }
+ if ( ! args.field || 'undefined' === typeof args.field || ! args.error || 'undefined' === typeof args.error ) {
return;
+ }
$('#jp-carousel-comment-post-results').slideUp('fast').html('<span class="jp-carousel-comment-post-error">'+args.error+'</span>').slideDown('fast');
$('#jp-carousel-comment-form-spinner').spin(false);
},
@@ -1261,8 +1353,53 @@ jQuery(document).ready(function($) {
clearCommentTextAreaValue: function() {
var commentTextArea = $('#jp-carousel-comment-form-comment-field');
- if ( commentTextArea )
+ if ( commentTextArea ) {
commentTextArea.val('');
+ }
+ },
+
+ nextSlide : function () {
+ var slides = this.jp_carousel( 'slides' );
+ var selected = this.jp_carousel( 'selectedSlide' );
+
+ if ( selected.length === 0 || ( slides.length > 2 && selected.is( slides.last() ) ) ) {
+ return slides.first();
+ }
+
+ return selected.next();
+ },
+
+ prevSlide : function () {
+ var slides = this.jp_carousel( 'slides' );
+ var selected = this.jp_carousel( 'selectedSlide' );
+
+ if ( selected.length === 0 || ( slides.length > 2 && selected.is( slides.first() ) ) ) {
+ return slides.last();
+ }
+
+ return selected.prev();
+ },
+
+ loadFullImage : function ( slide ) {
+ var image = slide.find( 'img:first' );
+
+ if ( ! image.data( 'loaded' ) ) {
+ // If the width of the slide is smaller than the width of the "thumbnail" we're already using,
+ // don't load the full image.
+
+ image.on( 'load.jetpack', function () {
+ image.off( 'load.jetpack' );
+ $( this ).closest( '.jp-carousel-slide' ).css( 'background-image', '' );
+ } );
+
+ if ( ! slide.data( 'preview-image' ) || ( slide.data( 'thumb-size' ) && slide.width() > slide.data( 'thumb-size' ).width ) ) {
+ image.attr( 'src', image.closest( '.jp-carousel-slide' ).data( 'src' ) );
+ } else {
+ image.attr( 'src', slide.data( 'preview-image' ) );
+ }
+
+ image.data( 'loaded', 1 );
+ }
}
};
@@ -1281,48 +1418,132 @@ jQuery(document).ready(function($) {
// register the event listener for starting the gallery
$( document.body ).on( 'click', 'div.gallery,div.tiled-gallery', function(e) {
- if ( ! $(this).jp_carousel( 'testForData', e.currentTarget ) )
+ if ( ! $(this).jp_carousel( 'testForData', e.currentTarget ) ) {
return;
- if ( $(e.target).parent().hasClass('gallery-caption') )
+ }
+ if ( $(e.target).parent().hasClass('gallery-caption') ) {
return;
+ }
e.preventDefault();
$(this).jp_carousel('open', {start_index: $(this).find('.gallery-item, .tiled-gallery-item').index($(e.target).parents('.gallery-item, .tiled-gallery-item'))});
});
- // Set an interval on page load to load the carousel if hash exists and not already opened.
// Makes carousel work on page load and when back button leads to same URL with carousel hash (ie: no actual document.ready trigger)
- $(document).ready(function(){
- last_known_location_hash = '';
+ $( window ).on( 'hashchange', function () {
+ var hashRegExp = /jp-carousel-(\d+)/,
+ matches, attachmentId, galleries, selectedThumbnail;
- var jp_carousel_open_interval = window.setInterval(function(){
- // We should have a URL hash by now.
- if ( ! document.location.hash || ! document.location.hash.match(/jp-carousel-(\d+)/) )
- return;
+ if ( ! window.location.hash || ! hashRegExp.test( window.location.hash ) ) {
+ return;
+ }
- if ( document.location.hash == last_known_location_hash )
- return;
+ if ( window.location.hash === last_known_location_hash ) {
+ return;
+ }
- last_known_location_hash = document.location.hash;
+ last_known_location_hash = window.location.hash;
+ matches = window.location.hash.match( hashRegExp );
+ attachmentId = parseInt( matches[1], 10 );
+ galleries = $( 'div.gallery, div.tiled-gallery' );
+
+ // Find the first thumbnail that matches the attachment ID in the location
+ // hash, then open the gallery that contains it.
+ galleries.each( function( _, galleryEl ) {
+ $( galleryEl ).find('img').each( function( imageIndex, imageEl ) {
+ if ( $( imageEl ).data( 'attachment-id' ) === parseInt( attachmentId, 10 ) ) {
+ selectedThumbnail = { index: imageIndex, gallery: galleryEl };
+ return false;
+ }
+ });
- var gallery = $('div.gallery, div.tiled-gallery'), index = -1, n = document.location.hash.match(/jp-carousel-(\d+)/);
+ if ( selectedThumbnail ) {
+ $( selectedThumbnail.gallery )
+ .jp_carousel( 'openOrSelectSlide', selectedThumbnail.index );
+ }
+ });
+ });
- if ( ! $(this).jp_carousel( 'testForData', gallery ) )
- return;
+ if ( window.location.hash ) {
+ $( window ).trigger( 'hashchange' );
+ }
+});
- n = parseInt(n[1], 10);
+/**
+ * jQuery Plugin to obtain touch gestures from iPhone, iPod Touch and iPad, should also work with Android mobile phones (not tested yet!)
+ * Common usage: wipe images (left and right to show the previous or next image)
+ *
+ * @author Andreas Waltl, netCU Internetagentur (http://www.netcu.de)
+ * Version 1.1.1, modified to pass the touchmove event to the callbacks.
+ */
+(function($) {
+$.fn.touchwipe = function(settings) {
+ var config = {
+ min_move_x: 20,
+ min_move_y: 20,
+ wipeLeft: function(/*e*/) { },
+ wipeRight: function(/*e*/) { },
+ wipeUp: function(/*e*/) { },
+ wipeDown: function(/*e*/) { },
+ preventDefaultEvents: true
+ };
- gallery.find('img').each(function(num, el){
- if ( n && $(el).data('attachment-id') == n ) { // n cannot be 0 (zero)
- index = num;
- return false;
+ if (settings) {
+ $.extend(config, settings);
+ }
+
+ this.each(function() {
+ var startX;
+ var startY;
+ var isMoving = false;
+
+ function cancelTouch() {
+ this.removeEventListener('touchmove', onTouchMove);
+ startX = null;
+ isMoving = false;
+ }
+
+ function onTouchMove(e) {
+ if(config.preventDefaultEvents) {
+ e.preventDefault();
+ }
+ if(isMoving) {
+ var x = e.touches[0].pageX;
+ var y = e.touches[0].pageY;
+ var dx = startX - x;
+ var dy = startY - y;
+ if(Math.abs(dx) >= config.min_move_x) {
+ cancelTouch();
+ if(dx > 0) {
+ config.wipeLeft(e);
+ } else {
+ config.wipeRight(e);
+ }
}
- });
+ else if(Math.abs(dy) >= config.min_move_y) {
+ cancelTouch();
+ if(dy > 0) {
+ config.wipeDown(e);
+ } else {
+ config.wipeUp(e);
+ }
+ }
+ }
+ }
- if ( index != -1 )
- gallery.jp_carousel('open', {start_index: index}); // open method checks if already opened
- }, 1000);
+ function onTouchStart(e)
+ {
+ if (e.touches.length === 1) {
+ startX = e.touches[0].pageX;
+ startY = e.touches[0].pageY;
+ isMoving = true;
+ this.addEventListener('touchmove', onTouchMove, false);
+ }
+ }
+ if ('ontouchstart' in document.documentElement) {
+ this.addEventListener('touchstart', onTouchStart, false);
+ }
});
-});
-// Swipe gesture detection
-(function($){$.fn.touchwipe=function(settings){var config={min_move_x:20,min_move_y:20,wipeLeft:function(){},wipeRight:function(){},wipeUp:function(){},wipeDown:function(){},preventDefaultEvents:true};if(settings)$.extend(config,settings);this.each(function(){var startX;var startY;var isMoving=false;function cancelTouch(){this.removeEventListener('touchmove',onTouchMove);startX=null;isMoving=false}function onTouchMove(e){if(config.preventDefaultEvents){e.preventDefault()}if(isMoving){var x=e.touches[0].pageX;var y=e.touches[0].pageY;var dx=startX-x;var dy=startY-y;if(Math.abs(dx)>=config.min_move_x){cancelTouch();if(dx>0){config.wipeLeft()}else{config.wipeRight()}}else if(Math.abs(dy)>=config.min_move_y){cancelTouch();if(dy>0){config.wipeDown()}else{config.wipeUp()}}}}function onTouchStart(e){if(e.touches.length==1){startX=e.touches[0].pageX;startY=e.touches[0].pageY;isMoving=true;this.addEventListener('touchmove',onTouchMove,false)}}if('ontouchstart'in document.documentElement){this.addEventListener('touchstart',onTouchStart,false)}});return this}})(jQuery);
+ return this;
+};
+})(jQuery);
diff --git a/plugins/jetpack/modules/carousel/jetpack-carousel.php b/plugins/jetpack/modules/carousel/jetpack-carousel.php
index f1d1babb..cfa2ec45 100644
--- a/plugins/jetpack/modules/carousel/jetpack-carousel.php
+++ b/plugins/jetpack/modules/carousel/jetpack-carousel.php
@@ -20,6 +20,8 @@ class Jetpack_Carousel {
var $first_run = true;
+ var $in_gallery = false;
+
var $in_jetpack = true;
function __construct() {
@@ -52,8 +54,9 @@ class Jetpack_Carousel {
// If on front-end, do the Carousel thang.
$this->prebuilt_widths = apply_filters( 'jp_carousel_widths', $this->prebuilt_widths );
add_filter( 'post_gallery', array( $this, 'enqueue_assets' ), 1000, 2 ); // load later than other callbacks hooked it
+ add_filter( 'post_gallery', array( $this, 'set_in_gallery' ), -1000 );
add_filter( 'gallery_style', array( $this, 'add_data_to_container' ) );
- add_filter( 'wp_get_attachment_link', array( $this, 'add_data_to_images' ), 10, 2 );
+ add_filter( 'wp_get_attachment_image_attributes', array( $this, 'add_data_to_images' ), 10, 2 );
}
if ( $this->in_jetpack && method_exists( 'Jetpack', 'module_configuration_load' ) ) {
@@ -79,14 +82,20 @@ class Jetpack_Carousel {
if ( ! empty( $output ) && ! apply_filters( 'jp_carousel_force_enable', false ) ) {
// Bail because someone is overriding the [gallery] shortcode.
remove_filter( 'gallery_style', array( $this, 'add_data_to_container' ) );
- remove_filter( 'wp_get_attachment_link', array( $this, 'add_data_to_images' ) );
+ remove_filter( 'wp_get_attachment_image_attributes', array( $this, 'add_data_to_images' ) );
return $output;
}
+ /**
+ * Fires when thumbnails are shown in Carousel.
+ *
+ * @since ?
+ * @module Carousel
+ **/
do_action( 'jp_carousel_thumbnails_shown' );
if ( $this->first_run ) {
- wp_enqueue_script( 'jetpack-carousel', plugins_url( 'jetpack-carousel.js', __FILE__ ), array( 'jquery.spin' ), $this->asset_version( '20130109' ), true );
+ wp_enqueue_script( 'jetpack-carousel', plugins_url( 'jetpack-carousel.js', __FILE__ ), array( 'jquery.spin' ), $this->asset_version( '20140505' ), true );
// Note: using home_url() instead of admin_url() for ajaxurl to be sure to get same domain on wpcom when using mapped domains (also works on self-hosted)
// Also: not hardcoding path since there is no guarantee site is running on site root in self-hosted context.
@@ -98,13 +107,14 @@ class Jetpack_Carousel {
'widths' => $this->prebuilt_widths,
'is_logged_in' => $is_logged_in,
'lang' => strtolower( substr( get_locale(), 0, 2 ) ),
- 'ajaxurl' => admin_url( 'admin-ajax.php', is_ssl() ? 'https' : 'http' ),
+ 'ajaxurl' => set_url_scheme( admin_url( 'admin-ajax.php' ) ),
'nonce' => wp_create_nonce( 'carousel_nonce' ),
'display_exif' => $this->test_1or0_option( get_option( 'carousel_display_exif' ), true ),
'display_geo' => $this->test_1or0_option( get_option( 'carousel_display_geo' ), true ),
'background_color' => $this->carousel_background_color_sanitize( get_option( 'carousel_background_color' ) ),
'comment' => __( 'Comment', 'jetpack' ),
'post_comment' => __( 'Post Comment', 'jetpack' ),
+ 'write_comment' => __( 'Write a Comment...', 'jetpack' ),
'loading_comments' => __( 'Loading Comments...', 'jetpack' ),
'download_original' => sprintf( __( 'View full size <span class="photo-size">%1$s<span class="photo-size-times">&times;</span>%2$s</span>', 'jetpack' ), '{0}', '{1}' ),
'no_comment_text' => __( 'Please be sure to submit some text with your comment.', 'jetpack' ),
@@ -145,15 +155,25 @@ class Jetpack_Carousel {
$localize_strings = apply_filters( 'jp_carousel_localize_strings', $localize_strings );
wp_localize_script( 'jetpack-carousel', 'jetpackCarouselStrings', $localize_strings );
- wp_enqueue_style( 'jetpack-carousel', plugins_url( 'jetpack-carousel.css', __FILE__ ), array(), $this->asset_version( '20120629' ) );
- global $is_IE;
- if( $is_IE )
- {
- $msie = strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE' ) + 4;
- $version = (float) substr( $_SERVER['HTTP_USER_AGENT'], $msie, strpos( $_SERVER['HTTP_USER_AGENT'], ';', $msie ) - $msie );
- if( $version < 9 )
- wp_enqueue_style( 'jetpack-carousel-ie8fix', plugins_url( 'jetpack-carousel-ie8fix.css', __FILE__ ), array(), $this->asset_version( '20121024' ) );
+ if( is_rtl() ) {
+ wp_enqueue_style( 'jetpack-carousel', plugins_url( '/rtl/jetpack-carousel-rtl.css', __FILE__ ), array(), $this->asset_version( '20120629' ) );
+ } else {
+ wp_enqueue_style( 'jetpack-carousel', plugins_url( 'jetpack-carousel.css', __FILE__ ), array(), $this->asset_version( '20120629' ) );
}
+
+ wp_register_style( 'jetpack-carousel-ie8fix', plugins_url( 'jetpack-carousel-ie8fix.css', __FILE__ ), array(), $this->asset_version( '20121024' ) );
+ $GLOBALS['wp_styles']->add_data( 'jetpack-carousel-ie8fix', 'conditional', 'lte IE 8' );
+ wp_enqueue_style( 'jetpack-carousel-ie8fix' );
+
+ /**
+ * Fires after carousel assets are enqueued for the first time.
+ * Allows for adding additional assets to the carousel page.
+ *
+ * @since ?
+ * @module Carousel
+ * @param boolean $first_run
+ * @param array $localized_strings
+ **/
do_action( 'jp_carousel_enqueue_assets', $this->first_run, $localize_strings );
$this->first_run = false;
@@ -162,11 +182,19 @@ class Jetpack_Carousel {
return $output;
}
- function add_data_to_images( $html, $attachment_id ) {
- if ( $this->first_run ) // not in a gallery
- return $html;
+ function set_in_gallery( $output ) {
+ $this->in_gallery = true;
+ return $output;
+ }
+
+ function add_data_to_images( $attr, $attachment = null ) {
+
+ // not in a gallery?
+ if ( ! $this->in_gallery ) {
+ return $attr;
+ }
- $attachment_id = intval( $attachment_id );
+ $attachment_id = intval( $attachment->ID );
$orig_file = wp_get_attachment_image_src( $attachment_id, 'full' );
$orig_file = isset( $orig_file[0] ) ? $orig_file[0] : wp_get_attachment_url( $attachment_id );
$meta = wp_get_attachment_metadata( $attachment_id );
@@ -174,7 +202,7 @@ class Jetpack_Carousel {
$img_meta = ( ! empty( $meta['image_meta'] ) ) ? (array) $meta['image_meta'] : array();
$comments_opened = intval( comments_open( $attachment_id ) );
- /*
+ /*
* Note: Cannot generate a filename from the width and height wp_get_attachment_image_src() returns because
* it takes the $content_width global variable themes can set in consideration, therefore returning sizes
* which when used to generate a filename will likely result in a 404 on the image.
@@ -209,26 +237,17 @@ class Jetpack_Carousel {
$img_meta = json_encode( array_map( 'strval', $img_meta ) );
- $html = str_replace(
- '<img ',
- sprintf(
- '<img data-attachment-id="%1$d" data-orig-file="%2$s" data-orig-size="%3$s" data-comments-opened="%4$s" data-image-meta="%5$s" data-image-title="%6$s" data-image-description="%7$s" data-medium-file="%8$s" data-large-file="%9$s" ',
- $attachment_id,
- esc_attr( $orig_file ),
- $size,
- $comments_opened,
- esc_attr( $img_meta ),
- esc_attr( $attachment_title ),
- esc_attr( $attachment_desc ),
- esc_attr( $medium_file ),
- esc_attr( $large_file )
- ),
- $html
- );
-
- $html = apply_filters( 'jp_carousel_add_data_to_images', $html, $attachment_id );
-
- return $html;
+ $attr['data-attachment-id'] = $attachment_id;
+ $attr['data-orig-file'] = esc_attr( $orig_file );
+ $attr['data-orig-size'] = $size;
+ $attr['data-comments-opened'] = $comments_opened;
+ $attr['data-image-meta'] = esc_attr( $img_meta );
+ $attr['data-image-title'] = esc_attr( $attachment_title );
+ $attr['data-image-description'] = esc_attr( $attachment_desc );
+ $attr['data-medium-file'] = esc_attr( $medium_file );
+ $attr['data-large-file'] = esc_attr( $large_file );
+
+ return $attr;
}
function add_data_to_container( $html ) {
@@ -264,6 +283,15 @@ class Jetpack_Carousel {
if ( ! headers_sent() )
header('Content-type: text/javascript');
+ /**
+ * Allows for the checking of privileges of the blog user before comments
+ * are packaged as JSON and sent back from the get_attachment_comments
+ * AJAX endpoint
+ *
+ * @duplicate yes
+ * @since ?
+ * @module Carousel
+ **/
do_action('jp_carousel_check_blog_user_privileges');
$attachment_id = ( isset( $_REQUEST['id'] ) ) ? (int) $_REQUEST['id'] : 0;
@@ -289,11 +317,14 @@ class Jetpack_Carousel {
// Can't just send the results, they contain the commenter's email address.
foreach ( $comments as $comment ) {
+ $avatar = get_avatar( $comment->comment_author_email, 64 );
+ if( ! $avatar )
+ $avatar = '';
$out[] = array(
'id' => $comment->comment_ID,
'parent_id' => $comment->comment_parent,
'author_markup' => get_comment_author_link( $comment->comment_ID ),
- 'gravatar_markup' => get_avatar( $comment->comment_author_email, 64 ),
+ 'gravatar_markup' => $avatar,
'date_gmt' => $comment->comment_date_gmt,
'content' => wpautop($comment->comment_content),
);
@@ -329,6 +360,11 @@ class Jetpack_Carousel {
$switched = true;
}
+ /**
+ * @duplicate yes
+ * @since ?
+ * @module Carousel
+ **/
do_action('jp_carousel_check_blog_user_privileges');
if ( ! comments_open( $_post_id ) )
@@ -376,6 +412,14 @@ class Jetpack_Carousel {
// Note: wp_new_comment() sanitizes and validates the values (too).
$comment_id = wp_new_comment( $comment_data );
+
+ /**
+ * Fires before adding a new comment to the database via the get_attachment_comments
+ * ajax endpoint
+ *
+ * @since ?
+ * @module Carousel
+ **/
do_action( 'jp_carousel_post_attachment_comment' );
$comment_status = wp_get_comment_status( $comment_id );
diff --git a/plugins/jetpack/modules/carousel/rtl/jetpack-carousel-rtl.css b/plugins/jetpack/modules/carousel/rtl/jetpack-carousel-rtl.css
index c34fcfba..373ee501 100644
--- a/plugins/jetpack/modules/carousel/rtl/jetpack-carousel-rtl.css
+++ b/plugins/jetpack/modules/carousel/rtl/jetpack-carousel-rtl.css
@@ -1,6 +1,6 @@
-/* This file was automatically generated on Apr 17 2013 14:28:54 */
+/* This file was automatically generated on Oct 06 2014 18:02:19 */
-* {
+.jp-carousel-wrap * {
line-height:inherit; /* prevent declarations of line-height in the universal selector */
}
@@ -58,12 +58,15 @@ only screen and (min-device-pixel-ratio: 1.5) {
.jp-carousel-photo-info {
position: relative;
+ right: 25%;
+ width: 50%;
+}
+
+.jp-carousel-transitions .jp-carousel-photo-info {
-webkit-transition: 400ms ease-out;
-moz-transition: 400ms ease-out;
-o-transition: 400ms ease-out;
transition: 400ms ease-out;
- right: 25%;
- width: 50%;
}
.jp-carousel-info h2 {
@@ -98,6 +101,10 @@ only screen and (min-device-pixel-ratio: 1.5) {
zoom: 1;
filter: alpha(opacity=20);
opacity: 0.2;
+}
+
+.jp-carousel-transitions .jp-carousel-next-button span,
+.jp-carousel-transitions .jp-carousel-previous-button span {
-webkit-transition: 500ms opacity ease-out;
-moz-transition: 500ms opacity ease-out;
-o-transition: 500ms opacity ease-out;
@@ -142,6 +149,9 @@ div.jp-carousel-buttons a {
div.jp-carousel-buttons a:hover {
color: #68c9e8;
border: none !important;
+}
+
+.jp-carousel-transitions div.jp-carousel-buttons a:hover {
-webkit-transition: none !important;
-moz-transition: none !important;
-o-transition: none !important;
@@ -157,7 +167,7 @@ div.jp-carousel-buttons a:hover {
}
.jp-carousel-slide {
- position:absolute;
+ position:fixed;
width:0;
bottom:0;
background-color:#000;
@@ -166,10 +176,24 @@ div.jp-carousel-buttons a:hover {
-moz-border-radius:2px;
-ms-border-radius:2px;
-o-border-radius:2px;
- -webkit-transition: 400ms ease-out;
- -moz-transition: 400ms ease-out;
- -o-transition: 400ms ease-out;
- transition: 400ms ease-out;
+}
+
+.jp-carousel-transitions .jp-carousel-slide {
+ -webkit-transition: 300ms ease-out;
+ -moz-transition: 300ms ease-out;
+ -o-transition: 300ms ease-out;
+ transition: 300ms ease-out;
+}
+
+.jp-carousel-slide.selected {
+ position: absolute !important;
+ filter: alpha(opacity=100);
+ opacity: 1;
+}
+
+.jp-carousel-slide {
+ filter: alpha(opacity=25);
+ opacity: 0.25;
}
.jp-carousel-slide img {
@@ -185,19 +209,15 @@ div.jp-carousel-buttons a:hover {
-moz-box-shadow: 0 2px 8px rgba(0,0,0,0.1);
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
zoom: 1;
- filter: alpha(opacity=25);
- opacity: 0.25;
+}
+
+.jp-carousel-transitions .jp-carousel-slide {
-webkit-transition: opacity 400ms linear;
-moz-transition: opacity 400ms linear;
-o-transition: opacity 400ms linear;
transition: opacity 400ms linear;
}
-.jp-carousel-slide.selected img {
- filter: alpha(opacity=100);
- opacity: 1;
-}
-
.jp-carousel-close-hint {
color: #999;
cursor: default;
@@ -206,6 +226,9 @@ div.jp-carousel-buttons a:hover {
position: absolute;
text-align: right;
width: 90%;
+}
+
+.jp-carousel-transitions .jp-carousel-close-hint {
-webkit-transition: color 200ms linear;
-moz-transition: color 200ms linear;
-o-transition: color 200ms linear;
@@ -227,6 +250,9 @@ div.jp-carousel-buttons a:hover {
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
+}
+
+.jp-carousel-transitions .jp-carousel-close-hint span {
-webkit-transition: border-color 200ms linear;
-moz-transition: border-color 200ms linear;
-o-transition: border-color 200ms linear;
@@ -246,41 +272,41 @@ div.jp-carousel-buttons a.jp-carousel-like,
div.jp-carousel-buttons a.jp-carousel-reblog,
div.jp-carousel-buttons a.jp-carousel-commentlink,
a.jp-carousel-image-download {
- background: url(.././images/carousel-sprite.png?4) no-repeat;
- background-size: 16px 160px;
+ background: url(.././images/carousel-sprite.png?5) no-repeat;
+ background-size: 16px 200px;
}
div.jp-carousel-buttons a.jp-carousel-reblog,
div.jp-carousel-buttons a.jp-carousel-commentlink {
- margin:0 0 0 14px !important;
+ margin: 0 0 0 14px !important;
}
div.jp-carousel-buttons a.jp-carousel-reblog.reblogged,
div.jp-carousel-buttons a.jp-carousel-like.liked {
background-color: #303030;
+ padding-right: auto;
padding-left: 8px !important;
border-radius: 2px;
- border-radius:2px;
- -webkit-border-radius:2px;
- -moz-border-radius:2px;
- -ms-border-radius:2px;
- -o-border-radius:2px;
+ border-radius: 2px;
+ -webkit-border-radius: 2px;
+ -moz-border-radius: 2px;
+ -ms-border-radius: 2px;
+ -o-border-radius: 2px;
}
div.jp-carousel-buttons a.jp-carousel-reblog.reblogged {
- margin:0 -12px 0 2px !important;
+ margin: 0 -12px 0 2px !important;
}
-
div.jp-carousel-buttons a.jp-carousel-reblog,
div.jp-carousel-buttons a.jp-carousel-reblog.reblogged:hover {
- background-position: 6px -36px;
+ background-position: 98% -36px;
padding-right: 26px !important;
color: #999;
}
div.jp-carousel-buttons a.jp-carousel-commentlink {
- background-position: 0px -116px;
+ background-position: 100% -156px;
padding-right: 19px !important;
}
@@ -289,7 +315,7 @@ div.jp-carousel-buttons a.jp-carousel-reblog.reblogged:hover {
}
div.jp-carousel-buttons a.jp-carousel-reblog:hover {
- background-position: 6px -56px;
+ background-position: 98% -56px;
color: #68c9e8;
}
@@ -311,7 +337,7 @@ only screen and (min-device-pixel-ratio: 1.5) {
div.jp-carousel-buttons a.jp-carousel-reblog,
div.jp-carousel-buttons a.jp-carousel-commentlink,
a.jp-carousel-image-download {
- background-image: url(.././images/carousel-sprite-2x.png?4);
+ background-image: url(.././images/carousel-sprite-2x.png?5);
}
}
@@ -548,7 +574,7 @@ a.jp-carousel-image-download {
font-weight: 400;
font-size: 13px;
text-decoration: none;
- background-position: 0 -82px;
+ background-position: 100% -82px;
}
a.jp-carousel-image-download span.photo-size {
@@ -563,7 +589,7 @@ a.jp-carousel-image-download span.photo-size-times {
}
a.jp-carousel-image-download:hover {
- background-position: 0 -102px;
+ background-position: 100% -122px;
color: #68c9e8;
border: none !important;
}
@@ -810,8 +836,8 @@ textarea#jp-carousel-comment-form-comment-field:focus::-webkit-input-placeholder
border-radius: 2px;
font: 13px/1.4 "Helvetica Neue", sans-serif !important;
border: 1px solid rgba( 255, 255, 255, 0.17 );
- -webkit-box-shadow: inset 0px 5px 5px 0px rgba(0, 0, 0, 1);
- box-shadow: inset 0px 5px 5px 0px rgba(0, 0, 0, 1);
+ -webkit-box-shadow: inset 0px 5px 5px 0px rgba(0, 0, 0, 1);
+ box-shadow: inset 0px 5px 5px 0px rgba(0, 0, 0, 1);
}
.jp-carousel-comment-post-error {
@@ -828,7 +854,7 @@ textarea#jp-carousel-comment-form-comment-field:focus::-webkit-input-placeholder
}
#jp-carousel-comments-loading {
- font: 444 15px/1.7 "Helvetica Neue", sans-serif !important;
+ font: 400 15px/1.7 "Helvetica Neue", sans-serif !important;
display: none;
color: #999;
text-align: right;
@@ -906,7 +932,7 @@ textarea#jp-carousel-comment-form-comment-field:focus::-webkit-input-placeholder
}
.jp-carousel-light div.jp-carousel-buttons a.jp-carousel-commentlink {
- background-position: 0px -136px;
+ background-position: 100% -176px;
}
.jp-carousel-light div.jp-carousel-buttons a.jp-carousel-like,
@@ -916,7 +942,7 @@ textarea#jp-carousel-comment-form-comment-field:focus::-webkit-input-placeholder
}
.jp-carousel-light div.jp-carousel-buttons a.jp-carousel-reblog.reblogged {
- background-position: 5px -36px;
+ background-position: 96% -36px;
}
.jp-carousel-light div.jp-carousel-buttons a.jp-carousel-like.liked {
@@ -996,11 +1022,11 @@ textarea#jp-carousel-comment-form-comment-field:focus::-webkit-input-placeholder
}
.jp-carousel-light a.jp-carousel-image-download {
- background-position: 0 -102px;
+ background-position: 100% -122px;
}
.jp-carousel-light a.jp-carousel-image-download:hover {
- background-position: 0 -102px;
+ background-position: 100% -122px;
color: #f1831e;
}
@@ -1028,8 +1054,8 @@ textarea#jp-carousel-comment-form-comment-field:focus::-webkit-input-placeholder
.jp-carousel-light #jp-carousel-comment-post-results span {
background: #f7f7f7;
border:1px solid #dfdfdf;
- -webkit-box-shadow: inset 0px 0px 5px rgba(0, 0, 0, 0.05);
- box-shadow: inset 0px 0px 5px rgba(0, 0, 0, 0.05);
+ -webkit-box-shadow: inset 0px 0px 5px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0px 0px 5px rgba(0, 0, 0, 0.05);
}
.jp-carousel-light .jp-carousel-slide {
@@ -1102,5 +1128,11 @@ textarea#jp-carousel-comment-form-comment-field:focus::-webkit-input-placeholder
.jp-carousel-left-column-wrapper {
padding: 0;
+ width: 100% !important;
+ }
+
+ .jp-carousel-photo-info {
+ right: 0 !important;
+ width: 100% !important;
}
}
diff --git a/plugins/jetpack/modules/comments.php b/plugins/jetpack/modules/comments.php
index 524db982..3b83acf3 100644
--- a/plugins/jetpack/modules/comments.php
+++ b/plugins/jetpack/modules/comments.php
@@ -2,11 +2,12 @@
/**
* Module Name: Jetpack Comments
- * Module Description: A new comment system that has integrated social media login options.
+ * Module Description: Let readers comment with WordPress.com, Twitter, Facebook, or Google+ accounts.
* First Introduced: 1.4
- * Sort Order: 2
+ * Sort Order: 20
* Requires Connection: Yes
* Auto Activate: No
+ * Module Tags: Social
*/
require dirname( __FILE__ ) . '/comments/comments.php';
@@ -35,3 +36,14 @@ function jetpack_comments_configuration_load() {
}
add_action( 'jetpack_modules_loaded', 'jetpack_comments_load' );
+
+Jetpack::dns_prefetch( array(
+ '//jetpack.wordpress.com',
+ '//s0.wp.com',
+ '//s1.wp.com',
+ '//s2.wp.com',
+ '//public-api.wordpress.com',
+ '//0.gravatar.com',
+ '//1.gravatar.com',
+ '//2.gravatar.com',
+) );
diff --git a/plugins/jetpack/modules/comments/base.php b/plugins/jetpack/modules/comments/base.php
index 93e59f00..92b4320b 100644
--- a/plugins/jetpack/modules/comments/base.php
+++ b/plugins/jetpack/modules/comments/base.php
@@ -270,6 +270,13 @@ class Highlander_Comments_Base {
// Set comment author cookies
if ( ( 'wordpress' != $id_source ) && is_user_logged_in() ) {
+ /**
+ * Changes the duration of a cookie.
+ *
+ * @since 1.4.0
+ *
+ * @param int comment_cookie_lifetime Cookie lifteime, default is 30000000 seconds (just over a year).
+ */
$comment_cookie_lifetime = apply_filters( 'comment_cookie_lifetime', 30000000 );
setcookie( 'comment_author_' . COOKIEHASH, $comment->comment_author, time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN );
setcookie( 'comment_author_email_' . COOKIEHASH, $comment->comment_author_email, time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN );
diff --git a/plugins/jetpack/modules/comments/comments.php b/plugins/jetpack/modules/comments/comments.php
index ad2d50b7..d4744560 100644
--- a/plugins/jetpack/modules/comments/comments.php
+++ b/plugins/jetpack/modules/comments/comments.php
@@ -53,6 +53,14 @@ class Jetpack_Comments extends Highlander_Comments_Base {
parent::__construct();
// Jetpack Comments is loaded
+
+ /**
+ * Fires after the Jetpack_Comments object has been instantiated
+ *
+ * @since 1.4.0
+ *
+ * @param array $jetpack_comments_loaded First element in array of type Jetpack_Comments
+ **/
do_action_ref_array( 'jetpack_comments_loaded', array( $this ) );
add_action( 'after_setup_theme', array( $this, 'set_default_color_theme_based_on_theme_settings' ), 100 );
}
@@ -172,7 +180,7 @@ class Jetpack_Comments extends Highlander_Comments_Base {
}
/**
- * Noop teh default comment form output, get some options, and output our
+ * Noop the default comment form output, get some options, and output our
* tricked out totally radical comment form.
*
* @since JetpackComments (1.4)
@@ -184,6 +192,13 @@ class Jetpack_Comments extends Highlander_Comments_Base {
// If users are required to be logged in, and they're not, then we don't need to do anything else
if ( get_option( 'comment_registration' ) && !is_user_logged_in() ) {
+ /**
+ * Changes the log in to comment prompt.
+ *
+ * @since 1.4.0
+ *
+ * @param string $var Default is "You must log in to post a comment."
+ */
echo '<p class="must-log-in">' . sprintf( apply_filters( 'jetpack_must_log_in_to_comment', __( 'You must <a href="%s">log in</a> to post a comment.', 'jetpack' ) ), wp_login_url( get_permalink() . '#respond' ) ) . '</p>';
return;
}
@@ -209,6 +224,13 @@ class Jetpack_Comments extends Highlander_Comments_Base {
'show_avatars' => ( get_option( 'show_avatars' ) ? '1' : '0' ),
'avatar_default' => get_option( 'avatar_default' ),
'greeting' => get_option( 'highlander_comment_form_prompt', __( 'Leave a Reply', 'jetpack' ) ),
+ /**
+ * Changes the comment form prompt.
+ *
+ * @since 2.3.0
+ *
+ * @param string $var Default is "Leave a Reply to %s."
+ */
'greeting_reply' => apply_filters( 'jetpack_comment_form_prompt_reply', __( 'Leave a Reply to %s' , 'jetpack' ) ),
'color_scheme' => get_option( 'jetpack_comment_form_color_scheme', $this->default_color_scheme ),
'lang' => get_bloginfo( 'language' ),
@@ -233,9 +255,9 @@ class Jetpack_Comments extends Highlander_Comments_Base {
}
$params['sig'] = $signature;
- $url_origin = ( is_ssl() ? 'https' : 'http' ) . '://jetpack.wordpress.com';
+ $url_origin = set_url_scheme( 'http://jetpack.wordpress.com' );
$url = "{$url_origin}/jetpack-comment/?" . http_build_query( $params );
- $url = "{$url}#parent=" . urlencode( ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
+ $url = "{$url}#parent=" . urlencode( set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ) );
$this->signed_url = $url;
$height = $params['comment_registration'] || is_user_logged_in() ? '315' : '430'; // Iframe can be shorter if we're not allowing guest commenting
$transparent = ( $params['color_scheme'] == 'transparent' ) ? 'true' : 'false';
@@ -267,7 +289,7 @@ class Jetpack_Comments extends Highlander_Comments_Base {
* @since JetpackComments (1.4)
*/
public function watch_comment_parent() {
- $url_origin = ( is_ssl() ? 'https' : 'http' ) . '://jetpack.wordpress.com';
+ $url_origin = set_url_scheme( 'http://jetpack.wordpress.com' );
?>
<!--[if IE]>
@@ -286,9 +308,9 @@ class Jetpack_Comments extends Highlander_Comments_Base {
tellFrameNewParent = function() {
if ( comm_par ) {
- frame.src = <?php echo json_encode( esc_url_raw( $this->signed_url ) ); ?> + '&replytocom=' + parseInt( comm_par, 10 ).toString();
+ frame.src = "<?php echo esc_url_raw( $this->signed_url ); ?>" + '&replytocom=' + parseInt( comm_par, 10 ).toString();
} else {
- frame.src = <?php echo json_encode( esc_url_raw( $this->signed_url ) ); ?>;
+ frame.src = "<?php echo esc_url_raw( $this->signed_url ); ?>";
}
};
@@ -496,7 +518,7 @@ h1 span {
</style>
</head>
<body>
- <h1><?php printf( __( 'Submitting Comment%s', 'jetpack' ), '<span id="ellipsis" class="hidden">&hellip;</span>' ); ?></h1>
+ <h1><?php printf( __( 'Submitting Comment%s', 'jetpack' ), '<span id="ellipsis" class="hidden">&hellip;</span>' ); ?></h1>
<script type="text/javascript">
try {
window.parent.location = <?php echo json_encode( $url ); ?>;
@@ -507,7 +529,7 @@ try {
}
ellipsis = document.getElementById( 'ellipsis' );
function toggleEllipsis() {
- ellipsis.className = ellipsis.className ? '' : 'hidden';
+ ellipsis.className = ellipsis.className ? '' : 'hidden';
}
setInterval( toggleEllipsis, 1200 );
</script>
diff --git a/plugins/jetpack/modules/contact-form.php b/plugins/jetpack/modules/contact-form.php
index 64c5600f..88abf0dd 100644
--- a/plugins/jetpack/modules/contact-form.php
+++ b/plugins/jetpack/modules/contact-form.php
@@ -1,11 +1,15 @@
<?php
/**
* Module Name: Contact Form
- * Module Description: Easily insert a contact form anywhere on your site.
- * Sort Order: 9
+ * Module Description: Insert a contact form anywhere on your site.
+ * Jumpstart Description: adds a button to your post and page editors, allowing you to build simple forms to help visitors stay in touch.
+ * Sort Order: 15
+ * Recommendation Order: 14
* First Introduced: 1.3
* Requires Connection: No
* Auto Activate: Yes
+ * Module Tags: Other
+ * Feature: Jumpstart
*/
include dirname( __FILE__ ) . '/contact-form/grunion-contact-form.php';
diff --git a/plugins/jetpack/modules/contact-form/admin.php b/plugins/jetpack/modules/contact-form/admin.php
index 96d49ed3..78452c17 100644
--- a/plugins/jetpack/modules/contact-form/admin.php
+++ b/plugins/jetpack/modules/contact-form/admin.php
@@ -1,7 +1,11 @@
<?php
function grunion_menu_alter() {
- wp_enqueue_style( 'grunion-menu-alter', plugins_url( 'css/menu-alter.css', __FILE__ ) );
+ if( is_rtl() ){
+ wp_enqueue_style( 'grunion-menu-alter', plugins_url( 'css/rtl/menu-alter-rtl.css', __FILE__ ) );
+ } else {
+ wp_enqueue_style( 'grunion-menu-alter', plugins_url( 'css/menu-alter.css', __FILE__ ) );
+ }
}
add_action( 'admin_enqueue_scripts', 'grunion_menu_alter' );
@@ -11,23 +15,28 @@ add_action( 'admin_enqueue_scripts', 'grunion_menu_alter' );
*/
add_action( 'media_buttons', 'grunion_media_button', 999 );
function grunion_media_button( ) {
- global $post_ID, $temp_ID;
+ global $post_ID, $temp_ID, $pagenow;
+
+ if ( 'press-this.php' === $pagenow ) {
+ return;
+ }
+
$iframe_post_id = (int) (0 == $post_ID ? $temp_ID : $post_ID);
- $title = esc_attr( __( 'Add a custom form', 'jetpack' ) );
+ $title = __( 'Add Contact Form', 'jetpack' );
$plugin_url = esc_url( GRUNION_PLUGIN_URL );
$site_url = esc_url( admin_url( "/admin-ajax.php?post_id={$iframe_post_id}&action=grunion_form_builder&TB_iframe=true&width=768" ) );
?>
- <a id="insert-jetpack-contact-form" class="button thickbox" title="<?php esc_html_e( 'Add Contact Form', 'jetpack' ); ?>" data-editor="content" href="<?php echo $site_url ?>&id=add_form">
- <span class="jetpack-contact-form-icon"></span> <?php esc_html_e( 'Add Contact Form', 'jetpack' ); ?>
+ <a id="insert-jetpack-contact-form" class="button thickbox" title="<?php echo esc_attr( $title ); ?>" data-editor="content" href="<?php echo $site_url ?>&id=add_form">
+ <span class="jetpack-contact-form-icon"></span> <?php echo esc_html( $title ); ?>
</a>
<?php
}
-add_action( 'wp_ajax_grunion_form_builder', 'display_form_view' );
+add_action( 'wp_ajax_grunion_form_builder', 'grunion_display_form_view' );
-function display_form_view() {
+function grunion_display_form_view() {
require_once GRUNION_PLUGIN_DIR . 'grunion-form-view.php';
exit;
}
@@ -74,7 +83,7 @@ color: #D98500;
#icon-edit.icon32-posts-feedback, #icon-post.icon32-posts-feedback { background: url("<?php echo GRUNION_PLUGIN_URL; ?>images/grunion-menu-big.png") no-repeat !important; }
@media only screen and (-moz-min-device-pixel-ratio: 1.5), only screen and (-o-min-device-pixel-ratio: 3/2), only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-device-pixel-ratio: 1.5) {
- #icon-edit.icon32-posts-feedback, #icon-post.icon32-posts-feedback { background: url("<?php echo GRUNION_PLUGIN_URL; ?>images/grunion-menu-big-2x.png") no-repeat !important; background-size: 30px 31px !important; }
+ #icon-edit.icon32-posts-feedback, #icon-post.icon32-posts-feedback { background: url("<?php echo GRUNION_PLUGIN_URL; ?>images/grunion-menu-big-2x.png") no-repeat !important; background-size: 30px 31px !important; }
}
#icon-edit.icon32-posts-feedback { background-position: 2px 2px !important; }
@@ -85,7 +94,9 @@ color: #D98500;
}
/**
- * Hack a 'Bulk Spam' option for bulk edit
+ * Hack a 'Bulk Spam' option for bulk edit in other than spam view
+ * Hack a 'Bulk Delete' option for bulk edit in spam view
+ *
* There isn't a better way to do this until
* http://core.trac.wordpress.org/changeset/17297 is resolved
*/
@@ -94,15 +105,59 @@ function grunion_add_bulk_edit_option() {
$screen = get_current_screen();
+ if ( 'edit-feedback' != $screen->id ) {
+ return;
+ }
+
+ // When viewing spam we want to be able to be able to bulk delete
+ // When viewing anything we want to be able to bulk move to spam
+ if ( isset( $_GET['post_status'] ) && 'spam' == $_GET['post_status'] ) {
+ // Create Delete Permanently bulk item
+ $option_val = 'delete';
+ $option_txt = __( 'Delete Permanently', 'jetpack' );
+ $pseudo_selector = 'last-child';
+
+ } else {
+ // Create Mark Spam bulk item
+ $option_val = 'spam';
+ $option_txt = __( 'Mark as Spam', 'jetpack' );
+ $pseudo_selector = 'first-child';
+ }
+
+ ?>
+ <script type="text/javascript">
+ jQuery(document).ready(function($) {
+ $('#posts-filter .actions select').filter('[name=action], [name=action2]').find('option:<?php echo $pseudo_selector; ?>').after('<option value="<?php echo $option_val; ?>"><?php echo esc_attr( $option_txt ); ?></option>' );
+ })
+ </script>
+ <?php
+}
+
+/**
+ * Hack an 'Empty Spam' button to spam view
+ *
+ * Leverages core's delete_all functionality
+ */
+add_action( 'admin_head', 'grunion_add_empty_spam_button' );
+function grunion_add_empty_spam_button() {
+ $screen = get_current_screen();
+
+ // Only add to feedback, only to spam view
if ( 'edit-feedback' != $screen->id
- || ( ! empty( $_GET['post_status'] ) && 'spam' == $_GET['post_status'] ) )
+ || empty( $_GET['post_status'] )
+ || 'spam' !== $_GET['post_status'] ) {
return;
+ }
+
+ // Get HTML for the button
+ $button_html = wp_nonce_field( 'bulk-destroy', '_destroy_nonce', true, false );
+ $button_html .= get_submit_button( __( 'Empty Spam', 'jetpack' ), 'apply', 'delete_all', false );
- $spam_text = __( 'Mark Spam', 'jetpack' );
+ // Add the button next to the filter button via js
?>
<script type="text/javascript">
jQuery(document).ready(function($) {
- $('#posts-filter .actions select[name=action] option:first-child').after('<option value="spam"><?php echo esc_attr( $spam_text ); ?></option>' );
+ $('#posts-filter #post-query-submit').after('<?php echo $button_html; ?>' );
})
</script>
<?php
@@ -123,8 +178,9 @@ function grunion_handle_bulk_spam() {
if ( ! empty( $_REQUEST['message'] ) && 'marked-spam' == $_REQUEST['message'] )
add_action( 'admin_notices', 'grunion_message_bulk_spam' );
- if ( empty( $_REQUEST['action'] ) || 'spam' != $_REQUEST['action'] )
+ if ( ( empty( $_REQUEST['action'] ) || 'spam' != $_REQUEST['action'] ) && ( empty( $_REQUEST['action2'] ) || 'spam' != $_REQUEST['action2'] ) ) {
return;
+ }
check_admin_referer('bulk-posts');
@@ -145,6 +201,16 @@ function grunion_handle_bulk_spam() {
);
$akismet_values = get_post_meta( $post_id, '_feedback_akismet_values', true );
wp_update_post( $post );
+
+ /**
+ * Fires after a comment has been marked by Akismet. Typically this
+ * means the comment is spam.
+ *
+ * @duplicate yes
+ * @since ?
+ * @param string $comment_status Usually 'spam'
+ * @param array $akismet_values From '_feedback_akismet_values' in comment meta
+ **/
do_action( 'contact_form_akismet', 'spam', $akismet_values );
}
@@ -184,7 +250,7 @@ function grunion_admin_view_tabs( $views ) {
preg_match( '|post_type=feedback\'( class="current")?\>(.*)\<span class=|', $views['all'], $match );
if ( !empty( $match[2] ) )
- $views['all'] = str_replace( $match[2], 'Messages ', $views['all'] );
+ $views['all'] = str_replace( $match[2], __( 'Messages', 'jetpack' ) . ' ', $views['all'] );
return $views;
}
@@ -205,13 +271,22 @@ add_action( 'manage_posts_custom_column', 'grunion_manage_post_columns', 10, 2 )
function grunion_manage_post_columns( $col, $post_id ) {
global $post;
+ /**
+ * Only call parse_fields_from_content if we're dealing with a Grunion custom column.
+ */
+ if ( ! in_array( $col, array( 'feedback_date', 'feedback_from', 'feedback_message' ) ) ) {
+ return;
+ }
+
+ $content_fields = Grunion_Contact_Form_Plugin::parse_fields_from_content( $post_id );
+
switch ( $col ) {
case 'feedback_from':
- $author_name = get_post_meta( $post_id, '_feedback_author', TRUE );
- $author_email = get_post_meta( $post_id, '_feedback_author_email', TRUE );
- $author_url = get_post_meta( $post_id, '_feedback_author_url', TRUE );
- $author_ip = get_post_meta( $post_id, '_feedback_ip', TRUE );
- $form_url = get_post_meta( $post_id, '_feedback_contact_form_url', TRUE );
+ $author_name = $content_fields['_feedback_author'];
+ $author_email = $content_fields['_feedback_author_email'];
+ $author_url = $content_fields['_feedback_author_url'];
+ $author_ip = $content_fields['_feedback_ip'];
+ $form_url = isset( $post->post_parent ) ? get_permalink( $post->post_parent ) : null;
$author_name_line = '';
if ( !empty( $author_name ) ) {
@@ -239,14 +314,15 @@ function grunion_manage_post_columns( $col, $post_id ) {
echo $author_url_line;
echo "<a href='edit.php?post_type=feedback&s={$author_ip}";
echo "&mode=detail'>{$author_ip}</a><br />";
- echo "<a href='{$form_url}'>{$form_url}</a>";
+ if ( $form_url ) {
+ echo '<a href="' . esc_url( $form_url ) . '">' . esc_html( $form_url ) . '</a>';
+ }
break;
case 'feedback_message':
- $post = get_post( $post_id );
$post_type_object = get_post_type_object( $post->post_type );
echo '<strong>';
- echo esc_html( get_post_meta( $post_id, '_feedback_subject', TRUE ) );
+ echo esc_html( $content_fields['_feedback_subject'] );
echo '</strong><br />';
echo sanitize_text_field( get_the_content( '' ) );
echo '<br />';
@@ -256,7 +332,8 @@ function grunion_manage_post_columns( $col, $post_id ) {
echo '<br /><hr />';
echo '<table cellspacing="0" cellpadding="0" style="">' . "\n";
foreach ( (array) $extra_fields as $k => $v ) {
- echo "<tr><td align='right'><b>". esc_html( $k ) ."</b></td><td>". sanitize_text_field( $v ) ."</td></tr>\n";
+ // Remove prefix from exta fields
+ echo "<tr><td align='right'><b>". esc_html( preg_replace( '#^\d+_#', '', $k ) ) ."</b></td><td>". sanitize_text_field( $v ) ."</td></tr>\n";
}
echo '</table>';
}
@@ -482,7 +559,7 @@ function grunion_ajax_shortcode_to_json() {
$content = stripslashes( $_POST['content'] );
// doesn't look like a post with a [contact-form] already.
- if ( false === strpos( $content, '[contact-form' ) ) {
+ if ( false === has_shortcode( $content, 'contact-form' ) ) {
die( '' );
}
@@ -548,21 +625,69 @@ function grunion_ajax_spam() {
$post = get_post( $post_id );
$post_type_object = get_post_type_object( $post->post_type );
- $akismet_values = get_post_meta( $post_id, '_feedback_akismet_values', TRUE );
+ $akismet_values = get_post_meta( $post_id, '_feedback_akismet_values', TRUE );
if ( $_POST['make_it'] == 'spam' ) {
$post->post_status = 'spam';
$status = wp_insert_post( $post );
wp_transition_post_status( 'spam', 'publish', $post );
+
+ /**
+ * @duplicate yes
+ * @since ?
+ * @param string $comment_status Usually 'spam'
+ * @param array $akismet_values From '_feedback_akismet_values' in comment meta
+ **/
do_action( 'contact_form_akismet', 'spam', $akismet_values );
} elseif ( $_POST['make_it'] == 'ham' ) {
$post->post_status = 'publish';
$status = wp_insert_post( $post );
wp_transition_post_status( 'publish', 'spam', $post );
+
+ /**
+ * @duplicate yes
+ * @since ?
+ * @param string $comment_status Usually 'spam'
+ * @param array $akismet_values From '_feedback_akismet_values' in comment meta
+ **/
do_action( 'contact_form_akismet', 'spam', $akismet_values );
+ $comment_author_email = $reply_to_addr = $message = $to = $headers = false;
+ $blog_url = parse_url( site_url() );
+
// resend the original email
$email = get_post_meta( $post_id, '_feedback_email', TRUE );
- wp_mail( $email['to'], $email['subject'], $email['message'], $email['headers'] );
+ $content_fields = Grunion_Contact_Form_Plugin::parse_fields_from_content( $post_id );
+
+ if ( !empty( $email ) && !empty( $content_fields ) ) {
+ if ( isset( $content_fields['_feedback_author_email'] ) )
+ $comment_author_email = $content_fields['_feedback_author_email'];
+
+ if ( isset( $email['to'] ) )
+ $to = $email['to'];
+
+ if ( isset( $email['message'] ) )
+ $message = $email['message'];
+
+ if ( isset( $email['headers'] ) )
+ $headers = $email['headers'];
+ else {
+ $headers = 'From: "' . $content_fields['_feedback_author'] .'" <wordpress@' . $blog_url['host'] . ">\r\n";
+
+ if ( !empty( $comment_author_email ) )
+ $reply_to_addr = $comment_author_email;
+ elseif ( is_array( $to ) )
+ $reply_to_addr = $to[0];
+
+ if ( $reply_to_addr )
+ $headers .= 'Reply-To: "' . $content_fields['_feedback_author'] .'" <' . $reply_to_addr . ">\r\n";
+
+ $headers .= "Content-Type: text/plain; charset=\"" . get_option('blog_charset') . "\"";
+ }
+
+ $subject = apply_filters( 'contact_form_subject', $content_fields['_feedback_subject'], $content_fields['_feedback_all_fields'] );
+
+ wp_mail( $to, $subject, $message, $headers );
+ }
} elseif( $_POST['make_it'] == 'publish' ) {
if ( !current_user_can($post_type_object->cap->delete_post, $post_id) )
wp_die( __( 'You are not allowed to move this item out of the Trash.', 'jetpack' ) );
@@ -639,3 +764,86 @@ function grunion_omnisearch_add_providers() {
new Jetpack_Omnisearch_Grunion;
}
}
+
+/**
+ * Add the scripts that will add the "Check for Spam" button to the Feedbacks dashboard page.
+ */
+function grunion_enable_spam_recheck() {
+ if ( ! defined( 'AKISMET_VERSION' ) ) {
+ return;
+ }
+
+ $screen = get_current_screen();
+
+ // Only add to feedback, only to non-spam view
+ if ( 'edit-feedback' != $screen->id || ( ! empty( $_GET['post_status'] ) && 'spam' == $_GET['post_status'] ) ) {
+ return;
+ }
+
+ // Add the scripts that handle the spam check event.
+ wp_register_script( 'grunion-admin', plugin_dir_url( __FILE__ ) . 'js/grunion-admin.js', array( 'jquery' ) );
+ wp_enqueue_script( 'grunion-admin' );
+
+ wp_enqueue_style( 'grunion.css' );
+
+ // Add the actual "Check for Spam" button.
+ add_action( 'admin_head', 'grunion_check_for_spam_button' );
+}
+
+add_action( 'admin_enqueue_scripts', 'grunion_enable_spam_recheck' );
+
+/**
+ * Add the "Check for Spam" button to the Feedbacks dashboard page.
+ */
+function grunion_check_for_spam_button() {
+ // Get HTML for the button
+ $button_html = get_submit_button(
+ __( 'Check for Spam', 'jetpack' ),
+ 'secondary',
+ 'jetpack-check-feedback-spam',
+ false,
+ array( 'class' => 'jetpack-check-feedback-spam' )
+ );
+ $button_html .= '<span class="jetpack-check-feedback-spam-spinner"></span>';
+
+ // Add the button next to the filter button via js
+ ?>
+ <script type="text/javascript">
+ jQuery( function( $ ) {
+ $( '#posts-filter #post-query-submit' ).after( '<?php echo $button_html; ?>' );
+ } );
+ </script>
+ <?php
+}
+
+/**
+ * Recheck all approved feedbacks for spam.
+ */
+function grunion_recheck_queue() {
+ global $wpdb;
+
+ $query = 'post_type=feedback&post_status=publish';
+
+ if ( isset( $_POST['limit'], $_POST['offset'] ) ) {
+ $query .= '&posts_per_page=' . intval( $_POST['limit'] ) . '&offset=' . intval( $_POST['offset'] );
+ }
+
+ $approved_feedbacks = get_posts( $query );
+
+ foreach ( $approved_feedbacks as $feedback ) {
+ $meta = get_post_meta( $feedback->ID, '_feedback_akismet_values', true );
+
+ $is_spam = apply_filters( 'jetpack_contact_form_is_spam', false, $meta );
+
+ if ( $is_spam ) {
+ wp_update_post( array( 'ID' => $feedback->ID, 'post_status' => 'spam' ) );
+ do_action( 'contact_form_akismet', 'spam', $akismet_values );
+ }
+ }
+
+ wp_send_json( array(
+ 'processed' => count( $approved_feedbacks ),
+ ) );
+}
+
+add_action( 'wp_ajax_grunion_recheck_queue', 'grunion_recheck_queue' );
diff --git a/plugins/jetpack/modules/contact-form/css/grunion.css b/plugins/jetpack/modules/contact-form/css/grunion.css
index d47948b4..6d0ea277 100644
--- a/plugins/jetpack/modules/contact-form/css/grunion.css
+++ b/plugins/jetpack/modules/contact-form/css/grunion.css
@@ -7,4 +7,6 @@
.contact-form label.checkbox, .contact-form label.radio { margin-bottom: 3px; float: none; font-weight: bold; display: inline-block; }
.contact-form label span { color: #AAA; margin-left: 4px; font-weight: normal; }
.form-errors .form-error-message { color: red; }
-.textwidget input[type='text'], .textwidget input[type='email'], .textwidget textarea { width: 250px; max-width: 98%; }
+.textwidget .contact-form input[type='text'], .textwidget .contact-form input[type='email'], .textwidget .contact-form textarea { width: 250px; max-width: 100%; box-sizing: border-box; }
+#jetpack-check-feedback-spam { margin: 1px 8px 0px 0px; }
+.jetpack-check-feedback-spam-spinner { display: inline-block; margin-top: 7px; }
diff --git a/plugins/jetpack/modules/contact-form/css/menu-alter-rtl.css b/plugins/jetpack/modules/contact-form/css/menu-alter-rtl.css
new file mode 100644
index 00000000..161313b1
--- /dev/null
+++ b/plugins/jetpack/modules/contact-form/css/menu-alter-rtl.css
@@ -0,0 +1,73 @@
+#menu-posts-feedback .wp-menu-image img {
+ display: none;
+}
+
+#adminmenu .menu-icon-feedback div.wp-menu-image {
+ background: none !important;
+}
+
+#adminmenu .menu-icon-feedback div.wp-menu-image:before {
+ content: '\f175';
+ margin-right: -1px;
+}
+
+.jetpack-contact-form-icon:before {
+ content: '\f175';
+ color: #888;
+ vertical-align: text-bottom;
+ font: normal 18px/1 'dashicons';
+ speak: none;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.pre-mp6 #adminmenu .menu-icon-feedback:hover div.wp-menu-image,
+.pre-mp6 #adminmenu .menu-icon-feedback.wp-has-current-submenu div.wp-menu-image,
+.pre-mp6 #adminmenu .menu-icon-feedback.current div.wp-menu-image {
+ background: url(../images/grunion-menu-hover.png) no-repeat 7px 7px !important;
+ background-size: 15px 16px !important;
+}
+
+.pre-mp6 #adminmenu .menu-icon-feedback div.wp-menu-image {
+ background: url(../images/grunion-menu.png) no-repeat 7px 7px !important;
+ background-size: 15px 16px !important;
+}
+
+.pre-mp6 #adminmenu .menu-icon-feedback div.wp-menu-image:before {
+ display: none;
+}
+
+.pre-mp6 .jetpack-contact-form-icon {
+ background: url(../images/grunion-form.png) no-repeat;
+ width: 16px;
+ height: 16px;
+ display: inline-block;
+ vertical-align: middle;
+ background-size: 13px 12px !important;
+}
+
+.pre-mp6 .jetpack-contact-form-icon:before {
+ display: none;
+}
+
+@media only screen and (-moz-min-device-pixel-ratio: 1.5),
+ only screen and (-o-min-device-pixel-ratio: 3/2),
+ only screen and (-webkit-min-device-pixel-ratio: 1.5),
+ only screen and (min-device-pixel-ratio: 1.5) {
+
+ .pre-mp6 #adminmenu .menu-icon-feedback:hover div.wp-menu-image,
+ .pre-mp6 #adminmenu .menu-icon-feedback.wp-has-current-submenu div.wp-menu-image,
+ .pre-mp6 #adminmenu .menu-icon-feedback.current div.wp-menu-image {
+ background-image: url(../images/grunion-menu-hover-2x.png);
+ }
+
+ .pre-mp6 #adminmenu .menu-icon-feedback div.wp-menu-image {
+ background-image: url(../images/grunion-menu-2x.png);
+ }
+
+ .pre-mp6 .jetpack-contact-form-icon {
+ background-image: url(../images/grunion-form-2x.png);
+ vertical-align: bottom;
+ }
+
+}
diff --git a/plugins/jetpack/modules/contact-form/css/menu-alter-rtl.min.css b/plugins/jetpack/modules/contact-form/css/menu-alter-rtl.min.css
new file mode 100644
index 00000000..afd563d1
--- /dev/null
+++ b/plugins/jetpack/modules/contact-form/css/menu-alter-rtl.min.css
@@ -0,0 +1 @@
+#menu-posts-feedback .wp-menu-image img{display:none}#adminmenu .menu-icon-feedback div.wp-menu-image{background:none!important}#adminmenu .menu-icon-feedback div.wp-menu-image:before{content:'\f175';margin-right:-1px}.jetpack-contact-form-icon:before{content:'\f175';color:#888;vertical-align:text-bottom;font:400 18px/1 dashicons;speak:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.pre-mp6 #adminmenu .menu-icon-feedback.current div.wp-menu-image,.pre-mp6 #adminmenu .menu-icon-feedback.wp-has-current-submenu div.wp-menu-image,.pre-mp6 #adminmenu .menu-icon-feedback:hover div.wp-menu-image{background:url(../images/grunion-menu-hover.png) 7px 7px/15px 16px no-repeat!important}.pre-mp6 #adminmenu .menu-icon-feedback div.wp-menu-image{background:url(../images/grunion-menu.png) 7px 7px/15px 16px no-repeat!important}.pre-mp6 #adminmenu .menu-icon-feedback div.wp-menu-image:before{display:none}.pre-mp6 .jetpack-contact-form-icon{background:url(../images/grunion-form.png) no-repeat;width:16px;height:16px;display:inline-block;vertical-align:middle;background-size:13px 12px!important}.pre-mp6 .jetpack-contact-form-icon:before{display:none}@media only screen and (-moz-min-device-pixel-ratio:1.5),only screen and (-o-min-device-pixel-ratio:3/2),only screen and (-webkit-min-device-pixel-ratio:1.5),only screen and (min-device-pixel-ratio:1.5){.pre-mp6 #adminmenu .menu-icon-feedback.current div.wp-menu-image,.pre-mp6 #adminmenu .menu-icon-feedback.wp-has-current-submenu div.wp-menu-image,.pre-mp6 #adminmenu .menu-icon-feedback:hover div.wp-menu-image{background-image:url(../images/grunion-menu-hover-2x.png)}.pre-mp6 #adminmenu .menu-icon-feedback div.wp-menu-image{background-image:url(../images/grunion-menu-2x.png)}.pre-mp6 .jetpack-contact-form-icon{background-image:url(../images/grunion-form-2x.png);vertical-align:bottom}} \ No newline at end of file
diff --git a/plugins/jetpack/modules/contact-form/css/menu-alter.css b/plugins/jetpack/modules/contact-form/css/menu-alter.css
index 1ba4a609..46c1d506 100644
--- a/plugins/jetpack/modules/contact-form/css/menu-alter.css
+++ b/plugins/jetpack/modules/contact-form/css/menu-alter.css
@@ -2,31 +2,52 @@
display: none;
}
-#adminmenu .menu-icon-feedback:hover div.wp-menu-image,
-#adminmenu .menu-icon-feedback.wp-has-current-submenu div.wp-menu-image,
-#adminmenu .menu-icon-feedback.current div.wp-menu-image {
- background: url(../images/grunion-menu-hover.png) no-repeat 7px 7px !important;
-}
-
#adminmenu .menu-icon-feedback div.wp-menu-image {
- background: url(../images/grunion-menu.png) no-repeat 7px 7px !important;
-}
-
-body.mp6 #adminmenu .menu-icon-feedback div.wp-menu-image {
background: none !important;
}
-body.mp6 #adminmenu .menu-icon-feedback div.wp-menu-image:before {
+#adminmenu .menu-icon-feedback div.wp-menu-image:before {
content: '\f175';
margin-left: -1px;
}
-.jetpack-contact-form-icon {
+.jetpack-contact-form-icon:before {
+ content: '\f175';
+ color: #888;
+ vertical-align: text-bottom;
+ font: normal 18px/1 'dashicons';
+ speak: none;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.pre-mp6 #adminmenu .menu-icon-feedback:hover div.wp-menu-image,
+.pre-mp6 #adminmenu .menu-icon-feedback.wp-has-current-submenu div.wp-menu-image,
+.pre-mp6 #adminmenu .menu-icon-feedback.current div.wp-menu-image {
+ background: url(../images/grunion-menu-hover.png) no-repeat 7px 7px !important;
+ background-size: 15px 16px !important;
+}
+
+.pre-mp6 #adminmenu .menu-icon-feedback div.wp-menu-image {
+ background: url(../images/grunion-menu.png) no-repeat 7px 7px !important;
+ background-size: 15px 16px !important;
+}
+
+.pre-mp6 #adminmenu .menu-icon-feedback div.wp-menu-image:before {
+ display: none;
+}
+
+.pre-mp6 .jetpack-contact-form-icon {
background: url(../images/grunion-form.png) no-repeat;
width: 16px;
height: 16px;
display: inline-block;
vertical-align: middle;
+ background-size: 13px 12px !important;
+}
+
+.pre-mp6 .jetpack-contact-form-icon:before {
+ display: none;
}
@media only screen and (-moz-min-device-pixel-ratio: 1.5),
@@ -34,23 +55,19 @@ body.mp6 #adminmenu .menu-icon-feedback div.wp-menu-image:before {
only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (min-device-pixel-ratio: 1.5) {
- #adminmenu .menu-icon-feedback:hover div.wp-menu-image,
- #adminmenu .menu-icon-feedback.wp-has-current-submenu div.wp-menu-image,
- #adminmenu .menu-icon-feedback.current div.wp-menu-image {
- background: url(../images/grunion-menu-hover-2x.png) no-repeat 7px 7px !important;
- background-size: 15px 16px !important;
+ .pre-mp6 #adminmenu .menu-icon-feedback:hover div.wp-menu-image,
+ .pre-mp6 #adminmenu .menu-icon-feedback.wp-has-current-submenu div.wp-menu-image,
+ .pre-mp6 #adminmenu .menu-icon-feedback.current div.wp-menu-image {
+ background-image: url(../images/grunion-menu-hover-2x.png);
}
- #adminmenu .menu-icon-feedback div.wp-menu-image {
- background: url(../images/grunion-menu-2x.png) no-repeat 7px 7px !important;
- background-size: 15px 16px !important;
+ .pre-mp6 #adminmenu .menu-icon-feedback div.wp-menu-image {
+ background-image: url(../images/grunion-menu-2x.png);
}
- .jetpack-contact-form-icon {
+ .pre-mp6 .jetpack-contact-form-icon {
background-image: url(../images/grunion-form-2x.png);
- background-size: 13px 12px !important;
vertical-align: bottom;
}
}
-
diff --git a/plugins/jetpack/modules/contact-form/css/menu-alter.min.css b/plugins/jetpack/modules/contact-form/css/menu-alter.min.css
new file mode 100644
index 00000000..a0929a22
--- /dev/null
+++ b/plugins/jetpack/modules/contact-form/css/menu-alter.min.css
@@ -0,0 +1 @@
+#menu-posts-feedback .wp-menu-image img{display:none}#adminmenu .menu-icon-feedback div.wp-menu-image{background:none!important}#adminmenu .menu-icon-feedback div.wp-menu-image:before{content:'\f175';margin-left:-1px}.jetpack-contact-form-icon:before{content:'\f175';color:#888;vertical-align:text-bottom;font:400 18px/1 dashicons;speak:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.pre-mp6 #adminmenu .menu-icon-feedback.current div.wp-menu-image,.pre-mp6 #adminmenu .menu-icon-feedback.wp-has-current-submenu div.wp-menu-image,.pre-mp6 #adminmenu .menu-icon-feedback:hover div.wp-menu-image{background:url(../images/grunion-menu-hover.png) 7px 7px/15px 16px no-repeat!important}.pre-mp6 #adminmenu .menu-icon-feedback div.wp-menu-image{background:url(../images/grunion-menu.png) 7px 7px/15px 16px no-repeat!important}.pre-mp6 #adminmenu .menu-icon-feedback div.wp-menu-image:before{display:none}.pre-mp6 .jetpack-contact-form-icon{background:url(../images/grunion-form.png) no-repeat;width:16px;height:16px;display:inline-block;vertical-align:middle;background-size:13px 12px!important}.pre-mp6 .jetpack-contact-form-icon:before{display:none}@media only screen and (-moz-min-device-pixel-ratio:1.5),only screen and (-o-min-device-pixel-ratio:3/2),only screen and (-webkit-min-device-pixel-ratio:1.5),only screen and (min-device-pixel-ratio:1.5){.pre-mp6 #adminmenu .menu-icon-feedback.current div.wp-menu-image,.pre-mp6 #adminmenu .menu-icon-feedback.wp-has-current-submenu div.wp-menu-image,.pre-mp6 #adminmenu .menu-icon-feedback:hover div.wp-menu-image{background-image:url(../images/grunion-menu-hover-2x.png)}.pre-mp6 #adminmenu .menu-icon-feedback div.wp-menu-image{background-image:url(../images/grunion-menu-2x.png)}.pre-mp6 .jetpack-contact-form-icon{background-image:url(../images/grunion-form-2x.png);vertical-align:bottom}} \ No newline at end of file
diff --git a/plugins/jetpack/modules/contact-form/css/rtl/grunion-rtl.css b/plugins/jetpack/modules/contact-form/css/rtl/grunion-rtl.css
index 5b1ae1ba..b456c2de 100644
--- a/plugins/jetpack/modules/contact-form/css/rtl/grunion-rtl.css
+++ b/plugins/jetpack/modules/contact-form/css/rtl/grunion-rtl.css
@@ -1,4 +1,4 @@
-/* This file was automatically generated on Feb 27 2013 21:33:34 */
+/* This file was automatically generated on Feb 02 2015 20:24:19 */
.contact-form .clear-form { clear: both; }
.contact-form input[type='text'], .contact-form input[type='email'] { width: 300px; max-width: 98%; margin-bottom: 13px; }
@@ -9,4 +9,6 @@
.contact-form label.checkbox, .contact-form label.radio { margin-bottom: 3px; float: none; font-weight: bold; display: inline-block; }
.contact-form label span { color: #AAA; margin-right: 4px; font-weight: normal; }
.form-errors .form-error-message { color: red; }
-.textwidget input[type='text'], .textwidget input[type='email'], .textwidget textarea { width: 250px; max-width: 98%; }
+.textwidget .contact-form input[type='text'], .textwidget .contact-form input[type='email'], .textwidget .contact-form textarea { width: 250px; max-width: 100%; box-sizing: border-box; }
+#jetpack-check-feedback-spam { margin: 1px 0px 0px 8px; }
+.jetpack-check-feedback-spam-spinner { display: inline-block; margin-top: 7px; }
diff --git a/plugins/jetpack/modules/contact-form/css/rtl/menu-alter-rtl.css b/plugins/jetpack/modules/contact-form/css/rtl/menu-alter-rtl.css
index f625fa48..200c90d9 100644
--- a/plugins/jetpack/modules/contact-form/css/rtl/menu-alter-rtl.css
+++ b/plugins/jetpack/modules/contact-form/css/rtl/menu-alter-rtl.css
@@ -1,58 +1,24 @@
-/* This file was automatically generated on Sep 05 2013 19:17:52 */
+/* This file was automatically generated on Aug 26 2014 19:31:54 */
#menu-posts-feedback .wp-menu-image img {
display: none;
}
-#adminmenu .menu-icon-feedback:hover div.wp-menu-image,
-#adminmenu .menu-icon-feedback.wp-has-current-submenu div.wp-menu-image,
-#adminmenu .menu-icon-feedback.current div.wp-menu-image {
- background: url(../../images/grunion-menu-hover.png) no-repeat 7px 7px !important;
-}
-
#adminmenu .menu-icon-feedback div.wp-menu-image {
- background: url(../../images/grunion-menu.png) no-repeat 7px 7px !important;
-}
-
-body.mp6 #adminmenu .menu-icon-feedback div.wp-menu-image {
background: none !important;
}
-body.mp6 #adminmenu .menu-icon-feedback div.wp-menu-image:before {
+#adminmenu .menu-icon-feedback div.wp-menu-image:before {
content: '\f175';
margin-right: -1px;
}
-.jetpack-contact-form-icon {
- background: url(../../images/grunion-form.png) no-repeat;
- width: 16px;
- height: 16px;
- display: inline-block;
- vertical-align: middle;
-}
-
-@media only screen and (-moz-min-device-pixel-ratio: 1.5),
- only screen and (-o-min-device-pixel-ratio: 3/2),
- only screen and (-webkit-min-device-pixel-ratio: 1.5),
- only screen and (min-device-pixel-ratio: 1.5) {
-
- #adminmenu .menu-icon-feedback:hover div.wp-menu-image,
- #adminmenu .menu-icon-feedback.wp-has-current-submenu div.wp-menu-image,
- #adminmenu .menu-icon-feedback.current div.wp-menu-image {
- background: url(../../images/grunion-menu-hover-2x.png) no-repeat 7px 7px !important;
- background-size: 15px 16px !important;
- }
-
- #adminmenu .menu-icon-feedback div.wp-menu-image {
- background: url(../../images/grunion-menu-2x.png) no-repeat 7px 7px !important;
- background-size: 15px 16px !important;
- }
-
- .jetpack-contact-form-icon {
- background-image: url(../../images/grunion-form-2x.png);
- background-size: 13px 12px !important;
- vertical-align: bottom;
- }
-
+.jetpack-contact-form-icon:before {
+ content: '\f175';
+ color: #888;
+ vertical-align: text-bottom;
+ font: normal 18px/1 'dashicons';
+ speak: none;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
}
-
diff --git a/plugins/jetpack/modules/contact-form/grunion-contact-form.php b/plugins/jetpack/modules/contact-form/grunion-contact-form.php
index e85c3fc2..a18de9cd 100644
--- a/plugins/jetpack/modules/contact-form/grunion-contact-form.php
+++ b/plugins/jetpack/modules/contact-form/grunion-contact-form.php
@@ -20,11 +20,14 @@ if ( is_admin() )
* Sets up various actions, filters, post types, post statuses, shortcodes.
*/
class Grunion_Contact_Form_Plugin {
+
/**
* @var string The Widget ID of the widget currently being processed. Used to build the unique contact-form ID for forms embedded in widgets.
*/
var $current_widget_id;
+ static $using_contact_form_field = false;
+
static function init() {
static $instance = false;
@@ -41,7 +44,7 @@ class Grunion_Contact_Form_Plugin {
* @param string $string
* @return string
*/
- static function strip_tags( $string ) {
+ public static function strip_tags( $string ) {
$string = wp_kses( $string, array() );
return str_replace( '&amp;', '&', $string ); // undo damage done by wp_kses_normalize_entities()
}
@@ -60,8 +63,8 @@ class Grunion_Contact_Form_Plugin {
add_filter( 'widget_text', array( $this, 'widget_shortcode_hack' ), 5 );
// Akismet to the rescue
- if ( function_exists( 'akismet_http_post' ) ) {
- add_filter( 'contact_form_is_spam', array( $this, 'is_spam_akismet' ), 10 );
+ if ( defined( 'AKISMET_VERSION' ) || function_exists( 'akismet_http_post' ) ) {
+ add_filter( 'jetpack_contact_form_is_spam', array( $this, 'is_spam_akismet' ), 10, 2 );
add_action( 'contact_form_akismet', array( $this, 'akismet_submit' ), 10, 2 );
}
@@ -94,6 +97,9 @@ class Grunion_Contact_Form_Plugin {
'capability_type' => 'page'
) );
+ // Add to REST API post type whitelist
+ add_filter( 'rest_api_allowed_post_types', array( $this, 'allow_feedback_rest_api_type' ) );
+
// Add "spam" as a post status
register_post_status( 'spam', array(
'label' => 'Spam',
@@ -123,8 +129,19 @@ class Grunion_Contact_Form_Plugin {
* }
* add_action('wp_print_styles', 'remove_grunion_style');
*/
+ if( is_rtl() ){
+ wp_register_style( 'grunion.css', GRUNION_PLUGIN_URL . 'css/rtl/grunion-rtl.css', array(), JETPACK__VERSION );
+ } else {
+ wp_register_style( 'grunion.css', GRUNION_PLUGIN_URL . 'css/grunion.css', array(), JETPACK__VERSION );
+ }
+ }
- wp_register_style( 'grunion.css', GRUNION_PLUGIN_URL . 'css/grunion.css', array(), JETPACK__VERSION );
+ /**
+ * Add to REST API post type whitelist
+ */
+ function allow_feedback_rest_api_type( $post_types ) {
+ $post_types[] = 'feedback';
+ return $post_types;
}
/**
@@ -133,9 +150,14 @@ class Grunion_Contact_Form_Plugin {
* Conditionally attached to `template_redirect`
*/
function process_form_submission() {
+ // Add a filter to replace tokens in the subject field with sanitized field values
+ add_filter( 'contact_form_subject', array( $this, 'replace_tokens_with_input' ), 10, 2 );
+
$id = stripslashes( $_POST['contact-form-id'] );
- check_admin_referer( "contact-form_{$id}" );
+ if ( is_user_logged_in() ) {
+ check_admin_referer( "contact-form_{$id}" );
+ }
$is_widget = 0 === strpos( $id, 'widget-' );
@@ -171,8 +193,25 @@ class Grunion_Contact_Form_Plugin {
$form = Grunion_Contact_Form::$last;
- if ( ! $form )
- return false;
+ // No form may mean user is using do_shortcode, grab the form using the stored post meta
+ if ( ! $form ) {
+
+ // Get shortcode from post meta
+ $shortcode = get_post_meta( $_POST['contact-form-id'], '_g_feedback_shortcode', true );
+
+ // Format it
+ if ( $shortcode != '' ) {
+ $shortcode = '[contact-form]' . $shortcode . '[/contact-form]';
+ do_shortcode( $shortcode );
+
+ // Recreate form
+ $form = Grunion_Contact_Form::$last;
+ }
+
+ if ( ! $form ) {
+ return false;
+ }
+ }
if ( is_wp_error( $form->errors ) && $form->errors->get_error_codes() )
return $form->errors;
@@ -218,13 +257,41 @@ class Grunion_Contact_Form_Plugin {
return $data;
}
-
/*
* Adds our contact-form shortcode
- * The "child" contact-field shortcode is added as needed by the contact-form shortcode handler
+ * The "child" contact-field shortcode is enabled as needed by the contact-form shortcode handler
*/
function add_shortcode() {
- add_shortcode( 'contact-form', array( 'Grunion_Contact_Form', 'parse' ) );
+ add_shortcode( 'contact-form', array( 'Grunion_Contact_Form', 'parse' ) );
+ add_shortcode( 'contact-field', array( 'Grunion_Contact_Form', 'parse_contact_field' ) );
+ }
+
+ static function tokenize_label( $label ) {
+ return '{' . trim( preg_replace( '#^\d+_#', '', $label ) ) . '}';
+ }
+
+ static function sanitize_value( $value ) {
+ return preg_replace( '=((<CR>|<LF>|0x0A/%0A|0x0D/%0D|\\n|\\r)\S).*=i', null, $value );
+ }
+
+ /**
+ * Replaces tokens like {city} or {City} (case insensitive) with the value
+ * of an input field of that name
+ *
+ * @param string $subject
+ * @param array $field_values Array with field label => field value associations
+ *
+ * @return string The filtered $subject with the tokens replaced
+ */
+ function replace_tokens_with_input( $subject, $field_values ) {
+ // Wrap labels into tokens (inside {})
+ $wrapped_labels = array_map( array( 'Grunion_Contact_Form_Plugin', 'tokenize_label' ), array_keys( $field_values ) );
+ // Sanitize all values
+ $sanitized_values = array_map( array( 'Grunion_Contact_Form_Plugin', 'sanitize_value' ), array_values( $field_values ) );
+
+ // Search for all valid tokens (based on existing fields) and replace with the field's value
+ $subject = str_ireplace( $wrapped_labels, $sanitized_values, $subject );
+ return $subject;
}
/**
@@ -267,10 +334,12 @@ class Grunion_Contact_Form_Plugin {
$old = $GLOBALS['shortcode_tags'];
remove_all_shortcodes();
+ Grunion_Contact_Form_Plugin::$using_contact_form_field = true;
$this->add_shortcode();
$text = do_shortcode( $text );
+ Grunion_Contact_Form_Plugin::$using_contact_form_field = false;
$GLOBALS['shortcode_tags'] = $old;
return $text;
@@ -302,23 +371,46 @@ class Grunion_Contact_Form_Plugin {
/**
* Submit contact-form data to Akismet to check for spam.
* If you're accepting a new item via $_POST, run it Grunion_Contact_Form_Plugin::prepare_for_akismet() first
- * Attached to `contact_form_is_spam`
+ * Attached to `jetpack_contact_form_is_spam`
*
+ * @param bool $is_spam
* @param array $form
* @return bool|WP_Error TRUE => spam, FALSE => not spam, WP_Error => stop processing entirely
*/
- function is_spam_akismet( $form ) {
+ function is_spam_akismet( $is_spam, $form = array() ) {
global $akismet_api_host, $akismet_api_port;
- if ( !function_exists( 'akismet_http_post' ) )
+ // The signature of this function changed from accepting just $form.
+ // If something only sends an array, assume it's still using the old
+ // signature and work around it.
+ if ( empty( $form ) && is_array( $is_spam ) ) {
+ $form = $is_spam;
+ $is_spam = false;
+ }
+
+ // If a previous filter has alrady marked this as spam, trust that and move on.
+ if ( $is_spam ) {
+ return $is_spam;
+ }
+
+ if ( !function_exists( 'akismet_http_post' ) && !defined( 'AKISMET_VERSION' ) )
return false;
$query_string = http_build_query( $form );
- $response = akismet_http_post( $query_string, $akismet_api_host, '/1.1/comment-check', $akismet_api_port );
+ if ( method_exists( 'Akismet', 'http_post' ) ) {
+ $response = Akismet::http_post( $query_string, 'comment-check' );
+ } else {
+ $response = akismet_http_post( $query_string, $akismet_api_host, '/1.1/comment-check', $akismet_api_port );
+ }
+
$result = false;
- if ( 'true' == trim( $response[1] ) ) // 'true' is spam
+
+ if ( isset( $response[0]['x-akismet-pro-tip'] ) && 'discard' === trim( $response[0]['x-akismet-pro-tip'] ) && get_option( 'akismet_strictness' ) === '1' )
+ $result = new WP_Error( 'feedback-discarded', __('Feedback discarded.', 'jetpack' ) );
+ elseif ( isset( $response[1] ) && 'true' == trim( $response[1] ) ) // 'true' is spam
$result = true;
+
return apply_filters( 'contact_form_is_spam_akismet', $result, $form );
}
@@ -334,9 +426,15 @@ class Grunion_Contact_Form_Plugin {
if ( !in_array( $as, array( 'ham', 'spam' ) ) )
return false;
- $query_string = http_build_query( $form );
+ $query_string = '';
+ if ( is_array( $form ) )
+ $query_string = http_build_query( $form );
+ if ( method_exists( 'Akismet', 'http_post' ) ) {
+ $response = Akismet::http_post( $query_string, "submit-{$as}" );
+ } else {
+ $response = akismet_http_post( $query_string, $akismet_api_host, "/1.1/submit-{$as}", $akismet_api_port );
+ }
- $response = akismet_http_post( $query_string, $akismet_api_host, "/1.1/submit-{$as}", $akismet_api_port );
return trim( $response[1] );
}
@@ -347,6 +445,10 @@ class Grunion_Contact_Form_Plugin {
if ( get_current_screen()->id != 'edit-feedback' )
return;
+ if ( ! current_user_can( 'export' ) ) {
+ return;
+ }
+
// if there aren't any feedbacks, bail out
if ( ! (int) wp_count_posts( 'feedback' )->publish )
return;
@@ -392,12 +494,15 @@ class Grunion_Contact_Form_Plugin {
check_admin_referer( 'feedback_export', 'feedback_export_nonce' );
+ if ( ! current_user_can( 'export' ) ) {
+ return;
+ }
+
$args = array(
'posts_per_page' => -1,
'post_type' => 'feedback',
'post_status' => 'publish',
- 'meta_key' => '_feedback_subject',
- 'orderby' => 'meta_value',
+ 'order' => 'ASC',
'fields' => 'ids',
'suppress_filters' => false,
);
@@ -413,6 +518,7 @@ class Grunion_Contact_Form_Plugin {
$feedbacks = get_posts( $args );
$filename = sanitize_file_name( $filename );
$fields = $this->get_field_names( $feedbacks );
+
array_unshift( $fields, __( 'Contact Form', 'jetpack' ) );
if ( empty( $feedbacks ) )
@@ -448,7 +554,7 @@ class Grunion_Contact_Form_Plugin {
// Get the feedbacks' parents' post IDs
$feedbacks = get_posts( array(
'fields' => 'id=>parent',
- 'posts_per_page' => -1,
+ 'posts_per_page' => 100000,
'post_type' => 'feedback',
'post_status' => 'publish',
'suppress_filters' => false,
@@ -457,7 +563,7 @@ class Grunion_Contact_Form_Plugin {
$posts = get_posts( array(
'orderby' => 'ID',
- 'posts_per_page' => -1,
+ 'posts_per_page' => 1000,
'post_type' => 'any',
'post__in' => array_values( $parents ),
'suppress_filters' => false,
@@ -482,14 +588,71 @@ class Grunion_Contact_Form_Plugin {
$all_fields = array();
foreach ( $posts as $post ){
- $extra_fields = array_keys( get_post_meta( $post, '_feedback_all_fields', true ) );
- $all_fields = array_merge( $all_fields, $extra_fields );
+ $fields = self::parse_fields_from_content( $post );
+
+ if ( isset( $fields['_feedback_all_fields'] ) ) {
+ $extra_fields = array_keys( $fields['_feedback_all_fields'] );
+ $all_fields = array_merge( $all_fields, $extra_fields );
+ }
}
$all_fields = array_unique( $all_fields );
return $all_fields;
}
+ public static function parse_fields_from_content( $post_id ) {
+ static $post_fields;
+
+ if ( !is_array( $post_fields ) )
+ $post_fields = array();
+
+ if ( isset( $post_fields[$post_id] ) )
+ return $post_fields[$post_id];
+
+ $all_values = array();
+ $post_content = get_post_field( 'post_content', $post_id );
+ $content = explode( '<!--more-->', $post_content );
+ $lines = array();
+
+ if ( count( $content ) > 1 ) {
+ $content = str_ireplace( array( '<br />', ')</p>' ), '', $content[1] );
+ $one_line = preg_replace( '/\s+/', ' ', $content );
+ $one_line = preg_replace( '/.*Array \( (.*)\)/', '$1', $one_line );
+
+ preg_match_all( '/\[([^\]]+)\] =\&gt\; ([^\[]+)/', $one_line, $matches );
+
+ if ( count( $matches ) > 1 )
+ $all_values = array_combine( array_map('trim', $matches[1]), array_map('trim', $matches[2]) );
+
+ $lines = array_filter( explode( "\n", $content ) );
+ }
+
+ $var_map = array(
+ 'AUTHOR' => '_feedback_author',
+ 'AUTHOR EMAIL' => '_feedback_author_email',
+ 'AUTHOR URL' => '_feedback_author_url',
+ 'SUBJECT' => '_feedback_subject',
+ 'IP' => '_feedback_ip'
+ );
+
+ $fields = array();
+
+ foreach( $lines as $line ) {
+ $vars = explode( ': ', $line, 2 );
+ if ( !empty( $vars ) ) {
+ if ( isset( $var_map[$vars[0]] ) ) {
+ $fields[$var_map[$vars[0]]] = self::strip_tags( trim( $vars[1] ) );
+ }
+ }
+ }
+
+ $fields['_feedback_all_fields'] = $all_values;
+
+ $post_fields[$post_id] = $fields;
+
+ return $fields;
+ }
+
/**
* Creates a valid csv row from a post id
*
@@ -498,10 +661,20 @@ class Grunion_Contact_Form_Plugin {
* @return String The csv row
*/
protected static function make_csv_row_from_feedback( $post_id, $fields ) {
- $all_fields = get_post_meta( $post_id, '_feedback_all_fields', true );
+ $content_fields = self::parse_fields_from_content( $post_id );
+ $all_fields = array();
+
+ if ( isset( $content_fields['_feedback_all_fields'] ) )
+ $all_fields = $content_fields['_feedback_all_fields'];
+
+ // Overwrite the parsed content with the content we stored in post_meta in a better format.
+ $extra_fields = get_post_meta( $post_id, '_feedback_extra_fields', true );
+ foreach ( $extra_fields as $extra_field => $extra_value ) {
+ $all_fields[$extra_field] = $extra_value;
+ }
// The first element in all of the exports will be the subject
- $row_items[] = get_post_meta( $post_id, '_feedback_subject', true );
+ $row_items[] = $content_fields['_feedback_subject'];
// Loop the fields array in order to fill the $row_items array correctly
foreach ( $fields as $field ) {
@@ -515,6 +688,10 @@ class Grunion_Contact_Form_Plugin {
return $row_items;
}
+
+ public static function get_ip_address() {
+ return isset( $_SERVER['REMOTE_ADDR'] ) ? $_SERVER['REMOTE_ADDR'] : null;
+ }
}
/**
@@ -571,7 +748,7 @@ class Crunion_Contact_Form_Shortcode {
$this->content = $content;
}
- $this->parse_content( $content );
+ $this->parse_content( $this->content );
}
/**
@@ -705,6 +882,11 @@ class Grunion_Contact_Form extends Crunion_Contact_Form_Shortcode {
static $last;
/**
+ * @var Whatever form we are currently looking at. If processed, will become $last
+ */
+ static $current_form;
+
+ /**
* @var bool Whether to print the grunion.css style when processing the contact-form shortcode
*/
static $style = false;
@@ -713,20 +895,23 @@ class Grunion_Contact_Form extends Crunion_Contact_Form_Shortcode {
global $post;
// Set up the default subject and recipient for this form
- $default_to = get_option( 'admin_email' );
+ $default_to = '';
$default_subject = "[" . get_option( 'blogname' ) . "]";
if ( !empty( $attributes['widget'] ) && $attributes['widget'] ) {
+ $default_to .= get_option( 'admin_email' );
$attributes['id'] = 'widget-' . $attributes['widget'];
-
$default_subject = sprintf( _x( '%1$s Sidebar', '%1$s = blog name', 'jetpack' ), $default_subject );
} else if ( $post ) {
$attributes['id'] = $post->ID;
$default_subject = sprintf( _x( '%1$s %2$s', '%1$s = blog name, %2$s = post title', 'jetpack' ), $default_subject, Grunion_Contact_Form_Plugin::strip_tags( $post->post_title ) );
$post_author = get_userdata( $post->post_author );
- $default_to = $post_author->user_email;
+ $default_to .= $post_author->user_email;
}
+ // Keep reference to $this for parsing form fields
+ self::$current_form = $this;
+
$this->defaults = array(
'to' => $default_to,
'subject' => $default_subject,
@@ -736,10 +921,10 @@ class Grunion_Contact_Form extends Crunion_Contact_Form_Shortcode {
'submit_button_text' => __( 'Submit &#187;', 'jetpack' ),
);
- $attributes = shortcode_atts( $this->defaults, $attributes );
+ $attributes = shortcode_atts( $this->defaults, $attributes, 'contact-form' );
- // We only add the contact-field shortcode temporarily while processing the contact-form shortcode
- add_shortcode( 'contact-field', array( $this, 'parse_contact_field' ) );
+ // We only enable the contact-field shortcode temporarily while processing the contact-form shortcode
+ Grunion_Contact_Form_Plugin::$using_contact_form_field = true;
parent::__construct( $attributes, $content );
@@ -760,10 +945,35 @@ class Grunion_Contact_Form extends Crunion_Contact_Form_Shortcode {
[contact-field label="' . __( 'Message', 'jetpack' ) . '" type="textarea" /]';
$this->parse_content( $default_form );
+
+ // Store the shortcode
+ $this->store_shortcode( $default_form, $attributes );
+ } else {
+ // Store the shortcode
+ $this->store_shortcode( $content, $attributes );
}
// $this->body and $this->fields have been setup. We no longer need the contact-field shortcode.
- remove_shortcode( 'contact-field' );
+ Grunion_Contact_Form_Plugin::$using_contact_form_field = false;
+ }
+
+ /**
+ * Store shortcode content for recall later
+ * - used to receate shortcode when user uses do_shortcode
+ *
+ * @param string $content
+ */
+ static function store_shortcode( $content = null, $attributes = null ) {
+
+ if ( $content != null and isset( $attributes['id'] ) ) {
+
+ $shortcode_meta = get_post_meta( $attributes['id'], '_g_feedback_shortcode', true );
+
+ if ( $shortcode_meta != '' or $shortcode_meta != $content ) {
+ update_post_meta( $attributes['id'], '_g_feedback_shortcode', $content );
+ }
+
+ }
}
/**
@@ -804,7 +1014,7 @@ class Grunion_Contact_Form extends Crunion_Contact_Form_Shortcode {
return '[contact-form]';
}
- if ( apply_filters( 'jetpack_bail_on_shortcode', false, 'contact-form' ) || is_feed() ) {
+ if ( is_feed() ) {
return '[contact-form]';
}
@@ -869,6 +1079,9 @@ class Grunion_Contact_Form extends Crunion_Contact_Form_Shortcode {
$url = get_permalink();
}
+ // For SSL/TLS page. See RFC 3986 Section 4.2
+ $url = set_url_scheme( $url );
+
// May eventually want to send this to admin-post.php...
$url = apply_filters( 'grunion_contact_form_form_action', "{$url}#contact-form-{$id}", $GLOBALS['post'], $id );
@@ -876,7 +1089,9 @@ class Grunion_Contact_Form extends Crunion_Contact_Form_Shortcode {
$r .= $form->body;
$r .= "\t<p class='contact-submit'>\n";
$r .= "\t\t<input type='submit' value='" . esc_attr( $form->get_attribute( 'submit_button_text' ) ) . "' class='pushbutton-wide'/>\n";
- $r .= "\t\t" . wp_nonce_field( 'contact-form_' . $id, '_wpnonce', true, false ) . "\n"; // nonce and referer
+ if ( is_user_logged_in() ) {
+ $r .= "\t\t" . wp_nonce_field( 'contact-form_' . $id, '_wpnonce', true, false ) . "\n"; // nonce and referer
+ }
$r .= "\t\t<input type='hidden' name='contact-form-id' value='$id' />\n";
$r .= "\t\t<input type='hidden' name='action' value='grunion-contact-form' />\n";
$r .= "\t</p>\n";
@@ -891,9 +1106,9 @@ class Grunion_Contact_Form extends Crunion_Contact_Form_Shortcode {
static function success_message( $feedback_id, $form ) {
$r_success_message = '';
- $feedback = get_post( $feedback_id );
-
- $field_ids = $form->get_field_ids();
+ $feedback = get_post( $feedback_id );
+ $field_ids = $form->get_field_ids();
+ $content_fields = Grunion_Contact_Form_Plugin::parse_fields_from_content( $feedback_id );
// Maps field_ids to post_meta keys
$field_value_map = array(
@@ -912,7 +1127,8 @@ class Grunion_Contact_Form extends Crunion_Contact_Form_Shortcode {
$field = $form->fields[$field_ids[$type]];
if ( $meta_key ) {
- $value = get_post_meta( $feedback_id, "_feedback_{$meta_key}", true );
+ if ( isset( $content_fields["_feedback_{$meta_key}"] ) )
+ $value = $content_fields["_feedback_{$meta_key}"];
} else {
// The feedback content is stored as the first "half" of post_content
$value = $feedback->post_content;
@@ -932,15 +1148,21 @@ class Grunion_Contact_Form extends Crunion_Contact_Form_Shortcode {
if ( $field_ids['extra'] ) {
// array indexed by field label (not field id)
$extra_fields = get_post_meta( $feedback_id, '_feedback_extra_fields', true );
+ $extra_field_keys = array_keys( $extra_fields );
+ $i = 0;
foreach ( $field_ids['extra'] as $field_id ) {
$field = $form->fields[$field_id];
+
$label = $field->get_attribute( 'label' );
+
$contact_form_message .= sprintf(
_x( '%1$s: %2$s', '%1$s = form field label, %2$s = form field value', 'jetpack' ),
wp_kses( $label, array() ),
- wp_kses( $extra_fields[$label], array() )
+ wp_kses( $extra_fields[$extra_field_keys[$i]], array() )
) . '<br />';
+
+ $i++;
}
}
@@ -959,20 +1181,44 @@ class Grunion_Contact_Form extends Crunion_Contact_Form_Shortcode {
* @param string|null $content The shortcode's inner content: [contact-field]$content[/contact-field]
* @return HTML for the contact form field
*/
- function parse_contact_field( $attributes, $content ) {
- $field = new Grunion_Contact_Form_Field( $attributes, $content, $this );
+ static function parse_contact_field( $attributes, $content ) {
+ // Don't try to parse contact form fields if not inside a contact form
+ if ( ! Grunion_Contact_Form_Plugin::$using_contact_form_field ) {
+ $att_strs = array();
+ foreach ( $attributes as $att => $val ) {
+ if ( is_numeric( $att ) ) { // Is a valueless attribute
+ $att_strs[] = esc_html( $val );
+ } else if ( isset( $val ) ) { // A regular attr - value pair
+ $att_strs[] = esc_html( $att ) . '=\'' . esc_html( $val ) . '\'';
+ }
+ }
+
+ $html = '[contact-field ' . implode( ' ', $att_strs );
+
+ if ( isset( $content ) && ! empty( $content ) ) { // If there is content, let's add a closing tag
+ $html .= ']' . esc_html( $content ) . '[/contact-field]';
+ } else { // Otherwise let's add a closing slash in the first tag
+ $html .= '/]';
+ }
+
+ return $html;
+ }
+
+ $form = Grunion_Contact_Form::$current_form;
+
+ $field = new Grunion_Contact_Form_Field( $attributes, $content, $form );
$field_id = $field->get_attribute( 'id' );
if ( $field_id ) {
- $this->fields[$field_id] = $field;
+ $form->fields[$field_id] = $field;
} else {
- $this->fields[] = $field;
+ $form->fields[] = $field;
}
if (
isset( $_POST['action'] ) && 'grunion-contact-form' === $_POST['action']
&&
- isset( $_POST['contact-form-id'] ) && $this->get_attribute( 'id' ) == $_POST['contact-form-id']
+ isset( $_POST['contact-form-id'] ) && $form->get_attribute( 'id' ) == $_POST['contact-form-id']
) {
// If we're processing a POST submission for this contact form, validate the field value so we can show errors as necessary.
$field->validate();
@@ -1012,6 +1258,7 @@ class Grunion_Contact_Form extends Crunion_Contact_Form_Shortcode {
switch ( $type ) {
case 'email' :
+ case 'telephone' :
case 'name' :
case 'url' :
case 'subject' :
@@ -1059,13 +1306,19 @@ class Grunion_Contact_Form extends Crunion_Contact_Form_Shortcode {
$valid_emails[] = $email;
}
- // No one to send it to :(
+ // No one to send it to, which means none of the "to" attributes are valid emails.
+ // Use default email instead.
if ( !$valid_emails ) {
- return false;
+ $valid_emails = $this->defaults['to'];
}
$to = $valid_emails;
+ // Last ditch effort to set a recipient if somehow none have been set.
+ if ( empty( $to ) ) {
+ $to = get_option( 'admin_email' );
+ }
+
// Make sure we're processing the form we think we're processing... probably a redundant check.
if ( $widget ) {
if ( 'widget-' . $widget != $_POST['contact-form-id'] ) {
@@ -1122,40 +1375,73 @@ class Grunion_Contact_Form extends Crunion_Contact_Form_Shortcode {
}
$all_values = $extra_values = array();
+ $i = 1; // Prefix counter for stored metadata
// For all fields, grab label and value
foreach ( $field_ids['all'] as $field_id ) {
$field = $this->fields[$field_id];
- $label = $field->get_attribute( 'label' );
+ $label = $i . '_' . $field->get_attribute( 'label' );
$value = $field->value;
+
$all_values[$label] = $value;
+ $i++; // Increment prefix counter for the next field
}
// For the "non-standard" fields, grab label and value
+ // Extra fields have their prefix starting from count( $all_values ) + 1
foreach ( $field_ids['extra'] as $field_id ) {
$field = $this->fields[$field_id];
- $label = $field->get_attribute( 'label' );
+ $label = $i . '_' . $field->get_attribute( 'label' );
$value = $field->value;
+
$extra_values[$label] = $value;
+ $i++; // Increment prefix counter for the next extra field
}
$contact_form_subject = trim( $contact_form_subject );
- $comment_author_IP = Grunion_Contact_Form_Plugin::strip_tags( $_SERVER['REMOTE_ADDR'] );
+ $comment_author_IP = Grunion_Contact_Form_Plugin::get_ip_address();
$vars = array( 'comment_author', 'comment_author_email', 'comment_author_url', 'contact_form_subject', 'comment_author_IP' );
foreach ( $vars as $var )
$$var = str_replace( array( "\n", "\r" ), '', $$var );
- $vars[] = 'comment_content';
+
+ // Ensure that Akismet gets all of the relevant information from the contact form,
+ // not just the textarea field and predetermined subject.
+ $akismet_vars = compact( $vars );
+ $akismet_vars['comment_content'] = $comment_content;
+
+ foreach ( array_merge( $field_ids['all'], $field_ids['extra'] ) as $field_id ) {
+ $field = $this->fields[$field_id];
+
+ // Normalize the label into a slug.
+ $field_slug = trim( // Strip all leading/trailing dashes.
+ preg_replace( // Normalize everything to a-z0-9_-
+ '/[^a-z0-9_]+/',
+ '-',
+ strtolower( $field->get_attribute( 'label' ) ) // Lowercase
+ ),
+ '-'
+ );
+
+ $field_value = trim( $field->value );
+
+ // Skip any values that are already in the array we're sending.
+ if ( $field_value && in_array( $field_value, $akismet_vars ) ) {
+ continue;
+ }
+
+ $akismet_vars[ 'contact_form_field_' . $field_slug ] = $field_value;
+ }
$spam = '';
- $akismet_values = $plugin->prepare_for_akismet( compact( $vars ) );
+ $akismet_values = $plugin->prepare_for_akismet( $akismet_vars );
// Is it spam?
- $is_spam = apply_filters( 'contact_form_is_spam', $akismet_values );
+ $is_spam = apply_filters( 'jetpack_contact_form_is_spam', false, $akismet_values );
if ( is_wp_error( $is_spam ) ) // WP_Error to abort
return $is_spam; // abort
- else if ( $is_spam === TRUE ) // TRUE to flag a spam
+ elseif ( $is_spam === TRUE ) // TRUE to flag a spam
$spam = '***SPAM*** ';
if ( !$comment_author )
@@ -1174,22 +1460,17 @@ class Grunion_Contact_Form extends Crunion_Contact_Form_Shortcode {
$reply_to_addr = $comment_author_email;
}
- $headers = 'From: ' . $comment_author .' <' . $from_email_addr . ">\r\n" .
- 'Reply-To: ' . $comment_author . ' <' . $reply_to_addr . ">\r\n" .
+ $headers = 'From: "' . $comment_author .'" <' . $from_email_addr . ">\r\n" .
+ 'Reply-To: "' . $comment_author . '" <' . $reply_to_addr . ">\r\n" .
"Content-Type: text/plain; charset=\"" . get_option('blog_charset') . "\"";
- $subject = apply_filters( 'contact_form_subject', $contact_form_subject );
+ $subject = apply_filters( 'contact_form_subject', $contact_form_subject, $all_values );
+ $url = $widget ? home_url( '/' ) : get_permalink( $post->ID );
$date_time_format = _x( '%1$s \a\t %2$s', '{$date_format} \a\t {$time_format}', 'jetpack' );
$date_time_format = sprintf( $date_time_format, get_option( 'date_format' ), get_option( 'time_format' ) );
$time = date_i18n( $date_time_format, current_time( 'timestamp' ) );
- $extra_content = '';
-
- foreach ( $extra_values as $label => $value ) {
- $extra_content .= $label . ': ' . trim( $value ) . "\n";
- }
-
$message = "$comment_author_label: $comment_author\n";
if ( !empty( $comment_author_email ) ) {
$message .= "$comment_author_email_label: $comment_author_email\n";
@@ -1200,17 +1481,14 @@ class Grunion_Contact_Form extends Crunion_Contact_Form_Shortcode {
if ( !empty( $comment_content_label ) ) {
$message .= "$comment_content_label: $comment_content\n";
}
- $message .= $extra_content . "\n";
-
+ if ( !empty( $extra_values ) ) {
+ foreach ( $extra_values as $label => $value ) {
+ $message .= preg_replace( '#^\d+_#i', '', $label ) . ': ' . trim( $value ) . "\n";
+ }
+ }
+ $message .= "\n";
$message .= __( 'Time:', 'jetpack' ) . ' ' . $time . "\n";
$message .= __( 'IP Address:', 'jetpack' ) . ' ' . $comment_author_IP . "\n";
-
- if ( $widget ) {
- $url = home_url( '/' );
- } else {
- $url = get_permalink( $post->ID );
- }
-
$message .= __( 'Contact Form URL:', 'jetpack' ) . " $url\n";
if ( is_user_logged_in() ) {
@@ -1227,11 +1505,9 @@ class Grunion_Contact_Form extends Crunion_Contact_Form_Shortcode {
$message = Grunion_Contact_Form_Plugin::strip_tags( $message );
// keep a copy of the feedback as a custom post type
- $feedback_mysql_time = current_time( 'mysql' );
- $feedback_title = "{$comment_author} - {$feedback_mysql_time}";
- $feedback_status = 'publish';
- if ( $is_spam === TRUE )
- $feedback_status = 'spam';
+ $feedback_time = current_time( 'mysql' );
+ $feedback_title = "{$comment_author} - {$feedback_time}";
+ $feedback_status = $is_spam === TRUE ? 'spam' : 'publish';
foreach ( (array) $akismet_values as $av_key => $av_value ) {
$akismet_values[$av_key] = Grunion_Contact_Form_Plugin::strip_tags( $av_value );
@@ -1256,29 +1532,32 @@ class Grunion_Contact_Form extends Crunion_Contact_Form_Shortcode {
add_filter( 'wp_insert_post_data', array( $plugin, 'insert_feedback_filter' ), 10, 2 );
$post_id = wp_insert_post( array(
- 'post_date' => addslashes( $feedback_mysql_time ),
+ 'post_date' => addslashes( $feedback_time ),
'post_type' => 'feedback',
'post_status' => addslashes( $feedback_status ),
'post_parent' => (int) $post->ID,
'post_title' => addslashes( wp_kses( $feedback_title, array() ) ),
- 'post_content' => addslashes( wp_kses( $comment_content . "\n<!--more-->\n" . "AUTHOR: {$comment_author}\nAUTHOR EMAIL: {$comment_author_email}\nAUTHOR URL: {$comment_author_url}\nSUBJECT: {$contact_form_subject}\nIP: {$comment_author_IP}\n" . print_r( $all_values, TRUE ), array() ) ), // so that search will pick up this data
+ 'post_content' => addslashes( wp_kses( $comment_content . "\n<!--more-->\n" . "AUTHOR: {$comment_author}\nAUTHOR EMAIL: {$comment_author_email}\nAUTHOR URL: {$comment_author_url}\nSUBJECT: {$subject}\nIP: {$comment_author_IP}\n" . print_r( $all_values, TRUE ), array() ) ), // so that search will pick up this data
'post_name' => md5( $feedback_title ),
) );
// once insert has finished we don't need this filter any more
remove_filter( 'wp_insert_post_data', array( $plugin, 'insert_feedback_filter' ), 10, 2 );
- update_post_meta( $post_id, '_feedback_author', addslashes( $comment_author ) );
- update_post_meta( $post_id, '_feedback_author_email', addslashes( $comment_author_email ) );
- update_post_meta( $post_id, '_feedback_author_url', addslashes( $comment_author_url ) );
- update_post_meta( $post_id, '_feedback_subject', addslashes( $contact_form_subject ) );
- update_post_meta( $post_id, '_feedback_ip', addslashes( $comment_author_IP ) );
- update_post_meta( $post_id, '_feedback_contact_form_url', addslashes( get_permalink( $post->ID ) ) );
- update_post_meta( $post_id, '_feedback_all_fields', $this->addslashes_deep( $all_values ) );
update_post_meta( $post_id, '_feedback_extra_fields', $this->addslashes_deep( $extra_values ) );
update_post_meta( $post_id, '_feedback_akismet_values', $this->addslashes_deep( $akismet_values ) );
- update_post_meta( $post_id, '_feedback_email', $this->addslashes_deep( array( 'to' => $to, 'subject' => $subject, 'message' => $message, 'headers' => $headers ) ) );
+ update_post_meta( $post_id, '_feedback_email', $this->addslashes_deep( compact( 'to', 'message' ) ) );
+ /**
+ * Fires right before the contact form message is sent via email to
+ * the recipient specified in the contact form.
+ *
+ * @since ?
+ * @module Contact_Forms
+ * @param integer $post_id Post contact form lives on
+ * @param array $all_values Contact form fields
+ * @param array $extra_values Contact form fields not included in $all_values
+ **/
do_action( 'grunion_pre_message_sent', $post_id, $all_values, $extra_values );
// schedule deletes of old spam feedbacks
@@ -1286,10 +1565,11 @@ class Grunion_Contact_Form extends Crunion_Contact_Form_Shortcode {
wp_schedule_event( time() + 250, 'daily', 'grunion_scheduled_delete' );
}
- if ( $is_spam !== TRUE )
+ if ( $is_spam !== TRUE && true === apply_filters( 'grunion_should_send_email', true, $post_id ) ) {
wp_mail( $to, "{$spam}{$subject}", $message, $headers );
- elseif ( apply_filters( 'grunion_still_email_spam', FALSE ) == TRUE ) // don't send spam by default. Filterable.
+ } elseif ( true === $is_spam && apply_filters( 'grunion_still_email_spam', FALSE ) == TRUE ) { // don't send spam by default. Filterable.
wp_mail( $to, "{$spam}{$subject}", $message, $headers );
+ }
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
return self::success_message( $post_id, $this );
@@ -1357,13 +1637,14 @@ class Grunion_Contact_Form_Field extends Crunion_Contact_Form_Shortcode {
*/
function __construct( $attributes, $content = null, $form = null ) {
$attributes = shortcode_atts( array(
- 'label' => null,
- 'type' => 'text',
- 'required' => false,
- 'options' => array(),
- 'id' => null,
- 'default' => null,
- ), $attributes );
+ 'label' => null,
+ 'type' => 'text',
+ 'required' => false,
+ 'options' => array(),
+ 'id' => null,
+ 'default' => null,
+ 'placeholder' => null,
+ ), $attributes, 'contact-field' );
// special default for subject field
if ( 'subject' == $attributes['type'] && is_null( $attributes['default'] ) && !is_null( $form ) ) {
@@ -1479,17 +1760,24 @@ class Grunion_Contact_Form_Field extends Crunion_Contact_Form_Shortcode {
$r = '';
- $field_id = $this->get_attribute( 'id' );
- $field_type = $this->get_attribute( 'type' );
- $field_label = $this->get_attribute( 'label' );
- $field_required = $this->get_attribute( 'required' );
+ $field_id = $this->get_attribute( 'id' );
+ $field_type = $this->get_attribute( 'type' );
+ $field_label = $this->get_attribute( 'label' );
+ $field_required = $this->get_attribute( 'required' );
+ $placeholder = $this->get_attribute( 'placeholder' );
+ $field_placeholder = ( ! empty( $placeholder ) ) ? "placeholder='" . esc_attr( $placeholder ) . "'" : '';
if ( isset( $_POST[$field_id] ) ) {
$this->value = stripslashes( (string) $_POST[$field_id] );
- } elseif ( is_user_logged_in() ) {
+ } elseif (
+ is_user_logged_in()
+ && ( ( defined( 'IS_WPCOM' ) && IS_WPCOM )
+ || true === apply_filters( 'jetpack_auto_fill_logged_in_user', false )
+ )
+ ) {
// Special defaults for logged-in users
switch ( $this->get_attribute( 'type' ) ) {
- case 'email';
+ case 'email' :
$this->value = $current_user->data->user_email;
break;
case 'name' :
@@ -1512,13 +1800,17 @@ class Grunion_Contact_Form_Field extends Crunion_Contact_Form_Shortcode {
case 'email' :
$r .= "\n<div>\n";
$r .= "\t\t<label for='" . esc_attr( $field_id ) . "' class='grunion-field-label email" . ( $this->is_error() ? ' form-error' : '' ) . "'>" . esc_html( $field_label ) . ( $field_required ? '<span>' . __( "(required)", 'jetpack' ) . '</span>' : '' ) . "</label>\n";
- $r .= "\t\t<input type='email' name='" . esc_attr( $field_id ) . "' id='" . esc_attr( $field_id ) . "' value='" . esc_attr( $field_value ) . "' class='email' />\n";
+ $r .= "\t\t<input type='email' name='" . esc_attr( $field_id ) . "' id='" . esc_attr( $field_id ) . "' value='" . esc_attr( $field_value ) . "' class='email' " . $field_placeholder . " " . ( $field_required ? "required aria-required='true'" : "" ) . "/>\n";
$r .= "\t</div>\n";
break;
+ case 'telephone' :
+ $r .= "\n<div>\n";
+ $r .= "\t\t<label for='" . esc_attr( $field_id ) . "' class='grunion-field-label telephone" . ( $this->is_error() ? ' form-error' : '' ) . "'>" . esc_html( $field_label ) . ( $field_required ? '<span>' . __( "(required)", 'jetpack' ) . '</span>' : '' ) . "</label>\n";
+ $r .= "\t\t<input type='tel' name='" . esc_attr( $field_id ) . "' id='" . esc_attr( $field_id ) . "' value='" . esc_attr( $field_value ) . "' class='telephone' " . $field_placeholder . "/>\n";
case 'textarea' :
$r .= "\n<div>\n";
$r .= "\t\t<label for='contact-form-comment-" . esc_attr( $field_id ) . "' class='grunion-field-label textarea" . ( $this->is_error() ? ' form-error' : '' ) . "'>" . esc_html( $field_label ) . ( $field_required ? '<span>' . __( "(required)", 'jetpack' ) . '</span>' : '' ) . "</label>\n";
- $r .= "\t\t<textarea name='" . esc_attr( $field_id ) . "' id='contact-form-comment-" . esc_attr( $field_id ) . "' rows='20'>" . esc_textarea( $field_value ) . "</textarea>\n";
+ $r .= "\t\t<textarea name='" . esc_attr( $field_id ) . "' id='contact-form-comment-" . esc_attr( $field_id ) . "' rows='20' " . $field_placeholder . " " . ( $field_required ? "required aria-required='true'" : "" ) . ">" . esc_textarea( $field_value ) . "</textarea>\n";
$r .= "\t</div>\n";
break;
case 'radio' :
@@ -1526,7 +1818,7 @@ class Grunion_Contact_Form_Field extends Crunion_Contact_Form_Shortcode {
foreach ( $this->get_attribute( 'options' ) as $option ) {
$option = Grunion_Contact_Form_Plugin::strip_tags( $option );
$r .= "\t\t<label class='grunion-radio-label radio" . ( $this->is_error() ? ' form-error' : '' ) . "'>";
- $r .= "<input type='radio' name='" . esc_attr( $field_id ) . "' value='" . esc_attr( $option ) . "' class='radio' " . checked( $option, $field_value, false ) . " /> ";
+ $r .= "<input type='radio' name='" . esc_attr( $field_id ) . "' value='" . esc_attr( $option ) . "' class='radio' " . checked( $option, $field_value, false ) . " " . ( $field_required ? "required aria-required='true'" : "" ) . "/> ";
$r .= esc_html( $option ) . "</label>\n";
$r .= "\t\t<div class='clear-form'></div>\n";
}
@@ -1535,7 +1827,7 @@ class Grunion_Contact_Form_Field extends Crunion_Contact_Form_Shortcode {
case 'checkbox' :
$r .= "\t<div>\n";
$r .= "\t\t<label class='grunion-field-label checkbox" . ( $this->is_error() ? ' form-error' : '' ) . "'>\n";
- $r .= "\t\t<input type='checkbox' name='" . esc_attr( $field_id ) . "' value='" . esc_attr__( 'Yes', 'jetpack' ) . "' class='checkbox' " . checked( (bool) $field_value, true, false ) . " /> \n";
+ $r .= "\t\t<input type='checkbox' name='" . esc_attr( $field_id ) . "' value='" . esc_attr__( 'Yes', 'jetpack' ) . "' class='checkbox' " . checked( (bool) $field_value, true, false ) . " " . ( $field_required ? "required aria-required='true'" : "" ) . "/> \n";
$r .= "\t\t" . esc_html( $field_label ) . ( $field_required ? '<span>'. __( "(required)", 'jetpack' ) . '</span>' : '' ) . "</label>\n";
$r .= "\t\t<div class='clear-form'></div>\n";
$r .= "\t</div>\n";
@@ -1543,7 +1835,7 @@ class Grunion_Contact_Form_Field extends Crunion_Contact_Form_Shortcode {
case 'select' :
$r .= "\n<div>\n";
$r .= "\t\t<label for='" . esc_attr( $field_id ) . "' class='grunion-field-label select" . ( $this->is_error() ? ' form-error' : '' ) . "'>" . esc_html( $field_label ) . ( $field_required ? '<span>'. __( "(required)", 'jetpack' ) . '</span>' : '' ) . "</label>\n";
- $r .= "\t<select name='" . esc_attr( $field_id ) . "' id='" . esc_attr( $field_id ) . "' class='select' >\n";
+ $r .= "\t<select name='" . esc_attr( $field_id ) . "' id='" . esc_attr( $field_id ) . "' class='select' " . ( $field_required ? "required aria-required='true'" : "" ) . ">\n";
foreach ( $this->get_attribute( 'options' ) as $option ) {
$option = Grunion_Contact_Form_Plugin::strip_tags( $option );
$r .= "\t\t<option" . selected( $option, $field_value, false ) . ">" . esc_html( $option ) . "</option>\n";
@@ -1554,7 +1846,7 @@ class Grunion_Contact_Form_Field extends Crunion_Contact_Form_Shortcode {
case 'date' :
$r .= "\n<div>\n";
$r .= "\t\t<label for='" . esc_attr( $field_id ) . "' class='grunion-field-label " . esc_attr( $field_type ) . ( $this->is_error() ? ' form-error' : '' ) . "'>" . esc_html( $field_label ) . ( $field_required ? '<span>' . __( "(required)", 'jetpack' ) . '</span>' : '' ) . "</label>\n";
- $r .= "\t\t<input type='date' name='" . esc_attr( $field_id ) . "' id='" . esc_attr( $field_id ) . "' value='" . esc_attr( $field_value ) . "' class='" . esc_attr( $field_type ) . "'/>\n";
+ $r .= "\t\t<input type='date' name='" . esc_attr( $field_id ) . "' id='" . esc_attr( $field_id ) . "' value='" . esc_attr( $field_value ) . "' class='" . esc_attr( $field_type ) . "' " . ( $field_required ? "required aria-required='true'" : "" ) . "/>\n";
$r .= "\t</div>\n";
wp_enqueue_script( 'grunion-frontend', plugins_url( 'js/grunion-frontend.js', __FILE__ ), array( 'jquery', 'jquery-ui-datepicker' ) );
@@ -1564,11 +1856,11 @@ class Grunion_Contact_Form_Field extends Crunion_Contact_Form_Shortcode {
// input fields like name, email, url that require special validation or handling at POST
$r .= "\n<div>\n";
$r .= "\t\t<label for='" . esc_attr( $field_id ) . "' class='grunion-field-label " . esc_attr( $field_type ) . ( $this->is_error() ? ' form-error' : '' ) . "'>" . esc_html( $field_label ) . ( $field_required ? '<span>' . __( "(required)", 'jetpack' ) . '</span>' : '' ) . "</label>\n";
- $r .= "\t\t<input type='text' name='" . esc_attr( $field_id ) . "' id='" . esc_attr( $field_id ) . "' value='" . esc_attr( $field_value ) . "' class='" . esc_attr( $field_type ) . "'/>\n";
+ $r .= "\t\t<input type='text' name='" . esc_attr( $field_id ) . "' id='" . esc_attr( $field_id ) . "' value='" . esc_attr( $field_value ) . "' class='" . esc_attr( $field_type ) . "' " . $field_placeholder . " " . ( $field_required ? "required aria-required='true'" : "" ) . "/>\n";
$r .= "\t</div>\n";
}
- return $r;
+ return apply_filters( 'grunion_contact_form_field_html', $r, $field_label, ( in_the_loop() ? get_the_ID() : null ) );
}
}
diff --git a/plugins/jetpack/modules/contact-form/grunion-form-view.php b/plugins/jetpack/modules/contact-form/grunion-form-view.php
index 79d1242a..b9eee53b 100644
--- a/plugins/jetpack/modules/contact-form/grunion-form-view.php
+++ b/plugins/jetpack/modules/contact-form/grunion-form-view.php
@@ -8,7 +8,7 @@ wp_localize_script( 'grunion', 'GrunionFB_i18n', array(
'nameLabel' => esc_attr( _x( 'Name', 'Label for HTML form "Name" field in contact form builder', 'jetpack' ) ),
'emailLabel' => esc_attr( _x( 'Email', 'Label for HTML form "Email" field in contact form builder', 'jetpack' ) ),
'urlLabel' => esc_attr( _x( 'Website', 'Label for HTML form "URL/Website" field in contact form builder', 'jetpack' ) ),
- 'commentLabel' => esc_attr( _x( 'Comment', 'Label for HTML form "Comment/Response" field in contact form builder', 'jetpack' ) ),
+ 'commentLabel' => esc_attr( _x( 'Comment', 'noun', 'jetpack' ) ),
'newLabel' => esc_attr( _x( 'New Field', 'Default label for new HTML form field in contact form builder', 'jetpack' ) ),
'optionsLabel' => esc_attr( _x( 'Options', 'Label for the set of options to be included in a user-created dropdown in contact form builder', 'jetpack' ) ),
'optionsLabel' => esc_attr( _x( 'Option', 'Label for an option to be included in a user-created dropdown in contact form builder', 'jetpack' ) ),
@@ -20,6 +20,7 @@ wp_localize_script( 'grunion', 'GrunionFB_i18n', array(
'savedMessage' => esc_attr__( 'Saved successfully', 'jetpack' ),
'requiredLabel' => esc_attr( _x( '(required)', 'This HTML form field is marked as required by the user in contact form builder', 'jetpack' ) ),
'exitConfirmMessage' => esc_attr__( 'Are you sure you want to exit the form editor without saving? Any changes you have made will be lost.', 'jetpack' ),
+ 'maxNewFields' => intval( apply_filters( 'grunion_max_new_fields', 5 ) ),
) );
?>
@@ -104,6 +105,25 @@ wp_localize_script( 'grunion', 'GrunionFB_i18n', array(
.fb-settings input[type='text'], .fb-settings textarea { background-image: none !important; }
.fb-success { position: absolute; top: -3px; right: 100px; padding: 6px 23px 4px 23px; background: #FFFFE0; font-weight: normal; border: 1px solid #E6DB55; color: #333; -moz-border-radius:4px; border-radius:4px; -webkit-border-radius:4px; }
.right { float: right; }
+ /* rtl */
+ body.rtl{ direction: rtl; font-family:Tahoma,Arial,sans-serif}
+ .rtl input[type='text'] { margin-left: 4px; margin-right: 0; }
+ .rtl input[type='checkbox'], .rtl input[type='radio'] { float: right; }
+ .rtl input[type='radio'] { margin-left: 8px; margin-right: 0; }
+ .rtl label.radio { margin: -2px 5px 0 0; }
+ .rtl label span.label-required { margin-right: 4px; margin-left:0 }
+ .rtl #sidemenu { padding-right:10px; padding-left: 0; left:auto; right: 0; }
+ .rtl #sidemenu a { float:right; }
+ .rtl .fb-add-field { padding-right: 10px; padding-left: 0; }
+ .rtl .fb-add-option { margin: 0 100px 14px 0; }
+ .rtl .fb-radio-label { margin-right: 8px; margin-left: 0; float: right; }
+ .rtl .fb-remove { right: auto; left: -26px; transform: scaleX(-1); }
+ .rtl .fb-remove-option { right: auto; left: 10px; }
+ .rtl .fb-reorder:hover div { left: 0; right: auto; }
+ .rtl .fb-right { left: 0; right: auto; margin: 57px 0 0 21px; }
+ .rtl .fb-right label { float: right; }
+ .rtl .fb-success { right: auto; left: 100px;}
+ .rtl .right { float: left; }
@media only screen and (-moz-min-device-pixel-ratio: 1.5), only screen and (-o-min-device-pixel-ratio: 3/2), only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-device-pixel-ratio: 1.5) {
.fb-remove { background: url('<?php echo GRUNION_PLUGIN_URL; ?>/images/grunion-remove-field-2x.png') no-repeat; background-size: 20px 23px; }
.fb-remove:hover { background: url('<?php echo GRUNION_PLUGIN_URL; ?>/images/grunion-remove-field-hover-2x.png') no-repeat; background-size: 20px 23px; }
@@ -113,7 +133,7 @@ wp_localize_script( 'grunion', 'GrunionFB_i18n', array(
</style>
</head>
-<body>
+<body <?php if ( is_rtl() ) { echo 'class="rtl"'; }?>>
<div id="media-upload-header">
<div id="fb-success" class="fb-success" style="display: none;"><?php esc_html_e( 'Your new field was saved successfully', 'jetpack' ); ?></div>
<ul id="sidemenu">
@@ -140,6 +160,8 @@ wp_localize_script( 'grunion', 'GrunionFB_i18n', array(
<div id="fb-email-desc" class="fb-desc" style="display: none;">
<h3><?php esc_html_e( 'Do I need to fill this out?', 'jetpack' ); ?></h3>
<p><?php esc_html_e( 'Nope. However, if you&#8217;d like to modify where your feedback is sent, or the subject line you can. If you don&#8217;t make any changes here, feedback will be sent to the author of the page/post and the subject will be the name of this page/post.', 'jetpack' ); ?></p>
+ <h3 style="margin-top: 21px;"><?php esc_html_e( 'Can I send a notification to more than one person?', 'jetpack' ); ?></h3>
+ <p><?php esc_html_e( 'Yep. You can enter multiple email addresses in the Email address field, and separate them with commas. A notification email will then be sent to each email address.', 'jetpack' ); ?></p>
<div class="clear"></div>
</div>
<div id="fb-add-field" style="display: none;">
diff --git a/plugins/jetpack/modules/contact-form/grunion-omnisearch.php b/plugins/jetpack/modules/contact-form/grunion-omnisearch.php
index 16221152..b3471007 100644
--- a/plugins/jetpack/modules/contact-form/grunion-omnisearch.php
+++ b/plugins/jetpack/modules/contact-form/grunion-omnisearch.php
@@ -10,6 +10,12 @@ class Jetpack_Omnisearch_Grunion extends WP_List_Table {
function __construct() {
self::$instance = $this;
add_filter( 'omnisearch_results', array( $this, 'search'), 12, 2 );
+
+ // Push 'post_type_obj' to accepted fields for WP_List_Table (since WP 4.2)
+ global $wp_version;
+ if ( version_compare( $wp_version, '4.2-z', '>=' ) && $this->compat_fields && is_array( $this->compat_fields ) ) {
+ array_push( $this->compat_fields, 'post_type_obj' );
+ }
}
function search( $results, $search_term ) {
@@ -51,15 +57,26 @@ class Jetpack_Omnisearch_Grunion extends WP_List_Table {
}
function column_default( $post, $column_name ) {
+ // Make sure the global $post is our post.
+ $_post = $GLOBALS['post'];
+ $GLOBALS['post'] = $post;
+ setup_postdata( $post );
+
switch ( $column_name ) {
case 'feedback_from':
case 'feedback_message':
case 'feedback_date':
ob_start();
grunion_manage_post_columns( $column_name, $post->ID );
- return ob_get_clean();
+ $column_contents = ob_get_clean();
+ break;
default:
- return '<pre>' . print_r( $post, true ) . '</pre>';
+ $column_contents = '<pre>' . print_r( $post, true ) . '</pre>';
+ break;
}
+
+ $GLOBALS['post'] = $_post;
+ wp_reset_postdata();
+ return $column_contents;
}
}
diff --git a/plugins/jetpack/modules/contact-form/images/blank-screen-akismet.png b/plugins/jetpack/modules/contact-form/images/blank-screen-akismet.png
index 9efcd478..a4ba1e2d 100644
--- a/plugins/jetpack/modules/contact-form/images/blank-screen-akismet.png
+++ b/plugins/jetpack/modules/contact-form/images/blank-screen-akismet.png
Binary files differ
diff --git a/plugins/jetpack/modules/contact-form/images/blank-screen-button.png b/plugins/jetpack/modules/contact-form/images/blank-screen-button.png
index 7e3127a3..58dfa26b 100644
--- a/plugins/jetpack/modules/contact-form/images/blank-screen-button.png
+++ b/plugins/jetpack/modules/contact-form/images/blank-screen-button.png
Binary files differ
diff --git a/plugins/jetpack/modules/contact-form/images/grunion-form.png b/plugins/jetpack/modules/contact-form/images/grunion-form.png
index 6f7d9ad3..f4a0cc1d 100644
--- a/plugins/jetpack/modules/contact-form/images/grunion-form.png
+++ b/plugins/jetpack/modules/contact-form/images/grunion-form.png
Binary files differ
diff --git a/plugins/jetpack/modules/contact-form/images/grunion-menu-2x.png b/plugins/jetpack/modules/contact-form/images/grunion-menu-2x.png
index 7c197441..e3807b1f 100644
--- a/plugins/jetpack/modules/contact-form/images/grunion-menu-2x.png
+++ b/plugins/jetpack/modules/contact-form/images/grunion-menu-2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/contact-form/images/grunion-menu-big-2x.png b/plugins/jetpack/modules/contact-form/images/grunion-menu-big-2x.png
index 960bbb6a..ace939af 100644
--- a/plugins/jetpack/modules/contact-form/images/grunion-menu-big-2x.png
+++ b/plugins/jetpack/modules/contact-form/images/grunion-menu-big-2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/contact-form/images/grunion-menu-big.png b/plugins/jetpack/modules/contact-form/images/grunion-menu-big.png
index 603ce56a..c8b944b6 100644
--- a/plugins/jetpack/modules/contact-form/images/grunion-menu-big.png
+++ b/plugins/jetpack/modules/contact-form/images/grunion-menu-big.png
Binary files differ
diff --git a/plugins/jetpack/modules/contact-form/images/grunion-menu-hover-2x.png b/plugins/jetpack/modules/contact-form/images/grunion-menu-hover-2x.png
index 21840d17..97b943e9 100644
--- a/plugins/jetpack/modules/contact-form/images/grunion-menu-hover-2x.png
+++ b/plugins/jetpack/modules/contact-form/images/grunion-menu-hover-2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/contact-form/images/grunion-menu-hover.png b/plugins/jetpack/modules/contact-form/images/grunion-menu-hover.png
index 3b83433a..6849b802 100644
--- a/plugins/jetpack/modules/contact-form/images/grunion-menu-hover.png
+++ b/plugins/jetpack/modules/contact-form/images/grunion-menu-hover.png
Binary files differ
diff --git a/plugins/jetpack/modules/contact-form/images/grunion-menu.png b/plugins/jetpack/modules/contact-form/images/grunion-menu.png
index 6054e237..94697e6a 100644
--- a/plugins/jetpack/modules/contact-form/images/grunion-menu.png
+++ b/plugins/jetpack/modules/contact-form/images/grunion-menu.png
Binary files differ
diff --git a/plugins/jetpack/modules/contact-form/images/grunion-remove-field-2x.png b/plugins/jetpack/modules/contact-form/images/grunion-remove-field-2x.png
index 244c102c..bfbca5ed 100644
--- a/plugins/jetpack/modules/contact-form/images/grunion-remove-field-2x.png
+++ b/plugins/jetpack/modules/contact-form/images/grunion-remove-field-2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/contact-form/images/grunion-remove-field-hover-2x.png b/plugins/jetpack/modules/contact-form/images/grunion-remove-field-hover-2x.png
index 11fc10ed..dca39da9 100644
--- a/plugins/jetpack/modules/contact-form/images/grunion-remove-field-hover-2x.png
+++ b/plugins/jetpack/modules/contact-form/images/grunion-remove-field-hover-2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/contact-form/images/grunion-remove-option-2x.png b/plugins/jetpack/modules/contact-form/images/grunion-remove-option-2x.png
index 061114b0..4272442c 100644
--- a/plugins/jetpack/modules/contact-form/images/grunion-remove-option-2x.png
+++ b/plugins/jetpack/modules/contact-form/images/grunion-remove-option-2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/contact-form/js/grunion-admin.js b/plugins/jetpack/modules/contact-form/js/grunion-admin.js
new file mode 100644
index 00000000..d3fe222d
--- /dev/null
+++ b/plugins/jetpack/modules/contact-form/js/grunion-admin.js
@@ -0,0 +1,29 @@
+/* global ajaxurl */
+jQuery( function ( $ ) {
+ $( document ).on( 'click', '#jetpack-check-feedback-spam:not(.button-disabled)', function( e ) {
+ e.preventDefault();
+
+ $( '#jetpack-check-feedback-spam:not(.button-disabled)' ).addClass( 'button-disabled' );
+ $( '.jetpack-check-feedback-spam-spinner' ).addClass( 'spinner' ).show();
+ grunion_check_for_spam( 0, 100 );
+ } );
+
+ function grunion_check_for_spam( offset, limit ) {
+ $.post(
+ ajaxurl,
+ {
+ 'action' : 'grunion_recheck_queue',
+ 'offset' : offset,
+ 'limit' : limit
+ },
+ function ( result ) {
+ if ( result.processed < limit ) {
+ window.location.reload();
+ }
+ else {
+ grunion_check_for_spam( offset + limit, limit );
+ }
+ }
+ );
+ }
+} );
diff --git a/plugins/jetpack/modules/contact-form/js/grunion.js b/plugins/jetpack/modules/contact-form/js/grunion.js
index bbfd89e3..727cea2f 100644
--- a/plugins/jetpack/modules/contact-form/js/grunion.js
+++ b/plugins/jetpack/modules/contact-form/js/grunion.js
@@ -1,3 +1,6 @@
+/* jshint onevar: false, devel: true, smarttabs: true */
+/* global GrunionFB_i18n: true, FB, ajax_nonce_shortcode, ajax_nonce_json, ajaxurl, postId */
+
if ( ! window.FB ) {
window.FB = {};
}
@@ -11,16 +14,17 @@ GrunionFB_i18n = jQuery.extend( {
optionsLabel: 'Options',
optionLabel: 'Option',
firstOptionLabel: 'First option',
- problemGeneratingForm: "Oops, there was a problem generating your form. You'll likely need to try again.",
- moveInstructions: "Drag up or down\nto re-arrange",
+ problemGeneratingForm: 'Oops, there was a problem generating your form. You\'ll likely need to try again.',
+ moveInstructions: 'Drag up or down\nto re-arrange',
moveLabel: 'move',
editLabel: 'edit',
savedMessage: 'Saved successfully',
requiredLabel: '(required)',
exitConfirmMessage: 'Are you sure you want to exit the form editor without saving? Any changes you have made will be lost.',
+ maxNewFields: 5
}, GrunionFB_i18n );
-GrunionFB_i18n.moveInstructions = GrunionFB_i18n.moveInstructions.replace( "\n", '<br />' );
+GrunionFB_i18n.moveInstructions = GrunionFB_i18n.moveInstructions.replace( '\n', '<br />' );
FB.span = jQuery( '<span>' );
FB.esc_html = function( string ) {
@@ -29,10 +33,10 @@ FB.esc_html = function( string ) {
FB.esc_attr = function( string ) {
string = FB.esc_html( string );
- return string.replace( '"', '&quot;' ).replace( "'", '&#039;' );
+ return string.replace( '"', '&quot;' ).replace( '\'', '&#039;' );
};
-FB.ContactForm = function() {
+FB.ContactForm = (function() {
var fbForm = { // Main object that generated shortcode via AJAX call
'action' : 'grunion_shortcode',
'_ajax_nonce' : ajax_nonce_shortcode,
@@ -72,7 +76,7 @@ FB.ContactForm = function() {
};
var debug = false; // will print errors to log if true
var grunionNewCount = 0; // increment for new fields
- var maxNewFields = 5; // Limits number of new fields available
+ var maxNewFields = GrunionFB_i18n.maxNewFields; // See filter in ../grunion-form-view.php
var optionsCache = {};
var optionsCount = 0; // increment for options
var shortcode;
@@ -108,16 +112,16 @@ FB.ContactForm = function() {
}
} catch(e) {
if (debug) {
- console.log("addField(): " + e);
+ console.log('addField(): ' + e);
}
}
}
function addOption () {
try {
- optionsCount++;
+ optionsCount = jQuery( '#fb-new-options .fb-options' ).length;
var thisId = jQuery('#fb-field-id').val();
var thisType = jQuery('#fb-new-type').val();
- if (thisType === "radio") {
+ if (thisType === 'radio') {
// Add to right col
jQuery('#fb-new-options').append('<div id="fb-option-box-' + optionsCount + '" class="fb-new-fields"><span optionid="' + optionsCount + '" class="fb-remove-option"></span><label></label><input type="text" id="fb-option' + optionsCount + '" optionid="' + optionsCount + '" value="' + GrunionFB_i18n.optionLabel + '" class="fb-options" /><div>');
// Add to preview
@@ -129,12 +133,12 @@ FB.ContactForm = function() {
jQuery('#fb-field'+ thisId).append('<option id="fb-' + thisId + '-' + optionsCount + '" value="' + thisId + '-' + optionsCount + '"></option>');
}
// Add to fbForm object
- fbForm.fields[thisId].options[optionsCount] = "";
+ fbForm.fields[thisId].options[optionsCount] = '';
// Add focus to new field
jQuery('#fb-option' + optionsCount).focus().select();
} catch(e) {
if (debug) {
- console.log("addOption(): " + e);
+ console.log('addOption(): ' + e);
}
}
}
@@ -148,7 +152,7 @@ FB.ContactForm = function() {
jQuery('#fb-field-id').val(index);
optionsCache[index] = {};
optionsCache[index].options = [];
- if (value.type === "radio" || value.type === "select") {
+ if (value.type === 'radio' || value.type === 'select') {
jQuery.each(value.options, function(i, value) {
optionsCache[index].options[i] = value;
});
@@ -157,16 +161,16 @@ FB.ContactForm = function() {
});
} catch(e) {
if (debug) {
- console.log("buildPreview(): " + e);
+ console.log('buildPreview(): ' + e);
}
}
}
function customOptions (id, thisType) {
try {
var thisOptions = '';
- for (i=0; i<optionsCache[id].options.length; i++) {
+ for (var i=0; i<optionsCache[id].options.length; i++) {
if (optionsCache[id].options[i] !== undefined) {
- if (thisType === "radio") {
+ if (thisType === 'radio') {
thisOptions = thisOptions + '<div id="fb-radio-' + id + '-' + i + '"><input type="radio" id="fb-field' + id + '" name="radio-' + id + '" /><span>' + FB.esc_html( optionsCache[id].options[i] ) + '</span><div class="clear"></div></div>';
} else {
thisOptions = thisOptions + '<option id="fb-' + id + '-' + i + '" value="' + id + '-' + i + '">' + FB.esc_html( optionsCache[id].options[i] ) + '</option>';
@@ -176,22 +180,22 @@ FB.ContactForm = function() {
return thisOptions;
} catch(e) {
if (debug) {
- console.log("customOptions(): " + e);
+ console.log('customOptions(): ' + e);
}
}
}
function deleteField (that) {
try {
grunionNewCount--;
- var thisId = that.attr("id");
+ var thisId = that.attr('id');
delete fbForm.fields[thisId];
- jQuery("#"+thisId).parent().parent().remove();
+ jQuery('#' + thisId).parent().parent().remove();
if (grunionNewCount <= maxNewFields) {
jQuery('#fb-new-field').show();
}
} catch(e) {
if (debug) {
- console.log("deleteField(): " + e);
+ console.log('deleteField(): ' + e);
}
}
}
@@ -203,7 +207,7 @@ FB.ContactForm = function() {
loadFieldEditor(thisId);
} catch(e) {
if (debug) {
- console.log("editField(): " + e);
+ console.log('editField(): ' + e);
}
}
}
@@ -216,7 +220,7 @@ FB.ContactForm = function() {
} catch(e) {
alert( GrunionFB_i18n.problemGeneratingForm );
if (debug) {
- console.log("grabShortcode(): " + e);
+ console.log('grabShortcode(): ' + e);
}
}
}
@@ -227,30 +231,31 @@ FB.ContactForm = function() {
function hidePopup () {
try {
// copied from wp-includes/js/thickbox/thickbox.js
- jQuery("#TB_imageOff", window.parent.document).unbind("click");
- jQuery("#TB_closeWindowButton", window.parent.document).unbind("click");
- jQuery("#TB_window", window.parent.document).fadeOut("fast");
- jQuery('#TB_window,#TB_overlay,#TB_HideSelect', window.parent.document).trigger("unload").unbind().remove();
- jQuery("#TB_load", window.parent.document).remove();
- if (typeof window.parent.document.body.style.maxHeight == "undefined") {//if IE 6
- jQuery("body","html", window.parent.document).css({height: "auto", width: "auto"});
- jQuery("html", window.parent.document).css("overflow","");
- }
- window.parent.document.onkeydown = "";
- window.parent.document.onkeyup = "";
+ jQuery('#TB_imageOff', window.parent.document).unbind('click');
+ jQuery('#TB_closeWindowButton', window.parent.document).unbind('click');
+ jQuery('#TB_window', window.parent.document).fadeOut('fast');
+ jQuery('body', window.parent.document).removeClass('modal-open');
+ jQuery('#TB_window,#TB_overlay,#TB_HideSelect', window.parent.document).trigger('unload').unbind().remove();
+ jQuery('#TB_load', window.parent.document).remove();
+ if (typeof window.parent.document.body.style.maxHeight === 'undefined') {//if IE 6
+ jQuery('body', 'html', window.parent.document).css({height: 'auto', width: 'auto'});
+ jQuery('html', window.parent.document).css('overflow', '');
+ }
+ window.parent.document.onkeydown = '';
+ window.parent.document.onkeyup = '';
return false;
} catch(e) {
if (debug) {
- console.log("hidePopup(): " + e);
+ console.log('hidePopup(): ' + e);
}
}
}
function hideShowEditLink (whichType, that) {
try {
- if (whichType === "show") {
+ if (whichType === 'show') {
// Prevents showing links twice
- if (jQuery(".fb-edit-field").is(":visible")) {
- jQuery(".fb-edit-field").remove();
+ if (jQuery('.fb-edit-field').is(':visible')) {
+ jQuery('.fb-edit-field').remove();
}
that.find('label').prepend('<span class="right fb-edit-field" style="font-weight: normal;"><a href="" class="fb-reorder"><div style="display: none;">' + GrunionFB_i18n.moveInstructions + '</div>' + GrunionFB_i18n.moveLabel + '</a>&nbsp;&nbsp;<span style="color: #C7D8DE;">|</span>&nbsp;&nbsp;<a href="" class="fb-edit">' + GrunionFB_i18n.editLabel + '</a></span>');
} else {
@@ -258,7 +263,7 @@ FB.ContactForm = function() {
}
} catch(e) {
if (debug) {
- console.log("hideShowEditLink(): " + e);
+ console.log('hideShowEditLink(): ' + e);
}
}
}
@@ -274,19 +279,18 @@ FB.ContactForm = function() {
jQuery('#fb-new-type').val(fbForm.fields[id].type);
// Load required
if (fbForm.fields[id].required) {
- jQuery('#fb-new-required').prop("checked", true);
+ jQuery('#fb-new-required').prop('checked', true);
} else {
- jQuery('#fb-new-required').prop("checked", false);
+ jQuery('#fb-new-required').prop('checked', false);
}
// Load options if there are any
- if (thisType === "select" || thisType === "radio") {
- var thisResult = '';
+ if (thisType === 'select' || thisType === 'radio') {
var thisOptions = fbForm.fields[id].options;
jQuery('#fb-options').show();
- jQuery('#fb-new-options').html(""); // Clear it all out
- for (i=0; i<thisOptions.length; i++) {
+ jQuery('#fb-new-options').html(''); // Clear it all out
+ for (var i=0; i<thisOptions.length; i++) {
if (thisOptions[i] !== undefined) {
- if (thisType === "radio") {
+ if (thisType === 'radio') {
jQuery('#fb-new-options').append('<div id="fb-option-box-' + i + '" class="fb-new-fields"><span optionid="' + i + '" class="fb-remove-option"></span><label></label><input type="text" id="fb-option' + i + '" optionid="' + i + '" value="' + FB.esc_attr( fbForm.fields[id].options[i] ) + '" class="fb-options" /><div>');
} else {
jQuery('#fb-new-options').append('<div id="fb-option-box-' + i + '" class="fb-new-fields"><span optionid="' + i + '" class="fb-remove-option"></span><label></label><input type="text" id="fb-option' + i + '" optionid="' + i + '" value="' + FB.esc_attr( fbForm.fields[id].options[i] ) + '" class="fb-options" /><div>');
@@ -298,7 +302,7 @@ FB.ContactForm = function() {
hideDesc();
} catch(e) {
if (debug) {
- console.log("loadFieldEditor(): " + e);
+ console.log('loadFieldEditor(): ' + e);
}
}
}
@@ -311,8 +315,9 @@ FB.ContactForm = function() {
fbForm.fields = defaultFields;
} else {
jQuery.each(data.fields, function(index, value) {
- if ( 1 == value.required )
+ if ( 1 === parseInt(value.required, 10) ) {
value.required = 'true';
+ }
fbForm.fields[index] = value;
});
fbForm.to = data.to;
@@ -320,7 +325,7 @@ FB.ContactForm = function() {
}
} catch(e) {
if (debug) {
- console.log("parseShortcode(): " + e);
+ console.log('parseShortcode(): ' + e);
}
}
}
@@ -332,7 +337,7 @@ FB.ContactForm = function() {
// Remove from right
jQuery('#fb-option-box-' + optionId).remove();
// Remove from preview
- if (thisType === "radio") {
+ if (thisType === 'radio') {
jQuery('#fb-radio-' + thisId + '-' + optionId).remove();
} else {
jQuery('#fb-' + thisId + '-' + optionId).remove();
@@ -342,7 +347,7 @@ FB.ContactForm = function() {
if (idx !== -1) { fbForm.fields[thisId].options.splice(idx, 1); }
} catch(e) {
if (debug) {
- console.log("removeOption(): " + e);
+ console.log('removeOption(): ' + e);
}
}
}
@@ -355,7 +360,7 @@ FB.ContactForm = function() {
fbForm.fields[thisId].options = []; // Removes all options
} catch(e) {
if (debug) {
- console.log("removeOptions(): " + e);
+ console.log('removeOptions(): ' + e);
}
}
}
@@ -375,19 +380,22 @@ FB.ContactForm = function() {
}
var win = window.dialogArguments || opener || parent || top;
+ var currentCode;
if (isVisual) {
- var currentCode = win.tinyMCE.activeEditor.getContent();
+ currentCode = win.tinyMCE.activeEditor.getContent();
} else {
- var currentCode = jQuery('#editorcontainer textarea', window.parent.document).val();
+ currentCode = jQuery('#editorcontainer textarea', window.parent.document).val();
/* WP 3.3+ */
- if ( typeof currentCode != 'string' ) {
+ if ( typeof currentCode !== 'string' ) {
currentCode = jQuery( '.wp-editor-area', window.parent.document ).val();
}
}
- var regexp = new RegExp("\\[contact-form\\b.*?\\/?\\](?:[\\s\\S]+?\\[\\/contact-form\\])?");
+ var regexp = new RegExp('\\[contact-form\\b.*?\\/?\\](?:[\\s\\S]+?\\[\\/contact-form\\])?');
// Remove new lines that cause BR tags to show up
response = response.replace(/\n/g,' ');
+ // Convert characters to comma
+ response = response.replace( '%26#x002c;' , ',' );
// Add new shortcode
if (currentCode.match(regexp)) {
@@ -415,7 +423,7 @@ FB.ContactForm = function() {
});
} catch(e) {
if (debug) {
- console.log("sendShortcodeToEditor(): " + e);
+ console.log('sendShortcodeToEditor(): ' + e);
}
}
}
@@ -433,13 +441,13 @@ FB.ContactForm = function() {
}, 2500);
} catch(e) {
if (debug) {
- console.log("showAndHideMessage(): " + e);
+ console.log('showAndHideMessage(): ' + e);
}
}
}
function switchTabs (whichType) {
try {
- if (whichType === "preview") {
+ if (whichType === 'preview') {
jQuery('#tab-preview a').addClass('current');
jQuery('#tab-settings a').removeClass('current');
jQuery('#fb-preview-form, #fb-desc').show();
@@ -453,7 +461,7 @@ FB.ContactForm = function() {
}
} catch(e) {
if (debug) {
- console.log("switchTabs(): " + e);
+ console.log('switchTabs(): ' + e);
}
}
}
@@ -471,7 +479,7 @@ FB.ContactForm = function() {
fbForm.fields[thisId].label = thisLabel;
} catch(e) {
if (debug) {
- console.log("updateLabel(): " + e);
+ console.log('updateLabel(): ' + e);
}
}
}
@@ -481,7 +489,7 @@ FB.ContactForm = function() {
fbForm.to = thisEmail;
} catch(e) {
if (debug) {
- console.log("updateMyEmail(): " + e);
+ console.log('updateMyEmail(): ' + e);
}
}
}
@@ -492,7 +500,7 @@ FB.ContactForm = function() {
var thisOptionValue = that.val();
var thisType = jQuery('#fb-new-type').val();
// Update preview
- if (thisType === "radio") {
+ if (thisType === 'radio') {
jQuery('#fb-radio-' + thisId + '-' + thisOptionid + ' span').text(thisOptionValue);
} else {
jQuery('#fb-' + thisId + '-' + thisOptionid).text(thisOptionValue);
@@ -501,7 +509,7 @@ FB.ContactForm = function() {
fbForm.fields[thisId].options[thisOptionid] = thisOptionValue;
} catch(e) {
if (debug) {
- console.log("updateOption(): " + e);
+ console.log('updateOption(): ' + e);
}
}
}
@@ -519,7 +527,7 @@ FB.ContactForm = function() {
}
} catch(e) {
if (debug) {
- console.log("updateRequired(): " + e);
+ console.log('updateRequired(): ' + e);
}
}
}
@@ -529,16 +537,15 @@ FB.ContactForm = function() {
fbForm.subject = thisSubject;
} catch(e) {
if (debug) {
- console.log("updateSubject(): " + e);
+ console.log('updateSubject(): ' + e);
}
}
}
function updateType(thisType, thisLabelText, thisRequired) {
try {
- var isLoaded = thisType;
var thisId = jQuery('#fb-field-id').val();
- if (!thisType) { var thisType = jQuery('#fb-new-type').val(); }
- if (!thisLabelText) { var thisLabelText = jQuery('#fb-new-field' + thisId + ' .label-text').text(); }
+ if (!thisType) { thisType = jQuery('#fb-new-type').val(); }
+ if (!thisLabelText) { thisLabelText = jQuery('#fb-new-field' + thisId + ' .label-text').text(); }
var isRequired = (thisRequired) ? '<span class="label-required">' + GrunionFB_i18n.requiredLabel + '</span>' : '';
var thisLabel = '<label fieldid="' + thisId + '" for="fb-field' + thisId + '"><span class="label-text">' + FB.esc_html( thisLabelText ) + '</span>' + isRequired + '</label>';
var thisRadio = '<input type="radio" name="radio-' + thisId + '" id="fb-field' + thisId + ' "disabled="disabled" />';
@@ -551,19 +558,19 @@ FB.ContactForm = function() {
var thisClear = '<div class="clear"></div>';
var thisSelect = '<select id="fb-field' + thisId + '" fieldid="' + thisId + '"><option id="fb-' + thisId + '-' + optionsCount + '" value="' + thisId + '-' + optionsCount + '">' + GrunionFB_i18n.firstOptionLabel + '</option></select>';
switch (thisType) {
- case "checkbox":
+ case 'checkbox':
removeOptions();
jQuery('#fb-new-field' + thisId + ' .fb-fields').html(thisRadioRemove + thisCheckbox + thisRadioLabel + thisClear);
break;
- case "email":
+ case 'email':
removeOptions();
jQuery('#fb-new-field' + thisId + ' .fb-fields').html(thisRemove + thisLabel + thisText);
break;
- case "name":
+ case 'name':
removeOptions();
jQuery('#fb-new-field' + thisId + ' .fb-fields').html(thisRemove + thisLabel + thisText);
break;
- case "radio":
+ case 'radio':
jQuery('#fb-new-field' + thisId + ' .fb-fields').html(thisLabel + thisRadioRemove + '<div fieldid="' + thisId + '" id="fb-custom-radio' + thisId + '"></div>');
if (optionsCache[thisId] !== undefined && optionsCache[thisId].options.length !== 0) {
fbForm.fields[thisId].options = optionsCache[thisId].options;
@@ -576,7 +583,7 @@ FB.ContactForm = function() {
jQuery('#fb-options').show();
setTimeout(function () { jQuery('#fb-option0').focus().select(); }, 100);
break;
- case "select":
+ case 'select':
jQuery('#fb-new-field' + thisId + ' .fb-fields').html(thisRemove + thisLabel + thisSelect);
if (optionsCache[thisId] !== undefined && optionsCache[thisId].options.length !== 0) {
fbForm.fields[thisId].options = optionsCache[thisId].options;
@@ -588,15 +595,15 @@ FB.ContactForm = function() {
jQuery('#fb-options').show();
setTimeout(function () { jQuery('#fb-option0').focus().select(); }, 100);
break;
- case "text":
+ case 'text':
removeOptions();
jQuery('#fb-new-field' + thisId + ' .fb-fields').html(thisRemove + thisLabel + thisText);
break;
- case "textarea":
+ case 'textarea':
removeOptions();
jQuery('#fb-new-field' + thisId + ' .fb-fields').html(thisRemove + thisLabel + thisTextarea);
break;
- case "url":
+ case 'url':
removeOptions();
jQuery('#fb-new-field' + thisId + ' .fb-fields').html(thisRemove + thisLabel + thisText);
break;
@@ -605,7 +612,7 @@ FB.ContactForm = function() {
fbForm.fields[thisId].type = thisType;
} catch(e) {
if (debug) {
- console.log("updateType(): " + e);
+ console.log('updateType(): ' + e);
}
}
}
@@ -615,7 +622,7 @@ FB.ContactForm = function() {
//Thickbox won't resize for some reason, we are manually doing it here
var totalWidth = jQuery('body', window.parent.document).width();
var totalHeight = jQuery('body', window.parent.document).height();
- var isIE6 = typeof document.body.style.maxHeight === "undefined";
+ var isIE6 = typeof document.body.style.maxHeight === 'undefined';
jQuery('#TB_window, #TB_iframeContent', window.parent.document).css('width', '768px');
jQuery('#TB_window', window.parent.document).css({ left: (totalWidth-768)/2 + 'px', top: '23px', position: 'absolute', marginLeft: '0' });
@@ -624,7 +631,7 @@ FB.ContactForm = function() {
}
} catch(e) {
if (debug) {
- console.log("resizePop(): " + e);
+ console.log('resizePop(): ' + e);
}
}
},
@@ -632,11 +639,12 @@ FB.ContactForm = function() {
// Scroll to top of page
window.parent.scroll(0,0);
//Check for existing form data
+ var contentSource;
if (jQuery('#edButtonPreview', window.parent.document).hasClass('active') || jQuery( '#wp-content-wrap', window.parent.document ).hasClass( 'tmce-active' ) ) {
var win = window.dialogArguments || opener || parent || top;
- var contentSource = win.tinyMCE.activeEditor.getContent();
+ contentSource = win.tinyMCE.activeEditor.getContent();
} else {
- var contentSource = jQuery('#content', window.parent.document).val();
+ contentSource = jQuery('#content', window.parent.document).val();
}
var data = {
action: 'grunion_shortcode_to_json',
@@ -734,13 +742,13 @@ FB.ContactForm = function() {
window.parent.location = thisHref;
return false;
});
- jQuery("#sortable").sortable({
+ jQuery('#sortable').sortable({
axis: 'y',
handle: '.fb-reorder',
revert: true,
start: function() { jQuery('.fb-edit-field').hide(); }
});
- jQuery("#draggable").draggable({
+ jQuery('#draggable').draggable({
axis: 'y',
handle: '.fb-reorder',
connectToSortable: '#sortable',
@@ -749,4 +757,4 @@ FB.ContactForm = function() {
});
}
};
-}();
+})();
diff --git a/plugins/jetpack/modules/custom-content-types.php b/plugins/jetpack/modules/custom-content-types.php
new file mode 100644
index 00000000..9b938b52
--- /dev/null
+++ b/plugins/jetpack/modules/custom-content-types.php
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * Module Name: Custom Content Types
+ * Module Description: Organize and display different types of content on your site, separate from posts and pages.
+ * First Introduced: 3.1
+ * Requires Connection: No
+ * Auto Activate: Yes
+ * Module Tags: Writing
+ * Sort Order: 34
+ */
+
+function jetpack_load_custom_post_types() {
+ include dirname( __FILE__ ) . "/custom-post-types/portfolios.php";
+}
+
+function jetpack_custom_post_types_loaded() {
+ Jetpack::enable_module_configurable( __FILE__ );
+ Jetpack::module_configuration_load( __FILE__, 'jetpack_custom_post_types_configuration_load' );
+}
+add_action( 'jetpack_modules_loaded', 'jetpack_custom_post_types_loaded' );
+
+function jetpack_custom_post_types_configuration_load() {
+ wp_safe_redirect( admin_url( 'options-writing.php#cpt-options' ) );
+ exit;
+}
+
+// Add Settings Section for CPT
+function jetpack_cpt_settings_api_init() {
+ add_settings_section(
+ 'jetpack_cpt_section',
+ '<span id="cpt-options">' . __( 'Your Custom Content Types', 'jetpack' ) . '</span>',
+ 'jetpack_cpt_section_callback',
+ 'writing'
+ );
+}
+add_action( 'admin_init', 'jetpack_cpt_settings_api_init' );
+
+/*
+ * Settings Description
+ */
+function jetpack_cpt_section_callback() {
+ ?>
+ <p>
+ <?php esc_html_e( 'Use these settings to display different types of content on your site.', 'jetpack' ); ?>
+ <a target="_blank" href="http://jetpack.me/support/custom-content-types/"><?php esc_html_e( 'Learn More', 'jetpack' ); ?></a>
+ </p>
+ <?php
+}
+
+jetpack_load_custom_post_types();
diff --git a/plugins/jetpack/modules/custom-css.php b/plugins/jetpack/modules/custom-css.php
index 55d5e484..ef7a3454 100644
--- a/plugins/jetpack/modules/custom-css.php
+++ b/plugins/jetpack/modules/custom-css.php
@@ -2,11 +2,12 @@
/**
* Module Name: Custom CSS
- * Module Description: Customize the appearance of your site using CSS but without modifying your theme.
- * Sort Order: 11
+ * Module Description: Customize your site’s CSS without modifying your theme.
+ * Sort Order: 2
* First Introduced: 1.7
* Requires Connection: No
* Auto Activate: Yes
+ * Module Tags: Appearance
*/
function jetpack_load_custom_css() {
@@ -16,13 +17,13 @@ function jetpack_load_custom_css() {
add_action( 'jetpack_modules_loaded', 'custom_css_loaded' );
function custom_css_loaded() {
- Jetpack::enable_module_configurable( __FILE__ );
- Jetpack::module_configuration_load( __FILE__, 'custom_css_configuration_load' );
+ Jetpack::enable_module_configurable( __FILE__ );
+ Jetpack::module_configuration_load( __FILE__, 'custom_css_configuration_load' );
}
function custom_css_configuration_load() {
- wp_safe_redirect( admin_url( 'themes.php?page=editcss#settingsdiv' ) );
- exit;
+ wp_safe_redirect( admin_url( 'themes.php?page=editcss#settingsdiv' ) );
+ exit;
}
jetpack_load_custom_css(); \ No newline at end of file
diff --git a/plugins/jetpack/modules/custom-css/csstidy/class.csstidy.php b/plugins/jetpack/modules/custom-css/csstidy/class.csstidy.php
index c5826a0c..a672204e 100644
--- a/plugins/jetpack/modules/custom-css/csstidy/class.csstidy.php
+++ b/plugins/jetpack/modules/custom-css/csstidy/class.csstidy.php
@@ -34,28 +34,28 @@
*
* @version 1.0
*/
-require_once('class.csstidy_ctype.php');
+require_once( dirname( __FILE__ ) . '/class.csstidy_ctype.php' );
/**
* Various CSS data needed for correct optimisations etc.
*
* @version 1.3
*/
-require('data.inc.php');
+require( dirname( __FILE__ ) . '/data.inc.php' );
/**
* Contains a class for printing CSS code
*
* @version 1.0
*/
-require('class.csstidy_print.php');
+require( dirname( __FILE__ ) . '/class.csstidy_print.php' );
/**
* Contains a class for optimising CSS code
*
* @version 1.0
*/
-require('class.csstidy_optimise.php');
+require( dirname( __FILE__ ) . '/class.csstidy_optimise.php' );
/**
* CSS Parser class
@@ -179,7 +179,7 @@ class csstidy {
* Example for a subvalue:
* background:url(foo.png) red no-repeat;
* "url(foo.png)", "red", and "no-repeat" are subvalues,
- * seperated by whitespace
+ * separated by whitespace
* @var string
* @access private
*/
diff --git a/plugins/jetpack/modules/custom-css/csstidy/cssparse-rtl.css b/plugins/jetpack/modules/custom-css/csstidy/cssparse-rtl.css
new file mode 100644
index 00000000..1b51323e
--- /dev/null
+++ b/plugins/jetpack/modules/custom-css/csstidy/cssparse-rtl.css
@@ -0,0 +1,118 @@
+@import url("cssparsed.css");
+
+html, body {
+font:0.8em Verdana,Helvetica,sans-serif;
+background:#F8F8F6;
+}
+
+code {
+font-size:1.2em;
+}
+
+div#rightcol {
+padding-right:32em;
+}
+
+fieldset {
+display:block;
+margin:0.5em 0;
+padding:1em;
+border:solid #7284AB 2px;
+}
+fieldset.code_output {
+display:inline;
+}
+
+h1 {
+font-size:2em;
+}
+
+small {
+font-size:0.7em;
+}
+
+fieldset#field_input {
+float:right;
+margin:0 0 1em 0.5em;
+}
+
+fieldset#options,fieldset#code_layout {
+width:31em;
+}
+
+input#submit {
+clear:both;
+display:block;
+margin:1em;
+}
+
+select {
+margin:2px 0 0;
+}
+
+label.block {
+display:block;
+}
+
+legend {
+background:#c4E1C3;
+padding:2px 4px;
+border:dashed 1px;
+}
+
+textarea#css_text {
+width:27em;
+height:370px;
+display:block;
+margin-left:1em;
+}
+
+.help {
+cursor:help;
+}
+
+p.important {
+border:solid 1px red;
+font-weight:bold;
+padding:1em;
+background:white;
+}
+
+p {
+margin:1em 0;
+}
+
+dl {
+padding-right:0.5em;
+}
+
+dt {
+font-weight:bold;
+margin:0;
+float:right;
+clear:both;
+height:1.5em;
+}
+
+dd {
+margin:0 4em 0 0;
+height:1.5em;
+}
+
+fieldset#messages {
+background:white;
+padding:0 1em 0 0;
+}
+
+fieldset#messages div {
+height:10em;
+overflow:auto;
+}
+
+dd.Warning {
+color:orange;
+}
+
+dd.Information {
+color:green;
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/custom-css/csstidy/cssparse-rtl.min.css b/plugins/jetpack/modules/custom-css/csstidy/cssparse-rtl.min.css
new file mode 100644
index 00000000..5cdcc9df
--- /dev/null
+++ b/plugins/jetpack/modules/custom-css/csstidy/cssparse-rtl.min.css
@@ -0,0 +1 @@
+code#copytext{white-space:pre;font-family:Verdana}.at{color:#00008b}.format{color:gray}.property{color:green}.selector{color:#00f}.value{color:red;right:500px}.comment{color:orange}body,html{font:.8em Verdana,Helvetica,sans-serif;background:#F8F8F6}code{font-size:1.2em}div#rightcol{padding-right:32em}fieldset{display:block;margin:.5em 0;padding:1em;border:2px solid #7284AB}fieldset.code_output{display:inline}h1{font-size:2em}small{font-size:.7em}fieldset#field_input{float:right;margin:0 0 1em .5em}fieldset#code_layout,fieldset#options{width:31em}input#submit{clear:both;display:block;margin:1em}select{margin:2px 0 0}label.block{display:block}legend{background:#c4E1C3;padding:2px 4px;border:1px dashed}textarea#css_text{width:27em;height:370px;display:block;margin-left:1em}.help{cursor:help}p.important{border:1px solid red;font-weight:700;padding:1em;background:#fff}p{margin:1em 0}dl{padding-right:.5em}dt{font-weight:700;margin:0;float:right;clear:both;height:1.5em}dd{margin:0 4em 0 0;height:1.5em}fieldset#messages{background:#fff;padding:0 1em 0 0}fieldset#messages div{height:10em;overflow:auto}dd.Warning{color:orange}dd.Information{color:green} \ No newline at end of file
diff --git a/plugins/jetpack/modules/custom-css/csstidy/cssparse.min.css b/plugins/jetpack/modules/custom-css/csstidy/cssparse.min.css
new file mode 100644
index 00000000..091db9a1
--- /dev/null
+++ b/plugins/jetpack/modules/custom-css/csstidy/cssparse.min.css
@@ -0,0 +1 @@
+code#copytext{white-space:pre;font-family:Verdana}.at{color:#00008b}.format{color:gray}.property{color:green}.selector{color:#00f}.value{color:red;left:500px}.comment{color:orange}body,html{font:.8em Verdana,Helvetica,sans-serif;background:#F8F8F6}code{font-size:1.2em}div#rightcol{padding-left:32em}fieldset{display:block;margin:.5em 0;padding:1em;border:2px solid #7284AB}fieldset.code_output{display:inline}h1{font-size:2em}small{font-size:.7em}fieldset#field_input{float:left;margin:0 .5em 1em 0}fieldset#code_layout,fieldset#options{width:31em}input#submit{clear:both;display:block;margin:1em}select{margin:2px 0 0}label.block{display:block}legend{background:#c4E1C3;padding:2px 4px;border:1px dashed}textarea#css_text{width:27em;height:370px;display:block;margin-right:1em}.help{cursor:help}p.important{border:1px solid red;font-weight:700;padding:1em;background:#fff}p{margin:1em 0}dl{padding-left:.5em}dt{font-weight:700;margin:0;float:left;clear:both;height:1.5em}dd{margin:0 0 0 4em;height:1.5em}fieldset#messages{background:#fff;padding:0 0 0 1em}fieldset#messages div{height:10em;overflow:auto}dd.Warning{color:orange}dd.Information{color:green} \ No newline at end of file
diff --git a/plugins/jetpack/modules/custom-css/csstidy/cssparsed-rtl.css b/plugins/jetpack/modules/custom-css/csstidy/cssparsed-rtl.css
new file mode 100644
index 00000000..9fe4b7ee
--- /dev/null
+++ b/plugins/jetpack/modules/custom-css/csstidy/cssparsed-rtl.css
@@ -0,0 +1,29 @@
+code#copytext {
+ white-space: pre;
+ font-family: Verdana;
+}
+
+.at {
+color:darkblue;
+}
+
+.format {
+color:gray;
+}
+
+.property {
+color:green;
+}
+
+.selector {
+color:blue;
+}
+
+.value {
+color:red;
+right: 500px;
+}
+
+.comment {
+color:orange;
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/custom-css/csstidy/cssparsed-rtl.min.css b/plugins/jetpack/modules/custom-css/csstidy/cssparsed-rtl.min.css
new file mode 100644
index 00000000..ba9903d0
--- /dev/null
+++ b/plugins/jetpack/modules/custom-css/csstidy/cssparsed-rtl.min.css
@@ -0,0 +1 @@
+code#copytext{white-space:pre;font-family:Verdana}.at{color:#00008b}.format{color:gray}.property{color:green}.selector{color:#00f}.value{color:red;right:500px}.comment{color:orange} \ No newline at end of file
diff --git a/plugins/jetpack/modules/custom-css/csstidy/cssparsed.min.css b/plugins/jetpack/modules/custom-css/csstidy/cssparsed.min.css
new file mode 100644
index 00000000..0a3f81e2
--- /dev/null
+++ b/plugins/jetpack/modules/custom-css/csstidy/cssparsed.min.css
@@ -0,0 +1 @@
+code#copytext{white-space:pre;font-family:Verdana}.at{color:#00008b}.format{color:gray}.property{color:green}.selector{color:#00f}.value{color:red;left:500px}.comment{color:orange} \ No newline at end of file
diff --git a/plugins/jetpack/modules/custom-css/csstidy/data-wp.inc.php b/plugins/jetpack/modules/custom-css/csstidy/data-wp.inc.php
index de2d0bd6..97dc2c20 100644
--- a/plugins/jetpack/modules/custom-css/csstidy/data-wp.inc.php
+++ b/plugins/jetpack/modules/custom-css/csstidy/data-wp.inc.php
@@ -49,6 +49,7 @@ foreach ( $GLOBALS['csstidy']['multiple_properties'] as $property ) {
$GLOBALS['csstidy']['at_rules']['-webkit-keyframes'] = 'at';
$GLOBALS['csstidy']['at_rules']['-moz-keyframes'] = 'at';
$GLOBALS['csstidy']['at_rules']['-ms-keyframes'] = 'at';
+$GLOBALS['csstidy']['at_rules']['-o-keyframes'] = 'at';
/**
* Non-standard viewport rule.
@@ -73,6 +74,7 @@ $GLOBALS['csstidy']['all_properties']['-webkit-transform-origin-x'] = 'CSS3.0';
$GLOBALS['csstidy']['all_properties']['-webkit-transform-origin-y'] = 'CSS3.0';
$GLOBALS['csstidy']['all_properties']['-webkit-transform-origin-z'] = 'CSS3.0';
$GLOBALS['csstidy']['all_properties']['-webkit-font-smoothing'] = 'CSS3.0';
+$GLOBALS['csstidy']['all_properties']['-moz-osx-font-smoothing'] = 'CSS3.0';
$GLOBALS['csstidy']['all_properties']['-font-smooth'] = 'CSS3.0';
$GLOBALS['csstidy']['all_properties']['-o-object-fit'] = 'CSS3.0';
$GLOBALS['csstidy']['all_properties']['object-fit'] = 'CSS3.0';
@@ -80,4 +82,5 @@ $GLOBALS['csstidy']['all_properties']['-o-object-position'] = 'CSS3.0';
$GLOBALS['csstidy']['all_properties']['object-position'] = 'CSS3.0';
$GLOBALS['csstidy']['all_properties']['text-overflow'] = 'CSS3.0';
$GLOBALS['csstidy']['all_properties']['zoom'] = 'CSS3.0';
+$GLOBALS['csstidy']['all_properties']['pointer-events'] = 'CSS3.0';
diff --git a/plugins/jetpack/modules/custom-css/csstidy/data.inc.php b/plugins/jetpack/modules/custom-css/csstidy/data.inc.php
index dfb576d2..ef8a6fe8 100644
--- a/plugins/jetpack/modules/custom-css/csstidy/data.inc.php
+++ b/plugins/jetpack/modules/custom-css/csstidy/data.inc.php
@@ -64,7 +64,7 @@ $GLOBALS['csstidy']['units'] = array('in','cm','mm','pt','pc','px','rem','em','%
* @global array $GLOBALS['csstidy']['at_rules']
* @version 1.0
*/
-$GLOBALS['csstidy']['at_rules'] = array('page' => 'is','font-face' => 'is','charset' => 'iv', 'import' => 'iv','namespace' => 'iv','media' => 'at','keyframes' => 'at');
+$GLOBALS['csstidy']['at_rules'] = array('page' => 'is','font-face' => 'is','charset' => 'iv', 'import' => 'iv','namespace' => 'iv','media' => 'at','keyframes' => 'at', 'supports' => 'at');
/**
* Properties that need a value with unit
@@ -75,7 +75,7 @@ $GLOBALS['csstidy']['at_rules'] = array('page' => 'is','font-face' => 'is','char
* @version 1.2
*/
$GLOBALS['csstidy']['unit_values'] = array ('background', 'background-position', 'background-size', 'border', 'border-top', 'border-right', 'border-bottom', 'border-left', 'border-width',
- 'border-top-width', 'border-right-width', 'border-left-width', 'border-bottom-width', 'bottom', 'border-spacing', 'column-gap', 'column-width',
+ 'border-top-width', 'border-right-width', 'border-left-width', 'border-bottom-width', 'bottom', 'border-spacing', 'column-gap', 'column-width',
'font-size', 'height', 'left', 'margin', 'margin-top', 'margin-right', 'margin-bottom', 'margin-left', 'max-height',
'max-width', 'min-height', 'min-width', 'outline', 'outline-width', 'padding', 'padding-top', 'padding-right',
'padding-bottom', 'padding-left', 'perspective', 'right', 'top', 'text-indent', 'letter-spacing', 'word-spacing', 'width');
@@ -269,7 +269,7 @@ $GLOBALS['csstidy']['replace_colors']['whitesmoke'] = '#f5f5f5';
$GLOBALS['csstidy']['replace_colors']['yellowgreen'] = '#9acd32';
/**
- * A list of all shorthand properties that are devided into four properties and/or have four subvalues
+ * A list of all shorthand properties that are divided into four properties and/or have four subvalues
*
* @global array $GLOBALS['csstidy']['shorthands']
* @todo Are there new ones in CSS3?
@@ -293,6 +293,7 @@ $GLOBALS['csstidy']['shorthands']['-moz-border-radius'] = 0;
* @version 1.0
* @see csstidy::property_is_next()
*/
+$GLOBALS['csstidy']['all_properties']['align-items'] = 'CSS3.0';
$GLOBALS['csstidy']['all_properties']['alignment-adjust'] = 'CSS3.0';
$GLOBALS['csstidy']['all_properties']['alignment-baseline'] = 'CSS3.0';
$GLOBALS['csstidy']['all_properties']['animation'] = 'CSS3.0';
@@ -428,6 +429,7 @@ $GLOBALS['csstidy']['all_properties']['image-orientation'] = 'CSS3.0';
$GLOBALS['csstidy']['all_properties']['image-rendering'] = 'CSS3.0';
$GLOBALS['csstidy']['all_properties']['image-resolution'] = 'CSS3.0';
$GLOBALS['csstidy']['all_properties']['inline-box-align'] = 'CSS3.0';
+$GLOBALS['csstidy']['all_properties']['justify-content'] = 'CSS3.0';
$GLOBALS['csstidy']['all_properties']['left'] = 'CSS2.0,CSS2.1,CSS3.0';
$GLOBALS['csstidy']['all_properties']['letter-spacing'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0';
$GLOBALS['csstidy']['all_properties']['line-break'] = 'CSS3.0';
diff --git a/plugins/jetpack/modules/custom-css/csstidy/lang.inc.php b/plugins/jetpack/modules/custom-css/csstidy/lang.inc.php
index 61f95c7c..d169ddfe 100644
--- a/plugins/jetpack/modules/custom-css/csstidy/lang.inc.php
+++ b/plugins/jetpack/modules/custom-css/csstidy/lang.inc.php
@@ -26,19 +26,16 @@
* @author Brett Zamir (brettz9 at yahoo dot com) 2007
*/
-
-if(isset($_GET['lang'])) {
- $l = $_GET['lang'];
-}
-else if(isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
- $l = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
- $l = strtolower(substr($l, 0, 2));
-}
-else {
- $l = '';
+if ( isset( $_GET['lang'] ) ) {
+ $l = $_GET['lang'];
+} elseif ( isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) {
+ $l = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
+ $l = strtolower( substr( $l, 0, 2 ) );
+} else {
+ $l = '';
}
-$l = (in_array($l, array('de', 'fr', 'zh'))) ? $l : 'en';
+$l = ( in_array( $l, array( 'de', 'fr', 'zh' ) ) ) ? $l : 'en';
// note 5 in all but French, and 40 in all are orphaned
@@ -89,7 +86,7 @@ $lang['en'][44] = 'Only safe optimisations';
$lang['en'][45] = 'Compress font-weight';
$lang['en'][46] = 'Save comments';
$lang['en'][47] = 'Do not change anything';
-$lang['en'][48] = 'Only seperate selectors (split at ,)';
+$lang['en'][48] = 'Only separate selectors (split at ,)';
$lang['en'][49] = 'Merge selectors with the same properties (fast)';
$lang['en'][50] = 'Merge selectors intelligently (slow)';
$lang['en'][51] = 'Preserve CSS';
diff --git a/plugins/jetpack/modules/custom-css/custom-css.php b/plugins/jetpack/modules/custom-css/custom-css.php
index 9c3e7e7c..0ec6b016 100644
--- a/plugins/jetpack/modules/custom-css/custom-css.php
+++ b/plugins/jetpack/modules/custom-css/custom-css.php
@@ -11,6 +11,10 @@ class Jetpack_Custom_CSS {
// Override the edit link, the default link causes a redirect loop
add_filter( 'get_edit_post_link', array( __CLASS__, 'revision_post_link' ), 10, 3 );
+ // Overwrite the content width global variable if one is set in the custom css
+ add_action( 'template_redirect', array( __CLASS__, 'set_content_width' ) );
+ add_action( 'admin_init', array( __CLASS__, 'set_content_width' ) );
+
if ( ! is_admin() )
add_filter( 'stylesheet_uri', array( __CLASS__, 'style_filter' ) );
@@ -53,9 +57,27 @@ class Jetpack_Custom_CSS {
// Do migration routine if necessary
Jetpack_Custom_CSS::upgrade();
+ /**
+ * Allows additional work when migrating safecss from wp_options to wp_post.
+ *
+ * @since ?
+ * @module Custom_CSS
+ **/
do_action( 'safecss_migrate_post' );
}
+ /**
+ * Never embed the style in the head on wpcom.
+ * Yes, this filter should be added to an unsynced file on wpcom, but
+ * there is no good syntactically-correct location to put it yet.
+ * @link https://github.com/Automattic/jetpack/commit/a1be114e9179f64d147124727a58e2cf76c7e5a1#commitcomment-7763921
+ */
+ if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
+ add_filter( 'safecss_embed_style', '__return_false' );
+ } else {
+ add_filter( 'safecss_embed_style', array( 'Jetpack_Custom_CSS', 'should_we_inline_custom_css' ), 10, 2 );
+ }
+
add_action( 'wp_head', array( 'Jetpack_Custom_CSS', 'link_tag' ), 101 );
add_filter( 'jetpack_content_width', array( 'Jetpack_Custom_CSS', 'jetpack_content_width' ) );
@@ -86,6 +108,17 @@ class Jetpack_Custom_CSS {
add_action( 'admin_notices', array( 'Jetpack_Custom_CSS', 'saved_message' ) );
}
+ // Prevent content filters running on CSS when restoring revisions
+ if ( isset( $_REQUEST[ 'action' ] ) && 'restore' === $_REQUEST[ 'action' ] && false !== strstr( $_SERVER[ 'REQUEST_URI' ], 'revision.php' ) ) {
+ $parent_post = get_post( wp_get_post_parent_id( intval( $_REQUEST[ 'revision' ] ) ) );
+ if ( $parent_post && ! is_wp_error( $parent_post ) && 'safecss' === $parent_post->post_type ) {
+ // Remove wp_filter_post_kses, this causes CSS escaping issues
+ remove_filter( 'content_save_pre', 'wp_filter_post_kses' );
+ remove_filter( 'content_filtered_save_pre', 'wp_filter_post_kses' );
+ remove_all_filters( 'content_save_pre' );
+ }
+ }
+
// Modify all internal links so that preview state persists
if ( Jetpack_Custom_CSS::is_preview() )
ob_start( array( 'Jetpack_Custom_CSS', 'buffer' ) );
@@ -98,6 +131,7 @@ class Jetpack_Custom_CSS {
* @param array $args Array of arguments:
* string $css The CSS (or LESS or Sass)
* bool $is_preview Whether this CSS is preview or published
+ * string preprocessor Which CSS preprocessor to use
* bool $add_to_existing Whether this CSS replaces the theme's CSS or supplements it.
* int $content_width A custom $content_width to go along with this CSS.
* @return int The post ID of the saved Custom CSS post.
@@ -123,6 +157,17 @@ class Jetpack_Custom_CSS {
remove_filter( 'content_filtered_save_pre', 'wp_filter_post_kses' );
remove_all_filters( 'content_save_pre' );
+ /**
+ * Fires prior to saving custom css values. Necessitated because the
+ * core WordPress save_pre filters were removed:
+ * - content_save_pre
+ * - content_filtered_save_pre
+ *
+ * @since ?
+ * @module Custom_CSS
+ * @see self::save() for proper $args fields
+ * @param array $args See Jetpack_Custom_CSS::save() docblock for more
+ **/
do_action( 'safecss_save_pre', $args );
$warnings = array();
@@ -162,10 +207,31 @@ class Jetpack_Custom_CSS {
// if we're not using a preprocessor
if ( ! $args['preprocessor'] ) {
+
+ /**
+ * Fires before parsing the css with CSSTidy, but only if
+ * the preprocessor is not configured for use
+ *
+ * @since ?
+ * @module Custom_CSS
+ * @param csstidy The csstidy object
+ * @param string $css
+ * @param array $args. See self::save() docblock for proper $args fields
+ **/
do_action( 'safecss_parse_pre', $csstidy, $css, $args );
$csstidy->parse( $css );
+ /**
+ * Fires after parsing the css with CSSTidy, but only if
+ * the preprocessor is not cinfigured for use
+ *
+ * @since ?
+ * @module Custom_CSS
+ * @param csstidy $csstidy The csstidy object
+ * @param array $warnings
+ * @param array $args - See self::save() docblock for proper $args fields
+ **/
do_action( 'safecss_parse_post', $csstidy, $warnings, $args );
$css = $csstidy->print->plain();
@@ -195,6 +261,10 @@ class Jetpack_Custom_CSS {
}
// Freetrial only.
+
+ /**
+ * @todo figure out what this is
+ **/
do_action( 'safecss_save_preview_post' );
}
@@ -401,6 +471,20 @@ class Jetpack_Custom_CSS {
return isset( $_GET['csspreview'] ) && $_GET['csspreview'] === 'true';
}
+ /**
+ * Currently this filter function gets called on
+ * 'template_redirect' action and
+ * 'admin_init' action
+ */
+ static function set_content_width(){
+ // Don't apply this filter on the Edit CSS page
+ if ( isset( $_GET ) && isset( $_GET['page'] ) && 'editcss' == $_GET['page'] && is_admin() ) {
+ return;
+ }
+
+ $GLOBALS['content_width'] = Jetpack::get_content_width();
+ }
+
/*
* False when the site has the Custom Design upgrade.
* Used only on WordPress.com.
@@ -416,11 +500,15 @@ class Jetpack_Custom_CSS {
return $default_css;
$option = ( Jetpack_Custom_CSS::is_preview() || Jetpack_Custom_CSS::is_freetrial() ) ? 'safecss_preview' : 'safecss';
+ $css = '';
if ( 'safecss' == $option ) {
- if ( get_option( 'safecss_revision_migrated' ) ) {
+ // Don't bother checking for a migrated 'safecss' option if it never existed.
+ if ( false === get_option( 'safecss' ) || get_option( 'safecss_revision_migrated' ) ) {
$safecss_post = Jetpack_Custom_CSS::get_post();
- $css = ( $compressed && $safecss_post['post_content_filtered'] ) ? $safecss_post['post_content_filtered'] : $safecss_post['post_content'];
+ if ( ! empty( $safecss_post ) ) {
+ $css = ( $compressed && $safecss_post['post_content_filtered'] ) ? $safecss_post['post_content_filtered'] : $safecss_post['post_content'];
+ }
} else {
$current_revision = Jetpack_Custom_CSS::get_current_revision();
if ( false === $current_revision ) {
@@ -453,7 +541,7 @@ class Jetpack_Custom_CSS {
apply_filters(
'safecss_default_css',
__(
- "Welcome to Custom CSS!\n\nCSS (Cascading Style Sheets) is a kind of code that tells the browser how to render a web page. You may delete these comments and get started with your customizations.\n\nBy default, your stylesheet will be loaded after the theme stylesheets, which means that your rules can take precedence and override the theme CSS rules. Just write here what you want to change, you don't need to copy all your theme's stylesheet content.",
+ "Welcome to Custom CSS!\n\nTo learn how this works, see http://wp.me/PEmnE-Bt",
'jetpack'
)
)
@@ -466,10 +554,31 @@ class Jetpack_Custom_CSS {
return $css;
}
+ static function replace_insecure_urls( $css ) {
+ if ( ! function_exists( '_sa_get_frontend_https_url_replacement_map' ) ) {
+ return $css;
+ }
+ list( $http_urls, $secure_urls ) = _sa_get_frontend_https_url_replacement_map();
+
+ return str_replace( $http_urls, $secure_urls, $css );
+ }
+
static function print_css() {
+
+ /**
+ * Fires right before printing the custom CSS inside the <head> element
+ *
+ * @since ?
+ * @module Custom_CSS
+ **/
do_action( 'safecss_print_pre' );
+ $css = Jetpack_Custom_CSS::get_css( true );
+ echo self::replace_insecure_urls( $css );
+ }
- echo Jetpack_Custom_CSS::get_css( true );
+ static function should_we_inline_custom_css( $should_we, $css ) {
+ // If the CSS is less than 2,000 characters, inline it! otherwise return what was passed in.
+ return ( strlen( $css ) < 2000 ) ? true : $should_we;
}
static function link_tag() {
@@ -524,21 +633,36 @@ class Jetpack_Custom_CSS {
if ( $css == '' )
return;
- $href = home_url( '/' );
- $href = add_query_arg( 'custom-css', 1, $href );
- $href = add_query_arg( 'csblog', $blog_id, $href );
- $href = add_query_arg( 'cscache', 6, $href );
- $href = add_query_arg( 'csrev', (int) get_option( $option . '_rev' ), $href );
+ if ( apply_filters( 'safecss_embed_style', false, $css ) ) {
- $href = apply_filters( 'safecss_href', $href, $blog_id );
+ echo "\r\n" . '<style id="custom-css-css">' . Jetpack_Custom_CSS::get_css( true ) . "</style>\r\n";
- if ( Jetpack_Custom_CSS::is_preview() )
- $href = add_query_arg( 'csspreview', 'true', $href );
+ } else {
- ?>
- <link rel="stylesheet" id="custom-css-css" type="text/css" href="<?php echo esc_url( $href ); ?>" />
- <?php
+ $href = home_url( '/' );
+ $href = add_query_arg( 'custom-css', 1, $href );
+ $href = add_query_arg( 'csblog', $blog_id, $href );
+ $href = add_query_arg( 'cscache', 6, $href );
+ $href = add_query_arg( 'csrev', (int) get_option( $option . '_rev' ), $href );
+
+ $href = apply_filters( 'safecss_href', $href, $blog_id );
+
+ if ( Jetpack_Custom_CSS::is_preview() )
+ $href = add_query_arg( 'csspreview', 'true', $href );
+ ?>
+ <link rel="stylesheet" id="custom-css-css" type="text/css" href="<?php echo esc_url( $href ); ?>" />
+ <?php
+
+ }
+
+ /**
+ * Fires after creating the <link> in the <head> element
+ * for the custom css stylesheet
+ *
+ * @since ?
+ * @module Custom_CSS
+ **/
do_action( 'safecss_link_tag_post' );
}
@@ -577,15 +701,16 @@ class Jetpack_Custom_CSS {
$message = apply_filters( 'safecss_preview_message', $message );
$preview_flag_js = "var flag = document.createElement('div');
- flag.innerHTML = " . json_encode( $message ) . ";
- flag.style.background = 'black';
- flag.style.color = 'white';
- flag.style.textAlign = 'center';
- flag.style.fontSize = '15px';
- flag.style.padding = '1px';
- document.body.style.paddingTop = '32px';
- document.body.insertBefore(flag, document.body.childNodes[0]);
- ";
+ flag.innerHTML = " . json_encode( $message ) . ";
+ flag.style.background = '#FF6600';
+ flag.style.color = 'white';
+ flag.style.textAlign = 'center';
+ flag.style.fontSize = '15px';
+ flag.style.padding = '2px';
+ flag.style.fontFamily = 'sans-serif';
+ document.body.style.paddingTop = '0px';
+ document.body.insertBefore(flag, document.body.childNodes[0]);
+ ";
$preview_flag_js = apply_filters( 'safecss_preview_flag_js', $preview_flag_js );
if ( $preview_flag_js ) {
@@ -604,7 +729,6 @@ class Jetpack_Custom_CSS {
$title = __( 'Edit CSS', 'jetpack' );
$hook = add_theme_page( $title, $title, 'edit_theme_options', 'editcss', array( 'Jetpack_Custom_CSS', 'admin' ) );
- add_action( "admin_head-$hook", array( 'Jetpack_Custom_CSS', 'admin_head' ) );
add_action( "load-revision.php", array( 'Jetpack_Custom_CSS', 'prettify_post_revisions' ) );
add_action( "load-$hook", array( 'Jetpack_Custom_CSS', 'update_title' ) );
}
@@ -647,29 +771,11 @@ class Jetpack_Custom_CSS {
wp_enqueue_style( 'custom-css-editor', plugins_url( 'custom-css/css/css-editor.css', __FILE__ ) );
if ( defined( 'SAFECSS_USE_ACE' ) && SAFECSS_USE_ACE ) {
- $url = plugins_url( 'custom-css/js/', __FILE__ );
-
- wp_enqueue_script( 'jquery.spin' );
- wp_enqueue_script( 'safecss-ace', $url . 'ace/ace.js', array(), '20130213', true );
- wp_enqueue_script( 'safecss-ace-css', $url . 'ace/mode-css.js', array( 'safecss-ace' ), '20130213', true );
- wp_enqueue_script( 'safecss-ace-less', $url . 'ace/mode-less.js', array( 'safecss-ace' ), '20130213', true );
- wp_enqueue_script( 'safecss-ace-scss', $url . 'ace/mode-scss.js', array( 'safecss-ace' ), '20130213', true );
- wp_enqueue_script( 'safecss-ace-use', $url . 'safecss-ace.js', array( 'jquery', 'safecss-ace-css' ), '20130213', true );
+ wp_register_style( 'jetpack-css-codemirror', plugins_url( 'custom-css/css/codemirror.css', __FILE__ ), array(), '20120905' );
+ wp_enqueue_style( 'jetpack-css-use-codemirror', plugins_url( 'custom-css/css/use-codemirror.css', __FILE__ ), array( 'jetpack-css-codemirror' ), '20120905' );
- wp_enqueue_style( 'custom-css-ace', plugins_url( 'custom-css/css/ace.css', __FILE__ ) );
- }
- }
-
- static function admin_head() {
- if ( defined( 'SAFECSS_USE_ACE' ) && SAFECSS_USE_ACE ) {
- ?>
- <script type="text/javascript">
- /*<![CDATA[*/
- var SAFECSS_USE_ACE = true;
- var safecssAceSrcPath = <?php echo json_encode( parse_url( plugins_url( 'custom-css/js/ace/', __FILE__ ), PHP_URL_PATH ) ); ?>;
- /*]]>*/
- </script>
- <?php
+ wp_register_script( 'jetpack-css-codemirror', plugins_url( 'custom-css/js/codemirror.min.js', __FILE__ ), array(), '3.16', true );
+ wp_enqueue_script( 'jetpack-css-use-codemirror', plugins_url( 'custom-css/js/use-codemirror.js', __FILE__ ), array( 'jquery', 'underscore', 'jetpack-css-codemirror' ), '20131009', true );
}
}
@@ -686,37 +792,39 @@ class Jetpack_Custom_CSS {
if ( ! empty( $safecss_post ) && 0 < $safecss_post['ID'] && wp_get_post_revisions( $safecss_post['ID'] ) )
add_meta_box( 'revisionsdiv', __( 'CSS Revisions', 'jetpack' ), array( __CLASS__, 'revisions_meta_box' ), 'editcss', 'side' );
?>
- <div class="wrap columns-2">
- <?php do_action( 'custom_design_header' ); ?>
+ <div class="wrap">
+ <?php
+
+ /**
+ * Fire right before the custom css page begins
+ *
+ * @since ?
+ * @module Custom_CSS
+ **/
+ do_action( 'custom_design_header' );
+
+ ?>
<h2><?php _e( 'CSS Stylesheet Editor', 'jetpack' ); ?></h2>
<form id="safecssform" action="" method="post">
<?php wp_nonce_field( 'safecss' ) ?>
<?php wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false ); ?>
<?php wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false ); ?>
<input type="hidden" name="action" value="save" />
- <div id="poststuff" class="metabox-holder has-right-sidebar">
+ <div id="poststuff">
<p class="css-support"><?php echo apply_filters( 'safecss_intro_text', __( 'New to CSS? Start with a <a href="http://www.htmldog.com/guides/cssbeginner/">beginner tutorial</a>. Questions?
Ask in the <a href="http://wordpress.org/support/forum/themes-and-templates">Themes and Templates forum</a>.', 'jetpack' ) ); ?></p>
- <div id="postbox-container-1" class="inner-sidebar">
- <?php do_meta_boxes( 'editcss', 'side', $safecss_post ); ?>
- </div>
- <div id="post-body">
+ <p class="css-support"><?php echo __( 'Note: Custom CSS will be reset when changing themes.', 'jetpack' ); ?></p>
+
+ <div id="post-body" class="metabox-holder columns-2">
<div id="post-body-content">
<div class="postarea">
- <?php if ( defined( 'SAFECSS_USE_ACE' ) && SAFECSS_USE_ACE ) { ?>
- <div id="safecss-container">
- <div id="safecss-ace"></div>
- </div>
- <script type="text/javascript">
- jQuery.fn.spin && jQuery("#safecss-container").spin( 'large' );
- </script>
- <textarea id="safecss" name="safecss" class="hide-if-js"><?php echo esc_textarea( Jetpack_Custom_CSS::get_css() ); ?></textarea>
- <div class="clear"></div>
- <?php } else { ?>
- <p><textarea id="safecss" name="safecss"><?php echo str_replace('</textarea>', '&lt;/textarea&gt', Jetpack_Custom_CSS::get_css()); ?></textarea></p>
- <?php } ?>
+ <textarea id="safecss" name="safecss"<?php if ( SAFECSS_USE_ACE ) echo ' class="hide-if-js"'; ?>><?php echo esc_textarea( Jetpack_Custom_CSS::get_css() ); ?></textarea>
+ <div class="clear"></div>
</div>
</div>
+ <div id="postbox-container-1" class="postbox-container">
+ <?php do_meta_boxes( 'editcss', 'side', $safecss_post ); ?>
+ </div>
</div>
<br class="clear" />
</div>
@@ -742,7 +850,7 @@ class Jetpack_Custom_CSS {
?>
<div class="misc-pub-section">
- <label><?php esc_html_e( 'Content Width:', 'jetpack' ); ?></label>
+ <label><?php esc_html_e( 'Media Width:', 'jetpack' ); ?></label>
<span id="content-width-display" data-default-text="<?php esc_attr_e( 'Default', 'jetpack' ); ?>" data-custom-text="<?php esc_attr_e( '%s px', 'jetpack' ); ?>"><?php echo $custom_content_width ? sprintf( esc_html__( '%s px', 'jetpack' ), $custom_content_width ) : esc_html_e( 'Default', 'jetpack' ); ?></span>
<a class="edit-content-width hide-if-no-js" href="#content-width"><?php echo esc_html_e( 'Edit', 'jetpack' ); ?></a>
<div id="content-width-select" class="hide-if-js">
@@ -887,7 +995,18 @@ class Jetpack_Custom_CSS {
<a class="cancel-css-mode hide-if-no-js" href="#css-mode"><?php esc_html_e( 'Cancel', 'jetpack' ); ?></a>
</div>
</div>
- <?php do_action( 'custom_css_submitbox_misc_actions' ); ?>
+ <?php
+
+ /**
+ * Allows addition of elements to the submit box for custom css
+ * on the wp-admin side
+ *
+ * @since ?
+ * @module Custom_CSS
+ **/
+ do_action( 'custom_css_submitbox_misc_actions' );
+
+ ?>
</div>
</div>
<div id="major-publishing-actions">
@@ -915,12 +1034,16 @@ class Jetpack_Custom_CSS {
* @return string
*/
static function revisions_meta_box( $safecss_post ) {
- if ( function_exists( 'wp_revisions_to_keep' ) )
- $max_revisions = wp_revisions_to_keep( $safecss_post );
- else
+
+ $show_all_revisions = isset( $_GET['show_all_rev'] );
+
+ if ( function_exists( 'wp_revisions_to_keep' ) ) {
+ $max_revisions = wp_revisions_to_keep( (object) $safecss_post );
+ } else {
$max_revisions = defined( 'WP_POST_REVISIONS' ) && is_numeric( WP_POST_REVISIONS ) ? (int) WP_POST_REVISIONS : 25;
+ }
- $posts_per_page = isset( $_GET['show_all_rev'] ) ? $max_revisions : 6;
+ $posts_per_page = $show_all_revisions ? $max_revisions : 6;
$revisions = new WP_Query( array(
'posts_per_page' => $posts_per_page,
@@ -952,7 +1075,7 @@ class Jetpack_Custom_CSS {
?></ul><?php
- if ( $revisions->found_posts > 6 ) {
+ if ( $revisions->found_posts > 6 && !$show_all_revisions ) {
?>
<br>
<a href="<?php echo add_query_arg( 'show_all_rev', 'true', menu_page_url( 'editcss', false ) ); ?>"><?php esc_html_e( 'Show more', 'jetpack' ); ?></a>
@@ -1069,6 +1192,10 @@ class Jetpack_Custom_CSS {
static function upgrade() {
$css = get_option( 'safecss' );
+ if ( get_option( 'safecss_revision_migrated' ) ) {
+ return false;
+ }
+
// Check if CSS is stored in wp_options
if ( $css ) {
// Remove the async actions from publish_post
@@ -1446,7 +1573,7 @@ function custom_css_minify( $css, $preprocessor = '' ) {
function custom_css_restore_revision( $_post_id, $_revision_id ) {
_deprecated_function( __FUNCTION__, '2.1', 'Jetpack_Custom_CSS::restore_revision()' );
- return Jetpack_Custom_CSS::restore_revision( $_post_id, $_revision_id );;
+ return Jetpack_Custom_CSS::restore_revision( $_post_id, $_revision_id );
}
function safecss_class() {
@@ -1462,12 +1589,28 @@ function safecss_class() {
}
function postparse() {
+
+ /**
+ * Do actions after parsing the css
+ *
+ * @since ?
+ * @module Custom_CSS
+ * @param safecss $obj
+ **/
do_action( 'csstidy_optimize_postparse', $this );
return parent::postparse();
}
function subvalue() {
+
+ /**
+ * Do action before optimizing the subvalue
+ *
+ * @since ?
+ * @module Custom_CSS
+ * @param safecss $obj
+ **/
do_action( 'csstidy_optimize_subvalue', $this );
return parent::subvalue();
@@ -1483,4 +1626,4 @@ if ( ! function_exists( 'safecss_filter_attr' ) ) {
add_action( 'init', array( 'Jetpack_Custom_CSS', 'init' ) );
-include dirname( __FILE__ ) . '/custom-css/preprocessors.php'; \ No newline at end of file
+include dirname( __FILE__ ) . '/custom-css/preprocessors.php';
diff --git a/plugins/jetpack/modules/custom-css/custom-css/css/ace.css b/plugins/jetpack/modules/custom-css/custom-css/css/ace.css
deleted file mode 100644
index e9418935..00000000
--- a/plugins/jetpack/modules/custom-css/custom-css/css/ace.css
+++ /dev/null
@@ -1,25 +0,0 @@
-#safecss-container {
- position: relative;
- width: 99.5%;
- height: 400px;
- border: 1px solid #dfdfdf;
- border-radius: 3px;
-}
-
-#safecss, #safecss-container .ace_editor, #safecss-container .ace_editor * {
- font-family: Consolas, Monaco, Courier, monospace !important;
-}
-
-#safecss-ace {
- width: 100%;
- height: 100%;
- display: none; /* Hide on load otherwise it looks weird */
-}
-
-#safecss-ace.ace_editor {
- display: block;
-}
-
-#safecss-container .ace-tm .ace_gutter {
- background-color: #ededed;
-}
diff --git a/plugins/jetpack/modules/custom-css/custom-css/css/codemirror-rtl.css b/plugins/jetpack/modules/custom-css/custom-css/css/codemirror-rtl.css
new file mode 100644
index 00000000..c44c3064
--- /dev/null
+++ b/plugins/jetpack/modules/custom-css/custom-css/css/codemirror-rtl.css
@@ -0,0 +1,262 @@
+/* NOAUTORTL */
+.rtl .CodeMirror {
+ direction: rtl; /* code should always be written left to right */
+}
+/* BASICS */
+.CodeMirror {
+ /* Set height, width, borders, and global font properties here */
+ font-family: monospace;
+ height: 400px;
+}
+.CodeMirror-scroll {
+ /* Set scrolling behaviour here */
+ overflow: auto;
+}
+
+/* PADDING */
+
+.CodeMirror-lines {
+ padding: 4px 0; /* Vertical padding around content */
+}
+.CodeMirror pre {
+ padding: 0 4px; /* Horizontal padding of content */
+}
+
+.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
+ background-color: white; /* The little square between H and V scrollbars */
+}
+
+/* GUTTER */
+
+.CodeMirror-gutters {
+ border-left: 1px solid #ddd;
+ background-color: #f7f7f7;
+ white-space: nowrap;
+}
+.CodeMirror-linenumbers {}
+.CodeMirror-linenumber {
+ padding: 0 5px 0 3px;
+ min-width: 20px;
+ text-align: left;
+ color: #999;
+}
+
+/* CURSOR */
+
+.CodeMirror div.CodeMirror-cursor {
+ border-right: 1px solid black;
+ z-index: 3;
+}
+/* Shown when moving in bi-directional text */
+.CodeMirror div.CodeMirror-secondarycursor {
+ border-right: 1px solid silver;
+}
+.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
+ width: auto;
+ border: 0;
+ background: #7e7;
+ z-index: 1;
+}
+/* Can style cursor different in overwrite (non-insert) mode */
+.CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite {}
+
+.cm-tab { display: inline-block; }
+
+/* DEFAULT THEME */
+
+.cm-s-default .cm-keyword {color: #708;}
+.cm-s-default .cm-atom {color: #219;}
+.cm-s-default .cm-number {color: #164;}
+.cm-s-default .cm-def {color: #00f;}
+.cm-s-default .cm-variable {color: black;}
+.cm-s-default .cm-variable-2 {color: #05a;}
+.cm-s-default .cm-variable-3 {color: #085;}
+.cm-s-default .cm-property {color: black;}
+.cm-s-default .cm-operator {color: black;}
+.cm-s-default .cm-comment {color: #a50;}
+.cm-s-default .cm-string {color: #a11;}
+.cm-s-default .cm-string-2 {color: #f50;}
+.cm-s-default .cm-meta {color: #555;}
+.cm-s-default .cm-error {color: #f00;}
+.cm-s-default .cm-qualifier {color: #555;}
+.cm-s-default .cm-builtin {color: #30a;}
+.cm-s-default .cm-bracket {color: #997;}
+.cm-s-default .cm-tag {color: #170;}
+.cm-s-default .cm-attribute {color: #00c;}
+.cm-s-default .cm-header {color: blue;}
+.cm-s-default .cm-quote {color: #090;}
+.cm-s-default .cm-hr {color: #999;}
+.cm-s-default .cm-link {color: #00c;}
+
+.cm-negative {color: #d44;}
+.cm-positive {color: #292;}
+.cm-header, .cm-strong {font-weight: bold;}
+.cm-em {font-style: italic;}
+.cm-link {text-decoration: underline;}
+
+.cm-invalidchar {color: #f00;}
+
+div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
+div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
+.CodeMirror-activeline-background {background: #e8f2ff;}
+
+/* STOP */
+
+/* The rest of this file contains styles related to the mechanics of
+ the editor. You probably shouldn't touch them. */
+
+.CodeMirror {
+ line-height: 1;
+ position: relative;
+ overflow: hidden;
+ background: white;
+ color: black;
+}
+
+.CodeMirror-scroll {
+ /* 30px is the magic margin used to hide the element's real scrollbars */
+ /* See overflow: hidden in .CodeMirror */
+ margin-bottom: -30px; margin-left: -30px;
+ padding-bottom: 30px; padding-left: 30px;
+ height: 100%;
+ outline: none; /* Prevent dragging from highlighting the element */
+ position: relative;
+}
+.CodeMirror-sizer {
+ position: relative;
+}
+
+/* The fake, visible scrollbars. Used to force redraw during scrolling
+ before actuall scrolling happens, thus preventing shaking and
+ flickering artifacts. */
+.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
+ position: absolute;
+ z-index: 6;
+ display: none;
+}
+.CodeMirror-vscrollbar {
+ left: 0; top: 0;
+ overflow-x: hidden;
+ overflow-y: scroll;
+}
+.CodeMirror-hscrollbar {
+ bottom: 0; right: 0;
+ overflow-y: hidden;
+ overflow-x: scroll;
+}
+.CodeMirror-scrollbar-filler {
+ left: 0; bottom: 0;
+}
+.CodeMirror-gutter-filler {
+ right: 0; bottom: 0;
+}
+
+.CodeMirror-gutters {
+ position: absolute; right: 0; top: 0;
+ padding-bottom: 30px;
+ z-index: 3;
+}
+.CodeMirror-gutter {
+ white-space: normal;
+ height: 100%;
+ padding-bottom: 30px;
+ margin-bottom: -32px;
+ display: inline-block;
+ /* Hack to make IE7 behave */
+ *zoom:1;
+ *display:inline;
+}
+.CodeMirror-gutter-elt {
+ position: absolute;
+ cursor: default;
+ z-index: 4;
+}
+
+.CodeMirror-lines {
+ cursor: text;
+}
+.CodeMirror pre {
+ /* Reset some styles that the rest of the page might have set */
+ -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
+ border-width: 0;
+ background: transparent;
+ font-family: inherit;
+ font-size: inherit;
+ margin: 0;
+ white-space: pre;
+ word-wrap: normal;
+ line-height: inherit;
+ color: inherit;
+ z-index: 2;
+ position: relative;
+ overflow: visible;
+}
+.CodeMirror-wrap pre {
+ word-wrap: break-word;
+ white-space: pre-wrap;
+ word-break: normal;
+}
+.CodeMirror-code pre {
+ border-left: 30px solid transparent;
+ width: -webkit-fit-content;
+ width: -moz-fit-content;
+ width: fit-content;
+}
+.CodeMirror-wrap .CodeMirror-code pre {
+ border-left: none;
+ width: auto;
+}
+.CodeMirror-linebackground {
+ position: absolute;
+ right: 0; left: 0; top: 0; bottom: 0;
+ z-index: 0;
+}
+
+.CodeMirror-linewidget {
+ position: relative;
+ z-index: 2;
+ overflow: auto;
+}
+
+.CodeMirror-widget {
+}
+
+.CodeMirror-wrap .CodeMirror-scroll {
+ overflow-x: hidden;
+}
+
+.CodeMirror-measure {
+ position: absolute;
+ width: 100%; height: 0px;
+ overflow: hidden;
+ visibility: hidden;
+}
+.CodeMirror-measure pre { position: static; }
+
+.CodeMirror div.CodeMirror-cursor {
+ position: absolute;
+ visibility: hidden;
+ border-left: none;
+ width: 0;
+}
+.CodeMirror-focused div.CodeMirror-cursor {
+ visibility: visible;
+}
+
+.CodeMirror-selected { background: #d9d9d9; }
+.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
+
+.cm-searching {
+ background: #ffa;
+ background: rgba(255, 255, 0, .4);
+}
+
+/* IE7 hack to prevent it from returning funny offsetTops on the spans */
+.CodeMirror span { *vertical-align: text-bottom; }
+
+@media print {
+ /* Hide the cursor when printing */
+ .CodeMirror div.CodeMirror-cursor {
+ visibility: hidden;
+ }
+}
diff --git a/plugins/jetpack/modules/custom-css/custom-css/css/codemirror-rtl.min.css b/plugins/jetpack/modules/custom-css/custom-css/css/codemirror-rtl.min.css
new file mode 100644
index 00000000..f4fc4e53
--- /dev/null
+++ b/plugins/jetpack/modules/custom-css/custom-css/css/codemirror-rtl.min.css
@@ -0,0 +1 @@
+.rtl .CodeMirror{direction:rtl}.CodeMirror{font-family:monospace;height:400px}.CodeMirror-scroll{overflow:auto}.CodeMirror-lines{padding:4px 0}.CodeMirror pre{padding:0 4px}.CodeMirror-gutter-filler,.CodeMirror-scrollbar-filler{background-color:#fff}.CodeMirror-gutters{border-left:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}.CodeMirror-linenumber{padding:0 5px 0 3px;min-width:20px;text-align:left;color:#999}.CodeMirror div.CodeMirror-cursor{border-right:1px solid #000;z-index:3}.CodeMirror div.CodeMirror-secondarycursor{border-right:1px solid silver}.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor{width:auto;border:0;background:#7e7;z-index:1}.cm-tab{display:inline-block}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable{color:#000}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-variable-3{color:#085}.cm-s-default .cm-operator,.cm-s-default .cm-property{color:#000}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta{color:#555}.cm-s-default .cm-error{color:red}.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-header{color:#00f}.cm-s-default .cm-quote{color:#090}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-invalidchar{color:red}div.CodeMirror span.CodeMirror-matchingbracket{color:#0f0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#f22}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{line-height:1;position:relative;overflow:hidden;background:#fff;color:#000}.CodeMirror-scroll{margin-bottom:-30px;margin-left:-30px;padding-bottom:30px;padding-left:30px;height:100%;outline:0;position:relative}.CodeMirror-sizer{position:relative}.CodeMirror-gutter-filler,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-vscrollbar{position:absolute;z-index:6;display:none}.CodeMirror-vscrollbar{left:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;right:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{left:0;bottom:0}.CodeMirror-gutter-filler{right:0;bottom:0}.CodeMirror-gutters{position:absolute;right:0;top:0;padding-bottom:30px;z-index:3}.CodeMirror-gutter{white-space:normal;height:100%;padding-bottom:30px;margin-bottom:-32px;display:inline-block}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-lines{cursor:text}.CodeMirror pre{border-radius:0;border-width:0;background:0 0;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible}.CodeMirror-wrap pre{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-code pre{border-left:30px solid transparent;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.CodeMirror-wrap .CodeMirror-code pre{border-left:none;width:auto}.CodeMirror-linebackground{position:absolute;right:0;left:0;top:0;bottom:0;z-index:0}.CodeMirror-linewidget{position:relative;z-index:2;overflow:auto}.CodeMirror-wrap .CodeMirror-scroll{overflow-x:hidden}.CodeMirror-measure{position:absolute;width:100%;height:0;overflow:hidden;visibility:hidden}.CodeMirror-measure pre{position:static}.CodeMirror div.CodeMirror-cursor{position:absolute;visibility:hidden;border-left:none;width:0}.CodeMirror-focused div.CodeMirror-cursor{visibility:visible}.CodeMirror-selected{background:#d9d9d9}.CodeMirror-focused .CodeMirror-selected{background:#d7d4f0}.cm-searching{background:#ffa;background:rgba(255,255,0,.4)}@media print{.CodeMirror div.CodeMirror-cursor{visibility:hidden}} \ No newline at end of file
diff --git a/plugins/jetpack/modules/custom-css/custom-css/css/codemirror.css b/plugins/jetpack/modules/custom-css/custom-css/css/codemirror.css
new file mode 100644
index 00000000..007a0711
--- /dev/null
+++ b/plugins/jetpack/modules/custom-css/custom-css/css/codemirror.css
@@ -0,0 +1,262 @@
+/* NOAUTORTL */
+.rtl .CodeMirror {
+ direction: ltr; /* code should always be written left to right */
+}
+/* BASICS */
+.CodeMirror {
+ /* Set height, width, borders, and global font properties here */
+ font-family: monospace;
+ height: 400px;
+}
+.CodeMirror-scroll {
+ /* Set scrolling behaviour here */
+ overflow: auto;
+}
+
+/* PADDING */
+
+.CodeMirror-lines {
+ padding: 4px 0; /* Vertical padding around content */
+}
+.CodeMirror pre {
+ padding: 0 4px; /* Horizontal padding of content */
+}
+
+.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
+ background-color: white; /* The little square between H and V scrollbars */
+}
+
+/* GUTTER */
+
+.CodeMirror-gutters {
+ border-right: 1px solid #ddd;
+ background-color: #f7f7f7;
+ white-space: nowrap;
+}
+.CodeMirror-linenumbers {}
+.CodeMirror-linenumber {
+ padding: 0 3px 0 5px;
+ min-width: 20px;
+ text-align: right;
+ color: #999;
+}
+
+/* CURSOR */
+
+.CodeMirror div.CodeMirror-cursor {
+ border-left: 1px solid black;
+ z-index: 3;
+}
+/* Shown when moving in bi-directional text */
+.CodeMirror div.CodeMirror-secondarycursor {
+ border-left: 1px solid silver;
+}
+.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
+ width: auto;
+ border: 0;
+ background: #7e7;
+ z-index: 1;
+}
+/* Can style cursor different in overwrite (non-insert) mode */
+.CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite {}
+
+.cm-tab { display: inline-block; }
+
+/* DEFAULT THEME */
+
+.cm-s-default .cm-keyword {color: #708;}
+.cm-s-default .cm-atom {color: #219;}
+.cm-s-default .cm-number {color: #164;}
+.cm-s-default .cm-def {color: #00f;}
+.cm-s-default .cm-variable {color: black;}
+.cm-s-default .cm-variable-2 {color: #05a;}
+.cm-s-default .cm-variable-3 {color: #085;}
+.cm-s-default .cm-property {color: black;}
+.cm-s-default .cm-operator {color: black;}
+.cm-s-default .cm-comment {color: #a50;}
+.cm-s-default .cm-string {color: #a11;}
+.cm-s-default .cm-string-2 {color: #f50;}
+.cm-s-default .cm-meta {color: #555;}
+.cm-s-default .cm-error {color: #f00;}
+.cm-s-default .cm-qualifier {color: #555;}
+.cm-s-default .cm-builtin {color: #30a;}
+.cm-s-default .cm-bracket {color: #997;}
+.cm-s-default .cm-tag {color: #170;}
+.cm-s-default .cm-attribute {color: #00c;}
+.cm-s-default .cm-header {color: blue;}
+.cm-s-default .cm-quote {color: #090;}
+.cm-s-default .cm-hr {color: #999;}
+.cm-s-default .cm-link {color: #00c;}
+
+.cm-negative {color: #d44;}
+.cm-positive {color: #292;}
+.cm-header, .cm-strong {font-weight: bold;}
+.cm-em {font-style: italic;}
+.cm-link {text-decoration: underline;}
+
+.cm-invalidchar {color: #f00;}
+
+div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
+div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
+.CodeMirror-activeline-background {background: #e8f2ff;}
+
+/* STOP */
+
+/* The rest of this file contains styles related to the mechanics of
+ the editor. You probably shouldn't touch them. */
+
+.CodeMirror {
+ line-height: 1;
+ position: relative;
+ overflow: hidden;
+ background: white;
+ color: black;
+}
+
+.CodeMirror-scroll {
+ /* 30px is the magic margin used to hide the element's real scrollbars */
+ /* See overflow: hidden in .CodeMirror */
+ margin-bottom: -30px; margin-right: -30px;
+ padding-bottom: 30px; padding-right: 30px;
+ height: 100%;
+ outline: none; /* Prevent dragging from highlighting the element */
+ position: relative;
+}
+.CodeMirror-sizer {
+ position: relative;
+}
+
+/* The fake, visible scrollbars. Used to force redraw during scrolling
+ before actuall scrolling happens, thus preventing shaking and
+ flickering artifacts. */
+.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
+ position: absolute;
+ z-index: 6;
+ display: none;
+}
+.CodeMirror-vscrollbar {
+ right: 0; top: 0;
+ overflow-x: hidden;
+ overflow-y: scroll;
+}
+.CodeMirror-hscrollbar {
+ bottom: 0; left: 0;
+ overflow-y: hidden;
+ overflow-x: scroll;
+}
+.CodeMirror-scrollbar-filler {
+ right: 0; bottom: 0;
+}
+.CodeMirror-gutter-filler {
+ left: 0; bottom: 0;
+}
+
+.CodeMirror-gutters {
+ position: absolute; left: 0; top: 0;
+ padding-bottom: 30px;
+ z-index: 3;
+}
+.CodeMirror-gutter {
+ white-space: normal;
+ height: 100%;
+ padding-bottom: 30px;
+ margin-bottom: -32px;
+ display: inline-block;
+ /* Hack to make IE7 behave */
+ *zoom:1;
+ *display:inline;
+}
+.CodeMirror-gutter-elt {
+ position: absolute;
+ cursor: default;
+ z-index: 4;
+}
+
+.CodeMirror-lines {
+ cursor: text;
+}
+.CodeMirror pre {
+ /* Reset some styles that the rest of the page might have set */
+ -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
+ border-width: 0;
+ background: transparent;
+ font-family: inherit;
+ font-size: inherit;
+ margin: 0;
+ white-space: pre;
+ word-wrap: normal;
+ line-height: inherit;
+ color: inherit;
+ z-index: 2;
+ position: relative;
+ overflow: visible;
+}
+.CodeMirror-wrap pre {
+ word-wrap: break-word;
+ white-space: pre-wrap;
+ word-break: normal;
+}
+.CodeMirror-code pre {
+ border-right: 30px solid transparent;
+ width: -webkit-fit-content;
+ width: -moz-fit-content;
+ width: fit-content;
+}
+.CodeMirror-wrap .CodeMirror-code pre {
+ border-right: none;
+ width: auto;
+}
+.CodeMirror-linebackground {
+ position: absolute;
+ left: 0; right: 0; top: 0; bottom: 0;
+ z-index: 0;
+}
+
+.CodeMirror-linewidget {
+ position: relative;
+ z-index: 2;
+ overflow: auto;
+}
+
+.CodeMirror-widget {
+}
+
+.CodeMirror-wrap .CodeMirror-scroll {
+ overflow-x: hidden;
+}
+
+.CodeMirror-measure {
+ position: absolute;
+ width: 100%; height: 0px;
+ overflow: hidden;
+ visibility: hidden;
+}
+.CodeMirror-measure pre { position: static; }
+
+.CodeMirror div.CodeMirror-cursor {
+ position: absolute;
+ visibility: hidden;
+ border-right: none;
+ width: 0;
+}
+.CodeMirror-focused div.CodeMirror-cursor {
+ visibility: visible;
+}
+
+.CodeMirror-selected { background: #d9d9d9; }
+.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
+
+.cm-searching {
+ background: #ffa;
+ background: rgba(255, 255, 0, .4);
+}
+
+/* IE7 hack to prevent it from returning funny offsetTops on the spans */
+.CodeMirror span { *vertical-align: text-bottom; }
+
+@media print {
+ /* Hide the cursor when printing */
+ .CodeMirror div.CodeMirror-cursor {
+ visibility: hidden;
+ }
+}
diff --git a/plugins/jetpack/modules/custom-css/custom-css/css/codemirror.min.css b/plugins/jetpack/modules/custom-css/custom-css/css/codemirror.min.css
new file mode 100644
index 00000000..041af1e0
--- /dev/null
+++ b/plugins/jetpack/modules/custom-css/custom-css/css/codemirror.min.css
@@ -0,0 +1 @@
+.rtl .CodeMirror{direction:ltr}.CodeMirror{font-family:monospace;height:400px}.CodeMirror-scroll{overflow:auto}.CodeMirror-lines{padding:4px 0}.CodeMirror pre{padding:0 4px}.CodeMirror-gutter-filler,.CodeMirror-scrollbar-filler{background-color:#fff}.CodeMirror-gutters{border-right:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}.CodeMirror-linenumber{padding:0 3px 0 5px;min-width:20px;text-align:right;color:#999}.CodeMirror div.CodeMirror-cursor{border-left:1px solid #000;z-index:3}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor{width:auto;border:0;background:#7e7;z-index:1}.cm-tab{display:inline-block}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable{color:#000}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-variable-3{color:#085}.cm-s-default .cm-operator,.cm-s-default .cm-property{color:#000}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta{color:#555}.cm-s-default .cm-error{color:red}.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-header{color:#00f}.cm-s-default .cm-quote{color:#090}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-invalidchar{color:red}div.CodeMirror span.CodeMirror-matchingbracket{color:#0f0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#f22}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{line-height:1;position:relative;overflow:hidden;background:#fff;color:#000}.CodeMirror-scroll{margin-bottom:-30px;margin-right:-30px;padding-bottom:30px;padding-right:30px;height:100%;outline:0;position:relative}.CodeMirror-sizer{position:relative}.CodeMirror-gutter-filler,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-vscrollbar{position:absolute;z-index:6;display:none}.CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{right:0;bottom:0}.CodeMirror-gutter-filler{left:0;bottom:0}.CodeMirror-gutters{position:absolute;left:0;top:0;padding-bottom:30px;z-index:3}.CodeMirror-gutter{white-space:normal;height:100%;padding-bottom:30px;margin-bottom:-32px;display:inline-block}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-lines{cursor:text}.CodeMirror pre{border-radius:0;border-width:0;background:0 0;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible}.CodeMirror-wrap pre{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-code pre{border-right:30px solid transparent;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.CodeMirror-wrap .CodeMirror-code pre{border-right:none;width:auto}.CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}.CodeMirror-linewidget{position:relative;z-index:2;overflow:auto}.CodeMirror-wrap .CodeMirror-scroll{overflow-x:hidden}.CodeMirror-measure{position:absolute;width:100%;height:0;overflow:hidden;visibility:hidden}.CodeMirror-measure pre{position:static}.CodeMirror div.CodeMirror-cursor{position:absolute;visibility:hidden;border-right:none;width:0}.CodeMirror-focused div.CodeMirror-cursor{visibility:visible}.CodeMirror-selected{background:#d9d9d9}.CodeMirror-focused .CodeMirror-selected{background:#d7d4f0}.cm-searching{background:#ffa;background:rgba(255,255,0,.4)}@media print{.CodeMirror div.CodeMirror-cursor{visibility:hidden}} \ No newline at end of file
diff --git a/plugins/jetpack/modules/custom-css/custom-css/css/css-editor.css b/plugins/jetpack/modules/custom-css/custom-css/css/css-editor.css
index 230072c6..f85bec14 100644
--- a/plugins/jetpack/modules/custom-css/custom-css/css/css-editor.css
+++ b/plugins/jetpack/modules/custom-css/custom-css/css/css-editor.css
@@ -24,4 +24,9 @@
}
#safecss-ace .ace_gutter {
z-index: 1;
-} \ No newline at end of file
+}
+
+#post-body-content{
+ margin-bottom: 20px;
+}
+
diff --git a/plugins/jetpack/modules/custom-css/custom-css/css/css-editor.min.css b/plugins/jetpack/modules/custom-css/custom-css/css/css-editor.min.css
new file mode 100644
index 00000000..62eb4809
--- /dev/null
+++ b/plugins/jetpack/modules/custom-css/custom-css/css/css-editor.min.css
@@ -0,0 +1 @@
+#revision-field-post_excerpt,#revision-field-post_title{display:none}#safecssform{position:relative}#poststuff{padding-top:0}#safecss{min-height:250px;width:100%}.misc-pub-section>span{font-weight:700}.misc-pub-section>div{margin-top:3px}#safecss-ace .ace_gutter{z-index:1}#post-body-content{margin-bottom:20px} \ No newline at end of file
diff --git a/plugins/jetpack/modules/custom-css/custom-css/css/rtl/codemirror-rtl.css b/plugins/jetpack/modules/custom-css/custom-css/css/rtl/codemirror-rtl.css
new file mode 100644
index 00000000..f028b965
--- /dev/null
+++ b/plugins/jetpack/modules/custom-css/custom-css/css/rtl/codemirror-rtl.css
@@ -0,0 +1,260 @@
+/* This file was automatically generated on Sep 10 2013 23:18:59 */
+
+/* BASICS */
+.CodeMirror {
+ /* Set height, width, borders, and global font properties here */
+ font-family: monospace;
+ height: 300px;
+}
+.CodeMirror-scroll {
+ /* Set scrolling behaviour here */
+ overflow: auto;
+}
+
+/* PADDING */
+
+.CodeMirror-lines {
+ padding: 4px 0; /* Vertical padding around content */
+}
+.CodeMirror pre {
+ padding: 0 4px; /* Horizontal padding of content */
+}
+
+.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
+ background-color: white; /* The little square between H and V scrollbars */
+}
+
+/* GUTTER */
+
+.CodeMirror-gutters {
+ border-left: 1px solid #ddd;
+ background-color: #f7f7f7;
+ white-space: nowrap;
+}
+.CodeMirror-linenumbers {}
+.CodeMirror-linenumber {
+ padding: 0 5px 0 3px;
+ min-width: 20px;
+ text-align: left;
+ color: #999;
+}
+
+/* CURSOR */
+
+.CodeMirror div.CodeMirror-cursor {
+ border-right: 1px solid black;
+ z-index: 3;
+}
+/* Shown when moving in bi-directional text */
+.CodeMirror div.CodeMirror-secondarycursor {
+ border-right: 1px solid silver;
+}
+.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
+ width: auto;
+ border: 0;
+ background: #7e7;
+ z-index: 1;
+}
+/* Can style cursor different in overwrite (non-insert) mode */
+.CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite {}
+
+.cm-tab { display: inline-block; }
+
+/* DEFAULT THEME */
+
+.cm-s-default .cm-keyword {color: #708;}
+.cm-s-default .cm-atom {color: #219;}
+.cm-s-default .cm-number {color: #164;}
+.cm-s-default .cm-def {color: #00f;}
+.cm-s-default .cm-variable {color: black;}
+.cm-s-default .cm-variable-2 {color: #05a;}
+.cm-s-default .cm-variable-3 {color: #085;}
+.cm-s-default .cm-property {color: black;}
+.cm-s-default .cm-operator {color: black;}
+.cm-s-default .cm-comment {color: #a50;}
+.cm-s-default .cm-string {color: #a11;}
+.cm-s-default .cm-string-2 {color: #f50;}
+.cm-s-default .cm-meta {color: #555;}
+.cm-s-default .cm-error {color: #f00;}
+.cm-s-default .cm-qualifier {color: #555;}
+.cm-s-default .cm-builtin {color: #30a;}
+.cm-s-default .cm-bracket {color: #997;}
+.cm-s-default .cm-tag {color: #170;}
+.cm-s-default .cm-attribute {color: #00c;}
+.cm-s-default .cm-header {color: blue;}
+.cm-s-default .cm-quote {color: #090;}
+.cm-s-default .cm-hr {color: #999;}
+.cm-s-default .cm-link {color: #00c;}
+
+.cm-negative {color: #d44;}
+.cm-positive {color: #292;}
+.cm-header, .cm-strong {font-weight: bold;}
+.cm-em {font-style: italic;}
+.cm-link {text-decoration: underline;}
+
+.cm-invalidchar {color: #f00;}
+
+div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
+div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
+.CodeMirror-activeline-background {background: #e8f2ff;}
+
+/* STOP */
+
+/* The rest of this file contains styles related to the mechanics of
+ the editor. You probably shouldn't touch them. */
+
+.CodeMirror {
+ line-height: 1;
+ position: relative;
+ overflow: hidden;
+ background: white;
+ color: black;
+}
+
+.CodeMirror-scroll {
+ /* 30px is the magic margin used to hide the element's real scrollbars */
+ /* See overflow: hidden in .CodeMirror */
+ margin-bottom: -30px; margin-left: -30px;
+ padding-bottom: 30px; padding-left: 30px;
+ height: 100%;
+ outline: none; /* Prevent dragging from highlighting the element */
+ position: relative;
+}
+.CodeMirror-sizer {
+ position: relative;
+}
+
+/* The fake, visible scrollbars. Used to force redraw during scrolling
+ before actuall scrolling happens, thus preventing shaking and
+ flickering artifacts. */
+.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
+ position: absolute;
+ z-index: 6;
+ display: none;
+}
+.CodeMirror-vscrollbar {
+ left: 0; top: 0;
+ overflow-x: hidden;
+ overflow-y: scroll;
+}
+.CodeMirror-hscrollbar {
+ bottom: 0; right: 0;
+ overflow-y: hidden;
+ overflow-x: scroll;
+}
+.CodeMirror-scrollbar-filler {
+ left: 0; bottom: 0;
+}
+.CodeMirror-gutter-filler {
+ right: 0; bottom: 0;
+}
+
+.CodeMirror-gutters {
+ position: absolute; right: 0; top: 0;
+ padding-bottom: 30px;
+ z-index: 3;
+}
+.CodeMirror-gutter {
+ white-space: normal;
+ height: 100%;
+ padding-bottom: 30px;
+ margin-bottom: -32px;
+ display: inline-block;
+ /* Hack to make IE7 behave */
+ *zoom:1;
+ *display:inline;
+}
+.CodeMirror-gutter-elt {
+ position: absolute;
+ cursor: default;
+ z-index: 4;
+}
+
+.CodeMirror-lines {
+ cursor: text;
+}
+.CodeMirror pre {
+ /* Reset some styles that the rest of the page might have set */
+ -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
+ border-width: 0;
+ background: transparent;
+ font-family: inherit;
+ font-size: inherit;
+ margin: 0;
+ white-space: pre;
+ word-wrap: normal;
+ line-height: inherit;
+ color: inherit;
+ z-index: 2;
+ position: relative;
+ overflow: visible;
+}
+.CodeMirror-wrap pre {
+ word-wrap: break-word;
+ white-space: pre-wrap;
+ word-break: normal;
+}
+.CodeMirror-code pre {
+ border-left: 30px solid transparent;
+ width: -webkit-fit-content;
+ width: -moz-fit-content;
+ width: fit-content;
+}
+.CodeMirror-wrap .CodeMirror-code pre {
+ border-left: none;
+ width: auto;
+}
+.CodeMirror-linebackground {
+ position: absolute;
+ right: 0; left: 0; top: 0; bottom: 0;
+ z-index: 0;
+}
+
+.CodeMirror-linewidget {
+ position: relative;
+ z-index: 2;
+ overflow: auto;
+}
+
+.CodeMirror-widget {
+}
+
+.CodeMirror-wrap .CodeMirror-scroll {
+ overflow-x: hidden;
+}
+
+.CodeMirror-measure {
+ position: absolute;
+ width: 100%; height: 0px;
+ overflow: hidden;
+ visibility: hidden;
+}
+.CodeMirror-measure pre { position: static; }
+
+.CodeMirror div.CodeMirror-cursor {
+ position: absolute;
+ visibility: hidden;
+ border-left: none;
+ width: 0;
+}
+.CodeMirror-focused div.CodeMirror-cursor {
+ visibility: visible;
+}
+
+.CodeMirror-selected { background: #d9d9d9; }
+.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
+
+.cm-searching {
+ background: #ffa;
+ background: rgba(255, 255, 0, .4);
+}
+
+/* IE7 hack to prevent it from returning funny offsetTops on the spans */
+.CodeMirror span { *vertical-align: text-bottom; }
+
+@media print {
+ /* Hide the cursor when printing */
+ .CodeMirror div.CodeMirror-cursor {
+ visibility: hidden;
+ }
+}
diff --git a/plugins/jetpack/modules/custom-css/custom-css/css/use-codemirror.css b/plugins/jetpack/modules/custom-css/custom-css/css/use-codemirror.css
new file mode 100644
index 00000000..924bb4d0
--- /dev/null
+++ b/plugins/jetpack/modules/custom-css/custom-css/css/use-codemirror.css
@@ -0,0 +1,6 @@
+.CodeMirror, #safecss {
+ font-family: Consolas, Monaco, monospace;
+ font-size: 12px;
+ line-height: 16px;
+ min-height: 300px;
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/custom-css/custom-css/css/use-codemirror.min.css b/plugins/jetpack/modules/custom-css/custom-css/css/use-codemirror.min.css
new file mode 100644
index 00000000..8dce7dda
--- /dev/null
+++ b/plugins/jetpack/modules/custom-css/custom-css/css/use-codemirror.min.css
@@ -0,0 +1 @@
+#safecss,.CodeMirror{font-family:Consolas,Monaco,monospace;font-size:12px;line-height:16px;min-height:300px} \ No newline at end of file
diff --git a/plugins/jetpack/modules/custom-css/custom-css/js/ace/ace.js b/plugins/jetpack/modules/custom-css/custom-css/js/ace/ace.js
deleted file mode 100644
index 375915bf..00000000
--- a/plugins/jetpack/modules/custom-css/custom-css/js/ace/ace.js
+++ /dev/null
@@ -1,10 +0,0 @@
-(function(){function o(e){var i=function(e,t){return r("",e,t)},s=t;e&&(t[e]||(t[e]={}),s=t[e]);if(!s.define||!s.define.packaged)n.original=s.define,s.define=n,s.define.packaged=!0;if(!s.require||!s.require.packaged)r.original=s.require,s.require=i,s.require.packaged=!0}var e="ace",t=function(){return this}();if(!e&&typeof requirejs!="undefined")return;var n=function(e,t,r){if(typeof e!="string"){n.original?n.original.apply(window,arguments):(console.error("dropping module because define wasn't a string."),console.trace());return}arguments.length==2&&(r=t),n.modules||(n.modules={}),n.modules[e]=r},r=function(e,t,n){if(Object.prototype.toString.call(t)==="[object Array]"){var i=[];for(var o=0,u=t.length;o<u;++o){var a=s(e,t[o]);if(!a&&r.original)return r.original.apply(window,arguments);i.push(a)}n&&n.apply(null,i)}else{if(typeof t=="string"){var f=s(e,t);return!f&&r.original?r.original.apply(window,arguments):(n&&n(),f)}if(r.original)return r.original.apply(window,arguments)}},i=function(e,t){if(t.indexOf("!")!==-1){var n=t.split("!");return i(e,n[0])+"!"+i(e,n[1])}if(t.charAt(0)=="."){var r=e.split("/").slice(0,-1).join("/");t=r+"/"+t;while(t.indexOf(".")!==-1&&s!=t){var s=t;t=t.replace(/\/\.\//,"/").replace(/[^\/]+\/\.\.\//,"")}}return t},s=function(e,t){t=i(e,t);var s=n.modules[t];if(!s)return null;if(typeof s=="function"){var o={},u={id:t,uri:"",exports:o,packaged:!0},a=function(e,n){return r(t,e,n)},f=s(a,o,u);return o=f||u.exports,n.modules[t]=o,o}return s};o(e)})(),ace.define("ace/ace",["require","exports","module","ace/lib/fixoldbrowsers","ace/lib/dom","ace/lib/event","ace/editor","ace/edit_session","ace/undomanager","ace/virtual_renderer","ace/multi_select","ace/worker/worker_client","ace/keyboard/hash_handler","ace/placeholder","ace/mode/folding/fold_mode","ace/config"],function(e,t,n){e("./lib/fixoldbrowsers");var r=e("./lib/dom"),i=e("./lib/event"),s=e("./editor").Editor,o=e("./edit_session").EditSession,u=e("./undomanager").UndoManager,a=e("./virtual_renderer").VirtualRenderer,f=e("./multi_select").MultiSelect;e("./worker/worker_client"),e("./keyboard/hash_handler"),e("./placeholder"),e("./mode/folding/fold_mode"),t.config=e("./config"),t.require=e,t.edit=function(e){if(typeof e=="string"){var n=e,e=document.getElementById(n);if(!e)throw"ace.edit can't find div #"+n}if(e.env&&e.env.editor instanceof s)return e.env.editor;var o=t.createEditSession(r.getInnerText(e));e.innerHTML="";var u=new s(new a(e));new f(u),u.setSession(o);var l={document:o,editor:u,onResize:u.resize.bind(u)};return i.addListener(window,"resize",l.onResize),e.env=u.env=l,u},t.createEditSession=function(e,t){var n=new o(e,n);return n.setUndoManager(new u),n},t.EditSession=o,t.UndoManager=u}),ace.define("ace/lib/fixoldbrowsers",["require","exports","module","ace/lib/regexp","ace/lib/es5-shim"],function(e,t,n){e("./regexp"),e("./es5-shim")}),ace.define("ace/lib/regexp",["require","exports","module"],function(e,t,n){function o(e){return(e.global?"g":"")+(e.ignoreCase?"i":"")+(e.multiline?"m":"")+(e.extended?"x":"")+(e.sticky?"y":"")}function u(e,t,n){if(Array.prototype.indexOf)return e.indexOf(t,n);for(var r=n||0;r<e.length;r++)if(e[r]===t)return r;return-1}var r={exec:RegExp.prototype.exec,test:RegExp.prototype.test,match:String.prototype.match,replace:String.prototype.replace,split:String.prototype.split},i=r.exec.call(/()??/,"")[1]===undefined,s=function(){var e=/^/g;return r.test.call(e,""),!e.lastIndex}();if(s&&i)return;RegExp.prototype.exec=function(e){var t=r.exec.apply(this,arguments),n,a;if(typeof e=="string"&&t){!i&&t.length>1&&u(t,"")>-1&&(a=RegExp(this.source,r.replace.call(o(this),"g","")),r.replace.call(e.slice(t.index),a,function(){for(var e=1;e<arguments.length-2;e++)arguments[e]===undefined&&(t[e]=undefined)}));if(this._xregexp&&this._xregexp.captureNames)for(var f=1;f<t.length;f++)n=this._xregexp.captureNames[f-1],n&&(t[n]=t[f]);!s&&this.global&&!t[0].length&&this.lastIndex>t.index&&this.lastIndex--}return t},s||(RegExp.prototype.test=function(e){var t=r.exec.call(this,e);return t&&this.global&&!t[0].length&&this.lastIndex>t.index&&this.lastIndex--,!!t})}),ace.define("ace/lib/es5-shim",["require","exports","module"],function(e,t,n){function m(e){try{return Object.defineProperty(e,"sentinel",{}),"sentinel"in e}catch(t){}}Function.prototype.bind||(Function.prototype.bind=function(t){var n=this;if(typeof n!="function")throw new TypeError;var r=o.call(arguments,1),i=function(){if(this instanceof i){var e=function(){};e.prototype=n.prototype;var s=new e,u=n.apply(s,r.concat(o.call(arguments)));return u!==null&&Object(u)===u?u:s}return n.apply(t,r.concat(o.call(arguments)))};return i});var r=Function.prototype.call,i=Array.prototype,s=Object.prototype,o=i.slice,u=r.bind(s.toString),a=r.bind(s.hasOwnProperty),f,l,c,h,p;if(p=a(s,"__defineGetter__"))f=r.bind(s.__defineGetter__),l=r.bind(s.__defineSetter__),c=r.bind(s.__lookupGetter__),h=r.bind(s.__lookupSetter__);Array.isArray||(Array.isArray=function(t){return u(t)=="[object Array]"}),Array.prototype.forEach||(Array.prototype.forEach=function(t){var n=D(this),r=arguments[1],i=0,s=n.length>>>0;if(u(t)!="[object Function]")throw new TypeError;while(i<s)i in n&&t.call(r,n[i],i,n),i++}),Array.prototype.map||(Array.prototype.map=function(t){var n=D(this),r=n.length>>>0,i=Array(r),s=arguments[1];if(u(t)!="[object Function]")throw new TypeError;for(var o=0;o<r;o++)o in n&&(i[o]=t.call(s,n[o],o,n));return i}),Array.prototype.filter||(Array.prototype.filter=function(t){var n=D(this),r=n.length>>>0,i=[],s=arguments[1];if(u(t)!="[object Function]")throw new TypeError;for(var o=0;o<r;o++)o in n&&t.call(s,n[o],o,n)&&i.push(n[o]);return i}),Array.prototype.every||(Array.prototype.every=function(t){var n=D(this),r=n.length>>>0,i=arguments[1];if(u(t)!="[object Function]")throw new TypeError;for(var s=0;s<r;s++)if(s in n&&!t.call(i,n[s],s,n))return!1;return!0}),Array.prototype.some||(Array.prototype.some=function(t){var n=D(this),r=n.length>>>0,i=arguments[1];if(u(t)!="[object Function]")throw new TypeError;for(var s=0;s<r;s++)if(s in n&&t.call(i,n[s],s,n))return!0;return!1}),Array.prototype.reduce||(Array.prototype.reduce=function(t){var n=D(this),r=n.length>>>0;if(u(t)!="[object Function]")throw new TypeError;if(!r&&arguments.length==1)throw new TypeError;var i=0,s;if(arguments.length>=2)s=arguments[1];else do{if(i in n){s=n[i++];break}if(++i>=r)throw new TypeError}while(!0);for(;i<r;i++)i in n&&(s=t.call(void 0,s,n[i],i,n));return s}),Array.prototype.reduceRight||(Array.prototype.reduceRight=function(t){var n=D(this),r=n.length>>>0;if(u(t)!="[object Function]")throw new TypeError;if(!r&&arguments.length==1)throw new TypeError;var i,s=r-1;if(arguments.length>=2)i=arguments[1];else do{if(s in n){i=n[s--];break}if(--s<0)throw new TypeError}while(!0);do s in this&&(i=t.call(void 0,i,n[s],s,n));while(s--);return i}),Array.prototype.indexOf||(Array.prototype.indexOf=function(t){var n=D(this),r=n.length>>>0;if(!r)return-1;var i=0;arguments.length>1&&(i=M(arguments[1])),i=i>=0?i:Math.max(0,r+i);for(;i<r;i++)if(i in n&&n[i]===t)return i;return-1}),Array.prototype.lastIndexOf||(Array.prototype.lastIndexOf=function(t){var n=D(this),r=n.length>>>0;if(!r)return-1;var i=r-1;arguments.length>1&&(i=Math.min(i,M(arguments[1]))),i=i>=0?i:r-Math.abs(i);for(;i>=0;i--)if(i in n&&t===n[i])return i;return-1}),Object.getPrototypeOf||(Object.getPrototypeOf=function(t){return t.__proto__||(t.constructor?t.constructor.prototype:s)});if(!Object.getOwnPropertyDescriptor){var d="Object.getOwnPropertyDescriptor called on a non-object: ";Object.getOwnPropertyDescriptor=function(t,n){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(d+t);if(!a(t,n))return;var r,i,o;r={enumerable:!0,configurable:!0};if(p){var u=t.__proto__;t.__proto__=s;var i=c(t,n),o=h(t,n);t.__proto__=u;if(i||o)return i&&(r.get=i),o&&(r.set=o),r}return r.value=t[n],r}}Object.getOwnPropertyNames||(Object.getOwnPropertyNames=function(t){return Object.keys(t)});if(!Object.create){var v;Object.prototype.__proto__===null?v=function(){return{__proto__:null}}:v=function(){var e={};for(var t in e)e[t]=null;return e.constructor=e.hasOwnProperty=e.propertyIsEnumerable=e.isPrototypeOf=e.toLocaleString=e.toString=e.valueOf=e.__proto__=null,e},Object.create=function(t,n){var r;if(t===null)r=v();else{if(typeof t!="object")throw new TypeError("typeof prototype["+typeof t+"] != 'object'");var i=function(){};i.prototype=t,r=new i,r.__proto__=t}return n!==void 0&&Object.defineProperties(r,n),r}}if(Object.defineProperty){var g=m({}),y=typeof document=="undefined"||m(document.createElement("div"));if(!g||!y)var b=Object.defineProperty}if(!Object.defineProperty||b){var w="Property description must be an object: ",E="Object.defineProperty called on non-object: ",S="getters & setters can not be defined on this javascript engine";Object.defineProperty=function(t,n,r){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(E+t);if(typeof r!="object"&&typeof r!="function"||r===null)throw new TypeError(w+r);if(b)try{return b.call(Object,t,n,r)}catch(i){}if(a(r,"value"))if(p&&(c(t,n)||h(t,n))){var o=t.__proto__;t.__proto__=s,delete t[n],t[n]=r.value,t.__proto__=o}else t[n]=r.value;else{if(!p)throw new TypeError(S);a(r,"get")&&f(t,n,r.get),a(r,"set")&&l(t,n,r.set)}return t}}Object.defineProperties||(Object.defineProperties=function(t,n){for(var r in n)a(n,r)&&Object.defineProperty(t,r,n[r]);return t}),Object.seal||(Object.seal=function(t){return t}),Object.freeze||(Object.freeze=function(t){return t});try{Object.freeze(function(){})}catch(x){Object.freeze=function(t){return function(n){return typeof n=="function"?n:t(n)}}(Object.freeze)}Object.preventExtensions||(Object.preventExtensions=function(t){return t}),Object.isSealed||(Object.isSealed=function(t){return!1}),Object.isFrozen||(Object.isFrozen=function(t){return!1}),Object.isExtensible||(Object.isExtensible=function(t){if(Object(t)===t)throw new TypeError;var n="";while(a(t,n))n+="?";t[n]=!0;var r=a(t,n);return delete t[n],r});if(!Object.keys){var T=!0,N=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],C=N.length;for(var k in{toString:null})T=!1;Object.keys=function P(e){if(typeof e!="object"&&typeof e!="function"||e===null)throw new TypeError("Object.keys called on a non-object");var P=[];for(var t in e)a(e,t)&&P.push(t);if(T)for(var n=0,r=C;n<r;n++){var i=N[n];a(e,i)&&P.push(i)}return P}}if(!Date.prototype.toISOString||(new Date(-621987552e5)).toISOString().indexOf("-000001")===-1)Date.prototype.toISOString=function(){var t,n,r,i;if(!isFinite(this))throw new RangeError;t=[this.getUTCMonth()+1,this.getUTCDate(),this.getUTCHours(),this.getUTCMinutes(),this.getUTCSeconds()],i=this.getUTCFullYear(),i=(i<0?"-":i>9999?"+":"")+("00000"+Math.abs(i)).slice(0<=i&&i<=9999?-4:-6),n=t.length;while(n--)r=t[n],r<10&&(t[n]="0"+r);return i+"-"+t.slice(0,2).join("-")+"T"+t.slice(2).join(":")+"."+("000"+this.getUTCMilliseconds()).slice(-3)+"Z"};Date.now||(Date.now=function(){return(new Date).getTime()}),Date.prototype.toJSON||(Date.prototype.toJSON=function(t){if(typeof this.toISOString!="function")throw new TypeError;return this.toISOString()}),Date.parse("+275760-09-13T00:00:00.000Z")!==864e13&&(Date=function(e){var t=function i(t,n,r,s,o,u,a){var f=arguments.length;if(this instanceof e){var l=f==1&&String(t)===t?new e(i.parse(t)):f>=7?new e(t,n,r,s,o,u,a):f>=6?new e(t,n,r,s,o,u):f>=5?new e(t,n,r,s,o):f>=4?new e(t,n,r,s):f>=3?new e(t,n,r):f>=2?new e(t,n):f>=1?new e(t):new e;return l.constructor=i,l}return e.apply(this,arguments)},n=new RegExp("^(\\d{4}|[+-]\\d{6})(?:-(\\d{2})(?:-(\\d{2})(?:T(\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.(\\d{3}))?)?(?:Z|(?:([-+])(\\d{2}):(\\d{2})))?)?)?)?$");for(var r in e)t[r]=e[r];return t.now=e.now,t.UTC=e.UTC,t.prototype=e.prototype,t.prototype.constructor=t,t.parse=function(r){var i=n.exec(r);if(i){i.shift();for(var s=1;s<7;s++)i[s]=+(i[s]||(s<3?1:0)),s==1&&i[s]--;var o=+i.pop(),u=+i.pop(),a=i.pop(),f=0;if(a){if(u>23||o>59)return NaN;f=(u*60+o)*6e4*(a=="+"?-1:1)}var l=+i[0];return 0<=l&&l<=99?(i[0]=l+400,e.UTC.apply(this,i)+f-126227808e5):e.UTC.apply(this,i)+f}return e.parse.apply(this,arguments)},t}(Date));var L=" \n \f\r   ᠎              \u2028\u2029";if(!String.prototype.trim||L.trim()){L="["+L+"]";var A=new RegExp("^"+L+L+"*"),O=new RegExp(L+L+"*$");String.prototype.trim=function(){return String(this).replace(A,"").replace(O,"")}}var M=function(e){return e=+e,e!==e?e=0:e!==0&&e!==1/0&&e!==-1/0&&(e=(e>0||-1)*Math.floor(Math.abs(e))),e},_="a"[0]!="a",D=function(e){if(e==null)throw new TypeError;return _&&typeof e=="string"&&e?e.split(""):Object(e)}}),ace.define("ace/lib/dom",["require","exports","module"],function(e,t,n){var r="http://www.w3.org/1999/xhtml";t.createElement=function(e,t){return document.createElementNS?document.createElementNS(t||r,e):document.createElement(e)},t.setText=function(e,t){e.innerText!==undefined&&(e.innerText=t),e.textContent!==undefined&&(e.textContent=t)},t.hasCssClass=function(e,t){var n=e.className.split(/\s+/g);return n.indexOf(t)!==-1},t.addCssClass=function(e,n){t.hasCssClass(e,n)||(e.className+=" "+n)},t.removeCssClass=function(e,t){var n=e.className.split(/\s+/g);for(;;){var r=n.indexOf(t);if(r==-1)break;n.splice(r,1)}e.className=n.join(" ")},t.toggleCssClass=function(e,t){var n=e.className.split(/\s+/g),r=!0;for(;;){var i=n.indexOf(t);if(i==-1)break;r=!1,n.splice(i,1)}return r&&n.push(t),e.className=n.join(" "),r},t.setCssClass=function(e,n,r){r?t.addCssClass(e,n):t.removeCssClass(e,n)},t.hasCssString=function(e,t){var n=0,r;t=t||document;if(t.createStyleSheet&&(r=t.styleSheets)){while(n<r.length)if(r[n++].owningElement.id===e)return!0}else if(r=t.getElementsByTagName("style"))while(n<r.length)if(r[n++].id===e)return!0;return!1},t.importCssString=function(n,i,s){s=s||document;if(i&&t.hasCssString(i,s))return null;var o;if(s.createStyleSheet)o=s.createStyleSheet(),o.cssText=n,i&&(o.owningElement.id=i);else{o=s.createElementNS?s.createElementNS(r,"style"):s.createElement("style"),o.appendChild(s.createTextNode(n)),i&&(o.id=i);var u=s.getElementsByTagName("head")[0]||s.documentElement;u.appendChild(o)}},t.importCssStylsheet=function(e,n){if(n.createStyleSheet)n.createStyleSheet(e);else{var r=t.createElement("link");r.rel="stylesheet",r.href=e;var i=n.getElementsByTagName("head")[0]||n.documentElement;i.appendChild(r)}},t.getInnerWidth=function(e){return parseInt(t.computedStyle(e,"paddingLeft"),10)+parseInt(t.computedStyle(e,"paddingRight"),10)+e.clientWidth},t.getInnerHeight=function(e){return parseInt(t.computedStyle(e,"paddingTop"),10)+parseInt(t.computedStyle(e,"paddingBottom"),10)+e.clientHeight},window.pageYOffset!==undefined?(t.getPageScrollTop=function(){return window.pageYOffset},t.getPageScrollLeft=function(){return window.pageXOffset}):(t.getPageScrollTop=function(){return document.body.scrollTop},t.getPageScrollLeft=function(){return document.body.scrollLeft}),window.getComputedStyle?t.computedStyle=function(e,t){return t?(window.getComputedStyle(e,"")||{})[t]||"":window.getComputedStyle(e,"")||{}}:t.computedStyle=function(e,t){return t?e.currentStyle[t]:e.currentStyle},t.scrollbarWidth=function(e){var n=t.createElement("p");n.style.width="100%",n.style.minWidth="0px",n.style.height="200px";var r=t.createElement("div"),i=r.style;i.position="absolute",i.left="-10000px",i.overflow="hidden",i.width="200px",i.minWidth="0px",i.height="150px",r.appendChild(n);var s=e.body||e.documentElement;s.appendChild(r);var o=n.offsetWidth;i.overflow="scroll";var u=n.offsetWidth;return o==u&&(u=r.clientWidth),s.removeChild(r),o-u},t.setInnerHtml=function(e,t){var n=e.cloneNode(!1);return n.innerHTML=t,e.parentNode.replaceChild(n,e),n},t.setInnerText=function(e,t){var n=e.ownerDocument;n.body&&"textContent"in n.body?e.textContent=t:e.innerText=t},t.getInnerText=function(e){var t=e.ownerDocument;return t.body&&"textContent"in t.body?e.textContent:e.innerText||e.textContent||""},t.getParentWindow=function(e){return e.defaultView||e.parentWindow}}),ace.define("ace/lib/event",["require","exports","module","ace/lib/keys","ace/lib/useragent","ace/lib/dom"],function(e,t,n){function o(e,t,n){var s=0;!i.isOpera||"KeyboardEvent"in window||!i.isMac?s=0|(t.ctrlKey?1:0)|(t.altKey?2:0)|(t.shiftKey?4:0)|(t.metaKey?8:0):s=0|(t.metaKey?1:0)|(t.altKey?2:0)|(t.shiftKey?4:0)|(t.ctrlKey?8:0);if(n in r.MODIFIER_KEYS){switch(r.MODIFIER_KEYS[n]){case"Alt":s=2;break;case"Shift":s=4;break;case"Ctrl":s=1;break;default:s=8}n=0}return s&8&&(n==91||n==93)&&(n=0),!!s||n in r.FUNCTION_KEYS||n in r.PRINTABLE_KEYS?e(t,s,n):!1}var r=e("./keys"),i=e("./useragent"),s=e("./dom");t.addListener=function(e,t,n){if(e.addEventListener)return e.addEventListener(t,n,!1);if(e.attachEvent){var r=function(){n(window.event)};n._wrapper=r,e.attachEvent("on"+t,r)}},t.removeListener=function(e,t,n){if(e.removeEventListener)return e.removeEventListener(t,n,!1);e.detachEvent&&e.detachEvent("on"+t,n._wrapper||n)},t.stopEvent=function(e){return t.stopPropagation(e),t.preventDefault(e),!1},t.stopPropagation=function(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0},t.preventDefault=function(e){e.preventDefault?e.preventDefault():e.returnValue=!1},t.getButton=function(e){return e.type=="dblclick"?0:e.type=="contextmenu"||e.ctrlKey&&i.isMac?2:e.preventDefault?e.button:{1:0,2:2,4:1}[e.button]},document.documentElement.setCapture?t.capture=function(e,n,r){function s(o){n(o),i||(i=!0,r(o)),t.removeListener(e,"mousemove",n),t.removeListener(e,"mouseup",s),t.removeListener(e,"losecapture",s),e.releaseCapture()}var i=!1;t.addListener(e,"mousemove",n),t.addListener(e,"mouseup",s),t.addListener(e,"losecapture",s),e.setCapture()}:t.capture=function(e,t,n){function r(e){t&&t(e),n&&n(e),document.removeEventListener("mousemove",t,!0),document.removeEventListener("mouseup",r,!0),e.stopPropagation()}document.addEventListener("mousemove",t,!0),document.addEventListener("mouseup",r,!0)},t.addMouseWheelListener=function(e,n){var r=8,i=function(e){e.wheelDelta!==undefined?e.wheelDeltaX!==undefined?(e.wheelX=-e.wheelDeltaX/r,e.wheelY=-e.wheelDeltaY/r):(e.wheelX=0,e.wheelY=-e.wheelDelta/r):e.axis&&e.axis==e.HORIZONTAL_AXIS?(e.wheelX=(e.detail||0)*5,e.wheelY=0):(e.wheelX=0,e.wheelY=(e.detail||0)*5),n(e)};t.addListener(e,"DOMMouseScroll",i),t.addListener(e,"mousewheel",i)},t.addMultiMouseDownListener=function(e,n,r,s){var o=0,u,a,f,l={2:"dblclick",3:"tripleclick",4:"quadclick"};t.addListener(e,"mousedown",function(e){if(t.getButton(e)!=0)o=0;else{var i=Math.abs(e.clientX-u)>5||Math.abs(e.clientY-a)>5;if(!f||i)o=0;o+=1,f&&clearTimeout(f),f=setTimeout(function(){f=null},n[o-1]||600)}o==1&&(u=e.clientX,a=e.clientY),r[s]("mousedown",e);if(o>4)o=0;else if(o>1)return r[s](l[o],e)}),i.isOldIE&&t.addListener(e,"dblclick",function(e){o=2,f&&clearTimeout(f),f=setTimeout(function(){f=null},n[o-1]||600),r[s]("mousedown",e),r[s](l[o],e)})},t.addCommandKeyListener=function(e,n){var r=t.addListener;if(i.isOldGecko||i.isOpera&&!("KeyboardEvent"in window)){var s=null;r(e,"keydown",function(e){s=e.keyCode}),r(e,"keypress",function(e){return o(n,e,s)})}else{var u=null;r(e,"keydown",function(e){return u=e.keyIdentifier||e.keyCode,o(n,e,e.keyCode)})}};if(window.postMessage&&!i.isOldIE){var u=1;t.nextTick=function(e,n){n=n||window;var r="zero-timeout-message-"+u;t.addListener(n,"message",function i(s){s.data==r&&(t.stopPropagation(s),t.removeListener(n,"message",i),e())}),n.postMessage(r,"*")}}t.nextFrame=window.requestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame,t.nextFrame?t.nextFrame=t.nextFrame.bind(window):t.nextFrame=function(e){setTimeout(e,17)}}),ace.define("ace/lib/keys",["require","exports","module","ace/lib/oop"],function(e,t,n){var r=e("./oop"),i=function(){var e={MODIFIER_KEYS:{16:"Shift",17:"Ctrl",18:"Alt",224:"Meta"},KEY_MODS:{ctrl:1,alt:2,option:2,shift:4,meta:8,command:8},FUNCTION_KEYS:{8:"Backspace",9:"Tab",13:"Return",19:"Pause",27:"Esc",32:"Space",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"Left",38:"Up",39:"Right",40:"Down",44:"Print",45:"Insert",46:"Delete",96:"Numpad0",97:"Numpad1",98:"Numpad2",99:"Numpad3",100:"Numpad4",101:"Numpad5",102:"Numpad6",103:"Numpad7",104:"Numpad8",105:"Numpad9",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"Numlock",145:"Scrolllock"},PRINTABLE_KEYS:{32:" ",48:"0",49:"1",50:"2",51:"3",52:"4",53:"5",54:"6",55:"7",56:"8",57:"9",59:";",61:"=",65:"a",66:"b",67:"c",68:"d",69:"e",70:"f",71:"g",72:"h",73:"i",74:"j",75:"k",76:"l",77:"m",78:"n",79:"o",80:"p",81:"q",82:"r",83:"s",84:"t",85:"u",86:"v",87:"w",88:"x",89:"y",90:"z",107:"+",109:"-",110:".",188:",",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"}};for(var t in e.FUNCTION_KEYS){var n=e.FUNCTION_KEYS[t].toLowerCase();e[n]=parseInt(t,10)}return r.mixin(e,e.MODIFIER_KEYS),r.mixin(e,e.PRINTABLE_KEYS),r.mixin(e,e.FUNCTION_KEYS),e.enter=e["return"],e.escape=e.esc,e.del=e["delete"],e[173]="-",e}();r.mixin(t,i),t.keyCodeToString=function(e){return(i[e]||String.fromCharCode(e)).toLowerCase()}}),ace.define("ace/lib/oop",["require","exports","module"],function(e,t,n){t.inherits=function(){var e=function(){};return function(t,n){e.prototype=n.prototype,t.super_=n.prototype,t.prototype=new e,t.prototype.constructor=t}}(),t.mixin=function(e,t){for(var n in t)e[n]=t[n]},t.implement=function(e,n){t.mixin(e,n)}}),ace.define("ace/lib/useragent",["require","exports","module"],function(e,t,n){t.OS={LINUX:"LINUX",MAC:"MAC",WINDOWS:"WINDOWS"},t.getOS=function(){return t.isMac?t.OS.MAC:t.isLinux?t.OS.LINUX:t.OS.WINDOWS};if(typeof navigator!="object")return;var r=(navigator.platform.match(/mac|win|linux/i)||["other"])[0].toLowerCase(),i=navigator.userAgent;t.isWin=r=="win",t.isMac=r=="mac",t.isLinux=r=="linux",t.isIE=navigator.appName=="Microsoft Internet Explorer"&&parseFloat(navigator.userAgent.match(/MSIE ([0-9]+[\.0-9]+)/)[1]),t.isOldIE=t.isIE&&t.isIE<9,t.isGecko=t.isMozilla=window.controllers&&window.navigator.product==="Gecko",t.isOldGecko=t.isGecko&&parseInt((navigator.userAgent.match(/rv\:(\d+)/)||[])[1],10)<4,t.isOpera=window.opera&&Object.prototype.toString.call(window.opera)=="[object Opera]",t.isWebKit=parseFloat(i.split("WebKit/")[1])||undefined,t.isChrome=parseFloat(i.split(" Chrome/")[1])||undefined,t.isAIR=i.indexOf("AdobeAIR")>=0,t.isIPad=i.indexOf("iPad")>=0,t.isTouchPad=i.indexOf("TouchPad")>=0}),ace.define("ace/editor",["require","exports","module","ace/lib/fixoldbrowsers","ace/lib/oop","ace/lib/lang","ace/lib/useragent","ace/keyboard/textinput","ace/mouse/mouse_handler","ace/mouse/fold_handler","ace/keyboard/keybinding","ace/edit_session","ace/search","ace/range","ace/lib/event_emitter","ace/commands/command_manager","ace/commands/default_commands"],function(e,t,n){e("./lib/fixoldbrowsers");var r=e("./lib/oop"),i=e("./lib/lang"),s=e("./lib/useragent"),o=e("./keyboard/textinput").TextInput,u=e("./mouse/mouse_handler").MouseHandler,a=e("./mouse/fold_handler").FoldHandler,f=e("./keyboard/keybinding").KeyBinding,l=e("./edit_session").EditSession,c=e("./search").Search,h=e("./range").Range,p=e("./lib/event_emitter").EventEmitter,d=e("./commands/command_manager").CommandManager,v=e("./commands/default_commands").commands,m=function(e,t){var n=e.getContainerElement();this.container=n,this.renderer=e,this.commands=new d(s.isMac?"mac":"win",v),this.textInput=new o(e.getTextAreaContainer(),this),this.renderer.textarea=this.textInput.getElement(),this.keyBinding=new f(this),this.$mouseHandler=new u(this),new a(this),this.$blockScrolling=0,this.$search=(new c).set({wrap:!0}),this.setSession(t||new l(""))};(function(){r.implement(this,p),this.setKeyboardHandler=function(e){this.keyBinding.setKeyboardHandler(e)},this.getKeyboardHandler=function(){return this.keyBinding.getKeyboardHandler()},this.setSession=function(e){if(this.session==e)return;if(this.session){var t=this.session;this.session.removeEventListener("change",this.$onDocumentChange),this.session.removeEventListener("changeMode",this.$onChangeMode),this.session.removeEventListener("tokenizerUpdate",this.$onTokenizerUpdate),this.session.removeEventListener("changeTabSize",this.$onChangeTabSize),this.session.removeEventListener("changeWrapLimit",this.$onChangeWrapLimit),this.session.removeEventListener("changeWrapMode",this.$onChangeWrapMode),this.session.removeEventListener("onChangeFold",this.$onChangeFold),this.session.removeEventListener("changeFrontMarker",this.$onChangeFrontMarker),this.session.removeEventListener("changeBackMarker",this.$onChangeBackMarker),this.session.removeEventListener("changeBreakpoint",this.$onChangeBreakpoint),this.session.removeEventListener("changeAnnotation",this.$onChangeAnnotation),this.session.removeEventListener("changeOverwrite",this.$onCursorChange),this.session.removeEventListener("changeScrollTop",this.$onScrollTopChange),this.session.removeEventListener("changeLeftTop",this.$onScrollLeftChange);var n=this.session.getSelection();n.removeEventListener("changeCursor",this.$onCursorChange),n.removeEventListener("changeSelection",this.$onSelectionChange)}this.session=e,this.$onDocumentChange=this.onDocumentChange.bind(this),e.addEventListener("change",this.$onDocumentChange),this.renderer.setSession(e),this.$onChangeMode=this.onChangeMode.bind(this),e.addEventListener("changeMode",this.$onChangeMode),this.$onTokenizerUpdate=this.onTokenizerUpdate.bind(this),e.addEventListener("tokenizerUpdate",this.$onTokenizerUpdate),this.$onChangeTabSize=this.renderer.onChangeTabSize.bind(this.renderer),e.addEventListener("changeTabSize",this.$onChangeTabSize),this.$onChangeWrapLimit=this.onChangeWrapLimit.bind(this),e.addEventListener("changeWrapLimit",this.$onChangeWrapLimit),this.$onChangeWrapMode=this.onChangeWrapMode.bind(this),e.addEventListener("changeWrapMode",this.$onChangeWrapMode),this.$onChangeFold=this.onChangeFold.bind(this),e.addEventListener("changeFold",this.$onChangeFold),this.$onChangeFrontMarker=this.onChangeFrontMarker.bind(this),this.session.addEventListener("changeFrontMarker",this.$onChangeFrontMarker),this.$onChangeBackMarker=this.onChangeBackMarker.bind(this),this.session.addEventListener("changeBackMarker",this.$onChangeBackMarker),this.$onChangeBreakpoint=this.onChangeBreakpoint.bind(this),this.session.addEventListener("changeBreakpoint",this.$onChangeBreakpoint),this.$onChangeAnnotation=this.onChangeAnnotation.bind(this),this.session.addEventListener("changeAnnotation",this.$onChangeAnnotation),this.$onCursorChange=this.onCursorChange.bind(this),this.session.addEventListener("changeOverwrite",this.$onCursorChange),this.$onScrollTopChange=this.onScrollTopChange.bind(this),this.session.addEventListener("changeScrollTop",this.$onScrollTopChange),this.$onScrollLeftChange=this.onScrollLeftChange.bind(this),this.session.addEventListener("changeScrollLeft",this.$onScrollLeftChange),this.selection=e.getSelection(),this.selection.addEventListener("changeCursor",this.$onCursorChange),this.$onSelectionChange=this.onSelectionChange.bind(this),this.selection.addEventListener("changeSelection",this.$onSelectionChange),this.onChangeMode(),this.$blockScrolling+=1,this.onCursorChange(),this.$blockScrolling-=1,this.onScrollTopChange(),this.onScrollLeftChange(),this.onSelectionChange(),this.onChangeFrontMarker(),this.onChangeBackMarker(),this.onChangeBreakpoint(),this.onChangeAnnotation(),this.session.getUseWrapMode()&&this.renderer.adjustWrapLimit(),this.renderer.updateFull(),this._emit("changeSession",{session:e,oldSession:t})},this.getSession=function(){return this.session},this.setValue=function(e,t){return this.session.doc.setValue(e),t?t==1?this.navigateFileEnd():t==-1&&this.navigateFileStart():this.selectAll(),e},this.getValue=function(){return this.session.getValue()},this.getSelection=function(){return this.selection},this.resize=function(e){this.renderer.onResize(e)},this.setTheme=function(e){this.renderer.setTheme(e)},this.getTheme=function(){return this.renderer.getTheme()},this.setStyle=function(e){this.renderer.setStyle(e)},this.unsetStyle=function(e){this.renderer.unsetStyle(e)},this.setFontSize=function(e){this.container.style.fontSize=e,this.renderer.updateFontSize()},this.$highlightBrackets=function(){this.session.$bracketHighlight&&(this.session.removeMarker(this.session.$bracketHighlight),this.session.$bracketHighlight=null);if(this.$highlightPending)return;var e=this;this.$highlightPending=!0,setTimeout(function(){e.$highlightPending=!1;var t=e.session.findMatchingBracket(e.getCursorPosition());if(t){var n=new h(t.row,t.column,t.row,t.column+1);e.session.$bracketHighlight=e.session.addMarker(n,"ace_bracket","text")}},50)},this.focus=function(){var e=this;setTimeout(function(){e.textInput.focus()}),this.textInput.focus()},this.isFocused=function(){return this.textInput.isFocused()},this.blur=function(){this.textInput.blur()},this.onFocus=function(){if(this.$isFocused)return;this.$isFocused=!0,this.renderer.showCursor(),this.renderer.visualizeFocus(),this._emit("focus")},this.onBlur=function(){if(!this.$isFocused)return;this.$isFocused=!1,this.renderer.hideCursor(),this.renderer.visualizeBlur(),this._emit("blur")},this.$cursorChange=function(){this.renderer.updateCursor()},this.onDocumentChange=function(e){var t=e.data,n=t.range,r;n.start.row==n.end.row&&t.action!="insertLines"&&t.action!="removeLines"?r=n.end.row:r=Infinity,this.renderer.updateLines(n.start.row,r),this._emit("change",e),this.$cursorChange()},this.onTokenizerUpdate=function(e){var t=e.data;this.renderer.updateLines(t.first,t.last)},this.onScrollTopChange=function(){this.renderer.scrollToY(this.session.getScrollTop())},this.onScrollLeftChange=function(){this.renderer.scrollToX(this.session.getScrollLeft())},this.onCursorChange=function(){this.$cursorChange(),this.$blockScrolling||this.renderer.scrollCursorIntoView(),this.$highlightBrackets(),this.$updateHighlightActiveLine(),this._emit("changeSelection")},this.$updateHighlightActiveLine=function(){var e=this.getSession(),t;this.$highlightActiveLine&&(this.$selectionStyle!="line"||!this.selection.isMultiLine())&&(t=this.getCursorPosition()),e.$highlightLineMarker&&!t?(e.removeMarker(e.$highlightLineMarker.id),e.$highlightLineMarker=null):!e.$highlightLineMarker&&t?e.$highlightLineMarker=e.highlightLines(t.row,t.row,"ace_active-line"):t&&(e.$highlightLineMarker.start.row=t.row,e.$highlightLineMarker.end.row=t.row,e._emit("changeBackMarker"))},this.onSelectionChange=function(e){var t=this.session;t.$selectionMarker&&t.removeMarker(t.$selectionMarker),t.$selectionMarker=null;if(!this.selection.isEmpty()){var n=this.selection.getRange(),r=this.getSelectionStyle();t.$selectionMarker=t.addMarker(n,"ace_selection",r)}else this.$updateHighlightActiveLine();var i=this.$highlightSelectedWord&&this.$getSelectionHighLightRegexp();this.session.highlight(i),this._emit("changeSelection")},this.$getSelectionHighLightRegexp=function(){var e=this.session,t=this.getSelectionRange();if(t.isEmpty()||t.isMultiLine())return;var n=t.start.column-1,r=t.end.column+1,i=e.getLine(t.start.row),s=i.length,o=i.substring(Math.max(n,0),Math.min(r,s));if(n>=0&&/^[\w\d]/.test(o)||r<=s&&/[\w\d]$/.test(o))return;o=i.substring(t.start.column,t.end.column);if(!/^[\w\d]+$/.test(o))return;var u=this.$search.$assembleRegExp({wholeWord:!0,caseSensitive:!0,needle:o});return u},this.onChangeFrontMarker=function(){this.renderer.updateFrontMarkers()},this.onChangeBackMarker=function(){this.renderer.updateBackMarkers()},this.onChangeBreakpoint=function(){this.renderer.updateBreakpoints()},this.onChangeAnnotation=function(){this.renderer.setAnnotations(this.session.getAnnotations())},this.onChangeMode=function(){this.renderer.updateText()},this.onChangeWrapLimit=function(){this.renderer.updateFull()},this.onChangeWrapMode=function(){this.renderer.onResize(!0)},this.onChangeFold=function(){this.$updateHighlightActiveLine(),this.renderer.updateFull()},this.getCopyText=function(){var e="";return this.selection.isEmpty()||(e=this.session.getTextRange(this.getSelectionRange())),this._emit("copy",e),e},this.onCopy=function(){this.commands.exec("copy",this)},this.onCut=function(){this.commands.exec("cut",this)},this.onPaste=function(e){if(this.$readOnly)return;this._emit("paste",e),this.insert(e)},this.execCommand=function(e,t){this.commands.exec(e,this,t)},this.insert=function(e){var t=this.session,n=t.getMode(),r=this.getCursorPosition();if(this.getBehavioursEnabled()){var i=n.transformAction(t.getState(r.row),"insertion",this,t,e);i&&(e=i.text)}e=e.replace(" ",this.session.getTabString());if(!this.selection.isEmpty())r=this.session.remove(this.getSelectionRange()),this.clearSelection();else if(this.session.getOverwrite()){var s=new h.fromPoints(r,r);s.end.column+=e.length,this.session.remove(s)}this.clearSelection();var o=r.column,u=t.getState(r.row),a=t.getLine(r.row),f=n.checkOutdent(u,a,e),l=t.insert(r,e);i&&i.selection&&(i.selection.length==2?this.selection.setSelectionRange(new h(r.row,o+i.selection[0],r.row,o+i.selection[1])):this.selection.setSelectionRange(new h(r.row+i.selection[0],i.selection[1],r.row+i.selection[2],i.selection[3])));if(t.getDocument().isNewLine(e)){var c=n.getNextLineIndent(u,a.slice(0,r.column),t.getTabString());this.moveCursorTo(r.row+1,0);var p=t.getTabSize(),d=Number.MAX_VALUE;for(var v=r.row+1;v<=l.row;++v){var m=0;a=t.getLine(v);for(var g=0;g<a.length;++g)if(a.charAt(g)==" ")m+=p;else{if(a.charAt(g)!=" ")break;m+=1}/[^\s]/.test(a)&&(d=Math.min(m,d))}for(var v=r.row+1;v<=l.row;++v){var y=d;a=t.getLine(v);for(var g=0;g<a.length&&y>0;++g)a.charAt(g)==" "?y-=p:a.charAt(g)==" "&&(y-=1);t.remove(new h(v,0,v,g))}t.indentRows(r.row+1,l.row,c)}f&&n.autoOutdent(u,t,r.row)},this.onTextInput=function(e){this.keyBinding.onTextInput(e)},this.onCommandKey=function(e,t,n){this.keyBinding.onCommandKey(e,t,n)},this.setOverwrite=function(e){this.session.setOverwrite(e)},this.getOverwrite=function(){return this.session.getOverwrite()},this.toggleOverwrite=function(){this.session.toggleOverwrite()},this.setScrollSpeed=function(e){this.$mouseHandler.setScrollSpeed(e)},this.getScrollSpeed=function(){return this.$mouseHandler.getScrollSpeed()},this.setDragDelay=function(e){this.$mouseHandler.setDragDelay(e)},this.getDragDelay=function(){return this.$mouseHandler.getDragDelay()},this.$selectionStyle="line",this.setSelectionStyle=function(e){if(this.$selectionStyle==e)return;this.$selectionStyle=e,this.onSelectionChange(),this._emit("changeSelectionStyle",{data:e})},this.getSelectionStyle=function(){return this.$selectionStyle},this.$highlightActiveLine=!0,this.setHighlightActiveLine=function(e){if(this.$highlightActiveLine==e)return;this.$highlightActiveLine=e,this.$updateHighlightActiveLine()},this.getHighlightActiveLine=function(){return this.$highlightActiveLine},this.$highlightGutterLine=!0,this.setHighlightGutterLine=function(e){if(this.$highlightGutterLine==e)return;this.renderer.setHighlightGutterLine(e),this.$highlightGutterLine=e},this.getHighlightGutterLine=function(){return this.$highlightGutterLine},this.$highlightSelectedWord=!0,this.setHighlightSelectedWord=function(e){if(this.$highlightSelectedWord==e)return;this.$highlightSelectedWord=e,this.$onSelectionChange()},this.getHighlightSelectedWord=function(){return this.$highlightSelectedWord},this.setAnimatedScroll=function(e){this.renderer.setAnimatedScroll(e)},this.getAnimatedScroll=function(){return this.renderer.getAnimatedScroll()},this.setShowInvisibles=function(e){this.renderer.setShowInvisibles(e)},this.getShowInvisibles=function(){return this.renderer.getShowInvisibles()},this.setDisplayIndentGuides=function(e){this.renderer.setDisplayIndentGuides(e)},this.getDisplayIndentGuides=function(){return this.renderer.getDisplayIndentGuides()},this.setShowPrintMargin=function(e){this.renderer.setShowPrintMargin(e)},this.getShowPrintMargin=function(){return this.renderer.getShowPrintMargin()},this.setPrintMarginColumn=function(e){this.renderer.setPrintMarginColumn(e)},this.getPrintMarginColumn=function(){return this.renderer.getPrintMarginColumn()},this.$readOnly=!1,this.setReadOnly=function(e){this.$readOnly=e},this.getReadOnly=function(){return this.$readOnly},this.$modeBehaviours=!0,this.setBehavioursEnabled=function(e){this.$modeBehaviours=e},this.getBehavioursEnabled=function(){return this.$modeBehaviours},this.$modeWrapBehaviours=!0,this.setWrapBehavioursEnabled=function(e){this.$modeWrapBehaviours=e},this.getWrapBehavioursEnabled=function(){return this.$modeWrapBehaviours},this.setShowFoldWidgets=function(e){var t=this.renderer.$gutterLayer;if(t.getShowFoldWidgets()==e)return;this.renderer.$gutterLayer.setShowFoldWidgets(e),this.$showFoldWidgets=e,this.renderer.updateFull()},this.getShowFoldWidgets=function(){return this.renderer.$gutterLayer.getShowFoldWidgets()},this.setFadeFoldWidgets=function(e){this.renderer.setFadeFoldWidgets(e)},this.getFadeFoldWidgets=function(){return this.renderer.getFadeFoldWidgets()},this.remove=function(e){this.selection.isEmpty()&&(e=="left"?this.selection.selectLeft():this.selection.selectRight());var t=this.getSelectionRange();if(this.getBehavioursEnabled()){var n=this.session,r=n.getState(t.start.row),i=n.getMode().transformAction(r,"deletion",this,n,t);i&&(t=i)}this.session.remove(t),this.clearSelection()},this.removeWordRight=function(){this.selection.isEmpty()&&this.selection.selectWordRight(),this.session.remove(this.getSelectionRange()),this.clearSelection()},this.removeWordLeft=function(){this.selection.isEmpty()&&this.selection.selectWordLeft(),this.session.remove(this.getSelectionRange()),this.clearSelection()},this.removeToLineStart=function(){this.selection.isEmpty()&&this.selection.selectLineStart(),this.session.remove(this.getSelectionRange()),this.clearSelection()},this.removeToLineEnd=function(){this.selection.isEmpty()&&this.selection.selectLineEnd();var e=this.getSelectionRange();e.start.column==e.end.column&&e.start.row==e.end.row&&(e.end.column=0,e.end.row++),this.session.remove(e),this.clearSelection()},this.splitLine=function(){this.selection.isEmpty()||(this.session.remove(this.getSelectionRange()),this.clearSelection());var e=this.getCursorPosition();this.insert("\n"),this.moveCursorToPosition(e)},this.transposeLetters=function(){if(!this.selection.isEmpty())return;var e=this.getCursorPosition(),t=e.column;if(t===0)return;var n=this.session.getLine(e.row),r,i;t<n.length?(r=n.charAt(t)+n.charAt(t-1),i=new h(e.row,t-1,e.row,t+1)):(r=n.charAt(t-1)+n.charAt(t-2),i=new h(e.row,t-2,e.row,t)),this.session.replace(i,r)},this.toLowerCase=function(){var e=this.getSelectionRange();this.selection.isEmpty()&&this.selection.selectWord();var t=this.getSelectionRange(),n=this.session.getTextRange(t);this.session.replace(t,n.toLowerCase()),this.selection.setSelectionRange(e)},this.toUpperCase=function(){var e=this.getSelectionRange();this.selection.isEmpty()&&this.selection.selectWord();var t=this.getSelectionRange(),n=this.session.getTextRange(t);this.session.replace(t,n.toUpperCase()),this.selection.setSelectionRange(e)},this.indent=function(){var e=this.session,t=this.getSelectionRange();if(!(t.start.row<t.end.row||t.start.column<t.end.column)){var r;if(this.session.getUseSoftTabs()){var s=e.getTabSize(),o=this.getCursorPosition(),u=e.documentToScreenColumn(o.row,o.column),a=s-u%s;r=i.stringRepeat(" ",a)}else r=" ";return this.insert(r)}var n=this.$getSelectedRows();e.indentRows(n.first,n.last," ")},this.blockOutdent=function(){var e=this.session.getSelection();this.session.outdentRows(e.getRange())},this.sortLines=function(){var e=this.$getSelectedRows(),t=this.session,n=[];for(i=e.first;i<=e.last;i++)n.push(t.getLine(i));n.sort(function(e,t){return e.toLowerCase()<t.toLowerCase()?-1:e.toLowerCase()>t.toLowerCase()?1:0});var r=new h(0,0,0,0);for(var i=e.first;i<=e.last;i++){var s=t.getLine(i);r.start.row=i,r.end.row=i,r.end.column=s.length,t.replace(r,n[i-e.first])}},this.toggleCommentLines=function(){var e=this.session.getState(this.getCursorPosition().row),t=this.$getSelectedRows();this.session.getMode().toggleCommentLines(e,this.session,t.first,t.last)},this.getNumberAt=function(e,t){var n=/[\-]?[0-9]+(?:\.[0-9]+)?/g;n.lastIndex=0;var r=this.session.getLine(e);while(n.lastIndex<t-1){var i=n.exec(r);if(i.index<=t&&i.index+i[0].length>=t){var s={value:i[0],start:i.index,end:i.index+i[0].length};return s}}return null},this.modifyNumber=function(e){var t=this.selection.getCursor().row,n=this.selection.getCursor().column,r=new h(t,n-1,t,n),i=this.session.getTextRange(r);if(!isNaN(parseFloat(i))&&isFinite(i)){var s=this.getNumberAt(t,n);if(s){var o=s.value.indexOf(".")>=0?s.start+s.value.indexOf(".")+1:s.end,u=s.start+s.value.length-o,a=parseFloat(s.value);a*=Math.pow(10,u),o!==s.end&&n<o?e*=Math.pow(10,s.end-n-1):e*=Math.pow(10,s.end-n),a+=e,a/=Math.pow(10,u);var f=a.toFixed(u),l=new h(t,s.start,t,s.end);this.session.replace(l,f),this.moveCursorTo(t,Math.max(s.start+1,n+f.length-s.value.length))}}},this.removeLines=function(){var e=this.$getSelectedRows(),t;e.first===0||e.last+1<this.session.getLength()?t=new h(e.first,0,e.last+1,0):t=new h(e.first-1,this.session.getLine(e.first-1).length,e.last,this.session.getLine(e.last).length),this.session.remove(t),this.clearSelection()},this.duplicateSelection=function(){var e=this.selection,t=this.session,n=e.getRange();if(n.isEmpty()){var r=n.start.row;t.duplicateLines(r,r)}else{var i=e.isBackwards(),s=e.isBackwards()?n.start:n.end,o=t.insert(s,t.getTextRange(n),!1);n.start=s,n.end=o,e.setSelectionRange(n,i)}},this.moveLinesDown=function(){this.$moveLines(function(e,t){return this.session.moveLinesDown(e,t)})},this.moveLinesUp=function(){this.$moveLines(function(e,t){return this.session.moveLinesUp(e,t)})},this.moveText=function(e,t){return this.$readOnly?null:this.session.moveText(e,t)},this.copyLinesUp=function(){this.$moveLines(function(e,t){return this.session.duplicateLines(e,t),0})},this.copyLinesDown=function(){this.$moveLines(function(e,t){return this.session.duplicateLines(e,t)})},this.$moveLines=function(e){var t=this.$getSelectedRows(),n=this.selection;if(!n.isMultiLine())var r=n.getRange(),i=n.isBackwards();var s=e.call(this,t.first,t.last);r?(r.start.row+=s,r.end.row+=s,n.setSelectionRange(r,i)):(n.setSelectionAnchor(t.last+s+1,0),n.$moveSelection(function(){n.moveCursorTo(t.first+s,0)}))},this.$getSelectedRows=function(){var e=this.getSelectionRange().collapseRows();return{first:e.start.row,last:e.end.row}},this.onCompositionStart=function(e){this.renderer.showComposition(this.getCursorPosition())},this.onCompositionUpdate=function(e){this.renderer.setCompositionText(e)},this.onCompositionEnd=function(){this.renderer.hideComposition()},this.getFirstVisibleRow=function(){return this.renderer.getFirstVisibleRow()},this.getLastVisibleRow=function(){return this.renderer.getLastVisibleRow()},this.isRowVisible=function(e){return e>=this.getFirstVisibleRow()&&e<=this.getLastVisibleRow()},this.isRowFullyVisible=function(e){return e>=this.renderer.getFirstFullyVisibleRow()&&e<=this.renderer.getLastFullyVisibleRow()},this.$getVisibleRowCount=function(){return this.renderer.getScrollBottomRow()-this.renderer.getScrollTopRow()+1},this.$moveByPage=function(e,t){var n=this.renderer,r=this.renderer.layerConfig,i=e*Math.floor(r.height/r.lineHeight);this.$blockScrolling++,t==1?this.selection.$moveSelection(function(){this.moveCursorBy(i,0)}):t==0&&(this.selection.moveCursorBy(i,0),this.selection.clearSelection()),this.$blockScrolling--;var s=n.scrollTop;n.scrollBy(0,i*r.lineHeight),t!=null&&n.scrollCursorIntoView(null,.5),n.animateScrolling(s)},this.selectPageDown=function(){this.$moveByPage(1,!0)},this.selectPageUp=function(){this.$moveByPage(-1,!0)},this.gotoPageDown=function(){this.$moveByPage(1,!1)},this.gotoPageUp=function(){this.$moveByPage(-1,!1)},this.scrollPageDown=function(){this.$moveByPage(1)},this.scrollPageUp=function(){this.$moveByPage(-1)},this.scrollToRow=function(e){this.renderer.scrollToRow(e)},this.scrollToLine=function(e,t,n,r){this.renderer.scrollToLine(e,t,n,r)},this.centerSelection=function(){var e=this.getSelectionRange(),t={row:Math.floor(e.start.row+(e.end.row-e.start.row)/2),column:Math.floor(e.start.column+(e.end.column-e.start.column)/2)};this.renderer.alignCursor(t,.5)},this.getCursorPosition=function(){return this.selection.getCursor()},this.getCursorPositionScreen=function(){return this.session.documentToScreenPosition(this.getCursorPosition())},this.getSelectionRange=function(){return this.selection.getRange()},this.selectAll=function(){this.$blockScrolling+=1,this.selection.selectAll(),this.$blockScrolling-=1},this.clearSelection=function(){this.selection.clearSelection()},this.moveCursorTo=function(e,t){this.selection.moveCursorTo(e,t)},this.moveCursorToPosition=function(e){this.selection.moveCursorToPosition(e)},this.jumpToMatching=function(e){var t=this.getCursorPosition(),n=this.session.getBracketRange(t);if(!n){n=this.find({needle:/[{}()\[\]]/g,preventScroll:!0,start:{row:t.row,column:t.column-1}});if(!n)return;var r=n.start;r.row==t.row&&Math.abs(r.column-t.column)<2&&(n=this.session.getBracketRange(r))}r=n&&n.cursor||r,r&&(e?n&&n.isEqual(this.getSelectionRange())?this.clearSelection():this.selection.selectTo(r.row,r.column):(this.clearSelection(),this.moveCursorTo(r.row,r.column)))},this.gotoLine=function(e,t,n){this.selection.clearSelection(),this.session.unfold({row:e-1,column:t||0}),this.$blockScrolling+=1,this.moveCursorTo(e-1,t||0),this.$blockScrolling-=1,this.isRowFullyVisible(e-1)||this.scrollToLine(e-1,!0,n)},this.navigateTo=function(e,t){this.clearSelection(),this.moveCursorTo(e,t)},this.navigateUp=function(e){this.selection.clearSelection(),e=e||1,this.selection.moveCursorBy(-e,0)},this.navigateDown=function(e){this.selection.clearSelection(),e=e||1,this.selection.moveCursorBy(e,0)},this.navigateLeft=function(e){if(!this.selection.isEmpty()){var t=this.getSelectionRange().start;this.moveCursorToPosition(t)}else{e=e||1;while(e--)this.selection.moveCursorLeft()}this.clearSelection()},this.navigateRight=function(e){if(!this.selection.isEmpty()){var t=this.getSelectionRange().end;this.moveCursorToPosition(t)}else{e=e||1;while(e--)this.selection.moveCursorRight()}this.clearSelection()},this.navigateLineStart=function(){this.selection.moveCursorLineStart(),this.clearSelection()},this.navigateLineEnd=function(){this.selection.moveCursorLineEnd(),this.clearSelection()},this.navigateFileEnd=function(){var e=this.renderer.scrollTop;this.selection.moveCursorFileEnd(),this.clearSelection(),this.renderer.animateScrolling(e)},this.navigateFileStart=function(){var e=this.renderer.scrollTop;this.selection.moveCursorFileStart(),this.clearSelection(),this.renderer.animateScrolling(e)},this.navigateWordRight=function(){this.selection.moveCursorWordRight(),this.clearSelection()},this.navigateWordLeft=function(){this.selection.moveCursorWordLeft(),this.clearSelection()},this.replace=function(e,t){t&&this.$search.set(t);var n=this.$search.find(this.session),r=0;return n?(this.$tryReplace(n,e)&&(r=1),n!==null&&(this.selection.setSelectionRange(n),this.renderer.scrollSelectionIntoView(n.start,n.end)),r):r},this.replaceAll=function(e,t){t&&this.$search.set(t);var n=this.$search.findAll(this.session),r=0;if(!n.length)return r;this.$blockScrolling+=1;var i=this.getSelectionRange();this.clearSelection(),this.selection.moveCursorTo(0,0);for(var s=n.length-1;s>=0;--s)this.$tryReplace(n[s],e)&&r++;return this.selection.setSelectionRange(i),this.$blockScrolling-=1,r},this.$tryReplace=function(e,t){var n=this.session.getTextRange(e);return t=this.$search.replace(n,t),t!==null?(e.end=this.session.replace(e,t),e):null},this.getLastSearchOptions=function(){return this.$search.getOptions()},this.find=function(e,t,n){t||(t={}),typeof e=="string"||e instanceof RegExp?t.needle=e:typeof e=="object"&&r.mixin(t,e);var i=this.selection.getRange();t.needle==null&&(e=this.session.getTextRange(i)||this.$search.$options.needle,e||(i=this.session.getWordRange(i.start.row,i.start.column),e=this.session.getTextRange(i)),this.$search.set({needle:e})),this.$search.set(t),t.start||this.$search.set({start:i});var s=this.$search.find(this.session);if(t.preventScroll)return s;if(s)return this.revealRange(s,n),s;t.backwards?i.start=i.end:i.end=i.start,this.selection.setRange(i)},this.findNext=function(e,t){this.find({skipCurrent:!0,backwards:!1},e,t)},this.findPrevious=function(e,t){this.find(e,{skipCurrent:!0,backwards:!0},t)},this.revealRange=function(e,t){this.$blockScrolling+=1,this.session.unfold(e),this.selection.setSelectionRange(e),this.$blockScrolling-=1;var n=this.renderer.scrollTop;this.renderer.scrollSelectionIntoView(e.start,e.end,.5),t!=0&&this.renderer.animateScrolling(n)},this.undo=function(){this.$blockScrolling++,this.session.getUndoManager().undo(),this.$blockScrolling--,this.renderer.scrollCursorIntoView(null,.5)},this.redo=function(){this.$blockScrolling++,this.session.getUndoManager().redo(),this.$blockScrolling--,this.renderer.scrollCursorIntoView(null,.5)},this.destroy=function(){this.renderer.destroy()}}).call(m.prototype),t.Editor=m}),ace.define("ace/lib/lang",["require","exports","module"],function(e,t,n){t.stringReverse=function(e){return e.split("").reverse().join("")},t.stringRepeat=function(e,t){return(new Array(t+1)).join(e)};var r=/^\s\s*/,i=/\s\s*$/;t.stringTrimLeft=function(e){return e.replace(r,"")},t.stringTrimRight=function(e){return e.replace(i,"")},t.copyObject=function(e){var t={};for(var n in e)t[n]=e[n];return t},t.copyArray=function(e){var t=[];for(var n=0,r=e.length;n<r;n++)e[n]&&typeof e[n]=="object"?t[n]=this.copyObject(e[n]):t[n]=e[n];return t},t.deepCopy=function(e){if(typeof e!="object")return e;var t=e.constructor();for(var n in e)typeof e[n]=="object"?t[n]=this.deepCopy(e[n]):t[n]=e[n];return t},t.arrayToMap=function(e){var t={};for(var n=0;n<e.length;n++)t[e[n]]=1;return t},t.createMap=function(e){var t=Object.create(null);for(var n in e)t[n]=e[n];return t},t.arrayRemove=function(e,t){for(var n=0;n<=e.length;n++)t===e[n]&&e.splice(n,1)},t.escapeRegExp=function(e){return e.replace(/([.*+?^${}()|[\]\/\\])/g,"\\$1")},t.escapeHTML=function(e){return e.replace(/&/g,"&#38;").replace(/"/g,"&#34;").replace(/'/g,"&#39;").replace(/</g,"&#60;")},t.getMatchOffsets=function(e,t){var n=[];return e.replace(t,function(e){n.push({offset:arguments[arguments.length-2],length:e.length})}),n},t.deferredCall=function(e){var t=null,n=function(){t=null,e()},r=function(e){return r.cancel(),t=setTimeout(n,e||0),r};return r.schedule=r,r.call=function(){return this.cancel(),e(),r},r.cancel=function(){return clearTimeout(t),t=null,r},r},t.delayedCall=function(e,t){var n=null,r=function(){n=null,e()},i=function(e){n&&clearTimeout(n),n=setTimeout(r,e||t)};return i.delay=i,i.schedule=function(e){n==null&&(n=setTimeout(r,e||0))},i.call=function(){this.cancel(),e()},i.cancel=function(){n&&clearTimeout(n),n=null},i.isPending=function(){return n},i}}),ace.define("ace/keyboard/textinput",["require","exports","module","ace/lib/event","ace/lib/useragent","ace/lib/dom","ace/lib/lang"],function(e,t,n){var r=e("../lib/event"),i=e("../lib/useragent"),s=e("../lib/dom"),o=e("../lib/lang"),u=function(e,t){function g(e){if(c)return;var t=e?2:1,r=2;try{n.setSelectionRange(t,r)}catch(i){}}function y(){if(c)return;n.value=u,i.isWebKit&&m.schedule()}function D(){setTimeout(function(){h&&(n.style.cssText=h,h=""),t.renderer.$keepTextAreaAtCursor==null&&(t.renderer.$keepTextAreaAtCursor=!0,t.renderer.$moveTextAreaToCursor())},0)}var n=s.createElement("textarea");n.className="ace_text-input",i.isTouchPad&&n.setAttribute("x-palm-disable-auto-cap",!0),n.wrap="off",n.autocorrect="off",n.autocapitalize="off",n.spellcheck=!1,n.style.top="-2em",e.insertBefore(n,e.firstChild);var u="",a=!1,f=!1,l=!1,c=!1,h="",p=!0,d=document.activeElement===n;r.addListener(n,"blur",function(){t.onBlur(),d=!1}),r.addListener(n,"focus",function(){d=!0,t.onFocus(),g()}),this.focus=function(){n.focus()},this.blur=function(){n.blur()},this.isFocused=function(){return d};var v=o.delayedCall(function(){d&&g(p)}),m=o.delayedCall(function(){c||(n.value=u,d&&g())});i.isWebKit||t.addEventListener("changeSelection",function(){t.selection.isEmpty()!=p&&(p=!p,v.schedule())}),y(),d&&t.onFocus();var b=function(e){return e.selectionStart===0&&e.selectionEnd===e.value.length};!n.setSelectionRange&&n.createTextRange&&(n.setSelectionRange=function(e,t){var n=this.createTextRange();n.collapse(!0),n.moveStart("character",e),n.moveEnd("character",t),n.select()},b=function(e){try{var t=e.ownerDocument.selection.createRange()}catch(n){}return!t||t.parentElement()!=e?!1:t.text==e.value});if(i.isOldIE){var w=!1,E=function(e){if(w)return;var t=n.value;if(c||!t||t==u)return;if(e&&t==u[0])return S.schedule();N(t),w=!0,y(),w=!1},S=o.delayedCall(E);r.addListener(n,"propertychange",E);var x={13:1,27:1};r.addListener(n,"keyup",function(e){c&&(!n.value||x[e.keyCode])&&setTimeout(_,0);if((n.value.charCodeAt(0)||0)<129)return;c?M():O()})}var T=function(e){if(a){a=!1;return}if(f){f=!1;return}b(n)&&(t.selectAll(),g())},N=function(e){l?(g(),e&&t.onPaste(e),l=!1):e==u[0]?t.execCommand("del",{source:"ace"}):(e.substring(0,2)==u?e=e.substr(2):e[0]==u[0]?e=e.substr(1):e[e.length-1]==u[0]&&(e=e.slice(0,-1)),e[e.length-1]==u[0]&&(e=e.slice(0,-1)),e&&t.onTextInput(e))},C=function(e){if(c)return;var t=n.value;y(),N(t)},k=function(e){var i=t.getCopyText();if(!i){r.preventDefault(e);return}var s=e.clipboardData||window.clipboardData;if(s){var o=s.setData("Text",i);o&&(t.onCut(),r.preventDefault(e))}o||(a=!0,n.value=i,n.select(),setTimeout(function(){a=!1,y(),g(),t.onCut()}))},L=function(e){var i=t.getCopyText();if(!i){r.preventDefault(e);return}var s=e.clipboardData||window.clipboardData;if(s){var o=s.setData("Text",i);o&&(t.onCopy(),r.preventDefault(e))}o||(f=!0,n.value=i,n.select(),setTimeout(function(){f=!1,y(),g(),t.onCopy()}))},A=function(e){var s=e.clipboardData||window.clipboardData;if(s){var o=s.getData("Text");o&&t.onPaste(o),i.isIE&&setTimeout(g),r.preventDefault(e)}else n.value="",l=!0};r.addCommandKeyListener(n,t.onCommandKey.bind(t)),r.addListener(n,"select",T),r.addListener(n,"input",C),r.addListener(n,"cut",k),r.addListener(n,"copy",L),r.addListener(n,"paste",A),(!("oncut"in n)||!("oncopy"in n)||!("onpaste"in n))&&r.addListener(e,"keydown",function(e){if(i.isMac&&!e.metaKey||!e.ctrlKey)return;switch(e.keyCode){case 67:L(e);break;case 86:A(e);break;case 88:k(e)}});var O=function(e){c=!0,t.onCompositionStart(),setTimeout(M,0)},M=function(){if(!c)return;t.onCompositionUpdate(n.value)},_=function(e){c=!1,t.onCompositionEnd()};r.addListener(n,"compositionstart",O),i.isGecko?r.addListener(n,"text",M):r.addListener(n,"keyup",M),r.addListener(n,"compositionend",_),this.getElement=function(){return n},this.onContextMenu=function(e){h||(h=n.style.cssText),n.style.cssText="z-index:100000;"+(i.isIE?"opacity:0.1;":""),g(t.selection.isEmpty()),t._emit("nativecontextmenu",{target:t});var s=t.container.getBoundingClientRect(),o=function(e){n.style.left=e.clientX-s.left-2+"px",n.style.top=e.clientY-s.top-2+"px"};o(e);if(e.type!="mousedown")return;t.renderer.$keepTextAreaAtCursor&&(t.renderer.$keepTextAreaAtCursor=null),i.isWin&&r.capture(t.container,o,D)},this.onContextMenuClose=D,i.isGecko||r.addListener(n,"contextmenu",function(e){t.textInput.onContextMenu(e),D()})};t.TextInput=u}),ace.define("ace/mouse/mouse_handler",["require","exports","module","ace/lib/event","ace/lib/useragent","ace/mouse/default_handlers","ace/mouse/default_gutter_handler","ace/mouse/mouse_event","ace/mouse/dragdrop"],function(e,t,n){var r=e("../lib/event"),i=e("../lib/useragent"),s=e("./default_handlers").DefaultHandlers,o=e("./default_gutter_handler").GutterHandler,u=e("./mouse_event").MouseEvent,a=e("./dragdrop").DragdropHandler,f=function(e){this.editor=e,new s(this),new o(this),new a(this),r.addListener(e.container,"mousedown",function(t){return e.focus(),r.preventDefault(t)});var t=e.renderer.getMouseEventTarget();r.addListener(t,"click",this.onMouseEvent.bind(this,"click")),r.addListener(t,"mousemove",this.onMouseMove.bind(this,"mousemove")),r.addMultiMouseDownListener(t,[300,300,250],this,"onMouseEvent"),r.addMouseWheelListener(e.container,this.onMouseWheel.bind(this,"mousewheel"));var n=e.renderer.$gutter;r.addListener(n,"mousedown",this.onMouseEvent.bind(this,"guttermousedown")),r.addListener(n,"click",this.onMouseEvent.bind(this,"gutterclick")),r.addListener(n,"dblclick",this.onMouseEvent.bind(this,"gutterdblclick")),r.addListener(n,"mousemove",this.onMouseEvent.bind(this,"guttermousemove"))};(function(){this.$scrollSpeed=1,this.setScrollSpeed=function(e){this.$scrollSpeed=e},this.getScrollSpeed=function(){return this.$scrollSpeed},this.onMouseEvent=function(e,t){this.editor._emit(e,new u(t,this.editor))},this.$dragDelay=250,this.setDragDelay=function(e){this.$dragDelay=e},this.getDragDelay=function(){return this.$dragDelay},this.onMouseMove=function(e,t){var n=this.editor._eventRegistry&&this.editor._eventRegistry.mousemove;if(!n||!n.length)return;this.editor._emit(e,new u(t,this.editor))},this.onMouseWheel=function(e,t){var n=new u(t,this.editor);n.speed=this.$scrollSpeed*2,n.wheelX=t.wheelX,n.wheelY=t.wheelY,this.editor._emit(e,n)},this.setState=function(e){this.state=e},this.captureMouse=function(e,t){t&&this.setState(t),this.x=e.x,this.y=e.y,this.isMousePressed=!0;var n=this.editor.renderer;n.$keepTextAreaAtCursor&&(n.$keepTextAreaAtCursor=null);var s=this,o=function(e){s.x=e.clientX,s.y=e.clientY},u=function(e){clearInterval(f),s[s.state+"End"]&&s[s.state+"End"](e),s.$clickSelection=null,n.$keepTextAreaAtCursor==null&&(n.$keepTextAreaAtCursor=!0,n.$moveTextAreaToCursor()),s.isMousePressed=!1},a=function(){s[s.state]&&s[s.state]()};if(i.isOldIE&&e.domEvent.type=="dblclick"){setTimeout(function(){a(),u(e.domEvent)});return}r.capture(this.editor.container,o,u);var f=setInterval(a,20)}}).call(f.prototype),t.MouseHandler=f}),ace.define("ace/mouse/default_handlers",["require","exports","module","ace/lib/dom","ace/lib/useragent"],function(e,t,n){function o(e){e.$clickSelection=null;var t=e.editor;t.setDefaultHandler("mousedown",this.onMouseDown.bind(e)),t.setDefaultHandler("dblclick",this.onDoubleClick.bind(e)),t.setDefaultHandler("tripleclick",this.onTripleClick.bind(e)),t.setDefaultHandler("quadclick",this.onQuadClick.bind(e)),t.setDefaultHandler("mousewheel",this.onMouseWheel.bind(e));var n=["select","startSelect","drag","dragEnd","dragWait","dragWaitEnd","startDrag","focusWait"];n.forEach(function(t){e[t]=this[t]},this),e.selectByLines=this.extendSelectionBy.bind(e,"getLineRange"),e.selectByWords=this.extendSelectionBy.bind(e,"getWordRange"),e.$focusWaitTimout=250}function u(e,t,n,r){return Math.sqrt(Math.pow(n-e,2)+Math.pow(r-t,2))}function a(e,t){if(e.start.row==e.end.row)var n=2*t.column-e.start.column-e.end.column;else var n=2*t.row-e.start.row-e.end.row;return n<0?{cursor:e.start,anchor:e.end}:{cursor:e.end,anchor:e.start}}var r=e("../lib/dom"),i=e("../lib/useragent"),s=5;(function(){this.onMouseDown=function(e){var t=e.inSelection(),n=e.getDocumentPosition();this.mousedownEvent=e;var r=this.editor,i=e.getButton();if(i!==0){var s=r.getSelectionRange(),o=s.isEmpty();o&&(r.moveCursorToPosition(n),r.selection.clearSelection()),r.textInput.onContextMenu(e.domEvent);return}if(t&&!r.isFocused()){r.focus();if(this.$focusWaitTimout&&!this.$clickSelection)return this.setState("focusWait"),this.captureMouse(e),e.preventDefault()}return!t||this.$clickSelection||e.getShiftKey()?this.startSelect(n):t&&(this.mousedownEvent.time=(new Date).getTime(),this.setState("dragWait")),this.captureMouse(e),e.preventDefault()},this.startSelect=function(e){e=e||this.editor.renderer.screenToTextCoordinates(this.x,this.y),this.mousedownEvent.getShiftKey()?this.editor.selection.selectToPosition(e):this.$clickSelection||(this.editor.moveCursorToPosition(e),this.editor.selection.clearSelection()),this.setState("select")},this.select=function(){var e,t=this.editor,n=t.renderer.screenToTextCoordinates(this.x,this.y);if(this.$clickSelection){var r=this.$clickSelection.comparePoint(n);if(r==-1)e=this.$clickSelection.end;else if(r==1)e=this.$clickSelection.start;else{var i=a(this.$clickSelection,n);n=i.cursor,e=i.anchor}t.selection.setSelectionAnchor(e.row,e.column)}t.selection.selectToPosition(n),t.renderer.scrollCursorIntoView()},this.extendSelectionBy=function(e){var t,n=this.editor,r=n.renderer.screenToTextCoordinates(this.x,this.y),i=n.selection[e](r.row,r.column);if(this.$clickSelection){var s=this.$clickSelection.comparePoint(i.start),o=this.$clickSelection.comparePoint(i.end);if(s==-1&&o<=0){t=this.$clickSelection.end;if(i.end.row!=r.row||i.end.column!=r.column)r=i.start}else if(o==1&&s>=0){t=this.$clickSelection.start;if(i.start.row!=r.row||i.start.column!=r.column)r=i.end}else if(s==-1&&o==1)r=i.end,t=i.start;else{var u=a(this.$clickSelection,r);r=u.cursor,t=u.anchor}n.selection.setSelectionAnchor(t.row,t.column)}n.selection.selectToPosition(r),n.renderer.scrollCursorIntoView()},this.startDrag=function(){var e=this.editor;this.setState("drag"),this.dragRange=e.getSelectionRange();var t=e.getSelectionStyle();this.dragSelectionMarker=e.session.addMarker(this.dragRange,"ace_selection",t),e.clearSelection(),r.addCssClass(e.container,"ace_dragging"),this.$dragKeybinding||(this.$dragKeybinding={handleKeyboard:function(e,t,n,r){if(n=="esc")return{command:this.command}},command:{exec:function(e){var t=e.$mouseHandler;t.dragCursor=null,t.dragEnd(),t.startSelect()}}}),e.keyBinding.addKeyboardHandler(this.$dragKeybinding)},this.focusWait=function(){var e=u(this.mousedownEvent.x,this.mousedownEvent.y,this.x,this.y),t=(new Date).getTime();(e>s||t-this.mousedownEvent.time>this.$focusWaitTimout)&&this.startSelect()},this.dragWait=function(e){var t=u(this.mousedownEvent.x,this.mousedownEvent.y,this.x,this.y),n=(new Date).getTime(),r=this.editor;t>s?this.startSelect(this.mousedownEvent.getDocumentPosition()):n-this.mousedownEvent.time>r.getDragDelay()&&this.startDrag()},this.dragWaitEnd=function(e){this.mousedownEvent.domEvent=e,this.startSelect()},this.drag=function(){var e=this.editor;this.dragCursor=e.renderer.screenToTextCoordinates(this.x,this.y),e.moveCursorToPosition(this.dragCursor),e.renderer.scrollCursorIntoView()},this.dragEnd=function(e){var t=this.editor,n=this.dragCursor,i=this.dragRange;r.removeCssClass(t.container,"ace_dragging"),t.session.removeMarker(this.dragSelectionMarker),t.keyBinding.removeKeyboardHandler(this.$dragKeybinding);if(!n)return;t.clearSelection();if(e&&(e.ctrlKey||e.altKey)){var s=t.session,o=i;o.end=s.insert(n,s.getTextRange(i)),o.start=n}else{if(i.contains(n.row,n.column))return;var o=t.moveText(i,n)}if(!o)return;t.selection.setSelectionRange(o)},this.onDoubleClick=function(e){var t=e.getDocumentPosition(),n=this.editor,r=n.session,i=r.getBracketRange(t);if(i){i.isEmpty()&&(i.start.column--,i.end.column++),this.$clickSelection=i,this.setState("select");return}this.$clickSelection=n.selection.getWordRange(t.row,t.column),this.setState("selectByWords")},this.onTripleClick=function(e){var t=e.getDocumentPosition(),n=this.editor;this.setState("selectByLines"),this.$clickSelection=n.selection.getLineRange(t.row)},this.onQuadClick=function(e){var t=this.editor;t.selectAll(),this.$clickSelection=t.getSelectionRange(),this.setState("null")},this.onMouseWheel=function(e){if(e.getShiftKey()||e.getAccelKey())return;var t=this.editor,n=t.renderer.isScrollableBy(e.wheelX*e.speed,e.wheelY*e.speed);if(n)this.$passScrollEvent=!1;else{if(this.$passScrollEvent)return;if(!this.$scrollStopTimeout){var r=this;this.$scrollStopTimeout=setTimeout(function(){r.$passScrollEvent=!0,r.$scrollStopTimeout=null},200)}}return t.renderer.scrollBy(e.wheelX*e.speed,e.wheelY*e.speed),e.preventDefault()}}).call(o.prototype),t.DefaultHandlers=o}),ace.define("ace/mouse/default_gutter_handler",["require","exports","module","ace/lib/dom","ace/lib/event"],function(e,t,n){function s(e){function f(){u=r.createElement("div"),u.className="ace_gutter-tooltip",u.style.maxWidth="500px",u.style.display="none",t.container.appendChild(u)}function l(){u||f();var e=o.getDocumentPosition().row,r=n.$annotations[e];if(!r)return c();var i=t.session.getLength();if(e==i){var s=t.renderer.pixelToScreenCoordinates(0,o.y).row,l=o.$pos;if(s>t.session.documentToScreenRow(l.row,l.column))return c()}if(a==r)return;a=r.text.join("<br/>"),u.style.display="block",u.innerHTML=a,t.on("mousewheel",c),h(o)}function c(){s&&(s=clearTimeout(s)),a&&(u.style.display="none",a=null,t.removeEventListener("mousewheel",c))}function h(e){var n=t.renderer.$gutter.getBoundingClientRect();u.style.left=e.x-n.left+15+"px",e.y+3*t.renderer.lineHeight+15<n.bottom?(u.style.bottom="",u.style.top=e.y-n.top+15+"px"):(u.style.top="",u.style.bottom=n.bottom-e.y+5+"px")}var t=e.editor,n=t.renderer.$gutterLayer;e.editor.setDefaultHandler("guttermousedown",function(r){if(!t.isFocused())return;var i=n.getRegion(r);if(i)return;var s=r.getDocumentPosition().row,o=t.session.selection;if(r.getShiftKey())o.selectTo(s,0);else{if(r.domEvent.detail==2)return t.selectAll(),r.preventDefault();e.$clickSelection=t.selection.getLineRange(s)}return e.captureMouse(r,"selectByLines"),r.preventDefault()});var s,o,u,a;e.editor.setDefaultHandler("guttermousemove",function(t){var n=t.domEvent.target||t.domEvent.srcElement;if(r.hasCssClass(n,"ace_fold-widget"))return c();a&&h(t),o=t;if(s)return;s=setTimeout(function(){s=null,o&&!e.isMousePressed?l():c()},50)}),i.addListener(t.renderer.$gutter,"mouseout",function(e){o=null;if(!a||s)return;s=setTimeout(function(){s=null,c()},50)})}var r=e("../lib/dom"),i=e("../lib/event");t.GutterHandler=s}),ace.define("ace/mouse/mouse_event",["require","exports","module","ace/lib/event","ace/lib/useragent"],function(e,t,n){var r=e("../lib/event"),i=e("../lib/useragent"),s=t.MouseEvent=function(e,t){this.domEvent=e,this.editor=t,this.x=this.clientX=e.clientX,this.y=this.clientY=e.clientY,this.$pos=null,this.$inSelection=null,this.propagationStopped=!1,this.defaultPrevented=!1};(function(){this.stopPropagation=function(){r.stopPropagation(this.domEvent),this.propagationStopped=!0},this.preventDefault=function(){r.preventDefault(this.domEvent),this.defaultPrevented=!0},this.stop=function(){this.stopPropagation(),this.preventDefault()},this.getDocumentPosition=function(){return this.$pos?this.$pos:(this.$pos=this.editor.renderer.screenToTextCoordinates(this.clientX,this.clientY),this.$pos)},this.inSelection=function(){if(this.$inSelection!==null)return this.$inSelection;var e=this.editor;if(e.getReadOnly())this.$inSelection=!1;else{var t=e.getSelectionRange();if(t.isEmpty())this.$inSelection=!1;else{var n=this.getDocumentPosition();this.$inSelection=t.contains(n.row,n.column)}}return this.$inSelection},this.getButton=function(){return r.getButton(this.domEvent)},this.getShiftKey=function(){return this.domEvent.shiftKey},this.getAccelKey=i.isMac?function(){return this.domEvent.metaKey}:function(){return this.domEvent.ctrlKey}}).call(s.prototype)}),ace.define("ace/mouse/dragdrop",["require","exports","module","ace/lib/event"],function(e,t,n){var r=e("../lib/event"),i=function(e){var t=e.editor,n,i,s,o,u,a,f,l=0,c=t.container;r.addListener(c,"dragenter",function(e){l++;if(!n){u=t.getSelectionRange(),a=t.selection.isBackwards();var i=t.getSelectionStyle();n=t.session.addMarker(u,"ace_selection",i),t.clearSelection(),clearInterval(o),o=setInterval(h,20)}return r.preventDefault(e)}),r.addListener(c,"dragover",function(e){return i=e.clientX,s=e.clientY,r.preventDefault(e)});var h=function(){f=t.renderer.screenToTextCoordinates(i,s),t.moveCursorToPosition(f),t.renderer.scrollCursorIntoView()};r.addListener(c,"dragleave",function(e){l--;if(l>0)return;return console.log(e.type,l,e.target),clearInterval(o),t.session.removeMarker(n),n=null,t.selection.setSelectionRange(u,a),r.preventDefault(e)}),r.addListener(c,"drop",function(e){return console.log(e.type,l,e.target),l=0,clearInterval(o),t.session.removeMarker(n),n=null,u.end=t.session.insert(f,e.dataTransfer.getData("Text")),u.start=f,t.focus(),t.selection.setSelectionRange(u),r.preventDefault(e)})};t.DragdropHandler=i}),ace.define("ace/mouse/fold_handler",["require","exports","module"],function(e,t,n){function r(e){e.on("click",function(t){var n=t.getDocumentPosition(),r=e.session,i=r.getFoldAt(n.row,n.column,1);i&&(t.getAccelKey()?r.removeFold(i):r.expandFold(i),t.stop())}),e.on("guttermousedown",function(t){var n=e.renderer.$gutterLayer.getRegion(t);if(n=="foldWidgets"){var r=t.getDocumentPosition().row,i=e.session;i.foldWidgets&&i.foldWidgets[r]&&e.session.onFoldWidgetClick(r,t),t.stop()}}),e.on("gutterdblclick",function(t){var n=e.renderer.$gutterLayer.getRegion(t);if(n=="foldWidgets"){var r=t.getDocumentPosition().row,i=e.session,s=i.foldWidgets;if(!s||s[r])return;var o=r-1,u;while(o>=0){var a=s[o];a==null&&(a=s[o]=i.getFoldWidget());if(a=="start"){var f=i.getFoldWidgetRange(o);u||(u=f);if(f&&f.end.row>=r)break}o--}o==-1&&(f=u);if(f){var r=f.start.row,l=i.getFoldAt(r,i.getLine(r).length,1);l?i.removeFold(l):(i.addFold("...",f),e.renderer.scrollCursorIntoView({row:f.start.row,column:0}))}t.stop()}})}t.FoldHandler=r}),ace.define("ace/keyboard/keybinding",["require","exports","module","ace/lib/keys","ace/lib/event"],function(e,t,n){var r=e("../lib/keys"),i=e("../lib/event"),s=function(e){this.$editor=e,this.$data={},this.$handlers=[],this.setDefaultHandler(e.commands)};(function(){this.setDefaultHandler=function(e){this.removeKeyboardHandler(this.$defaultHandler),this.$defaultHandler=e,this.addKeyboardHandler(e,0),this.$data={editor:this.$editor}},this.setKeyboardHandler=function(e){if(this.$handlers[this.$handlers.length-1]==e)return;while(this.$handlers[1])this.removeKeyboardHandler(this.$handlers[1]);this.addKeyboardHandler(e,1)},this.addKeyboardHandler=function(e,t){if(!e)return;var n=this.$handlers.indexOf(e);n!=-1&&this.$handlers.splice(n,1),t==undefined?this.$handlers.push(e):this.$handlers.splice(t,0,e),n==-1&&e.attach&&e.attach(this.$editor)},this.removeKeyboardHandler=function(e){var t=this.$handlers.indexOf(e);return t==-1?!1:(this.$handlers.splice(t,1),e.detach&&e.detach(this.$editor),!0)},this.getKeyboardHandler=function(){return this.$handlers[this.$handlers.length-1]},this.$callKeyboardHandlers=function(e,t,n,r){var s;for(var o=this.$handlers.length;o--;){s=this.$handlers[o].handleKeyboard(this.$data,e,t,n,r);if(s&&s.command)break}if(!s||!s.command)return!1;var u=!1,a=this.$editor.commands;return s.command!="null"?u=a.exec(s.command,this.$editor,s.args,r):u=s.passEvent!=1,u&&r&&e!=-1&&i.stopEvent(r),u},this.onCommandKey=function(e,t,n){var i=r.keyCodeToString(n);this.$callKeyboardHandlers(t,i,n,e)},this.onTextInput=function(e){var t=this.$callKeyboardHandlers(-1,e);t||this.$editor.commands.exec("insertstring",this.$editor,e)}}).call(s.prototype),t.KeyBinding=s}),ace.define("ace/edit_session",["require","exports","module","ace/config","ace/lib/oop","ace/lib/lang","ace/lib/net","ace/lib/event_emitter","ace/selection","ace/mode/text","ace/range","ace/document","ace/background_tokenizer","ace/search_highlight","ace/edit_session/folding","ace/edit_session/bracket_match"],function(e,t,n){var r=e("./config"),i=e("./lib/oop"),s=e("./lib/lang"),o=e("./lib/net"),u=e("./lib/event_emitter").EventEmitter,a=e("./selection").Selection,f=e("./mode/text").Mode,l=e("./range").Range,c=e("./document").Document,h=e("./background_tokenizer").BackgroundTokenizer,p=e("./search_highlight").SearchHighlight,d=function(e,t){this.$breakpoints=[],this.$decorations=[],this.$frontMarkers={},this.$backMarkers={},this.$markerId=1,this.$undoSelect=!0,this.$foldData=[],this.$foldData.toString=function(){var e="";return this.forEach(function(t){e+="\n"+t.toString()}),e},this.on("changeFold",this.onChangeFold.bind(this)),this.$onChange=this.onChange.bind(this);if(typeof e!="object"||!e.getLine)e=new c(e);this.setDocument(e),this.selection=new a(this),this.setMode(t)};(function(){function y(e){return e<4352?!1:e>=4352&&e<=4447||e>=4515&&e<=4519||e>=4602&&e<=4607||e>=9001&&e<=9002||e>=11904&&e<=11929||e>=11931&&e<=12019||e>=12032&&e<=12245||e>=12272&&e<=12283||e>=12288&&e<=12350||e>=12353&&e<=12438||e>=12441&&e<=12543||e>=12549&&e<=12589||e>=12593&&e<=12686||e>=12688&&e<=12730||e>=12736&&e<=12771||e>=12784&&e<=12830||e>=12832&&e<=12871||e>=12880&&e<=13054||e>=13056&&e<=19903||e>=19968&&e<=42124||e>=42128&&e<=42182||e>=43360&&e<=43388||e>=44032&&e<=55203||e>=55216&&e<=55238||e>=55243&&e<=55291||e>=63744&&e<=64255||e>=65040&&e<=65049||e>=65072&&e<=65106||e>=65108&&e<=65126||e>=65128&&e<=65131||e>=65281&&e<=65376||e>=65504&&e<=65510}i.implement(this,u),this.setDocument=function(e){this.doc&&this.doc.removeListener("change",this.$onChange),this.doc=e,e.on("change",this.$onChange),this.bgTokenizer&&this.bgTokenizer.setDocument(this.getDocument()),this.resetCaches()},this.getDocument=function(){return this.doc},this.$resetRowCache=function(e){if(!e){this.$docRowCache=[],this.$screenRowCache=[];return}var t=this.$getRowCacheIndex(this.$docRowCache,e)+1,n=this.$docRowCache.length;this.$docRowCache.splice(t,n),this.$screenRowCache.splice(t,n)},this.$getRowCacheIndex=function(e,t){var n=0,r=e.length-1;while(n<=r){var i=n+r>>1,s=e[i];if(t>s)n=i+1;else{if(!(t<s))return i;r=i-1}}return n-1},this.resetCaches=function(){this.$modified=!0,this.$wrapData=[],this.$rowLengthCache=[],this.$resetRowCache(0),this.bgTokenizer&&this.bgTokenizer.start(0)},this.onChangeFold=function(e){var t=e.data;this.$resetRowCache(t.start.row)},this.onChange=function(e){var t=e.data;this.$modified=!0,this.$resetRowCache(t.range.start.row);var n=this.$updateInternalDataOnChange(e);!this.$fromUndo&&this.$undoManager&&!t.ignore&&(this.$deltasDoc.push(t),n&&n.length!=0&&this.$deltasFold.push({action:"removeFolds",folds:n}),this.$informUndoManager.schedule()),this.bgTokenizer.$updateOnChange(t),this._emit("change",e)},this.setValue=function(e){this.doc.setValue(e),this.selection.moveCursorTo(0,0),this.selection.clearSelection(),this.$resetRowCache(0),this.$deltas=[],this.$deltasDoc=[],this.$deltasFold=[],this.getUndoManager().reset()},this.getValue=this.toString=function(){return this.doc.getValue()},this.getSelection=function(){return this.selection},this.getState=function(e){return this.bgTokenizer.getState(e)},this.getTokens=function(e){return this.bgTokenizer.getTokens(e)},this.getTokenAt=function(e,t){var n=this.bgTokenizer.getTokens(e),r,i=0;if(t==null)s=n.length-1,i=this.getLine(e).length;else for(var s=0;s<n.length;s++){i+=n[s].value.length;if(i>=t)break}return r=n[s],r?(r.index=s,r.start=i-r.value.length,r):null},this.setUndoManager=function(e){this.$undoManager=e,this.$deltas=[],this.$deltasDoc=[],this.$deltasFold=[],this.$informUndoManager&&this.$informUndoManager.cancel();if(e){var t=this;this.$syncInformUndoManager=function(){t.$informUndoManager.cancel(),t.$deltasFold.length&&(t.$deltas.push({group:"fold",deltas:t.$deltasFold}),t.$deltasFold=[]),t.$deltasDoc.length&&(t.$deltas.push({group:"doc",deltas:t.$deltasDoc}),t.$deltasDoc=[]),t.$deltas.length>0&&e.execute({action:"aceupdate",args:[t.$deltas,t]}),t.$deltas=[]},this.$informUndoManager=s.deferredCall(this.$syncInformUndoManager)}},this.$defaultUndoManager={undo:function(){},redo:function(){},reset:function(){}},this.getUndoManager=function(){return this.$undoManager||this.$defaultUndoManager},this.getTabString=function(){return this.getUseSoftTabs()?s.stringRepeat(" ",this.getTabSize()):" "},this.$useSoftTabs=!0,this.setUseSoftTabs=function(e){if(this.$useSoftTabs===e)return;this.$useSoftTabs=e},this.getUseSoftTabs=function(){return this.$useSoftTabs},this.$tabSize=4,this.setTabSize=function(e){if(isNaN(e)||this.$tabSize===e)return;this.$modified=!0,this.$rowLengthCache=[],this.$tabSize=e,this._emit("changeTabSize")},this.getTabSize=function(){return this.$tabSize},this.isTabStop=function(e){return this.$useSoftTabs&&e.column%this.$tabSize==0},this.$overwrite=!1,this.setOverwrite=function(e){if(this.$overwrite==e)return;this.$overwrite=e,this._emit("changeOverwrite")},this.getOverwrite=function(){return this.$overwrite},this.toggleOverwrite=function(){this.setOverwrite(!this.$overwrite)},this.addGutterDecoration=function(e,t){this.$decorations[e]||(this.$decorations[e]=""),this.$decorations[e]+=" "+t,this._emit("changeBreakpoint",{})},this.removeGutterDecoration=function(e,t){this.$decorations[e]=(this.$decorations[e]||"").replace(" "+t,""),this._emit("changeBreakpoint",{})},this.getBreakpoints=function(){return this.$breakpoints},this.setBreakpoints=function(e){this.$breakpoints=[];for(var t=0;t<e.length;t++)this.$breakpoints[e[t]]="ace_breakpoint";this._emit("changeBreakpoint",{})},this.clearBreakpoints=function(){this.$breakpoints=[],this._emit("changeBreakpoint",{})},this.setBreakpoint=function(e,t){t===undefined&&(t="ace_breakpoint"),t?this.$breakpoints[e]=t:delete this.$breakpoints[e],this._emit("changeBreakpoint",{})},this.clearBreakpoint=function(e){delete this.$breakpoints[e],this._emit("changeBreakpoint",{})},this.addMarker=function(e,t,n,r){var i=this.$markerId++,s={range:e,type:n||"line",renderer:typeof n=="function"?n:null,clazz:t,inFront:!!r,id:i};return r?(this.$frontMarkers[i]=s,this._emit("changeFrontMarker")):(this.$backMarkers[i]=s,this._emit("changeBackMarker")),i},this.addDynamicMarker=function(e,t){if(!e.update)return;var n=this.$markerId++;return e.id=n,e.inFront=!!t,t?(this.$frontMarkers[n]=e,this._emit("changeFrontMarker")):(this.$backMarkers[n]=e,this._emit("changeBackMarker")),e},this.removeMarker=function(e){var t=this.$frontMarkers[e]||this.$backMarkers[e];if(!t)return;var n=t.inFront?this.$frontMarkers:this.$backMarkers;t&&(delete n[e],this._emit(t.inFront?"changeFrontMarker":"changeBackMarker"))},this.getMarkers=function(e){return e?this.$frontMarkers:this.$backMarkers},this.highlight=function(e){if(!this.$searchHighlight){var t=new p(null,"ace_selected-word","text");this.$searchHighlight=this.addDynamicMarker(t)}this.$searchHighlight.setRegexp(e)},this.highlightLines=function(e,t,n,r){typeof t!="number"&&(n=t,t=e),n||(n="ace_step");var i=new l(e,0,t,Infinity),s=this.addMarker(i,n,"fullLine",r);return i.id=s,i},this.setAnnotations=function(e){this.$annotations=e,this._emit("changeAnnotation",{})},this.getAnnotations=function(){return this.$annotations||[]},this.clearAnnotations=function(){this.$annotations={},this._emit("changeAnnotation",{})},this.$detectNewLine=function(e){var t=e.match(/^.*?(\r?\n)/m);t?this.$autoNewLine=t[1]:this.$autoNewLine="\n"},this.getWordRange=function(e,t){var n=this.getLine(e),r=!1;t>0&&(r=!!n.charAt(t-1).match(this.tokenRe)),r||(r=!!n.charAt(t).match(this.tokenRe));if(r)var i=this.tokenRe;else if(/^\s+$/.test(n.slice(t-1,t+1)))var i=/\s/;else var i=this.nonTokenRe;var s=t;if(s>0){do s--;while(s>=0&&n.charAt(s).match(i));s++}var o=t;while(o<n.length&&n.charAt(o).match(i))o++;return new l(e,s,e,o)},this.getAWordRange=function(e,t){var n=this.getWordRange(e,t),r=this.getLine(n.end.row);while(r.charAt(n.end.column).match(/[ \t]/))n.end.column+=1;return n},this.setNewLineMode=function(e){this.doc.setNewLineMode(e)},this.getNewLineMode=function(){return this.doc.getNewLineMode()},this.$useWorker=!0,this.setUseWorker=function(e){if(this.$useWorker==e)return;this.$useWorker=e,this.$stopWorker(),e&&this.$startWorker()},this.getUseWorker=function(){return this.$useWorker},this.onReloadTokenizer=function(e){var t=e.data;this.bgTokenizer.start(t.first),this._emit("tokenizerUpdate",e)},this.$modes={},this._loadMode=function(t,n){function a(e){if(i.$modes[t])return n(i.$modes[t]);i.$modes[t]=new e.Mode,i.$modes[t].$id=t,i._emit("loadmode",{name:t,mode:i.$modes[t]}),n(i.$modes[t])}function l(e,t){if(!r.get("packaged"))return t();o.loadScript(r.moduleUrl(e,"mode"),t)}this.$modes["null"]||(this.$modes["null"]=this.$modes["ace/mode/text"]=new f);if(this.$modes[t])return n(this.$modes[t]);var i=this,s;try{s=e(t)}catch(u){}if(s&&s.Mode)return a(s);this.$mode||this.$setModePlaceholder(),l(t,function(){e([t],a)})},this.$setModePlaceholder=function(){this.$mode=this.$modes["null"];var e=this.$mode.getTokenizer();if(!this.bgTokenizer){this.bgTokenizer=new h(e);var t=this;this.bgTokenizer.addEventListener("update",function(e){t._emit("tokenizerUpdate",e)})}else this.bgTokenizer.setTokenizer(e);this.bgTokenizer.setDocument(this.getDocument()),this.tokenRe=this.$mode.tokenRe,this.nonTokenRe=this.$mode.nonTokenRe},this.$mode=null,this.$modeId=null,this.setMode=function(e){e=e||"null";if(typeof e=="string"){if(this.$modeId==e)return;this.$modeId=e;var t=this;this._loadMode(e,function(n){if(t.$modeId!==e)return;t.setMode(n)});return}if(this.$mode===e)return;this.$mode=e,this.$modeId=e.$id,this.$stopWorker(),this.$useWorker&&this.$startWorker();var n=e.getTokenizer();if(n.addEventListener!==undefined){var r=this.onReloadTokenizer.bind(this);n.addEventListener("update",r)}if(!this.bgTokenizer){this.bgTokenizer=new h(n);var t=this;this.bgTokenizer.addEventListener("update",function(e){t._emit("tokenizerUpdate",e)})}else this.bgTokenizer.setTokenizer(n);this.bgTokenizer.setDocument(this.getDocument()),this.bgTokenizer.start(0),this.tokenRe=e.tokenRe,this.nonTokenRe=e.nonTokenRe,this.$setFolding(e.foldingRules),this._emit("changeMode")},this.$stopWorker=function(){this.$worker&&this.$worker.terminate(),this.$worker=null},this.$startWorker=function(){if(typeof Worker!="undefined"&&!e.noWorker)try{this.$worker=this.$mode.createWorker(this)}catch(t){console.log("Could not load worker"),console.log(t),this.$worker=null}else this.$worker=null},this.getMode=function(){return this.$mode},this.$scrollTop=0,this.setScrollTop=function(e){e=Math.round(Math.max(0,e));if(this.$scrollTop===e)return;this.$scrollTop=e,this._emit("changeScrollTop",e)},this.getScrollTop=function(){return this.$scrollTop},this.$scrollLeft=0,this.setScrollLeft=function(e){e=Math.round(Math.max(0,e));if(this.$scrollLeft===e)return;this.$scrollLeft=e,this._emit("changeScrollLeft",e)},this.getScrollLeft=function(){return this.$scrollLeft},this.getScreenWidth=function(){return this.$computeWidth(),this.screenWidth},this.$computeWidth=function(e){if(this.$modified||e){this.$modified=!1;if(this.$useWrapMode)return this.screenWidth=this.$wrapLimit;var t=this.doc.getAllLines(),n=this.$rowLengthCache,r=0,i=0,s=this.$foldData[i],o=s?s.start.row:Infinity,u=t.length;for(var a=0;a<u;a++){if(a>o){a=s.end.row+1;if(a>=u)break;s=this.$foldData[i++],o=s?s.start.row:Infinity}n[a]==null&&(n[a]=this.$getStringScreenWidth(t[a])[0]),n[a]>r&&(r=n[a])}this.screenWidth=r}},this.getLine=function(e){return this.doc.getLine(e)},this.getLines=function(e,t){return this.doc.getLines(e,t)},this.getLength=function(){return this.doc.getLength()},this.getTextRange=function(e){return this.doc.getTextRange(e||this.selection.getRange())},this.insert=function(e,t){return this.doc.insert(e,t)},this.remove=function(e){return this.doc.remove(e)},this.undoChanges=function(e,t){if(!e.length)return;this.$fromUndo=!0;var n=null;for(var r=e.length-1;r!=-1;r--){var i=e[r];i.group=="doc"?(this.doc.revertDeltas(i.deltas),n=this.$getUndoSelection(i.deltas,!0,n)):i.deltas.forEach(function(e){this.addFolds(e.folds)},this)}return this.$fromUndo=!1,n&&this.$undoSelect&&!t&&this.selection.setSelectionRange(n),n},this.redoChanges=function(e,t){if(!e.length)return;this.$fromUndo=!0;var n=null;for(var r=0;r<e.length;r++){var i=e[r];i.group=="doc"&&(this.doc.applyDeltas(i.deltas),n=this.$getUndoSelection(i.deltas,!1,n))}return this.$fromUndo=!1,n&&this.$undoSelect&&!t&&this.selection.setSelectionRange(n),n},this.setUndoSelect=function(e){this.$undoSelect=e},this.$getUndoSelection=function(e,t,n){function r(e){var n=e.action=="insertText"||e.action=="insertLines";return t?!n:n}var i=e[0],s,o,u=!1;r(i)?(s=i.range.clone(),u=!0):(s=l.fromPoints(i.range.start,i.range.start),u=!1);for(var a=1;a<e.length;a++)i=e[a],r(i)?(o=i.range.start,s.compare(o.row,o.column)==-1&&s.setStart(i.range.start),o=i.range.end,s.compare(o.row,o.column)==1&&s.setEnd(i.range.end),u=!0):(o=i.range.start,s.compare(o.row,o.column)==-1&&(s=l.fromPoints(i.range.start,i.range.start)),u=!1);if(n!=null){var f=n.compareRange(s);f==1?s.setStart(n.start):f==-1&&s.setEnd(n.end)}return s},this.replace=function(e,t){return this.doc.replace(e,t)},this.moveText=function(e,t){var n=this.getTextRange(e);this.remove(e);var r=t.row,i=t.column;!e.isMultiLine()&&e.start.row==r&&e.end.column<i&&(i-=n.length);if(e.isMultiLine()&&e.end.row<r){var s=this.doc.$split(n);r-=s.length-1}var o=r+e.end.row-e.start.row,u=e.isMultiLine()?e.end.column:i+e.end.column-e.start.column,a=new l(r,i,o,u);return this.insert(a.start,n),a},this.indentRows=function(e,t,n){n=n.replace(/\t/g,this.getTabString());for(var r=e;r<=t;r++)this.insert({row:r,column:0},n)},this.outdentRows=function(e){var t=e.collapseRows(),n=new l(0,0,0,0),r=this.getTabSize();for(var i=t.start.row;i<=t.end.row;++i){var s=this.getLine(i);n.start.row=i,n.end.row=i;for(var o=0;o<r;++o)if(s.charAt(o)!=" ")break;o<r&&s.charAt(o)==" "?(n.start.column=o,n.end.column=o+1):(n.start.column=0,n.end.column=o),this.remove(n)}},this.moveLinesUp=function(e,t){if(e<=0)return 0;var n=this.doc.removeLines(e,t);return this.doc.insertLines(e-1,n),-1},this.moveLinesDown=function(e,t){if(t>=this.doc.getLength()-1)return 0;var n=this.doc.removeLines(e,t);return this.doc.insertLines(e+1,n),1},this.duplicateLines=function(e,t){var e=this.$clipRowToDocument(e),t=this.$clipRowToDocument(t),n=this.getLines(e,t);this.doc.insertLines(e,n);var r=t-e+1;return r},this.$clipRowToDocument=function(e){return Math.max(0,Math.min(e,this.doc.getLength()-1))},this.$clipColumnToRow=function(e,t){return t<0?0:Math.min(this.doc.getLine(e).length,t)},this.$clipPositionToDocument=function(e,t){t=Math.max(0,t);if(e<0)e=0,t=0;else{var n=this.doc.getLength();e>=n?(e=n-1,t=this.doc.getLine(n-1).length):t=Math.min(this.doc.getLine(e).length,t)}return{row:e,column:t}},this.$clipRangeToDocument=function(e){e.start.row<0?(e.start.row=0,e.start.column=0):e.start.column=this.$clipColumnToRow(e.start.row,e.start.column);var t=this.doc.getLength()-1;return e.end.row>t?(e.end.row=t,e.end.column=this.doc.getLine(t).length):e.end.column=this.$clipColumnToRow(e.end.row,e.end.column),e},this.$wrapLimit=80,this.$useWrapMode=!1,this.$wrapLimitRange={min:null,max:null},this.setUseWrapMode=function(e){if(e!=this.$useWrapMode){this.$useWrapMode=e,this.$modified=!0,this.$resetRowCache(0);if(e){var t=this.getLength();this.$wrapData=[];for(var n=0;n<t;n++)this.$wrapData.push([]);this.$updateWrapData(0,t-1)}this._emit("changeWrapMode")}},this.getUseWrapMode=function(){return this.$useWrapMode},this.setWrapLimitRange=function(e,t){if(this.$wrapLimitRange.min!==e||this.$wrapLimitRange.max!==t)this.$wrapLimitRange.min=e,this.$wrapLimitRange.max=t,this.$modified=!0,this._emit("changeWrapMode")},this.adjustWrapLimit=function(e){var t=this.$constrainWrapLimit(e);return t!=this.$wrapLimit&&t>0?(this.$wrapLimit=t,this.$modified=!0,this.$useWrapMode&&(this.$updateWrapData(0,this.getLength()-1),this.$resetRowCache(0),this._emit("changeWrapLimit")),!0):!1},this.$constrainWrapLimit=function(e){var t=this.$wrapLimitRange.min;t&&(e=Math.max(t,e));var n=this.$wrapLimitRange.max;return n&&(e=Math.min(n,e)),Math.max(1,e)},this.getWrapLimit=function(){return this.$wrapLimit},this.getWrapLimitRange=function(){return{min:this.$wrapLimitRange.min,max:this.$wrapLimitRange.max}},this.$updateInternalDataOnChange=function(e){var t=this.$useWrapMode,n,r=e.data.action,i=e.data.range.start.row,s=e.data.range.end.row,o=e.data.range.start,u=e.data.range.end,a=null;r.indexOf("Lines")!=-1?(r=="insertLines"?s=i+e.data.lines.length:s=i,n=e.data.lines?e.data.lines.length:s-i):n=s-i;if(n!=0)if(r.indexOf("remove")!=-1){this[t?"$wrapData":"$rowLengthCache"].splice(i,n);var f=this.$foldData;a=this.getFoldsInRange(e.data.range),this.removeFolds(a);var l=this.getFoldLine(u.row),c=0;if(l){l.addRemoveChars(u.row,u.column,o.column-u.column),l.shiftRow(-n);var h=this.getFoldLine(i);h&&h!==l&&(h.merge(l),l=h),c=f.indexOf(l)+1}for(c;c<f.length;c++){var l=f[c];l.start.row>=u.row&&l.shiftRow(-n)}s=i}else{var p;if(t){p=[i,0];for(var d=0;d<n;d++)p.push([]);this.$wrapData.splice.apply(this.$wrapData,p)}else p=Array(n),p.unshift(i,0),this.$rowLengthCache.splice.apply(this.$rowLengthCache,p);var f=this.$foldData,l=this.getFoldLine(i),c=0;if(l){var v=l.range.compareInside(o.row,o.column);v==0?(l=l.split(o.row,o.column),l.shiftRow(n),l.addRemoveChars(s,0,u.column-o.column)):v==-1&&(l.addRemoveChars(i,0,u.column-o.column),l.shiftRow(n)),c=f.indexOf(l)+1}for(c;c<f.length;c++){var l=f[c];l.start.row>=i&&l.shiftRow(n)}}else{n=Math.abs(e.data.range.start.column-e.data.range.end.column),r.indexOf("remove")!=-1&&(a=this.getFoldsInRange(e.data.range),this.removeFolds(a),n=-n);var l=this.getFoldLine(i);l&&l.addRemoveChars(i,o.column,n)}return t&&this.$wrapData.length!=this.doc.getLength()&&console.error("doc.getLength() and $wrapData.length have to be the same!"),t?this.$updateWrapData(i,s):this.$updateRowLengthCache(i,s),a},this.$updateRowLengthCache=function(e,t,n){this.$rowLengthCache[e]=null,this.$rowLengthCache[t]=null},this.$updateWrapData=function(e,t){var n=this.doc.getAllLines(),r=this.getTabSize(),i=this.$wrapData,o=this.$wrapLimit,u,f,l=e;t=Math.min(t,n.length-1);while(l<=t){f=this.getFoldLine(l,f);if(!f)u=this.$getDisplayTokens(s.stringTrimRight(n[l])),i[l]=this.$computeWrapSplits(u,o,r),l++;else{u=[],f.walk(function(e,t,r,i){var s;if(e!=null){s=this.$getDisplayTokens(e,u.length),s[0]=a;for(var o=1;o<s.length;o++)s[o]=c}else s=this.$getDisplayTokens(n[t].substring(i,r),u.length);u=u.concat(s)}.bind(this),f.end.row,n[f.end.row].length+1);while(u.length!=0&&u[u.length-1]>=v)u.pop();i[f.start.row]=this.$computeWrapSplits(u,o,r),l=f.end.row+1}}};var t=1,n=2,a=3,c=4,d=9,v=10,m=11,g=12;this.$computeWrapSplits=function(e,t){function o(t){var r=e.slice(i,t),o=r.length;r.join("").replace(/12/g,function(){o-=1}).replace(/2/g,function(){o-=1}),s+=o,n.push(s),i=t}if(e.length==0)return[];var n=[],r=e.length,i=0,s=0;while(r-i>t){var u=i+t;if(e[u]>=v){while(e[u]>=v)u++;o(u);continue}if(e[u]==a||e[u]==c){for(u;u!=i-1;u--)if(e[u]==a)break;if(u>i){o(u);continue}u=i+t;for(u;u<e.length;u++)if(e[u]!=c)break;if(u==e.length)break;o(u);continue}var f=Math.max(u-10,i-1);while(u>f&&e[u]<a)u--;while(u>f&&e[u]==d)u--;if(u>f){o(++u);continue}u=i+t,o(u)}return n},this.$getDisplayTokens=function(e,r){var i=[],s;r=r||0;for(var o=0;o<e.length;o++){var u=e.charCodeAt(o);if(u==9){s=this.getScreenTabSize(i.length+r),i.push(m);for(var a=1;a<s;a++)i.push(g)}else u==32?i.push(v):u>39&&u<48||u>57&&u<64?i.push(d):u>=4352&&y(u)?i.push(t,n):i.push(t)}return i},this.$getStringScreenWidth=function(e,t,n){if(t==0)return[0,0];t==null&&(t=Infinity),n=n||0;var r,i;for(i=0;i<e.length;i++){r=e.charCodeAt(i),r==9?n+=this.getScreenTabSize(n):r>=4352&&y(r)?n+=2:n+=1;if(n>t)break}return[n,i]},this.getRowLength=function(e){return!this.$useWrapMode||!this.$wrapData[e]?1:this.$wrapData[e].length+1},this.getScreenLastRowColumn=function(e){var t=this.screenToDocumentPosition(e,Number.MAX_VALUE);return this.documentToScreenColumn(t.row,t.column)},this.getDocumentLastRowColumn=function(e,t){var n=this.documentToScreenRow(e,t);return this.getScreenLastRowColumn(n)},this.getDocumentLastRowColumnPosition=function(e,t){var n=this.documentToScreenRow(e,t);return this.screenToDocumentPosition(n,Number.MAX_VALUE/10)},this.getRowSplitData=function(e){return this.$useWrapMode?this.$wrapData[e]:undefined},this.getScreenTabSize=function(e){return this.$tabSize-e%this.$tabSize},this.screenToDocumentRow=function(e,t){return this.screenToDocumentPosition(e,t).row},this.screenToDocumentColumn=function(e,t){return this.screenToDocumentPosition(e,t).column},this.screenToDocumentPosition=function(e,t){if(e<0)return{row:0,column:0};var n,r=0,i=0,s,o=0,u=0,a=this.$screenRowCache,f=this.$getRowCacheIndex(a,e),l=a.length;if(l&&f>=0)var o=a[f],r=this.$docRowCache[f],c=e>a[l-1];else var c=!l;var h=this.getLength()-1,p=this.getNextFoldLine(r),d=p?p.start.row:Infinity;while(o<=e){u=this.getRowLength(r);if(o+u-1>=e||r>=h)break;o+=u,r++,r>d&&(r=p.end.row+1,p=this.getNextFoldLine(r,p),d=p?p.start.row:Infinity),c&&(this.$docRowCache.push(r),this.$screenRowCache.push(o))}if(p&&p.start.row<=r)n=this.getFoldDisplayLine(p),r=p.start.row;else{if(o+u<=e||r>h)return{row:h,column:this.getLine(h).length};n=this.getLine(r),p=null}if(this.$useWrapMode){var v=this.$wrapData[r];v&&(s=v[e-o],e>o&&v.length&&(i=v[e-o-1]||v[v.length-1],n=n.substring(i)))}return i+=this.$getStringScreenWidth(n,t)[1],this.$useWrapMode&&i>=s&&(i=s-1),p?p.idxToPosition(i):{row:r,column:i}},this.documentToScreenPosition=function(e,t){if(typeof t=="undefined")var n=this.$clipPositionToDocument(e.row,e.column);else n=this.$clipPositionToDocument(e,t);e=n.row,t=n.column;var r=0,i=null,s=null;s=this.getFoldAt(e,t,1),s&&(e=s.start.row,t=s.start.column);var o,u=0,a=this.$docRowCache,f=this.$getRowCacheIndex(a,e),l=a.length;if(l&&f>=0)var u=a[f],r=this.$screenRowCache[f],c=e>a[l-1];else var c=!l;var h=this.getNextFoldLine(u),p=h?h.start.row:Infinity;while(u<e){if(u>=p){o=h.end.row+1;if(o>e)break;h=this.getNextFoldLine(o,h),p=h?h.start.row:Infinity}else o=u+1;r+=this.getRowLength(u),u=o,c&&(this.$docRowCache.push(u),this.$screenRowCache.push(r))}var d="";h&&u>=p?(d=this.getFoldDisplayLine(h,e,t),i=h.start.row):(d=this.getLine(e).substring(0,t),i=e);if(this.$useWrapMode){var v=this.$wrapData[i],m=0;while(d.length>=v[m])r++,m++;d=d.substring(v[m-1]||0,d.length)}return{row:r,column:this.$getStringScreenWidth(d)[0]}},this.documentToScreenColumn=function(e,t){return this.documentToScreenPosition(e,t).column},this.documentToScreenRow=function(e,t){return this.documentToScreenPosition(e,t).row},this.getScreenLength=function(){var e=0,t=null;if(!this.$useWrapMode){e=this.getLength();var n=this.$foldData;for(var r=0;r<n.length;r++)t=n[r],e-=t.end.row-t.start.row}else{var i=this.$wrapData.length,s=0,r=0,t=this.$foldData[r++],o=t?t.start.row:Infinity;while(s<i)e+=this.$wrapData[s].length+1,s++,s>o&&(s=t.end.row+1,t=this.$foldData[r++],o=t?t.start.row:Infinity)}return e}}).call(d.prototype),e("./edit_session/folding").Folding.call(d.prototype),e("./edit_session/bracket_match").BracketMatch.call(d.prototype),t.EditSession=d}),ace.define("ace/config",["require","exports","module","ace/lib/lang"],function(e,t,n){"no use strict";function o(e){return e.replace(/-(.)/g,function(e,t){return t.toUpperCase()})}var r=e("./lib/lang"),i=function(){return this}(),s={packaged:!1,workerPath:null,modePath:null,themePath:null,basePath:"",suffix:".js",$moduleUrls:{}};t.get=function(e){if(!s.hasOwnProperty(e))throw new Error("Unknown config key: "+e);return s[e]},t.set=function(e,t){if(!s.hasOwnProperty(e))throw new Error("Unknown config key: "+e);s[e]=t},t.all=function(){return r.copyObject(s)},t.moduleUrl=function(e,t){if(s.$moduleUrls[e])return s.$moduleUrls[e];var n=e.split("/");t=t||n[n.length-2]||"";var r=n[n.length-1].replace(t,"").replace(/(^[\-_])|([\-_]$)/,"");!r&&n.length>1&&(r=n[n.length-2]);var i=s[t+"Path"];return i==null&&(i=s.basePath),i&&i.slice(-1)!="/"&&(i+="/"),i+t+"-"+r+this.get("suffix")},t.setModuleUrl=function(e,t){return s.$moduleUrls[e]=t},t.init=function(){s.packaged=e.packaged||n.packaged||i.define&&define.packaged;if(!i.document)return"";var r={},u="",a=document.getElementsByTagName("script");for(var f=0;f<a.length;f++){var l=a[f],c=l.src||l.getAttribute("src");if(!c)continue;var h=l.attributes;for(var p=0,d=h.length;p<d;p++){var v=h[p];v.name.indexOf("data-ace-")===0&&(r[o(v.name.replace(/^data-ace-/,""))]=v.value)}var m=c.match(/^(.*)\/ace(\-\w+)?\.js(\?|$)/);m&&(u=m[1])}u&&(r.base=r.base||u,r.packaged=!0),r.workerPath=r.workerPath||r.base,r.modePath=r.modePath||r.base,r.themePath=r.themePath||r.base,delete r.base;for(var g in r)typeof r[g]!="undefined"&&t.set(g,r[g])}}),ace.define("ace/lib/net",["require","exports","module","ace/lib/useragent"],function(e,t,n){var r=e("./useragent");t.get=function(e,n){var r=t.createXhr();r.open("GET",e,!0),r.onreadystatechange=function(e){r.readyState===4&&n(r.responseText)},r.send(null)};var i=["Msxml2.XMLHTTP","Microsoft.XMLHTTP","Msxml2.XMLHTTP.4.0"];t.createXhr=function(){var e,t,n;if(typeof XMLHttpRequest!="undefined")return new XMLHttpRequest;for(t=0;t<3;t++){n=i[t];try{e=new ActiveXObject(n)}catch(r){}if(e){i=[n];break}}if(!e)throw new Error("createXhr(): XMLHttpRequest not available");return e},t.loadScript=function(e,t){var n=document.getElementsByTagName("head")[0],i=document.createElement("script");i.src=e,n.appendChild(i),r.isOldIE?i.onreadystatechange=function(){this.readyState=="loaded"&&t()}:i.onload=t}}),ace.define("ace/lib/event_emitter",["require","exports","module"],function(e,t,n){var r={};r._emit=r._dispatchEvent=function(e,t){this._eventRegistry=this._eventRegistry||{},this._defaultHandlers=this._defaultHandlers||{};var n=this._eventRegistry[e]||[],r=this._defaultHandlers[e];if(!n.length&&!r)return;if(typeof t!="object"||!t)t={};t.type||(t.type=e),t.stopPropagation||(t.stopPropagation=function(){this.propagationStopped=!0}),t.preventDefault||(t.preventDefault=function(){this.defaultPrevented=!0});for(var i=0;i<n.length;i++){n[i](t);if(t.propagationStopped)break}if(r&&!t.defaultPrevented)return r(t)},r.setDefaultHandler=function(e,t){this._defaultHandlers=this._defaultHandlers||{};if(this._defaultHandlers[e])throw new Error("The default handler for '"+e+"' is already set");this._defaultHandlers[e]=t},r.on=r.addEventListener=function(e,t){this._eventRegistry=this._eventRegistry||{};var n=this._eventRegistry[e];n||(n=this._eventRegistry[e]=[]),n.indexOf(t)==-1&&n.push(t)},r.removeListener=r.removeEventListener=function(e,t){this._eventRegistry=this._eventRegistry||{};var n=this._eventRegistry[e];if(!n)return;var r=n.indexOf(t);r!==-1&&n.splice(r,1)},r.removeAllListeners=function(e){this._eventRegistry&&(this._eventRegistry[e]=[])},t.EventEmitter=r}),ace.define("ace/selection",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/lib/event_emitter","ace/range"],function(e,t,n){var r=e("./lib/oop"),i=e("./lib/lang"),s=e("./lib/event_emitter").EventEmitter,o=e("./range").Range,u=function(e){this.session=e,this.doc=e.getDocument(),this.clearSelection(),this.lead=this.selectionLead=this.doc.createAnchor(0,0),this.anchor=this.selectionAnchor=this.doc.createAnchor(0,0);var t=this;this.lead.on("change",function(e){t._emit("changeCursor"),t.$isEmpty||t._emit("changeSelection"),!t.$keepDesiredColumnOnChange&&e.old.column!=e.value.column&&(t.$desiredColumn=null)}),this.selectionAnchor.on("change",function(){t.$isEmpty||t._emit("changeSelection")})};(function(){r.implement(this,s),this.isEmpty=function(){return this.$isEmpty||this.anchor.row==this.lead.row&&this.anchor.column==this.lead.column},this.isMultiLine=function(){return this.isEmpty()?!1:this.getRange().isMultiLine()},this.getCursor=function(){return this.lead.getPosition()},this.setSelectionAnchor=function(e,t){this.anchor.setPosition(e,t),this.$isEmpty&&(this.$isEmpty=!1,this._emit("changeSelection"))},this.getSelectionAnchor=function(){return this.$isEmpty?this.getSelectionLead():this.anchor.getPosition()},this.getSelectionLead=function(){return this.lead.getPosition()},this.shiftSelection=function(e){if(this.$isEmpty){this.moveCursorTo(this.lead.row,this.lead.column+e);return}var t=this.getSelectionAnchor(),n=this.getSelectionLead(),r=this.isBackwards();(!r||t.column!==0)&&this.setSelectionAnchor(t.row,t.column+e),(r||n.column!==0)&&this.$moveSelection(function(){this.moveCursorTo(n.row,n.column+e)})},this.isBackwards=function(){var e=this.anchor,t=this.lead;return e.row>t.row||e.row==t.row&&e.column>t.column},this.getRange=function(){var e=this.anchor,t=this.lead;return this.isEmpty()?o.fromPoints(t,t):this.isBackwards()?o.fromPoints(t,e):o.fromPoints(e,t)},this.clearSelection=function(){this.$isEmpty||(this.$isEmpty=!0,this._emit("changeSelection"))},this.selectAll=function(){var e=this.doc.getLength()-1;this.setSelectionAnchor(0,0),this.moveCursorTo(e,this.doc.getLine(e).length)},this.setRange=this.setSelectionRange=function(e,t){t?(this.setSelectionAnchor(e.end.row,e.end.column),this.selectTo(e.start.row,e.start.column)):(this.setSelectionAnchor(e.start.row,e.start.column),this.selectTo(e.end.row,e.end.column)),this.$desiredColumn=null},this.$moveSelection=function(e){var t=this.lead;this.$isEmpty&&this.setSelectionAnchor(t.row,t.column),e.call(this)},this.selectTo=function(e,t){this.$moveSelection(function(){this.moveCursorTo(e,t)})},this.selectToPosition=function(e){this.$moveSelection(function(){this.moveCursorToPosition(e)})},this.selectUp=function(){this.$moveSelection(this.moveCursorUp)},this.selectDown=function(){this.$moveSelection(this.moveCursorDown)},this.selectRight=function(){this.$moveSelection(this.moveCursorRight)},this.selectLeft=function(){this.$moveSelection(this.moveCursorLeft)},this.selectLineStart=function(){this.$moveSelection(this.moveCursorLineStart)},this.selectLineEnd=function(){this.$moveSelection(this.moveCursorLineEnd)},this.selectFileEnd=function(){this.$moveSelection(this.moveCursorFileEnd)},this.selectFileStart=function(){this.$moveSelection(this.moveCursorFileStart)},this.selectWordRight=function(){this.$moveSelection(this.moveCursorWordRight)},this.selectWordLeft=function(){this.$moveSelection(this.moveCursorWordLeft)},this.getWordRange=function(e,t){if(typeof t=="undefined"){var n=e||this.lead;e=n.row,t=n.column}return this.session.getWordRange(e,t)},this.selectWord=function(){this.setSelectionRange(this.getWordRange())},this.selectAWord=function(){var e=this.getCursor(),t=this.session.getAWordRange(e.row,e.column);this.setSelectionRange(t)},this.getLineRange=function(e,t){var n=typeof e=="number"?e:this.lead.row,r,i=this.session.getFoldLine(n);return i?(n=i.start.row,r=i.end.row):r=n,t?new o(n,0,r,this.session.getLine(r).length):new o(n,0,r+1,0)},this.selectLine=function(){this.setSelectionRange(this.getLineRange())},this.moveCursorUp=function(){this.moveCursorBy(-1,0)},this.moveCursorDown=function(){this.moveCursorBy(1,0)},this.moveCursorLeft=function(){var e=this.lead.getPosition(),t;if(t=this.session.getFoldAt(e.row,e.column,-1))this.moveCursorTo(t.start.row,t.start.column);else if(e.column==0)e.row>0&&this.moveCursorTo(e.row-1,this.doc.getLine(e.row-1).length);else{var n=this.session.getTabSize();this.session.isTabStop(e)&&this.doc.getLine(e.row).slice(e.column-n,e.column).split(" ").length-1==n?this.moveCursorBy(0,-n):this.moveCursorBy(0,-1)}},this.moveCursorRight=function(){var e=this.lead.getPosition(),t;if(t=this.session.getFoldAt(e.row,e.column,1))this.moveCursorTo(t.end.row,t.end.column);else if(this.lead.column==this.doc.getLine(this.lead.row).length)this.lead.row<this.doc.getLength()-1&&this.moveCursorTo(this.lead.row+1,0);else{var n=this.session.getTabSize(),e=this.lead;this.session.isTabStop(e)&&this.doc.getLine(e.row).slice(e.column,e.column+n).split(" ").length-1==n?this.moveCursorBy(0,n):this.moveCursorBy(0,1)}},this.moveCursorLineStart=function(){var e=this.lead.row,t=this.lead.column,n=this.session.documentToScreenRow(e,t),r=this.session.screenToDocumentPosition(n,0),i=this.session.getDisplayLine(e,null,r.row,r.column),s=i.match(/^\s*/);s[0].length==t?this.moveCursorTo(r.row,r.column):this.moveCursorTo(r.row,r.column+s[0].length)},this.moveCursorLineEnd=function(){var e=this.lead,t=this.session.getDocumentLastRowColumnPosition(e.row,e.column);if(this.lead.column==t.column){var n=this.session.getLine(t.row);if(t.column==n.length){var r=n.search(/\s+$/);r>0&&(t.column=r)}}this.moveCursorTo(t.row,t.column)},this.moveCursorFileEnd=function(){var e=this.doc.getLength()-1,t=this.doc.getLine(e).length;this.moveCursorTo(e,t)},this.moveCursorFileStart=function(){this.moveCursorTo(0,0)},this.moveCursorLongWordRight=function(){var e=this.lead.row,t=this.lead.column,n=this.doc.getLine(e),r=n.substring(t),i;this.session.nonTokenRe.lastIndex=0,this.session.tokenRe.lastIndex=0;var s=this.session.getFoldAt(e,t,1);if(s){this.moveCursorTo(s.end.row,s.end.column);return}if(i=this.session.nonTokenRe.exec(r))t+=this.session.nonTokenRe.lastIndex,this.session.nonTokenRe.lastIndex=0,r=n.substring(t);if(t>=n.length){this.moveCursorTo(e,n.length),this.moveCursorRight(),e<this.doc.getLength()-1&&this.moveCursorWordRight();return}if(i=this.session.tokenRe.exec(r))t+=this.session.tokenRe.lastIndex,this.session.tokenRe.lastIndex=0;this.moveCursorTo(e,t)},this.moveCursorLongWordLeft=function(){var e=this.lead.row,t=this.lead.column,n;if(n=this.session.getFoldAt(e,t,-1)){this.moveCursorTo(n.start.row,n.start.column);return}var r=this.session.getFoldStringAt(e,t,-1);r==null&&(r=this.doc.getLine(e).substring(0,t));var s=i.stringReverse(r),o;this.session.nonTokenRe.lastIndex=0,this.session.tokenRe.lastIndex=0;if(o=this.session.nonTokenRe.exec(s))t-=this.session.nonTokenRe.lastIndex,s=s.slice(this.session.nonTokenRe.lastIndex),this.session.nonTokenRe.lastIndex=0;if(t<=0){this.moveCursorTo(e,0),this.moveCursorLeft(),e>0&&this.moveCursorWordLeft();return}if(o=this.session.tokenRe.exec(s))t-=this.session.tokenRe.lastIndex,this.session.tokenRe.lastIndex=0;this.moveCursorTo(e,t)},this.$shortWordEndIndex=function(e){var t,n=0,r,i=/\s/,s=this.session.tokenRe;s.lastIndex=0;if(t=this.session.tokenRe.exec(e))n=this.session.tokenRe.lastIndex;else{while((r=e[n])&&i.test(r))n++;if(n<=1){s.lastIndex=0;while((r=e[n])&&!s.test(r)){s.lastIndex=0,n++;if(i.test(r)){if(n>2){n--;break}while((r=e[n])&&i.test(r))n++;if(n>2)break}}}}return s.lastIndex=0,n},this.moveCursorShortWordRight=function(){var e=this.lead.row,t=this.lead.column,n=this.doc.getLine(e),r=n.substring(t),i=this.session.getFoldAt(e,t,1);if(i)return this.moveCursorTo(i.end.row,i.end.column);if(t==n.length){var s=this.doc.getLength();do e++,r=this.doc.getLine(e);while(e<s&&/^\s*$/.test(r));/^\s+/.test(r)||(r=""),t=0}var o=this.$shortWordEndIndex(r);this.moveCursorTo(e,t+o)},this.moveCursorShortWordLeft=function(){var e=this.lead.row,t=this.lead.column,n;if(n=this.session.getFoldAt(e,t,-1))return this.moveCursorTo(n.start.row,n.start.column);var r=this.session.getLine(e).substring(0,t);if(t==0){do e--,r=this.doc.getLine(e);while(e>0&&/^\s*$/.test(r));t=r.length,/\s+$/.test(r)||(r="")}var s=i.stringReverse(r),o=this.$shortWordEndIndex(s);return this.moveCursorTo(e,t-o)},this.moveCursorWordRight=function(){this.session.$selectLongWords?this.moveCursorLongWordRight():this.moveCursorShortWordRight()},this.moveCursorWordLeft=function(){this.session.$selectLongWords?this.moveCursorLongWordLeft():this.moveCursorShortWordLeft()},this.moveCursorBy=function(e,t){var n=this.session.documentToScreenPosition(this.lead.row,this.lead.column);t===0&&(this.$desiredColumn?n.column=this.$desiredColumn:this.$desiredColumn=n.column);var r=this.session.screenToDocumentPosition(n.row+e,n.column);this.moveCursorTo(r.row,r.column+t,t===0)},this.moveCursorToPosition=function(e){this.moveCursorTo(e.row,e.column)},this.moveCursorTo=function(e,t,n){var r=this.session.getFoldAt(e,t,1);r&&(e=r.start.row,t=r.start.column),this.$keepDesiredColumnOnChange=!0,this.lead.setPosition(e,t),this.$keepDesiredColumnOnChange=!1,n||(this.$desiredColumn=null)},this.moveCursorToScreen=function(e,t,n){var r=this.session.screenToDocumentPosition(e,t);this.moveCursorTo(r.row,r.column,n)},this.detach=function(){this.lead.detach(),this.anchor.detach(),this.session=this.doc=null},this.fromOrientedRange=function(e){this.setSelectionRange(e,e.cursor==e.start),this.$desiredColumn=e.desiredColumn||this.$desiredColumn},this.toOrientedRange=function(e){var t=this.getRange();return e?(e.start.column=t.start.column,e.start.row=t.start.row,e.end.column=t.end.column,e.end.row=t.end.row):e=t,e.cursor=this.isBackwards()?e.start:e.end,e.desiredColumn=this.$desiredColumn,e}}).call(u.prototype),t.Selection=u}),ace.define("ace/range",["require","exports","module"],function(e,t,n){var r=function(e,t,n,r){this.start={row:e,column:t},this.end={row:n,column:r}};(function(){this.isEqual=function(e){return this.start.row==e.start.row&&this.end.row==e.end.row&&this.start.column==e.start.column&&this.end.column==e.end.column},this.toString=function(){return"Range: ["+this.start.row+"/"+this.start.column+"] -> ["+this.end.row+"/"+this.end.column+"]"},this.contains=function(e,t){return this.compare(e,t)==0},this.compareRange=function(e){var t,n=e.end,r=e.start;return t=this.compare(n.row,n.column),t==1?(t=this.compare(r.row,r.column),t==1?2:t==0?1:0):t==-1?-2:(t=this.compare(r.row,r.column),t==-1?-1:t==1?42:0)},this.comparePoint=function(e){return this.compare(e.row,e.column)},this.containsRange=function(e){return this.comparePoint(e.start)==0&&this.comparePoint(e.end)==0},this.intersects=function(e){var t=this.compareRange(e);return t==-1||t==0||t==1},this.isEnd=function(e,t){return this.end.row==e&&this.end.column==t},this.isStart=function(e,t){return this.start.row==e&&this.start.column==t},this.setStart=function(e,t){typeof e=="object"?(this.start.column=e.column,this.start.row=e.row):(this.start.row=e,this.start.column=t)},this.setEnd=function(e,t){typeof e=="object"?(this.end.column=e.column,this.end.row=e.row):(this.end.row=e,this.end.column=t)},this.inside=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)||this.isStart(e,t)?!1:!0:!1},this.insideStart=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)?!1:!0:!1},this.insideEnd=function(e,t){return this.compare(e,t)==0?this.isStart(e,t)?!1:!0:!1},this.compare=function(e,t){return!this.isMultiLine()&&e===this.start.row?t<this.start.column?-1:t>this.end.column?1:0:e<this.start.row?-1:e>this.end.row?1:this.start.row===e?t>=this.start.column?0:-1:this.end.row===e?t<=this.end.column?0:1:0},this.compareStart=function(e,t){return this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.compareEnd=function(e,t){return this.end.row==e&&this.end.column==t?1:this.compare(e,t)},this.compareInside=function(e,t){return this.end.row==e&&this.end.column==t?1:this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.clipRows=function(e,t){if(this.end.row>t)var n={row:t+1,column:0};if(this.start.row>t)var i={row:t+1,column:0};if(this.start.row<e)var i={row:e,column:0};if(this.end.row<e)var n={row:e,column:0};return r.fromPoints(i||this.start,n||this.end)},this.extend=function(e,t){var n=this.compare(e,t);if(n==0)return this;if(n==-1)var i={row:e,column:t};else var s={row:e,column:t};return r.fromPoints(i||this.start,s||this.end)},this.isEmpty=function(){return this.start.row==this.end.row&&this.start.column==this.end.column},this.isMultiLine=function(){return this.start.row!==this.end.row},this.clone=function(){return r.fromPoints(this.start,this.end)},this.collapseRows=function(){return this.end.column==0?new r(this.start.row,0,Math.max(this.start.row,this.end.row-1),0):new r(this.start.row,0,this.end.row,0)},this.toScreenRange=function(e){var t=e.documentToScreenPosition(this.start),n=e.documentToScreenPosition(this.end);return new r(t.row,t.column,n.row,n.column)}}).call(r.prototype),r.fromPoints=function(e,t){return new r(e.row,e.column,t.row,t.column)},t.Range=r}),ace.define("ace/mode/text",["require","exports","module","ace/tokenizer","ace/mode/text_highlight_rules","ace/mode/behaviour","ace/unicode"],function(e,t,n){var r=e("../tokenizer").Tokenizer,i=e("./text_highlight_rules").TextHighlightRules,s=e("./behaviour").Behaviour,o=e("../unicode"),u=function(){this.$tokenizer=new r((new i).getRules()),this.$behaviour=new s};(function(){this.tokenRe=new RegExp("^["+o.packages.L+o.packages.Mn+o.packages.Mc+o.packages.Nd+o.packages.Pc+"\\$_]+","g"),this.nonTokenRe=new RegExp("^(?:[^"+o.packages.L+o.packages.Mn+o.packages.Mc+o.packages.Nd+o.packages.Pc+"\\$_]|s])+","g"),this.getTokenizer=function(){return this.$tokenizer},this.toggleCommentLines=function(e,t,n,r){},this.getNextLineIndent=function(e,t,n){return""},this.checkOutdent=function(e,t,n){return!1},this.autoOutdent=function(e,t,n){},this.$getIndent=function(e){var t=e.match(/^(\s+)/);return t?t[1]:""},this.createWorker=function(e){return null},this.createModeDelegates=function(e){if(!this.$embeds)return;this.$modes={};for(var t=0;t<this.$embeds.length;t++)e[this.$embeds[t]]&&(this.$modes[this.$embeds[t]]=new e[this.$embeds[t]]);var n=["toggleCommentLines","getNextLineIndent","checkOutdent","autoOutdent","transformAction"];for(var t=0;t<n.length;t++)(function(e){var r=n[t],i=e[r];e[n[t]]=function(){return this.$delegator(r,arguments,i)}})(this)},this.$delegator=function(e,t,n){var r=t[0];for(var i=0;i<this.$embeds.length;i++){if(!this.$modes[this.$embeds[i]])continue;var s=r.split(this.$embeds[i]);if(!s[0]&&s[1]){t[0]=s[1];var o=this.$modes[this.$embeds[i]];return o[e].apply(o,t)}}var u=n.apply(this,t);return n?u:undefined},this.transformAction=function(e,t,n,r,i){if(this.$behaviour){var s=this.$behaviour.getBehaviours();for(var o in s)if(s[o][t]){var u=s[o][t].apply(this,arguments);if(u)return u}}}}).call(u.prototype),t.Mode=u}),ace.define("ace/tokenizer",["require","exports","module"],function(e,t,n){var r=function(e,t){t=t?"g"+t:"g",this.rules=e,this.regExps={},this.matchMappings={};for(var n in this.rules){var r=this.rules[n],i=r,s=[],o=0,u=this.matchMappings[n]={};for(var a=0;a<i.length;a++){i[a].regex instanceof RegExp&&(i[a].regex=i[a].regex.toString().slice(1,-1));var f=(new RegExp("(?:("+i[a].regex+")|(.))")).exec("a").length-2,l=i[a].regex.replace(/\\([0-9]+)/g,function(e,t){return"\\"+(parseInt(t,10)+o+1)});if(f>1&&i[a].token.length!==f-1)throw new Error("For "+i[a].regex+" the matching groups ("+(f-1)+") and length of the token array ("+i[a].token.length+") don't match (rule #"+a+" of state "+n+")");u[o]={rule:a,len:f},o+=f,s.push(l)}this.regExps[n]=new RegExp("(?:("+s.join(")|(")+")|(.))",t)}};(function(){this.getLineTokens=function(e,t){var n=t||"start",r=this.rules[n],i=this.matchMappings[n],s=this.regExps[n];s.lastIndex=0;var o,u=[],a=0,f={type:null,value:""};while(o=s.exec(e)){var l="text",c=null,h=[o[0]];for(var p=0;p<o.length-2;p++){if(o[p+1]===undefined)continue;c=r[i[p].rule],i[p].len>1&&(h=o.slice(p+2,p+1+i[p].len)),typeof c.token=="function"?l=c.token.apply(this,h):l=c.token;if(c.next){n=c.next,r=this.rules[n],i=this.matchMappings[n],a=s.lastIndex,s=this.regExps[n];if(s===undefined)throw new Error("You indicated a state of "+c.next+" to go to, but it doesn't exist!");s.lastIndex=a}break}if(h[0]){typeof l=="string"&&(h=[h.join("")],l=[l]);for(var p=0;p<h.length;p++){if(!h[p])continue;(!c||c.merge||l[p]==="text")&&f.type===l[p]?f.value+=h[p]:(f.type&&u.push(f),f={type:l[p],value:h[p]})}}if(a==e.length)break;a=s.lastIndex}return f.type&&u.push(f),{tokens:u,state:n}}}).call(r.prototype),t.Tokenizer=r}),ace.define("ace/mode/text_highlight_rules",["require","exports","module","ace/lib/lang"],function(e,t,n){var r=e("../lib/lang"),i=function(){this.$rules={start:[{token:"empty_line",regex:"^$"},{token:"text",regex:".+"}]}};(function(){this.addRules=function(e,t){for(var n in e){var r=e[n];for(var i=0;i<r.length;i++){var s=r[i];s.next&&(s.next=t+s.next)}this.$rules[t+n]=r}},this.getRules=function(){return this.$rules},this.embedRules=function(e,t,n,i,s){var o=(new e).getRules();if(i)for(var u=0;u<i.length;u++)i[u]=t+i[u];else{i=[];for(var a in o)i.push(t+a)}this.addRules(o,t);var f=Array.prototype[s?"push":"unshift"];for(var u=0;u<i.length;u++)f.apply(this.$rules[i[u]],r.deepCopy(n));this.$embeds||(this.$embeds=[]),this.$embeds.push(t)},this.getEmbeds=function(){return this.$embeds},this.createKeywordMapper=function(e,t,n,r){var i=Object.create(null);return Object.keys(e).forEach(function(t){var s=e[t];n&&(s=s.toLowerCase());var o=s.split(r||"|");for(var u=o.length;u--;)i[o[u]]=t}),e=null,n?function(e){return i[e.toLowerCase()]||t}:function(e){return i[e]||t}},this.getKeywords=function(){return this.$keywords}}).call(i.prototype),t.TextHighlightRules=i}),ace.define("ace/mode/behaviour",["require","exports","module"],function(e,t,n){var r=function(){this.$behaviours={}};(function(){this.add=function(e,t,n){switch(undefined){case this.$behaviours:this.$behaviours={};case this.$behaviours[e]:this.$behaviours[e]={}}this.$behaviours[e][t]=n},this.addBehaviours=function(e){for(var t in e)for(var n in e[t])this.add(t,n,e[t][n])},this.remove=function(e){this.$behaviours&&this.$behaviours[e]&&delete this.$behaviours[e]},this.inherit=function(e,t){if(typeof e=="function")var n=(new e).getBehaviours(t);else var n=e.getBehaviours(t);this.addBehaviours(n)},this.getBehaviours=function(e){if(!e)return this.$behaviours;var t={};for(var n=0;n<e.length;n++)this.$behaviours[e[n]]&&(t[e[n]]=this.$behaviours[e[n]]);return t}}).call(r.prototype),t.Behaviour=r}),ace.define("ace/unicode",["require","exports","module"],function(e,t,n){function r(e){var n=/\w{4}/g;for(var r in e)t.packages[r]=e[r].replace(n,"\\u$&")}t.packages={},r({L:"0041-005A0061-007A00AA00B500BA00C0-00D600D8-00F600F8-02C102C6-02D102E0-02E402EC02EE0370-037403760377037A-037D03860388-038A038C038E-03A103A3-03F503F7-0481048A-05250531-055605590561-058705D0-05EA05F0-05F20621-064A066E066F0671-06D306D506E506E606EE06EF06FA-06FC06FF07100712-072F074D-07A507B107CA-07EA07F407F507FA0800-0815081A082408280904-0939093D09500958-0961097109720979-097F0985-098C098F09900993-09A809AA-09B009B209B6-09B909BD09CE09DC09DD09DF-09E109F009F10A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A59-0A5C0A5E0A72-0A740A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABD0AD00AE00AE10B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3D0B5C0B5D0B5F-0B610B710B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BD00C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D0C580C590C600C610C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBD0CDE0CE00CE10D05-0D0C0D0E-0D100D12-0D280D2A-0D390D3D0D600D610D7A-0D7F0D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60E01-0E300E320E330E40-0E460E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB00EB20EB30EBD0EC0-0EC40EC60EDC0EDD0F000F40-0F470F49-0F6C0F88-0F8B1000-102A103F1050-1055105A-105D106110651066106E-10701075-1081108E10A0-10C510D0-10FA10FC1100-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A1380-138F13A0-13F41401-166C166F-167F1681-169A16A0-16EA1700-170C170E-17111720-17311740-17511760-176C176E-17701780-17B317D717DC1820-18771880-18A818AA18B0-18F51900-191C1950-196D1970-19741980-19AB19C1-19C71A00-1A161A20-1A541AA71B05-1B331B45-1B4B1B83-1BA01BAE1BAF1C00-1C231C4D-1C4F1C5A-1C7D1CE9-1CEC1CEE-1CF11D00-1DBF1E00-1F151F18-1F1D1F20-1F451F48-1F4D1F50-1F571F591F5B1F5D1F5F-1F7D1F80-1FB41FB6-1FBC1FBE1FC2-1FC41FC6-1FCC1FD0-1FD31FD6-1FDB1FE0-1FEC1FF2-1FF41FF6-1FFC2071207F2090-209421022107210A-211321152119-211D212421262128212A-212D212F-2139213C-213F2145-2149214E218321842C00-2C2E2C30-2C5E2C60-2CE42CEB-2CEE2D00-2D252D30-2D652D6F2D80-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDE2E2F300530063031-3035303B303C3041-3096309D-309F30A1-30FA30FC-30FF3105-312D3131-318E31A0-31B731F0-31FF3400-4DB54E00-9FCBA000-A48CA4D0-A4FDA500-A60CA610-A61FA62AA62BA640-A65FA662-A66EA67F-A697A6A0-A6E5A717-A71FA722-A788A78BA78CA7FB-A801A803-A805A807-A80AA80C-A822A840-A873A882-A8B3A8F2-A8F7A8FBA90A-A925A930-A946A960-A97CA984-A9B2A9CFAA00-AA28AA40-AA42AA44-AA4BAA60-AA76AA7AAA80-AAAFAAB1AAB5AAB6AAB9-AABDAAC0AAC2AADB-AADDABC0-ABE2AC00-D7A3D7B0-D7C6D7CB-D7FBF900-FA2DFA30-FA6DFA70-FAD9FB00-FB06FB13-FB17FB1DFB1F-FB28FB2A-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FBB1FBD3-FD3DFD50-FD8FFD92-FDC7FDF0-FDFBFE70-FE74FE76-FEFCFF21-FF3AFF41-FF5AFF66-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDC",Ll:"0061-007A00AA00B500BA00DF-00F600F8-00FF01010103010501070109010B010D010F01110113011501170119011B011D011F01210123012501270129012B012D012F01310133013501370138013A013C013E014001420144014601480149014B014D014F01510153015501570159015B015D015F01610163016501670169016B016D016F0171017301750177017A017C017E-0180018301850188018C018D019201950199-019B019E01A101A301A501A801AA01AB01AD01B001B401B601B901BA01BD-01BF01C601C901CC01CE01D001D201D401D601D801DA01DC01DD01DF01E101E301E501E701E901EB01ED01EF01F001F301F501F901FB01FD01FF02010203020502070209020B020D020F02110213021502170219021B021D021F02210223022502270229022B022D022F02310233-0239023C023F0240024202470249024B024D024F-02930295-02AF037103730377037B-037D039003AC-03CE03D003D103D5-03D703D903DB03DD03DF03E103E303E503E703E903EB03ED03EF-03F303F503F803FB03FC0430-045F04610463046504670469046B046D046F04710473047504770479047B047D047F0481048B048D048F04910493049504970499049B049D049F04A104A304A504A704A904AB04AD04AF04B104B304B504B704B904BB04BD04BF04C204C404C604C804CA04CC04CE04CF04D104D304D504D704D904DB04DD04DF04E104E304E504E704E904EB04ED04EF04F104F304F504F704F904FB04FD04FF05010503050505070509050B050D050F05110513051505170519051B051D051F0521052305250561-05871D00-1D2B1D62-1D771D79-1D9A1E011E031E051E071E091E0B1E0D1E0F1E111E131E151E171E191E1B1E1D1E1F1E211E231E251E271E291E2B1E2D1E2F1E311E331E351E371E391E3B1E3D1E3F1E411E431E451E471E491E4B1E4D1E4F1E511E531E551E571E591E5B1E5D1E5F1E611E631E651E671E691E6B1E6D1E6F1E711E731E751E771E791E7B1E7D1E7F1E811E831E851E871E891E8B1E8D1E8F1E911E931E95-1E9D1E9F1EA11EA31EA51EA71EA91EAB1EAD1EAF1EB11EB31EB51EB71EB91EBB1EBD1EBF1EC11EC31EC51EC71EC91ECB1ECD1ECF1ED11ED31ED51ED71ED91EDB1EDD1EDF1EE11EE31EE51EE71EE91EEB1EED1EEF1EF11EF31EF51EF71EF91EFB1EFD1EFF-1F071F10-1F151F20-1F271F30-1F371F40-1F451F50-1F571F60-1F671F70-1F7D1F80-1F871F90-1F971FA0-1FA71FB0-1FB41FB61FB71FBE1FC2-1FC41FC61FC71FD0-1FD31FD61FD71FE0-1FE71FF2-1FF41FF61FF7210A210E210F2113212F21342139213C213D2146-2149214E21842C30-2C5E2C612C652C662C682C6A2C6C2C712C732C742C76-2C7C2C812C832C852C872C892C8B2C8D2C8F2C912C932C952C972C992C9B2C9D2C9F2CA12CA32CA52CA72CA92CAB2CAD2CAF2CB12CB32CB52CB72CB92CBB2CBD2CBF2CC12CC32CC52CC72CC92CCB2CCD2CCF2CD12CD32CD52CD72CD92CDB2CDD2CDF2CE12CE32CE42CEC2CEE2D00-2D25A641A643A645A647A649A64BA64DA64FA651A653A655A657A659A65BA65DA65FA663A665A667A669A66BA66DA681A683A685A687A689A68BA68DA68FA691A693A695A697A723A725A727A729A72BA72DA72F-A731A733A735A737A739A73BA73DA73FA741A743A745A747A749A74BA74DA74FA751A753A755A757A759A75BA75DA75FA761A763A765A767A769A76BA76DA76FA771-A778A77AA77CA77FA781A783A785A787A78CFB00-FB06FB13-FB17FF41-FF5A",Lu:"0041-005A00C0-00D600D8-00DE01000102010401060108010A010C010E01100112011401160118011A011C011E01200122012401260128012A012C012E01300132013401360139013B013D013F0141014301450147014A014C014E01500152015401560158015A015C015E01600162016401660168016A016C016E017001720174017601780179017B017D018101820184018601870189-018B018E-0191019301940196-0198019C019D019F01A001A201A401A601A701A901AC01AE01AF01B1-01B301B501B701B801BC01C401C701CA01CD01CF01D101D301D501D701D901DB01DE01E001E201E401E601E801EA01EC01EE01F101F401F6-01F801FA01FC01FE02000202020402060208020A020C020E02100212021402160218021A021C021E02200222022402260228022A022C022E02300232023A023B023D023E02410243-02460248024A024C024E03700372037603860388-038A038C038E038F0391-03A103A3-03AB03CF03D2-03D403D803DA03DC03DE03E003E203E403E603E803EA03EC03EE03F403F703F903FA03FD-042F04600462046404660468046A046C046E04700472047404760478047A047C047E0480048A048C048E04900492049404960498049A049C049E04A004A204A404A604A804AA04AC04AE04B004B204B404B604B804BA04BC04BE04C004C104C304C504C704C904CB04CD04D004D204D404D604D804DA04DC04DE04E004E204E404E604E804EA04EC04EE04F004F204F404F604F804FA04FC04FE05000502050405060508050A050C050E05100512051405160518051A051C051E0520052205240531-055610A0-10C51E001E021E041E061E081E0A1E0C1E0E1E101E121E141E161E181E1A1E1C1E1E1E201E221E241E261E281E2A1E2C1E2E1E301E321E341E361E381E3A1E3C1E3E1E401E421E441E461E481E4A1E4C1E4E1E501E521E541E561E581E5A1E5C1E5E1E601E621E641E661E681E6A1E6C1E6E1E701E721E741E761E781E7A1E7C1E7E1E801E821E841E861E881E8A1E8C1E8E1E901E921E941E9E1EA01EA21EA41EA61EA81EAA1EAC1EAE1EB01EB21EB41EB61EB81EBA1EBC1EBE1EC01EC21EC41EC61EC81ECA1ECC1ECE1ED01ED21ED41ED61ED81EDA1EDC1EDE1EE01EE21EE41EE61EE81EEA1EEC1EEE1EF01EF21EF41EF61EF81EFA1EFC1EFE1F08-1F0F1F18-1F1D1F28-1F2F1F38-1F3F1F48-1F4D1F591F5B1F5D1F5F1F68-1F6F1FB8-1FBB1FC8-1FCB1FD8-1FDB1FE8-1FEC1FF8-1FFB21022107210B-210D2110-211221152119-211D212421262128212A-212D2130-2133213E213F214521832C00-2C2E2C602C62-2C642C672C692C6B2C6D-2C702C722C752C7E-2C802C822C842C862C882C8A2C8C2C8E2C902C922C942C962C982C9A2C9C2C9E2CA02CA22CA42CA62CA82CAA2CAC2CAE2CB02CB22CB42CB62CB82CBA2CBC2CBE2CC02CC22CC42CC62CC82CCA2CCC2CCE2CD02CD22CD42CD62CD82CDA2CDC2CDE2CE02CE22CEB2CEDA640A642A644A646A648A64AA64CA64EA650A652A654A656A658A65AA65CA65EA662A664A666A668A66AA66CA680A682A684A686A688A68AA68CA68EA690A692A694A696A722A724A726A728A72AA72CA72EA732A734A736A738A73AA73CA73EA740A742A744A746A748A74AA74CA74EA750A752A754A756A758A75AA75CA75EA760A762A764A766A768A76AA76CA76EA779A77BA77DA77EA780A782A784A786A78BFF21-FF3A",Lt:"01C501C801CB01F21F88-1F8F1F98-1F9F1FA8-1FAF1FBC1FCC1FFC",Lm:"02B0-02C102C6-02D102E0-02E402EC02EE0374037A0559064006E506E607F407F507FA081A0824082809710E460EC610FC17D718431AA71C78-1C7D1D2C-1D611D781D9B-1DBF2071207F2090-20942C7D2D6F2E2F30053031-3035303B309D309E30FC-30FEA015A4F8-A4FDA60CA67FA717-A71FA770A788A9CFAA70AADDFF70FF9EFF9F",Lo:"01BB01C0-01C3029405D0-05EA05F0-05F20621-063F0641-064A066E066F0671-06D306D506EE06EF06FA-06FC06FF07100712-072F074D-07A507B107CA-07EA0800-08150904-0939093D09500958-096109720979-097F0985-098C098F09900993-09A809AA-09B009B209B6-09B909BD09CE09DC09DD09DF-09E109F009F10A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A59-0A5C0A5E0A72-0A740A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABD0AD00AE00AE10B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3D0B5C0B5D0B5F-0B610B710B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BD00C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D0C580C590C600C610C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBD0CDE0CE00CE10D05-0D0C0D0E-0D100D12-0D280D2A-0D390D3D0D600D610D7A-0D7F0D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60E01-0E300E320E330E40-0E450E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB00EB20EB30EBD0EC0-0EC40EDC0EDD0F000F40-0F470F49-0F6C0F88-0F8B1000-102A103F1050-1055105A-105D106110651066106E-10701075-1081108E10D0-10FA1100-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A1380-138F13A0-13F41401-166C166F-167F1681-169A16A0-16EA1700-170C170E-17111720-17311740-17511760-176C176E-17701780-17B317DC1820-18421844-18771880-18A818AA18B0-18F51900-191C1950-196D1970-19741980-19AB19C1-19C71A00-1A161A20-1A541B05-1B331B45-1B4B1B83-1BA01BAE1BAF1C00-1C231C4D-1C4F1C5A-1C771CE9-1CEC1CEE-1CF12135-21382D30-2D652D80-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDE3006303C3041-3096309F30A1-30FA30FF3105-312D3131-318E31A0-31B731F0-31FF3400-4DB54E00-9FCBA000-A014A016-A48CA4D0-A4F7A500-A60BA610-A61FA62AA62BA66EA6A0-A6E5A7FB-A801A803-A805A807-A80AA80C-A822A840-A873A882-A8B3A8F2-A8F7A8FBA90A-A925A930-A946A960-A97CA984-A9B2AA00-AA28AA40-AA42AA44-AA4BAA60-AA6FAA71-AA76AA7AAA80-AAAFAAB1AAB5AAB6AAB9-AABDAAC0AAC2AADBAADCABC0-ABE2AC00-D7A3D7B0-D7C6D7CB-D7FBF900-FA2DFA30-FA6DFA70-FAD9FB1DFB1F-FB28FB2A-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FBB1FBD3-FD3DFD50-FD8FFD92-FDC7FDF0-FDFBFE70-FE74FE76-FEFCFF66-FF6FFF71-FF9DFFA0-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDC",M:"0300-036F0483-04890591-05BD05BF05C105C205C405C505C70610-061A064B-065E067006D6-06DC06DE-06E406E706E806EA-06ED07110730-074A07A6-07B007EB-07F30816-0819081B-08230825-08270829-082D0900-0903093C093E-094E0951-0955096209630981-098309BC09BE-09C409C709C809CB-09CD09D709E209E30A01-0A030A3C0A3E-0A420A470A480A4B-0A4D0A510A700A710A750A81-0A830ABC0ABE-0AC50AC7-0AC90ACB-0ACD0AE20AE30B01-0B030B3C0B3E-0B440B470B480B4B-0B4D0B560B570B620B630B820BBE-0BC20BC6-0BC80BCA-0BCD0BD70C01-0C030C3E-0C440C46-0C480C4A-0C4D0C550C560C620C630C820C830CBC0CBE-0CC40CC6-0CC80CCA-0CCD0CD50CD60CE20CE30D020D030D3E-0D440D46-0D480D4A-0D4D0D570D620D630D820D830DCA0DCF-0DD40DD60DD8-0DDF0DF20DF30E310E34-0E3A0E47-0E4E0EB10EB4-0EB90EBB0EBC0EC8-0ECD0F180F190F350F370F390F3E0F3F0F71-0F840F860F870F90-0F970F99-0FBC0FC6102B-103E1056-1059105E-10601062-10641067-106D1071-10741082-108D108F109A-109D135F1712-17141732-1734175217531772177317B6-17D317DD180B-180D18A91920-192B1930-193B19B0-19C019C819C91A17-1A1B1A55-1A5E1A60-1A7C1A7F1B00-1B041B34-1B441B6B-1B731B80-1B821BA1-1BAA1C24-1C371CD0-1CD21CD4-1CE81CED1CF21DC0-1DE61DFD-1DFF20D0-20F02CEF-2CF12DE0-2DFF302A-302F3099309AA66F-A672A67CA67DA6F0A6F1A802A806A80BA823-A827A880A881A8B4-A8C4A8E0-A8F1A926-A92DA947-A953A980-A983A9B3-A9C0AA29-AA36AA43AA4CAA4DAA7BAAB0AAB2-AAB4AAB7AAB8AABEAABFAAC1ABE3-ABEAABECABEDFB1EFE00-FE0FFE20-FE26",Mn:"0300-036F0483-04870591-05BD05BF05C105C205C405C505C70610-061A064B-065E067006D6-06DC06DF-06E406E706E806EA-06ED07110730-074A07A6-07B007EB-07F30816-0819081B-08230825-08270829-082D0900-0902093C0941-0948094D0951-095509620963098109BC09C1-09C409CD09E209E30A010A020A3C0A410A420A470A480A4B-0A4D0A510A700A710A750A810A820ABC0AC1-0AC50AC70AC80ACD0AE20AE30B010B3C0B3F0B41-0B440B4D0B560B620B630B820BC00BCD0C3E-0C400C46-0C480C4A-0C4D0C550C560C620C630CBC0CBF0CC60CCC0CCD0CE20CE30D41-0D440D4D0D620D630DCA0DD2-0DD40DD60E310E34-0E3A0E47-0E4E0EB10EB4-0EB90EBB0EBC0EC8-0ECD0F180F190F350F370F390F71-0F7E0F80-0F840F860F870F90-0F970F99-0FBC0FC6102D-10301032-10371039103A103D103E10581059105E-10601071-1074108210851086108D109D135F1712-17141732-1734175217531772177317B7-17BD17C617C9-17D317DD180B-180D18A91920-19221927192819321939-193B1A171A181A561A58-1A5E1A601A621A65-1A6C1A73-1A7C1A7F1B00-1B031B341B36-1B3A1B3C1B421B6B-1B731B801B811BA2-1BA51BA81BA91C2C-1C331C361C371CD0-1CD21CD4-1CE01CE2-1CE81CED1DC0-1DE61DFD-1DFF20D0-20DC20E120E5-20F02CEF-2CF12DE0-2DFF302A-302F3099309AA66FA67CA67DA6F0A6F1A802A806A80BA825A826A8C4A8E0-A8F1A926-A92DA947-A951A980-A982A9B3A9B6-A9B9A9BCAA29-AA2EAA31AA32AA35AA36AA43AA4CAAB0AAB2-AAB4AAB7AAB8AABEAABFAAC1ABE5ABE8ABEDFB1EFE00-FE0FFE20-FE26",Mc:"0903093E-09400949-094C094E0982098309BE-09C009C709C809CB09CC09D70A030A3E-0A400A830ABE-0AC00AC90ACB0ACC0B020B030B3E0B400B470B480B4B0B4C0B570BBE0BBF0BC10BC20BC6-0BC80BCA-0BCC0BD70C01-0C030C41-0C440C820C830CBE0CC0-0CC40CC70CC80CCA0CCB0CD50CD60D020D030D3E-0D400D46-0D480D4A-0D4C0D570D820D830DCF-0DD10DD8-0DDF0DF20DF30F3E0F3F0F7F102B102C10311038103B103C105610571062-10641067-106D108310841087-108C108F109A-109C17B617BE-17C517C717C81923-19261929-192B193019311933-193819B0-19C019C819C91A19-1A1B1A551A571A611A631A641A6D-1A721B041B351B3B1B3D-1B411B431B441B821BA11BA61BA71BAA1C24-1C2B1C341C351CE11CF2A823A824A827A880A881A8B4-A8C3A952A953A983A9B4A9B5A9BAA9BBA9BD-A9C0AA2FAA30AA33AA34AA4DAA7BABE3ABE4ABE6ABE7ABE9ABEAABEC",Me:"0488048906DE20DD-20E020E2-20E4A670-A672",N:"0030-003900B200B300B900BC-00BE0660-066906F0-06F907C0-07C90966-096F09E6-09EF09F4-09F90A66-0A6F0AE6-0AEF0B66-0B6F0BE6-0BF20C66-0C6F0C78-0C7E0CE6-0CEF0D66-0D750E50-0E590ED0-0ED90F20-0F331040-10491090-10991369-137C16EE-16F017E0-17E917F0-17F91810-18191946-194F19D0-19DA1A80-1A891A90-1A991B50-1B591BB0-1BB91C40-1C491C50-1C5920702074-20792080-20892150-21822185-21892460-249B24EA-24FF2776-27932CFD30073021-30293038-303A3192-31953220-32293251-325F3280-328932B1-32BFA620-A629A6E6-A6EFA830-A835A8D0-A8D9A900-A909A9D0-A9D9AA50-AA59ABF0-ABF9FF10-FF19",Nd:"0030-00390660-066906F0-06F907C0-07C90966-096F09E6-09EF0A66-0A6F0AE6-0AEF0B66-0B6F0BE6-0BEF0C66-0C6F0CE6-0CEF0D66-0D6F0E50-0E590ED0-0ED90F20-0F291040-10491090-109917E0-17E91810-18191946-194F19D0-19DA1A80-1A891A90-1A991B50-1B591BB0-1BB91C40-1C491C50-1C59A620-A629A8D0-A8D9A900-A909A9D0-A9D9AA50-AA59ABF0-ABF9FF10-FF19",Nl:"16EE-16F02160-21822185-218830073021-30293038-303AA6E6-A6EF",No:"00B200B300B900BC-00BE09F4-09F90BF0-0BF20C78-0C7E0D70-0D750F2A-0F331369-137C17F0-17F920702074-20792080-20892150-215F21892460-249B24EA-24FF2776-27932CFD3192-31953220-32293251-325F3280-328932B1-32BFA830-A835",P:"0021-00230025-002A002C-002F003A003B003F0040005B-005D005F007B007D00A100AB00B700BB00BF037E0387055A-055F0589058A05BE05C005C305C605F305F40609060A060C060D061B061E061F066A-066D06D40700-070D07F7-07F90830-083E0964096509700DF40E4F0E5A0E5B0F04-0F120F3A-0F3D0F850FD0-0FD4104A-104F10FB1361-13681400166D166E169B169C16EB-16ED1735173617D4-17D617D8-17DA1800-180A1944194519DE19DF1A1E1A1F1AA0-1AA61AA8-1AAD1B5A-1B601C3B-1C3F1C7E1C7F1CD32010-20272030-20432045-20512053-205E207D207E208D208E2329232A2768-277527C527C627E6-27EF2983-299829D8-29DB29FC29FD2CF9-2CFC2CFE2CFF2E00-2E2E2E302E313001-30033008-30113014-301F3030303D30A030FBA4FEA4FFA60D-A60FA673A67EA6F2-A6F7A874-A877A8CEA8CFA8F8-A8FAA92EA92FA95FA9C1-A9CDA9DEA9DFAA5C-AA5FAADEAADFABEBFD3EFD3FFE10-FE19FE30-FE52FE54-FE61FE63FE68FE6AFE6BFF01-FF03FF05-FF0AFF0C-FF0FFF1AFF1BFF1FFF20FF3B-FF3DFF3FFF5BFF5DFF5F-FF65",Pd:"002D058A05BE140018062010-20152E172E1A301C303030A0FE31FE32FE58FE63FF0D",Ps:"0028005B007B0F3A0F3C169B201A201E2045207D208D23292768276A276C276E27702772277427C527E627E827EA27EC27EE2983298529872989298B298D298F299129932995299729D829DA29FC2E222E242E262E283008300A300C300E3010301430163018301A301DFD3EFE17FE35FE37FE39FE3BFE3DFE3FFE41FE43FE47FE59FE5BFE5DFF08FF3BFF5BFF5FFF62",Pe:"0029005D007D0F3B0F3D169C2046207E208E232A2769276B276D276F27712773277527C627E727E927EB27ED27EF298429862988298A298C298E2990299229942996299829D929DB29FD2E232E252E272E293009300B300D300F3011301530173019301B301E301FFD3FFE18FE36FE38FE3AFE3CFE3EFE40FE42FE44FE48FE5AFE5CFE5EFF09FF3DFF5DFF60FF63",Pi:"00AB2018201B201C201F20392E022E042E092E0C2E1C2E20",Pf:"00BB2019201D203A2E032E052E0A2E0D2E1D2E21",Pc:"005F203F20402054FE33FE34FE4D-FE4FFF3F",Po:"0021-00230025-0027002A002C002E002F003A003B003F0040005C00A100B700BF037E0387055A-055F058905C005C305C605F305F40609060A060C060D061B061E061F066A-066D06D40700-070D07F7-07F90830-083E0964096509700DF40E4F0E5A0E5B0F04-0F120F850FD0-0FD4104A-104F10FB1361-1368166D166E16EB-16ED1735173617D4-17D617D8-17DA1800-18051807-180A1944194519DE19DF1A1E1A1F1AA0-1AA61AA8-1AAD1B5A-1B601C3B-1C3F1C7E1C7F1CD3201620172020-20272030-2038203B-203E2041-20432047-205120532055-205E2CF9-2CFC2CFE2CFF2E002E012E06-2E082E0B2E0E-2E162E182E192E1B2E1E2E1F2E2A-2E2E2E302E313001-3003303D30FBA4FEA4FFA60D-A60FA673A67EA6F2-A6F7A874-A877A8CEA8CFA8F8-A8FAA92EA92FA95FA9C1-A9CDA9DEA9DFAA5C-AA5FAADEAADFABEBFE10-FE16FE19FE30FE45FE46FE49-FE4CFE50-FE52FE54-FE57FE5F-FE61FE68FE6AFE6BFF01-FF03FF05-FF07FF0AFF0CFF0EFF0FFF1AFF1BFF1FFF20FF3CFF61FF64FF65",S:"0024002B003C-003E005E0060007C007E00A2-00A900AC00AE-00B100B400B600B800D700F702C2-02C502D2-02DF02E5-02EB02ED02EF-02FF03750384038503F604820606-0608060B060E060F06E906FD06FE07F609F209F309FA09FB0AF10B700BF3-0BFA0C7F0CF10CF20D790E3F0F01-0F030F13-0F170F1A-0F1F0F340F360F380FBE-0FC50FC7-0FCC0FCE0FCF0FD5-0FD8109E109F13601390-139917DB194019E0-19FF1B61-1B6A1B74-1B7C1FBD1FBF-1FC11FCD-1FCF1FDD-1FDF1FED-1FEF1FFD1FFE20442052207A-207C208A-208C20A0-20B8210021012103-21062108210921142116-2118211E-2123212521272129212E213A213B2140-2144214A-214D214F2190-2328232B-23E82400-24262440-244A249C-24E92500-26CD26CF-26E126E326E8-26FF2701-27042706-2709270C-27272729-274B274D274F-27522756-275E2761-276727942798-27AF27B1-27BE27C0-27C427C7-27CA27CC27D0-27E527F0-29822999-29D729DC-29FB29FE-2B4C2B50-2B592CE5-2CEA2E80-2E992E9B-2EF32F00-2FD52FF0-2FFB300430123013302030363037303E303F309B309C319031913196-319F31C0-31E33200-321E322A-32503260-327F328A-32B032C0-32FE3300-33FF4DC0-4DFFA490-A4C6A700-A716A720A721A789A78AA828-A82BA836-A839AA77-AA79FB29FDFCFDFDFE62FE64-FE66FE69FF04FF0BFF1C-FF1EFF3EFF40FF5CFF5EFFE0-FFE6FFE8-FFEEFFFCFFFD",Sm:"002B003C-003E007C007E00AC00B100D700F703F60606-060820442052207A-207C208A-208C2140-2144214B2190-2194219A219B21A021A321A621AE21CE21CF21D221D421F4-22FF2308-230B23202321237C239B-23B323DC-23E125B725C125F8-25FF266F27C0-27C427C7-27CA27CC27D0-27E527F0-27FF2900-29822999-29D729DC-29FB29FE-2AFF2B30-2B442B47-2B4CFB29FE62FE64-FE66FF0BFF1C-FF1EFF5CFF5EFFE2FFE9-FFEC",Sc:"002400A2-00A5060B09F209F309FB0AF10BF90E3F17DB20A0-20B8A838FDFCFE69FF04FFE0FFE1FFE5FFE6",Sk:"005E006000A800AF00B400B802C2-02C502D2-02DF02E5-02EB02ED02EF-02FF0375038403851FBD1FBF-1FC11FCD-1FCF1FDD-1FDF1FED-1FEF1FFD1FFE309B309CA700-A716A720A721A789A78AFF3EFF40FFE3",So:"00A600A700A900AE00B000B60482060E060F06E906FD06FE07F609FA0B700BF3-0BF80BFA0C7F0CF10CF20D790F01-0F030F13-0F170F1A-0F1F0F340F360F380FBE-0FC50FC7-0FCC0FCE0FCF0FD5-0FD8109E109F13601390-1399194019E0-19FF1B61-1B6A1B74-1B7C210021012103-21062108210921142116-2118211E-2123212521272129212E213A213B214A214C214D214F2195-2199219C-219F21A121A221A421A521A7-21AD21AF-21CD21D021D121D321D5-21F32300-2307230C-231F2322-2328232B-237B237D-239A23B4-23DB23E2-23E82400-24262440-244A249C-24E92500-25B625B8-25C025C2-25F72600-266E2670-26CD26CF-26E126E326E8-26FF2701-27042706-2709270C-27272729-274B274D274F-27522756-275E2761-276727942798-27AF27B1-27BE2800-28FF2B00-2B2F2B452B462B50-2B592CE5-2CEA2E80-2E992E9B-2EF32F00-2FD52FF0-2FFB300430123013302030363037303E303F319031913196-319F31C0-31E33200-321E322A-32503260-327F328A-32B032C0-32FE3300-33FF4DC0-4DFFA490-A4C6A828-A82BA836A837A839AA77-AA79FDFDFFE4FFE8FFEDFFEEFFFCFFFD",Z:"002000A01680180E2000-200A20282029202F205F3000",Zs:"002000A01680180E2000-200A202F205F3000",Zl:"2028",Zp:"2029",C:"0000-001F007F-009F00AD03780379037F-0383038B038D03A20526-05300557055805600588058B-059005C8-05CF05EB-05EF05F5-0605061C061D0620065F06DD070E070F074B074C07B2-07BF07FB-07FF082E082F083F-08FF093A093B094F095609570973-097809800984098D098E0991099209A909B109B3-09B509BA09BB09C509C609C909CA09CF-09D609D8-09DB09DE09E409E509FC-0A000A040A0B-0A0E0A110A120A290A310A340A370A3A0A3B0A3D0A43-0A460A490A4A0A4E-0A500A52-0A580A5D0A5F-0A650A76-0A800A840A8E0A920AA90AB10AB40ABA0ABB0AC60ACA0ACE0ACF0AD1-0ADF0AE40AE50AF00AF2-0B000B040B0D0B0E0B110B120B290B310B340B3A0B3B0B450B460B490B4A0B4E-0B550B58-0B5B0B5E0B640B650B72-0B810B840B8B-0B8D0B910B96-0B980B9B0B9D0BA0-0BA20BA5-0BA70BAB-0BAD0BBA-0BBD0BC3-0BC50BC90BCE0BCF0BD1-0BD60BD8-0BE50BFB-0C000C040C0D0C110C290C340C3A-0C3C0C450C490C4E-0C540C570C5A-0C5F0C640C650C70-0C770C800C810C840C8D0C910CA90CB40CBA0CBB0CC50CC90CCE-0CD40CD7-0CDD0CDF0CE40CE50CF00CF3-0D010D040D0D0D110D290D3A-0D3C0D450D490D4E-0D560D58-0D5F0D640D650D76-0D780D800D810D840D97-0D990DB20DBC0DBE0DBF0DC7-0DC90DCB-0DCE0DD50DD70DE0-0DF10DF5-0E000E3B-0E3E0E5C-0E800E830E850E860E890E8B0E8C0E8E-0E930E980EA00EA40EA60EA80EA90EAC0EBA0EBE0EBF0EC50EC70ECE0ECF0EDA0EDB0EDE-0EFF0F480F6D-0F700F8C-0F8F0F980FBD0FCD0FD9-0FFF10C6-10CF10FD-10FF1249124E124F12571259125E125F1289128E128F12B112B612B712BF12C112C612C712D7131113161317135B-135E137D-137F139A-139F13F5-13FF169D-169F16F1-16FF170D1715-171F1737-173F1754-175F176D17711774-177F17B417B517DE17DF17EA-17EF17FA-17FF180F181A-181F1878-187F18AB-18AF18F6-18FF191D-191F192C-192F193C-193F1941-1943196E196F1975-197F19AC-19AF19CA-19CF19DB-19DD1A1C1A1D1A5F1A7D1A7E1A8A-1A8F1A9A-1A9F1AAE-1AFF1B4C-1B4F1B7D-1B7F1BAB-1BAD1BBA-1BFF1C38-1C3A1C4A-1C4C1C80-1CCF1CF3-1CFF1DE7-1DFC1F161F171F1E1F1F1F461F471F4E1F4F1F581F5A1F5C1F5E1F7E1F7F1FB51FC51FD41FD51FDC1FF01FF11FF51FFF200B-200F202A-202E2060-206F20722073208F2095-209F20B9-20CF20F1-20FF218A-218F23E9-23FF2427-243F244B-245F26CE26E226E4-26E727002705270A270B2728274C274E2753-2755275F27602795-279727B027BF27CB27CD-27CF2B4D-2B4F2B5A-2BFF2C2F2C5F2CF2-2CF82D26-2D2F2D66-2D6E2D70-2D7F2D97-2D9F2DA72DAF2DB72DBF2DC72DCF2DD72DDF2E32-2E7F2E9A2EF4-2EFF2FD6-2FEF2FFC-2FFF3040309730983100-3104312E-3130318F31B8-31BF31E4-31EF321F32FF4DB6-4DBF9FCC-9FFFA48D-A48FA4C7-A4CFA62C-A63FA660A661A674-A67BA698-A69FA6F8-A6FFA78D-A7FAA82C-A82FA83A-A83FA878-A87FA8C5-A8CDA8DA-A8DFA8FC-A8FFA954-A95EA97D-A97FA9CEA9DA-A9DDA9E0-A9FFAA37-AA3FAA4EAA4FAA5AAA5BAA7C-AA7FAAC3-AADAAAE0-ABBFABEEABEFABFA-ABFFD7A4-D7AFD7C7-D7CAD7FC-F8FFFA2EFA2FFA6EFA6FFADA-FAFFFB07-FB12FB18-FB1CFB37FB3DFB3FFB42FB45FBB2-FBD2FD40-FD4FFD90FD91FDC8-FDEFFDFEFDFFFE1A-FE1FFE27-FE2FFE53FE67FE6C-FE6FFE75FEFD-FF00FFBF-FFC1FFC8FFC9FFD0FFD1FFD8FFD9FFDD-FFDFFFE7FFEF-FFFBFFFEFFFF",Cc:"0000-001F007F-009F",Cf:"00AD0600-060306DD070F17B417B5200B-200F202A-202E2060-2064206A-206FFEFFFFF9-FFFB",Co:"E000-F8FF",Cs:"D800-DFFF",Cn:"03780379037F-0383038B038D03A20526-05300557055805600588058B-059005C8-05CF05EB-05EF05F5-05FF06040605061C061D0620065F070E074B074C07B2-07BF07FB-07FF082E082F083F-08FF093A093B094F095609570973-097809800984098D098E0991099209A909B109B3-09B509BA09BB09C509C609C909CA09CF-09D609D8-09DB09DE09E409E509FC-0A000A040A0B-0A0E0A110A120A290A310A340A370A3A0A3B0A3D0A43-0A460A490A4A0A4E-0A500A52-0A580A5D0A5F-0A650A76-0A800A840A8E0A920AA90AB10AB40ABA0ABB0AC60ACA0ACE0ACF0AD1-0ADF0AE40AE50AF00AF2-0B000B040B0D0B0E0B110B120B290B310B340B3A0B3B0B450B460B490B4A0B4E-0B550B58-0B5B0B5E0B640B650B72-0B810B840B8B-0B8D0B910B96-0B980B9B0B9D0BA0-0BA20BA5-0BA70BAB-0BAD0BBA-0BBD0BC3-0BC50BC90BCE0BCF0BD1-0BD60BD8-0BE50BFB-0C000C040C0D0C110C290C340C3A-0C3C0C450C490C4E-0C540C570C5A-0C5F0C640C650C70-0C770C800C810C840C8D0C910CA90CB40CBA0CBB0CC50CC90CCE-0CD40CD7-0CDD0CDF0CE40CE50CF00CF3-0D010D040D0D0D110D290D3A-0D3C0D450D490D4E-0D560D58-0D5F0D640D650D76-0D780D800D810D840D97-0D990DB20DBC0DBE0DBF0DC7-0DC90DCB-0DCE0DD50DD70DE0-0DF10DF5-0E000E3B-0E3E0E5C-0E800E830E850E860E890E8B0E8C0E8E-0E930E980EA00EA40EA60EA80EA90EAC0EBA0EBE0EBF0EC50EC70ECE0ECF0EDA0EDB0EDE-0EFF0F480F6D-0F700F8C-0F8F0F980FBD0FCD0FD9-0FFF10C6-10CF10FD-10FF1249124E124F12571259125E125F1289128E128F12B112B612B712BF12C112C612C712D7131113161317135B-135E137D-137F139A-139F13F5-13FF169D-169F16F1-16FF170D1715-171F1737-173F1754-175F176D17711774-177F17DE17DF17EA-17EF17FA-17FF180F181A-181F1878-187F18AB-18AF18F6-18FF191D-191F192C-192F193C-193F1941-1943196E196F1975-197F19AC-19AF19CA-19CF19DB-19DD1A1C1A1D1A5F1A7D1A7E1A8A-1A8F1A9A-1A9F1AAE-1AFF1B4C-1B4F1B7D-1B7F1BAB-1BAD1BBA-1BFF1C38-1C3A1C4A-1C4C1C80-1CCF1CF3-1CFF1DE7-1DFC1F161F171F1E1F1F1F461F471F4E1F4F1F581F5A1F5C1F5E1F7E1F7F1FB51FC51FD41FD51FDC1FF01FF11FF51FFF2065-206920722073208F2095-209F20B9-20CF20F1-20FF218A-218F23E9-23FF2427-243F244B-245F26CE26E226E4-26E727002705270A270B2728274C274E2753-2755275F27602795-279727B027BF27CB27CD-27CF2B4D-2B4F2B5A-2BFF2C2F2C5F2CF2-2CF82D26-2D2F2D66-2D6E2D70-2D7F2D97-2D9F2DA72DAF2DB72DBF2DC72DCF2DD72DDF2E32-2E7F2E9A2EF4-2EFF2FD6-2FEF2FFC-2FFF3040309730983100-3104312E-3130318F31B8-31BF31E4-31EF321F32FF4DB6-4DBF9FCC-9FFFA48D-A48FA4C7-A4CFA62C-A63FA660A661A674-A67BA698-A69FA6F8-A6FFA78D-A7FAA82C-A82FA83A-A83FA878-A87FA8C5-A8CDA8DA-A8DFA8FC-A8FFA954-A95EA97D-A97FA9CEA9DA-A9DDA9E0-A9FFAA37-AA3FAA4EAA4FAA5AAA5BAA7C-AA7FAAC3-AADAAAE0-ABBFABEEABEFABFA-ABFFD7A4-D7AFD7C7-D7CAD7FC-D7FFFA2EFA2FFA6EFA6FFADA-FAFFFB07-FB12FB18-FB1CFB37FB3DFB3FFB42FB45FBB2-FBD2FD40-FD4FFD90FD91FDC8-FDEFFDFEFDFFFE1A-FE1FFE27-FE2FFE53FE67FE6C-FE6FFE75FEFDFEFEFF00FFBF-FFC1FFC8FFC9FFD0FFD1FFD8FFD9FFDD-FFDFFFE7FFEF-FFF8FFFEFFFF"})}),ace.define("ace/document",["require","exports","module","ace/lib/oop","ace/lib/event_emitter","ace/range","ace/anchor"],function(e,t,n){var r=e("./lib/oop"),i=e("./lib/event_emitter").EventEmitter,s=e("./range").Range,o=e("./anchor").Anchor,u=function(e){this.$lines=[],e.length==0?this.$lines=[""]:Array.isArray(e)?this.insertLines(0,e):this.insert({row:0,column:0},e)};(function(){r.implement(this,i),this.setValue=function(e){var t=this.getLength();this.remove(new s(0,0,t,this.getLine(t-1).length)),this.insert({row:0,column:0},e)},this.getValue=function(){return this.getAllLines().join(this.getNewLineCharacter())},this.createAnchor=function(e,t){return new o(this,e,t)},"aaa".split(/a/).length==0?this.$split=function(e){return e.replace(/\r\n|\r/g,"\n").split("\n")}:this.$split=function(e){return e.split(/\r\n|\r|\n/)},this.$detectNewLine=function(e){var t=e.match(/^.*?(\r\n|\r|\n)/m);t?this.$autoNewLine=t[1]:this.$autoNewLine="\n"},this.getNewLineCharacter=function(){switch(this.$newLineMode){case"windows":return"\r\n";case"unix":return"\n";case"auto":return this.$autoNewLine}},this.$autoNewLine="\n",this.$newLineMode="auto",this.setNewLineMode=function(e){if(this.$newLineMode===e)return;this.$newLineMode=e},this.getNewLineMode=function(){return this.$newLineMode},this.isNewLine=function(e){return e=="\r\n"||e=="\r"||e=="\n"},this.getLine=function(e){return this.$lines[e]||""},this.getLines=function(e,t){return this.$lines.slice(e,t+1)},this.getAllLines=function(){return this.getLines(0,this.getLength())},this.getLength=function(){return this.$lines.length},this.getTextRange=function(e){if(e.start.row==e.end.row)return this.$lines[e.start.row].substring(e.start.column,e.end.column);var t=this.getLines(e.start.row+1,e.end.row-1);return t.unshift((this.$lines[e.start.row]||"").substring(e.start.column)),t.push((this.$lines[e.end.row]||"").substring(0,e.end.column)),t.join(this.getNewLineCharacter())},this.$clipPosition=function(e){var t=this.getLength();return e.row>=t&&(e.row=Math.max(0,t-1),e.column=this.getLine(t-1).length),e},this.insert=function(e,t){if(!t||t.length===0)return e;e=this.$clipPosition(e),this.getLength()<=1&&this.$detectNewLine(t);var n=this.$split(t),r=n.splice(0,1)[0],i=n.length==0?null:n.splice(n.length-1,1)[0];return e=this.insertInLine(e,r),i!==null&&(e=this.insertNewLine(e),e=this.insertLines(e.row,n),e=this.insertInLine(e,i||"")),e},this.insertLines=function(e,t){if(t.length==0)return{row:e,column:0};if(t.length>65535){var n=this.insertLines(e,t.slice(65535));t=t.slice(0,65535)}var r=[e,0];r.push.apply(r,t),this.$lines.splice.apply(this.$lines,r);var i=new s(e,0,e+t.length,0),o={action:"insertLines",range:i,lines:t};return this._emit("change",{data:o}),n||i.end},this.insertNewLine=function(e){e=this.$clipPosition(e);var t=this.$lines[e.row]||"";this.$lines[e.row]=t.substring(0,e.column),this.$lines.splice(e.row+1,0,t.substring(e.column,t.length));var n={row:e.row+1,column:0},r={action:"insertText",range:s.fromPoints(e,n),text:this.getNewLineCharacter()};return this._emit("change",{data:r}),n},this.insertInLine=function(e,t){if(t.length==0)return e;var n=this.$lines[e.row]||"";this.$lines[e.row]=n.substring(0,e.column)+t+n.substring(e.column);var r={row:e.row,column:e.column+t.length},i={action:"insertText",range:s.fromPoints(e,r),text:t};return this._emit("change",{data:i}),r},this.remove=function(e){e.start=this.$clipPosition(e.start),e.end=this.$clipPosition(e.end);if(e.isEmpty())return e.start;var t=e.start.row,n=e.end.row;if(e.isMultiLine()){var r=e.start.column==0?t:t+1,i=n-1;e.end.column>0&&this.removeInLine(n,0,e.end.column),i>=r&&this.removeLines(r,i),r!=t&&(this.removeInLine(t,e.start.column,this.getLine(t).length),this.removeNewLine(e.start.row))}else this.removeInLine(t,e.start.column,e.end.column);return e.start},this.removeInLine=function(e,t,n){if(t==n)return;var r=new s(e,t,e,n),i=this.getLine(e),o=i.substring(t,n),u=i.substring(0,t)+i.substring(n,i.length);this.$lines.splice(e,1,u);var a={action:"removeText",range:r,text:o};return this._emit("change",{data:a}),r.start},this.removeLines=function(e,t){var n=new s(e,0,t+1,0),r=this.$lines.splice(e,t-e+1),i={action:"removeLines",range:n,nl:this.getNewLineCharacter(),lines:r};return this._emit("change",{data:i}),r},this.removeNewLine=function(e){var t=this.getLine(e),n=this.getLine(e+1),r=new s(e,t.length,e+1,0),i=t+n;this.$lines.splice(e,2,i);var o={action:"removeText",range:r,text:this.getNewLineCharacter()};this._emit("change",{data:o})},this.replace=function(e,t){if(t.length==0&&e.isEmpty())return e.start;if(t==this.getTextRange(e))return e.end;this.remove(e);if(t)var n=this.insert(e.start,t);else n=e.start;return n},this.applyDeltas=function(e){for(var t=0;t<e.length;t++){var n=e[t],r=s.fromPoints(n.range.start,n.range.end);n.action=="insertLines"?this.insertLines(r.start.row,n.lines):n.action=="insertText"?this.insert(r.start,n.text):n.action=="removeLines"?this.removeLines(r.start.row,r.end.row-1):n.action=="removeText"&&this.remove(r)}},this.revertDeltas=function(e){for(var t=e.length-1;t>=0;t--){var n=e[t],r=s.fromPoints(n.range.start,n.range.end);n.action=="insertLines"?this.removeLines(r.start.row,r.end.row-1):n.action=="insertText"?this.remove(r):n.action=="removeLines"?this.insertLines(r.start.row,n.lines):n.action=="removeText"&&this.insert(r.start,n.text)}}}).call(u.prototype),t.Document=u}),ace.define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"],function(e,t,n){var r=e("./lib/oop"),i=e("./lib/event_emitter").EventEmitter,s=t.Anchor=function(e,t,n){this.document=e,typeof n=="undefined"?this.setPosition(t.row,t.column):this.setPosition(t,n),this.$onChange=this.onChange.bind(this),e.on("change",this.$onChange)};(function(){r.implement(this,i),this.getPosition=function(){return this.$clipPositionToDocument(this.row,this.column)},this.getDocument=function(){return this.document},this.onChange=function(e){var t=e.data,n=t.range;if(n.start.row==n.end.row&&n.start.row!=this.row)return;if(n.start.row>this.row)return;if(n.start.row==this.row&&n.start.column>this.column)return;var r=this.row,i=this.column;t.action==="insertText"?n.start.row===r&&n.start.column<=i?n.start.row===n.end.row?i+=n.end.column-n.start.column:(i-=n.start.column,r+=n.end.row-n.start.row):n.start.row!==n.end.row&&n.start.row<r&&(r+=n.end.row-n.start.row):t.action==="insertLines"?n.start.row<=r&&(r+=n.end.row-n.start.row):t.action=="removeText"?n.start.row==r&&n.start.column<i?n.end.column>=i?i=n.start.column:i=Math.max(0,i-(n.end.column-n.start.column)):n.start.row!==n.end.row&&n.start.row<r?(n.end.row==r&&(i=Math.max(0,i-n.end.column)+n.start.column),r-=n.end.row-n.start.row):n.end.row==r&&(r-=n.end.row-n.start.row,i=Math.max(0,i-n.end.column)+n.start.column):t.action=="removeLines"&&n.start.row<=r&&(n.end.row<=r?r-=n.end.row-n.start.row:(r=n.start.row,i=0)),this.setPosition(r,i,!0)},this.setPosition=function(e,t,n){var r;n?r={row:e,column:t}:r=this.$clipPositionToDocument(e,t);if(this.row==r.row&&this.column==r.column)return;var i={row:this.row,column:this.column};this.row=r.row,this.column=r.column,this._emit("change",{old:i,value:r})},this.detach=function(){this.document.removeEventListener("change",this.$onChange)},this.$clipPositionToDocument=function(e,t){var n={};return e>=this.document.getLength()?(n.row=Math.max(0,this.document.getLength()-1),n.column=this.document.getLine(n.row).length):e<0?(n.row=0,n.column=0):(n.row=e,n.column=Math.min(this.document.getLine(n.row).length,Math.max(0,t))),t<0&&(n.column=0),n}}).call(s.prototype)}),ace.define("ace/background_tokenizer",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"],function(e,t,n){var r=e("./lib/oop"),i=e("./lib/event_emitter").EventEmitter,s=5e3,o=function(e,t){this.running=!1,this.lines=[],this.states=[],this.currentLine=0,this.tokenizer=e;var n=this;this.$worker=function(){if(!n.running)return;var e=new Date,t=n.currentLine,r=n.doc,i=0,s=r.getLength();while(n.currentLine<s){n.$tokenizeRow(n.currentLine);while(n.lines[n.currentLine])n.currentLine++;i++;if(i%5==0&&new Date-e>20){n.fireUpdateEvent(t,n.currentLine-1),n.running=setTimeout(n.$worker,20);return}}n.running=!1,n.fireUpdateEvent(t,s-1)}};(function(){r.implement(this,i),this.setTokenizer=function(e){this.tokenizer=e,this.lines=[],this.states=[],this.start(0)},this.setDocument=function(e){this.doc=e,this.lines=[],this.states=[],this.stop()},this.fireUpdateEvent=function(e,t){var n={first:e,last:t};this._emit("update",{data:n})},this.start=function(e){this.currentLine=Math.min(e||0,this.currentLine,this.doc.getLength()),this.lines.splice(this.currentLine,this.lines.length),this.states.splice(this.currentLine,this.states.length),this.stop(),this.running=setTimeout(this.$worker,700)},this.$updateOnChange=function(e){var t=e.range,n=t.start.row,r=t.end.row-n;if(r===0)this.lines[n]=null;else if(e.action=="removeText"||e.action=="removeLines")this.lines.splice(n,r+1,null),this.states.splice(n,r+1,null);else{var i=Array(r+1);i.unshift(n,1),this.lines.splice.apply(this.lines,i),this.states.splice.apply(this.states,i)}this.currentLine=Math.min(n,this.currentLine,this.doc.getLength()),this.stop(),this.running=setTimeout(this.$worker,700)},this.stop=function(){this.running&&clearTimeout(this.running),this.running=!1},this.getTokens=function(e){return this.lines[e]||this.$tokenizeRow(e)},this.getState=function(e){return this.currentLine==e&&this.$tokenizeRow(e),this.states[e]||"start"},this.$tokenizeRow=function(e){var t=this.doc.getLine(e),n=this.states[e-1];if(t.length>s){var r={value:t.substr(s),type:"text"};t=t.slice(0,s)}var i=this.tokenizer.getLineTokens(t,n);return r&&(i.tokens.push(r),i.state="start"),this.states[e]!==i.state?(this.states[e]=i.state,this.lines[e+1]=null,this.currentLine>e+1&&(this.currentLine=e+1)):this.currentLine==e&&(this.currentLine=e+1),this.lines[e]=i.tokens}}).call(o.prototype),t.BackgroundTokenizer=o}),ace.define("ace/search_highlight",["require","exports","module","ace/lib/lang","ace/lib/oop","ace/range"],function(e,t,n){var r=e("./lib/lang"),i=e("./lib/oop"),s=e("./range").Range,o=function(e,t,n){this.setRegexp(e),this.clazz=t,this.type=n||"text"};(function(){this.MAX_RANGES=500,this.setRegexp=function(e){if(this.regExp+""==e+"")return;this.regExp=e,this.cache=[]},this.update=function(e,t,n,i){if(!this.regExp)return;var o=i.firstRow,u=i.lastRow;for(var a=o;a<=u;a++){var f=this.cache[a];f==null&&(f=r.getMatchOffsets(n.getLine(a),this.regExp),f.length>this.MAX_RANGES&&(f=f.slice(0,this.MAX_RANGES)),f=f.map(function(e){return new s(a,e.offset,a,e.offset+e.length)}),this.cache[a]=f.length?f:"");for(var l=f.length;l--;)t.drawSingleLineMarker(e,f[l].toScreenRange(n),this.clazz,i,null,this.type)}}}).call(o.prototype),t.SearchHighlight=o}),ace.define("ace/edit_session/folding",["require","exports","module","ace/range","ace/edit_session/fold_line","ace/edit_session/fold","ace/token_iterator"],function(e,t,n){function u(){this.getFoldAt=function(e,t,n){var r=this.getFoldLine(e);if(!r)return null;var i=r.folds;for(var s=0;s<i.length;s++){var o=i[s];if(o.range.contains(e,t)){if(n==1&&o.range.isEnd(e,t))continue;if(n==-1&&o.range.isStart(e,t))continue;return o}}},this.getFoldsInRange=function(e){e=e.clone();var t=e.start,n=e.end,r=this.$foldData,i=[];t.column+=1,n.column-=1;for(var s=0;s<r.length;s++){var o=r[s].range.compareRange(e);if(o==2)continue;if(o==-2)break;var u=r[s].folds;for(var a=0;a<u.length;a++){var f=u[a];o=f.range.compareRange(e);if(o==-2)break;if(o==2)continue;if(o==42)break;i.push(f)}}return i},this.getAllFolds=function(){function n(t){e.push(t);if(!t.subFolds)return;for(var r=0;r<t.subFolds.length;r++)n(t.subFolds[r])}var e=[],t=this.$foldData;for(var r=0;r<t.length;r++)for(var i=0;i<t[r].folds.length;i++)n(t[r].folds[i]);return e},this.getFoldStringAt=function(e,t,n,r){r=r||this.getFoldLine(e);if(!r)return null;var i={end:{column:0}},s,o;for(var u=0;u<r.folds.length;u++){o=r.folds[u];var a=o.range.compareEnd(e,t);if(a==-1){s=this.getLine(o.start.row).substring(i.end.column,o.start.column);break}if(a===0)return null;i=o}return s||(s=this.getLine(o.start.row).substring(i.end.column)),n==-1?s.substring(0,t-i.end.column):n==1?s.substring(t-i.end.column):s},this.getFoldLine=function(e,t){var n=this.$foldData,r=0;t&&(r=n.indexOf(t)),r==-1&&(r=0);for(r;r<n.length;r++){var i=n[r];if(i.start.row<=e&&i.end.row>=e)return i;if(i.end.row>e)return null}return null},this.getNextFoldLine=function(e,t){var n=this.$foldData,r=0;t&&(r=n.indexOf(t)),r==-1&&(r=0);for(r;r<n.length;r++){var i=n[r];if(i.end.row>=e)return i}return null},this.getFoldedRowCount=function(e,t){var n=this.$foldData,r=t-e+1;for(var i=0;i<n.length;i++){var s=n[i],o=s.end.row,u=s.start.row;if(o>=t){u<t&&(u>=e?r-=t-u:r=0);break}o>=e&&(u>=e?r-=o-u:r-=o-e+1)}return r},this.$addFoldLine=function(e){return this.$foldData.push(e),this.$foldData.sort(function(e,t){return e.start.row-t.start.row}),e},this.addFold=function(e,t){var n=this.$foldData,r=!1,o;e instanceof s?o=e:o=new s(t,e),this.$clipRangeToDocument(o.range);var u=o.start.row,a=o.start.column,f=o.end.row,l=o.end.column;if(u==f&&l-a<2)throw"The range has to be at least 2 characters width";var c=this.getFoldAt(u,a,1),h=this.getFoldAt(f,l,-1);if(c&&h==c)return c.addSubFold(o);if(c&&!c.range.isStart(u,a)||h&&!h.range.isEnd(f,l))throw"A fold can't intersect already existing fold"+o.range+c.range;var p=this.getFoldsInRange(o.range);p.length>0&&(this.removeFolds(p),o.subFolds=p);for(var d=0;d<n.length;d++){var v=n[d];if(f==v.start.row){v.addFold(o),r=!0;break}if(u==v.end.row){v.addFold(o),r=!0;if(!o.sameRow){var m=n[d+1];if(m&&m.start.row==f){v.merge(m);break}}break}if(f<=v.start.row)break}return r||(v=this.$addFoldLine(new i(this.$foldData,o))),this.$useWrapMode?this.$updateWrapData(v.start.row,v.start.row):this.$updateRowLengthCache(v.start.row,v.start.row),this.$modified=!0,this._emit("changeFold",{data:o}),o},this.addFolds=function(e){e.forEach(function(e){this.addFold(e)},this)},this.removeFold=function(e){var t=e.foldLine,n=t.start.row,r=t.end.row,i=this.$foldData,s=t.folds;if(s.length==1)i.splice(i.indexOf(t),1);else if(t.range.isEnd(e.end.row,e.end.column))s.pop(),t.end.row=s[s.length-1].end.row,t.end.column=s[s.length-1].end.column;else if(t.range.isStart(e.start.row,e.start.column))s.shift(),t.start.row=s[0].start.row,t.start.column=s[0].start.column;else if(e.sameRow)s.splice(s.indexOf(e),1);else{var o=t.split(e.start.row,e.start.column);s=o.folds,s.shift(),o.start.row=s[0].start.row,o.start.column=s[0].start.column}this.$useWrapMode?this.$updateWrapData(n,r):this.$updateRowLengthCache(n,r),this.$modified=!0,this._emit("changeFold",{data:e})},this.removeFolds=function(e){var t=[];for(var n=0;n<e.length;n++)t.push(e[n]);t.forEach(function(e){this.removeFold(e)},this),this.$modified=!0},this.expandFold=function(e){this.removeFold(e),e.subFolds.forEach(function(e){this.addFold(e)},this),e.subFolds=[]},this.expandFolds=function(e){e.forEach(function(e){this.expandFold(e)},this)},this.unfold=function(e,t){var n,i;e==null?n=new r(0,0,this.getLength(),0):typeof e=="number"?n=new r(e,0,e,this.getLine(e).length):"row"in e?n=r.fromPoints(e,e):n=e,i=this.getFoldsInRange(n);if(t)this.removeFolds(i);else while(i.length)this.expandFolds(i),i=this.getFoldsInRange(n)},this.isRowFolded=function(e,t){return!!this.getFoldLine(e,t)},this.getRowFoldEnd=function(e,t){var n=this.getFoldLine(e,t);return n?n.end.row:e},this.getFoldDisplayLine=function(e,t,n,r,i){r==null&&(r=e.start.row,i=0),t==null&&(t=e.end.row,n=this.getLine(t).length);var s=this.doc,o="";return e.walk(function(e,t,n,u){if(t<r)return;if(t==r){if(n<i)return;u=Math.max(i,u)}e!=null?o+=e:o+=s.getLine(t).substring(u,n)}.bind(this),t,n),o},this.getDisplayLine=function(e,t,n,r){var i=this.getFoldLine(e);if(!i){var s;return s=this.doc.getLine(e),s.substring(r||0,t||s.length)}return this.getFoldDisplayLine(i,e,t,n,r)},this.$cloneFoldData=function(){var e=[];return e=this.$foldData.map(function(t){var n=t.folds.map(function(e){return e.clone()});return new i(e,n)}),e},this.toggleFold=function(e){var t=this.selection,n=t.getRange(),r,i;if(n.isEmpty()){var s=n.start;r=this.getFoldAt(s.row,s.column);if(r){this.expandFold(r);return}(i=this.findMatchingBracket(s))?n.comparePoint(i)==1?n.end=i:(n.start=i,n.start.column++,n.end.column--):(i=this.findMatchingBracket({row:s.row,column:s.column+1}))?(n.comparePoint(i)==1?n.end=i:n.start=i,n.start.column++):n=this.getCommentFoldRange(s.row,s.column)||n}else{var o=this.getFoldsInRange(n);if(e&&o.length){this.expandFolds(o);return}o.length==1&&(r=o[0])}r||(r=this.getFoldAt(n.start.row,n.start.column));if(r&&r.range.toString()==n.toString()){this.expandFold(r);return}var u="...";if(!n.isMultiLine()){u=this.getTextRange(n);if(u.length<4)return;u=u.trim().substring(0,2)+".."}this.addFold(u,n)},this.getCommentFoldRange=function(e,t,n){var i=new o(this,e,t),s=i.getCurrentToken();if(s&&/^comment|string/.test(s.type)){var u=new r,a=new RegExp(s.type.replace(/\..*/,"\\."));if(n!=1){do s=i.stepBackward();while(s&&a.test(s.type));i.stepForward()}u.start.row=i.getCurrentTokenRow(),u.start.column=i.getCurrentTokenColumn()+2,i=new o(this,e,t);if(n!=-1){do s=i.stepForward();while(s&&a.test(s.type));s=i.stepBackward()}else s=i.getCurrentToken();return u.end.row=i.getCurrentTokenRow(),u.end.column=i.getCurrentTokenColumn()+s.value.length-2,u}},this.foldAll=function(e,t){var n=this.foldWidgets;t=t||this.getLength();for(var r=e||0;r<t;r++){n[r]==null&&(n[r]=this.getFoldWidget(r));if(n[r]!="start")continue;var i=this.getFoldWidgetRange(r);if(i&&i.end.row<=t)try{this.addFold("...",i)}catch(s){}}},this.$foldStyles={manual:1,markbegin:1,markbeginend:1},this.$foldStyle="markbegin",this.setFoldStyle=function(e){if(!this.$foldStyles[e])throw new Error("invalid fold style: "+e+"["+Object.keys(this.$foldStyles).join(", ")+"]");if(this.$foldStyle==e)return;this.$foldStyle=e,e=="manual"&&this.unfold();var t=this.$foldMode;this.$setFolding(null),this.$setFolding(t)},this.$setFolding=function(e){if(this.$foldMode==e)return;this.$foldMode=e,this.removeListener("change",this.$updateFoldWidgets),this._emit("changeAnnotation");if(!e||this.$foldStyle=="manual"){this.foldWidgets=null;return}this.foldWidgets=[],this.getFoldWidget=e.getFoldWidget.bind(e,this,this.$foldStyle),this.getFoldWidgetRange=e.getFoldWidgetRange.bind(e,this,this.$foldStyle),this.$updateFoldWidgets=this.updateFoldWidgets.bind(this),this.on("change",this.$updateFoldWidgets)},this.onFoldWidgetClick=function(e,t){t=t.domEvent;var n=this.getFoldWidget(e),r=this.getLine(e),i=t.shiftKey,s=i||t.ctrlKey||t.altKey||t.metaKey,o;n=="end"?o=this.getFoldAt(e,0,-1):o=this.getFoldAt(e,r.length,1);if(o){s?this.removeFold(o):this.expandFold(o);return}var u=this.getFoldWidgetRange(e);if(u){if(!u.isMultiLine()){o=this.getFoldAt(u.start.row,u.start.column,1);if(o&&u.isEqual(o.range)){this.removeFold(o);return}}i||this.addFold("...",u),s&&this.foldAll(u.start.row+1,u.end.row)}else s&&this.foldAll(e+1,this.getLength()),(t.target||t.srcElement).className+=" ace_invalid"},this.updateFoldWidgets=function(e){var t=e.data,n=t.range,r=n.start.row,i=n.end.row-r;if(i===0)this.foldWidgets[r]=null;else if(t.action=="removeText"||t.action=="removeLines")this.foldWidgets.splice(r,i+1,null);else{var s=Array(i+1);s.unshift(r,1),this.foldWidgets.splice.apply(this.foldWidgets,s)}}}var r=e("../range").Range,i=e("./fold_line").FoldLine,s=e("./fold").Fold,o=e("../token_iterator").TokenIterator;t.Folding=u}),ace.define("ace/edit_session/fold_line",["require","exports","module","ace/range"],function(e,t,n){function i(e,t){this.foldData=e,Array.isArray(t)?this.folds=t:t=this.folds=[t];var n=t[t.length-1];this.range=new r(t[0].start.row,t[0].start.column,n.end.row,n.end.column),this.start=this.range.start,this.end=this.range.end,this.folds.forEach(function(e){e.setFoldLine(this)},this)}var r=e("../range").Range;(function(){this.shiftRow=function(e){this.start.row+=e,this.end.row+=e,this.folds.forEach(function(t){t.start.row+=e,t.end.row+=e})},this.addFold=function(e){if(e.sameRow){if(e.start.row<this.startRow||e.endRow>this.endRow)throw"Can't add a fold to this FoldLine as it has no connection";this.folds.push(e),this.folds.sort(function(e,t){return-e.range.compareEnd(t.start.row,t.start.column)}),this.range.compareEnd(e.start.row,e.start.column)>0?(this.end.row=e.end.row,this.end.column=e.end.column):this.range.compareStart(e.end.row,e.end.column)<0&&(this.start.row=e.start.row,this.start.column=e.start.column)}else if(e.start.row==this.end.row)this.folds.push(e),this.end.row=e.end.row,this.end.column=e.end.column;else{if(e.end.row!=this.start.row)throw"Trying to add fold to FoldRow that doesn't have a matching row";this.folds.unshift(e),this.start.row=e.start.row,this.start.column=e.start.column}e.foldLine=this},this.containsRow=function(e){return e>=this.start.row&&e<=this.end.row},this.walk=function(e,t,n){var r=0,i=this.folds,s,o,u,a=!0;t==null&&(t=this.end.row,n=this.end.column);for(var f=0;f<i.length;f++){s=i[f],o=s.range.compareStart(t,n);if(o==-1){e(null,t,n,r,a);return}u=e(null,s.start.row,s.start.column,r,a),u=!u&&e(s.placeholder,s.start.row,s.start.column,r);if(u||o==0)return;a=!s.sameRow,r=s.end.column}e(null,t,n,r,a)},this.getNextFoldTo=function(e,t){var n,r;for(var i=0;i<this.folds.length;i++){n=this.folds[i],r=n.range.compareEnd(e,t);if(r==-1)return{fold:n,kind:"after"};if(r==0)return{fold:n,kind:"inside"}}return null},this.addRemoveChars=function(e,t,n){var r=this.getNextFoldTo(e,t),i,s;if(r){i=r.fold;if(r.kind=="inside"&&i.start.column!=t&&i.start.row!=e)window.console&&window.console.log(e,t,i);else if(i.start.row==e){s=this.folds;var o=s.indexOf(i);o==0&&(this.start.column+=n);for(o;o<s.length;o++){i=s[o],i.start.column+=n;if(!i.sameRow)return;i.end.column+=n}this.end.column+=n}}},this.split=function(e,t){var n=this.getNextFoldTo(e,t).fold,r=this.folds,s=this.foldData;if(!n)return null;var o=r.indexOf(n),u=r[o-1];this.end.row=u.end.row,this.end.column=u.end.column,r=r.splice(o,r.length-o);var a=new i(s,r);return s.splice(s.indexOf(this)+1,0,a),a},this.merge=function(e){var t=e.folds;for(var n=0;n<t.length;n++)this.addFold(t[n]);var r=this.foldData;r.splice(r.indexOf(e),1)},this.toString=function(){var e=[this.range.toString()+": ["];return this.folds.forEach(function(t){e.push(" "+t.toString())}),e.push("]"),e.join("\n")},this.idxToPosition=function(e){var t=0,n;for(var r=0;r<this.folds.length;r++){var n=this.folds[r];e-=n.start.column-t;if(e<0)return{row:n.start.row,column:n.start.column+e};e-=n.placeholder.length;if(e<0)return n.start;t=n.end.column}return{row:this.end.row,column:this.end.column+e}}}).call(i.prototype),t.FoldLine=i}),ace.define("ace/edit_session/fold",["require","exports","module"],function(e,t,n){var r=t.Fold=function(e,t){this.foldLine=null,this.placeholder=t,this.range=e,this.start=e.start,this.end=e.end,this.sameRow=e.start.row==e.end.row,this.subFolds=[]};(function(){this.toString=function(){return'"'+this.placeholder+'" '+this.range.toString()},this.setFoldLine=function(e){this.foldLine=e,this.subFolds.forEach(function(t){t.setFoldLine(e)})},this.clone=function(){var e=this.range.clone(),t=new r(e,this.placeholder);return this.subFolds.forEach(function(e){t.subFolds.push(e.clone())}),t},this.addSubFold=function(e){if(this.range.isEqual(e))return this;if(!this.range.containsRange(e))throw"A fold can't intersect already existing fold"+e.range+this.range;var t=e.range.start.row,n=e.range.start.column;for(var r=0,i=-1;r<this.subFolds.length;r++){i=this.subFolds[r].range.compare(t,n);if(i!=1)break}var s=this.subFolds[r];if(i==0)return s.addSubFold(e);var t=e.range.end.row,n=e.range.end.column;for(var o=r,i=-1;o<this.subFolds.length;o++){i=this.subFolds[o].range.compare(t,n);if(i!=1)break}var u=this.subFolds[o];if(i==0)throw"A fold can't intersect already existing fold"+e.range+this.range;var a=this.subFolds.splice(r,o-r,e);return e.setFoldLine(this.foldLine),e}}).call(r.prototype)}),ace.define("ace/token_iterator",["require","exports","module"],function(e,t,n){var r=function(e,t,n){this.$session=e,this.$row=t,this.$rowTokens=e.getTokens(t);var r=e.getTokenAt(t,n);this.$tokenIndex=r?r.index:-1};(function(){this.stepBackward=function(){this.$tokenIndex-=1;while(this.$tokenIndex<0){this.$row-=1;if(this.$row<0)return this.$row=0,null;this.$rowTokens=this.$session.getTokens(this.$row),this.$tokenIndex=this.$rowTokens.length-1}return this.$rowTokens[this.$tokenIndex]},this.stepForward=function(){var e=this.$session.getLength();this.$tokenIndex+=1;while(this.$tokenIndex>=this.$rowTokens.length){this.$row+=1;if(this.$row>=e)return this.$row=e-1,null;this.$rowTokens=this.$session.getTokens(this.$row),this.$tokenIndex=0}return this.$rowTokens[this.$tokenIndex]},this.getCurrentToken=function(){return this.$rowTokens[this.$tokenIndex]},this.getCurrentTokenRow=function(){return this.$row},this.getCurrentTokenColumn=function(){var e=this.$rowTokens,t=this.$tokenIndex,n=e[t].start;if(n!==undefined)return n;n=0;while(t>0)t-=1,n+=e[t].value.length;return n}}).call(r.prototype),t.TokenIterator=r}),ace.define("ace/edit_session/bracket_match",["require","exports","module","ace/token_iterator","ace/range"],function(e,t,n){function s(){this.findMatchingBracket=function(e,t){if(e.column==0)return null;var n=t||this.getLine(e.row).charAt(e.column-1);if(n=="")return null;var r=n.match(/([\(\[\{])|([\)\]\}])/);return r?r[1]?this.$findClosingBracket(r[1],e):this.$findOpeningBracket(r[2],e):null},this.getBracketRange=function(e){var t=this.getLine(e.row),n=!0,r,s=t.charAt(e.column-1),o=s&&s.match(/([\(\[\{])|([\)\]\}])/);o||(s=t.charAt(e.column),e={row:e.row,column:e.column+1},o=s&&s.match(/([\(\[\{])|([\)\]\}])/),n=!1);if(!o)return null;if(o[1]){var u=this.$findClosingBracket(o[1],e);if(!u)return null;r=i.fromPoints(e,u),n||(r.end.column++,r.start.column--),r.cursor=r.end}else{var u=this.$findOpeningBracket(o[2],e);if(!u)return null;r=i.fromPoints(u,e),n||(r.start.column++,r.end.column--),r.cursor=r.start}return r},this.$brackets={")":"(","(":")","]":"[","[":"]","{":"}","}":"{"},this.$findOpeningBracket=function(e,t,n){var i=this.$brackets[e],s=1,o=new r(this,t.row,t.column),u=o.getCurrentToken();u||(u=o.stepForward());if(!u)return;n||(n=new RegExp("(\\.?"+u.type.replace(".","\\.").replace("rparen",".paren")+")+"));var a=t.column-o.getCurrentTokenColumn()-2,f=u.value;for(;;){while(a>=0){var l=f.charAt(a);if(l==i){s-=1;if(s==0)return{row:o.getCurrentTokenRow(),column:a+o.getCurrentTokenColumn()}}else l==e&&(s+=1);a-=1}do u=o.stepBackward();while(u&&!n.test(u.type));if(u==null)break;f=u.value,a=f.length-1}return null},this.$findClosingBracket=function(e,t,n){var i=this.$brackets[e],s=1,o=new r(this,t.row,t.column),u=o.getCurrentToken();u||(u=o.stepForward());if(!u)return;n||(n=new RegExp("(\\.?"+u.type.replace(".","\\.").replace("lparen",".paren")+")+"));var a=t.column-o.getCurrentTokenColumn();for(;;){var f=u.value,l=f.length;while(a<l){var c=f.charAt(a);if(c==i){s-=1;if(s==0)return{row:o.getCurrentTokenRow(),column:a+o.getCurrentTokenColumn()}}else c==e&&(s+=1);a+=1}do u=o.stepForward();while(u&&!n.test(u.type));if(u==null)break;a=0}return null}}var r=e("../token_iterator").TokenIterator,i=e("../range").Range;t.BracketMatch=s}),ace.define("ace/search",["require","exports","module","ace/lib/lang","ace/lib/oop","ace/range"],function(e,t,n){var r=e("./lib/lang"),i=e("./lib/oop"),s=e("./range").Range,o=function(){this.$options={}};(function(){this.set=function(e){return i.mixin(this.$options,e),this},this.getOptions=function(){return r.copyObject(this.$options)},this.setOptions=function(e){this.$options=e},this.find=function(e){var t=this.$matchIterator(e,this.$options);if(!t)return!1;var n=null;return t.forEach(function(e,t,r){if(!e.start){var i=e.offset+(r||0);n=new s(t,i,t,i+e.length)}else n=e;return!0}),n},this.findAll=function(e){var t=this.$options;if(!t.needle)return[];this.$assembleRegExp(t);var n=t.range,i=n?e.getLines(n.start.row,n.end.row):e.doc.getAllLines(),o=[],u=t.re;if(t.$isMultiLine){var a=u.length,f=i.length-a;for(var l=u.offset||0;l<=f;l++){for(var c=0;c<a;c++)if(i[l+c].search(u[c])==-1)break;var h=i[l],p=i[l+a-1],d=h.match(u[0])[0].length,v=p.match(u[a-1])[0].length;o.push(new s(l,h.length-d,l+a-1,v))}}else for(var m=0;m<i.length;m++){var g=r.getMatchOffsets(i[m],u);for(var c=0;c<g.length;c++){var y=g[c];o.push(new s(m,y.offset,m,y.offset+y.length))}}if(n){var b=n.start.column,w=n.start.column,m=0,c=o.length-1;while(m<c&&o[m].start.column<b&&o[m].start.row==n.start.row)m++;while(m<c&&o[c].end.column>w&&o[c].end.row==n.end.row)c--;return o.slice(m,c+1)}return o},this.replace=function(e,t){var n=this.$options,r=this.$assembleRegExp(n);if(n.$isMultiLine)return t;if(!r)return;var i=r.exec(e);if(!i||i[0].length!=e.length)return null;t=e.replace(r,t);if(n.preserveCase){t=t.split("");for(var s=Math.min(e.length,e.length);s--;){var o=e[s];o&&o.toLowerCase()!=o?t[s]=t[s].toUpperCase():t[s]=t[s].toLowerCase()}t=t.join("")}return t},this.$matchIterator=function(e,t){var n=this.$assembleRegExp(t);if(!n)return!1;var i=this,o,u=t.backwards;if(t.$isMultiLine)var a=n.length,f=function(t,r,i){var u=t.search(n[0]);if(u==-1)return;for(var f=1;f<a;f++){t=e.getLine(r+f);if(t.search(n[f])==-1)return}var l=t.match(n[a-1])[0].length,c=new s(r,u,r+a-1,l);n.offset==1?(c.start.row--,c.start.column=Number.MAX_VALUE):i&&(c.start.column+=i);if(o(c))return!0};else if(u)var f=function(e,t,i){var s=r.getMatchOffsets(e,n);for(var u=s.length-1;u>=0;u--)if(o(s[u],t,i))return!0};else var f=function(e,t,i){var s=r.getMatchOffsets(e,n);for(var u=0;u<s.length;u++)if(o(s[u],t,i))return!0};return{forEach:function(n){o=n,i.$lineIterator(e,t).forEach(f)}}},this.$assembleRegExp=function(e){if(e.needle instanceof RegExp)return e.re=e.needle;var t=e.needle;if(!e.needle)return e.re=!1;e.regExp||(t=r.escapeRegExp(t)),e.wholeWord&&(t="\\b"+t+"\\b");var n=e.caseSensitive?"g":"gi";e.$isMultiLine=/[\n\r]/.test(t);if(e.$isMultiLine)return e.re=this.$assembleMultilineRegExp(t,n);try{var i=new RegExp(t,n)}catch(s){i=!1}return e.re=i},this.$assembleMultilineRegExp=function(e,t){var n=e.replace(/\r\n|\r|\n/g,"$\n^").split("\n"),r=[];for(var i=0;i<n.length;i++)try{r.push(new RegExp(n[i],t))}catch(s){return!1}return n[0]==""?(r.shift(),r.offset=1):r.offset=0,r},this.$lineIterator=function(e,t){var n=t.backwards==1,r=t.skipCurrent!=0,i=t.range,s=t.start;s||(s=i?i[n?"end":"start"]:e.selection.getRange()),s.start&&(s=s[r!=n?"end":"start"]);var o=i?i.start.row:0,u=i?i.end.row:e.getLength()-1,a=n?function(n){var r=s.row,i=e.getLine(r).substring(0,s.column);if(n(i,r))return;for(r--;r>=o;r--)if(n(e.getLine(r),r))return;if(t.wrap==0)return;for(r=u,o=s.row;r>=o;r--)if(n(e.getLine(r),r))return}:function(n){var r=s.row,i=e.getLine(r).substr(s.column);if(n(i,r,s.column))return;for(r+=1;r<=u;r++)if(n(e.getLine(r),r))return;if(t.wrap==0)return;for(r=o,u=s.row;r<=u;r++)if(n(e.getLine(r),r))return};return{forEach:a}}}).call(o.prototype),t.Search=o}),ace.define("ace/commands/command_manager",["require","exports","module","ace/lib/oop","ace/keyboard/hash_handler","ace/lib/event_emitter"],function(e,t,n){var r=e("../lib/oop"),i=e("../keyboard/hash_handler").HashHandler,s=e("../lib/event_emitter").EventEmitter,o=function(e,t){this.platform=e,this.commands=this.byName={},this.commmandKeyBinding={},this.addCommands(t),this.setDefaultHandler("exec",function(e){return e.command.exec(e.editor,e.args||{})})};r.inherits(o,i),function(){r.implement(this,s),this.exec=function(e,t,n){typeof e=="string"&&(e=this.commands[e]);if(!e)return!1;if(t&&t.$readOnly&&!e.readOnly)return!1;var r=this._emit("exec",{editor:t,command:e,args:n});return r===!1?!1:!0},this.toggleRecording=function(e){if(this.$inReplay)return;return e&&e._emit("changeStatus"),this.recording?(this.macro.pop(),this.removeEventListener("exec",this.$addCommandToMacro),this.macro.length||(this.macro=this.oldMacro),this.recording=!1):(this.$addCommandToMacro||(this.$addCommandToMacro=function(e){this.macro.push([e.command,e.args])}.bind(this)),this.oldMacro=this.macro,this.macro=[],this.on("exec",this.$addCommandToMacro),this.recording=!0)},this.replay=function(e){if(this.$inReplay||!this.macro)return;if(this.recording)return this.toggleRecording(e);try{this.$inReplay=!0,this.macro.forEach(function(t){typeof t=="string"?this.exec(t,e):this.exec(t[0],e,t[1])},this)}finally{this.$inReplay=!1}},this.trimMacro=function(e){return e.map(function(e){return typeof e[0]!="string"&&(e[0]=e[0].name),e[1]||(e=e[0]),e})}}.call(o.prototype),t.CommandManager=o}),ace.define("ace/keyboard/hash_handler",["require","exports","module","ace/lib/keys"],function(e,t,n){function i(e,t){this.platform=t,this.commands={},this.commmandKeyBinding={},this.addCommands(e)}var r=e("../lib/keys");(function(){this.addCommand=function(e){this.commands[e.name]&&this.removeCommand(e),this.commands[e.name]=e,e.bindKey&&this._buildKeyHash(e)},this.removeCommand=function(e){var t=typeof e=="string"?e:e.name;e=this.commands[t],delete this.commands[t];var n=this.commmandKeyBinding;for(var r in n)for(var i in n[r])n[r][i]==e&&delete n[r][i]},this.bindKey=function(e,t){if(!e)return;if(typeof t=="function"){this.addCommand({exec:t,bindKey:e,name:e});return}var n=this.commmandKeyBinding;e.split("|").forEach(function(e){var r=this.parseKeys(e,t),i=r.hashId;(n[i]||(n[i]={}))[r.key]=t},this)},this.addCommands=function(e){e&&Object.keys(e).forEach(function(t){var n=e[t];if(typeof n=="string")return this.bindKey(n,t);typeof n=="function"&&(n={exec:n}),n.name||(n.name=t),this.addCommand(n)},this)},this.removeCommands=function(e){Object.keys(e).forEach(function(t){this.removeCommand(e[t])},this)},this.bindKeys=function(e){Object.keys(e).forEach(function(t){this.bindKey(t,e[t])},this)},this._buildKeyHash=function(e){var t=e.bindKey;if(!t)return;var n=typeof t=="string"?t:t[this.platform];this.bindKey(n,e)},this.parseKeys=function(e){var t=e.toLowerCase().split(/[\-\+]([\-\+])?/).filter(function(e){return e}),n=t.pop(),i=r[n];if(r.FUNCTION_KEYS[i])n=r.FUNCTION_KEYS[i].toLowerCase();else{if(!t.length)return{key:n,hashId:-1};if(t.length==1&&t[0]=="shift")return{key:n.toUpperCase(),hashId:-1}}var s=0;for(var o=t.length;o--;){var u=r.KEY_MODS[t[o]];if(u==null)throw"invalid modifier "+t[o]+" in "+e;s|=u}return{key:n,hashId:s}},this.findKeyCommand=function(t,n){var r=this.commmandKeyBinding;return r[t]&&r[t][n]},this.handleKeyboard=function(e,t,n,r){return{command:this.findKeyCommand(t,n)}}}).call(i.prototype),t.HashHandler=i}),ace.define("ace/commands/default_commands",["require","exports","module","ace/lib/lang"],function(e,t,n){function i(e,t){return{win:e,mac:t}}var r=e("../lib/lang");t.commands=[{name:"selectall",bindKey:i("Ctrl-A","Command-A"),exec:function(e){e.selectAll()},readOnly:!0},{name:"centerselection",bindKey:i(null,"Ctrl-L"),exec:function(e){e.centerSelection()},readOnly:!0},{name:"gotoline",bindKey:i("Ctrl-L","Command-L"),exec:function(e){var t=parseInt(prompt("Enter line number:"),10);isNaN(t)||e.gotoLine(t)},readOnly:!0},{name:"fold",bindKey:i("Alt-L|Ctrl-F1","Command-Alt-L|Command-F1"),exec:function(e){e.session.toggleFold(!1)},readOnly:!0},{name:"unfold",bindKey:i("Alt-Shift-L|Ctrl-Shift-F1","Command-Alt-Shift-L|Command-Shift-F1"),exec:function(e){e.session.toggleFold(!0)},readOnly:!0},{name:"foldall",bindKey:i("Alt-0","Command-Option-0"),exec:function(e){e.session.foldAll()},readOnly:!0},{name:"unfoldall",bindKey:i("Alt-Shift-0","Command-Option-Shift-0"),exec:function(e){e.session.unfold()},readOnly:!0},{name:"findnext",bindKey:i("Ctrl-K","Command-G"),exec:function(e){e.findNext()},readOnly:!0},{name:"findprevious",bindKey:i("Ctrl-Shift-K","Command-Shift-G"),exec:function(e){e.findPrevious()},readOnly:!0},{name:"find",bindKey:i("Ctrl-F","Command-F"),exec:function(e){var t=prompt("Find:",e.getCopyText());e.find(t)},readOnly:!0},{name:"overwrite",bindKey:"Insert",exec:function(e){e.toggleOverwrite()},readOnly:!0},{name:"selecttostart",bindKey:i("Ctrl-Shift-Home","Command-Shift-Up"),exec:function(e){e.getSelection().selectFileStart()},multiSelectAction:"forEach",readOnly:!0},{name:"gotostart",bindKey:i("Ctrl-Home","Command-Home|Command-Up"),exec:function(e){e.navigateFileStart()},multiSelectAction:"forEach",readOnly:!0},{name:"selectup",bindKey:i("Shift-Up","Shift-Up"),exec:function(e){e.getSelection().selectUp()},multiSelectAction:"forEach",readOnly:!0},{name:"golineup",bindKey:i("Up","Up|Ctrl-P"),exec:function(e,t){e.navigateUp(t.times)},multiSelectAction:"forEach",readOnly:!0},{name:"selecttoend",bindKey:i("Ctrl-Shift-End","Command-Shift-Down"),exec:function(e){e.getSelection().selectFileEnd()},multiSelectAction:"forEach",readOnly:!0},{name:"gotoend",bindKey:i("Ctrl-End","Command-End|Command-Down"),exec:function(e){e.navigateFileEnd()},multiSelectAction:"forEach",readOnly:!0},{name:"selectdown",bindKey:i("Shift-Down","Shift-Down"),exec:function(e){e.getSelection().selectDown()},multiSelectAction:"forEach",readOnly:!0},{name:"golinedown",bindKey:i("Down","Down|Ctrl-N"),exec:function(e,t){e.navigateDown(t.times)},multiSelectAction:"forEach",readOnly:!0},{name:"selectwordleft",bindKey:i("Ctrl-Shift-Left","Option-Shift-Left"),exec:function(e){e.getSelection().selectWordLeft()},multiSelectAction:"forEach",readOnly:!0},{name:"gotowordleft",bindKey:i("Ctrl-Left","Option-Left"),exec:function(e){e.navigateWordLeft()},multiSelectAction:"forEach",readOnly:!0},{name:"selecttolinestart",bindKey:i("Alt-Shift-Left","Command-Shift-Left"),exec:function(e){e.getSelection().selectLineStart()},multiSelectAction:"forEach",readOnly:!0},{name:"gotolinestart",bindKey:i("Alt-Left|Home","Command-Left|Home|Ctrl-A"),exec:function(e){e.navigateLineStart()},multiSelectAction:"forEach",readOnly:!0},{name:"selectleft",bindKey:i("Shift-Left","Shift-Left"),exec:function(e){e.getSelection().selectLeft()},multiSelectAction:"forEach",readOnly:!0},{name:"gotoleft",bindKey:i("Left","Left|Ctrl-B"),exec:function(e,t){e.navigateLeft(t.times)},multiSelectAction:"forEach",readOnly:!0},{name:"selectwordright",bindKey:i("Ctrl-Shift-Right","Option-Shift-Right"),exec:function(e){e.getSelection().selectWordRight()},multiSelectAction:"forEach",readOnly:!0},{name:"gotowordright",bindKey:i("Ctrl-Right","Option-Right"),exec:function(e){e.navigateWordRight()},multiSelectAction:"forEach",readOnly:!0},{name:"selecttolineend",bindKey:i("Alt-Shift-Right","Command-Shift-Right"),exec:function(e){e.getSelection().selectLineEnd()},multiSelectAction:"forEach",readOnly:!0},{name:"gotolineend",bindKey:i("Alt-Right|End","Command-Right|End|Ctrl-E"),exec:function(e){e.navigateLineEnd()},multiSelectAction:"forEach",readOnly:!0},{name:"selectright",bindKey:i("Shift-Right","Shift-Right"),exec:function(e){e.getSelection().selectRight()},multiSelectAction:"forEach",readOnly:!0},{name:"gotoright",bindKey:i("Right","Right|Ctrl-F"),exec:function(e,t){e.navigateRight(t.times)},multiSelectAction:"forEach",readOnly:!0},{name:"selectpagedown",bindKey:"Shift-PageDown",exec:function(e){e.selectPageDown()},readOnly:!0},{name:"pagedown",bindKey:i(null,"Option-PageDown"),exec:function(e){e.scrollPageDown()},readOnly:!0},{name:"gotopagedown",bindKey:i("PageDown","PageDown|Ctrl-V"),exec:function(e){e.gotoPageDown()},readOnly:!0},{name:"selectpageup",bindKey:"Shift-PageUp",exec:function(e){e.selectPageUp()},readOnly:!0},{name:"pageup",bindKey:i(null,"Option-PageUp"),exec:function(e){e.scrollPageUp()},readOnly:!0},{name:"gotopageup",bindKey:"PageUp",exec:function(e){e.gotoPageUp()},readOnly:!0},{name:"scrollup",bindKey:i("Ctrl-Up",null),exec:function(e){e.renderer.scrollBy(0,-2*e.renderer.layerConfig.lineHeight)},readOnly:!0},{name:"scrolldown",bindKey:i("Ctrl-Down",null),exec:function(e){e.renderer.scrollBy(0,2*e.renderer.layerConfig.lineHeight)},readOnly:!0},{name:"selectlinestart",bindKey:"Shift-Home",exec:function(e){e.getSelection().selectLineStart()},multiSelectAction:"forEach",readOnly:!0},{name:"selectlineend",bindKey:"Shift-End",exec:function(e){e.getSelection().selectLineEnd()},multiSelectAction:"forEach",readOnly:!0},{name:"togglerecording",bindKey:i("Ctrl-Alt-E","Command-Option-E"),exec:function(e){e.commands.toggleRecording(e)},readOnly:!0},{name:"replaymacro",bindKey:i("Ctrl-Shift-E","Command-Shift-E"),exec:function(e){e.commands.replay(e)},readOnly:!0},{name:"jumptomatching",bindKey:i("Ctrl-P","Ctrl-Shift-P"),exec:function(e){e.jumpToMatching()},multiSelectAction:"forEach",readOnly:!0},{name:"selecttomatching",bindKey:i("Ctrl-Shift-P",null),exec:function(e){e.jumpToMatching(!0)},readOnly:!0},{name:"cut",exec:function(e){var t=e.getSelectionRange();e._emit("cut",t),e.selection.isEmpty()||(e.session.remove(t),e.clearSelection())},multiSelectAction:"forEach"},{name:"removeline",bindKey:i("Ctrl-D","Command-D"),exec:function(e){e.removeLines()},multiSelectAction:"forEach"},{name:"duplicateSelection",bindKey:i("Ctrl-Shift-D","Command-Shift-D"),exec:function(e){e.duplicateSelection()},multiSelectAction:"forEach"},{name:"sortlines",bindKey:i("Ctrl-Alt-S","Command-Alt-S"),exec:function(e){e.sortLines()},multiSelectAction:"forEach"},{name:"togglecomment",bindKey:i("Ctrl-/","Command-/"),exec:function(e){e.toggleCommentLines()},multiSelectAction:"forEach"},{name:"modifyNumberUp",bindKey:i("Ctrl-Shift-Up","Alt-Shift-Up"),exec:function(e){e.modifyNumber(1)},multiSelectAction:"forEach"},{name:"modifyNumberDown",bindKey:i("Ctrl-Shift-Down","Alt-Shift-Down"),exec:function(e){e.modifyNumber(-1)},multiSelectAction:"forEach"},{name:"replace",bindKey:i("Ctrl-R","Command-Option-F"),exec:function(e){var t=prompt("Find:",e.getCopyText());if(!t)return;var n=prompt("Replacement:");if(!n)return;e.replace(n,{needle:t})}},{name:"replaceall",bindKey:i("Ctrl-Shift-R","Command-Shift-Option-F"),exec:function(e){var t=prompt("Find:");if(!t)return;var n=prompt("Replacement:");if(!n)return;e.replaceAll(n,{needle:t})}},{name:"undo",bindKey:i("Ctrl-Z","Command-Z"),exec:function(e){e.undo()}},{name:"redo",bindKey:i("Ctrl-Shift-Z|Ctrl-Y","Command-Shift-Z|Command-Y"),exec:function(e){e.redo()}},{name:"copylinesup",bindKey:i("Alt-Shift-Up","Command-Option-Up"),exec:function(e){e.copyLinesUp()}},{name:"movelinesup",bindKey:i("Alt-Up","Option-Up"),exec:function(e){e.moveLinesUp()}},{name:"copylinesdown",bindKey:i("Alt-Shift-Down","Command-Option-Down"),exec:function(e){e.copyLinesDown()}},{name:"movelinesdown",bindKey:i("Alt-Down","Option-Down"),exec:function(e){e.moveLinesDown()}},{name:"del",bindKey:i("Delete","Delete|Ctrl-D"),exec:function(e){e.remove("right")},multiSelectAction:"forEach"},{name:"backspace",bindKey:i("Command-Backspace|Option-Backspace|Shift-Backspace|Backspace","Ctrl-Backspace|Command-Backspace|Shift-Backspace|Backspace|Ctrl-H"),exec:function(e){e.remove("left")},multiSelectAction:"forEach"},{name:"removetolinestart",bindKey:i("Alt-Backspace","Command-Backspace"),exec:function(e){e.removeToLineStart()},multiSelectAction:"forEach"},{name:"removetolineend",bindKey:i("Alt-Delete","Ctrl-K"),exec:function(e){e.removeToLineEnd()},multiSelectAction:"forEach"},{name:"removewordleft",bindKey:i("Ctrl-Backspace","Alt-Backspace|Ctrl-Alt-Backspace"),exec:function(e){e.removeWordLeft()},multiSelectAction:"forEach"},{name:"removewordright",bindKey:i("Ctrl-Delete","Alt-Delete"),exec:function(e){e.removeWordRight()},multiSelectAction:"forEach"},{name:"outdent",bindKey:i("Shift-Tab","Shift-Tab"),exec:function(e){e.blockOutdent()},multiSelectAction:"forEach"},{name:"indent",bindKey:i("Tab","Tab"),exec:function(e){e.indent()},multiSelectAction:"forEach"},{name:"insertstring",exec:function(e,t){e.insert(t)},multiSelectAction:"forEach"},{name:"inserttext",exec:function(e,t){e.insert(r.stringRepeat(t.text||"",t.times||1))},multiSelectAction:"forEach"},{name:"splitline",bindKey:i(null,"Ctrl-O"),exec:function(e){e.splitLine()},multiSelectAction:"forEach"},{name:"transposeletters",bindKey:i("Ctrl-T","Ctrl-T"),exec:function(e){e.transposeLetters()},multiSelectAction:function(e){e.transposeSelections(1)}},{name:"touppercase",bindKey:i("Ctrl-U","Ctrl-U"),exec:function(e){e.toUpperCase()},multiSelectAction:"forEach"},{name:"tolowercase",bindKey:i("Ctrl-Shift-U","Ctrl-Shift-U"),exec:function(e){e.toLowerCase()},multiSelectAction:"forEach"}]}),ace.define("ace/undomanager",["require","exports","module"],function(e,t,n){var r=function(){this.reset()};(function(){this.execute=function(e){var t=e.args[0];this.$doc=e.args[1],this.$undoStack.push(t),this.$redoStack=[]},this.undo=function(e){var t=this.$undoStack.pop(),n=null;return t&&(n=this.$doc.undoChanges(t,e),this.$redoStack.push(t)),n},this.redo=function(e){var t=this.$redoStack.pop(),n=null;return t&&(n=this.$doc.redoChanges(t,e),this.$undoStack.push(t)),n},this.reset=function(){this.$undoStack=[],this.$redoStack=[]},this.hasUndo=function(){return this.$undoStack.length>0},this.hasRedo=function(){return this.$redoStack.length>0}}).call(r.prototype),t.UndoManager=r}),ace.define("ace/virtual_renderer",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/event","ace/lib/useragent","ace/config","ace/lib/net","ace/layer/gutter","ace/layer/marker","ace/layer/text","ace/layer/cursor","ace/scrollbar","ace/renderloop","ace/lib/event_emitter"],function(e,t,n){var r=e("./lib/oop"),i=e("./lib/dom"),s=e("./lib/event"),o=e("./lib/useragent"),u=e("./config"),a=e("./lib/net"),f=e("./layer/gutter").Gutter,l=e("./layer/marker").Marker,c=e("./layer/text").Text,h=e("./layer/cursor").Cursor,p=e("./scrollbar").ScrollBar,d=e("./renderloop").RenderLoop,v=e("./lib/event_emitter").EventEmitter,m=".ace_editor {position: absolute;overflow: hidden;font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;font-size: 12px;}.ace_scroller {position: absolute;overflow: hidden;}.ace_content {position: absolute;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;cursor: text;}.ace_gutter {position: absolute;overflow : hidden;height: 100%;width: auto;cursor: default;z-index: 4;}.ace_gutter-active-line {position: absolute;left: 0;right: 0;}.ace_scroller.ace_scroll-left {box-shadow: 17px 0 16px -16px rgba(0, 0, 0, 0.4) inset;}.ace_gutter-cell {padding-left: 19px;padding-right: 6px;background-repeat: no-repeat;}.ace_gutter-cell.ace_error {background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QUM2OEZDQTQ4RTU0MTFFMUEzM0VFRTM2RUY1M0RBMjYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QUM2OEZDQTU4RTU0MTFFMUEzM0VFRTM2RUY1M0RBMjYiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpBQzY4RkNBMjhFNTQxMUUxQTMzRUVFMzZFRjUzREEyNiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpBQzY4RkNBMzhFNTQxMUUxQTMzRUVFMzZFRjUzREEyNiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PkgXxbAAAAJbSURBVHjapFNNaBNBFH4zs5vdZLP5sQmNpT82QY209heh1ioWisaDRcSKF0WKJ0GQnrzrxasHsR6EnlrwD0TagxJabaVEpFYxLWlLSS822tr87m66ccfd2GKyVhA6MMybgfe97/vmPUQphd0sZjto9XIn9OOsvlu2nkqRzVU+6vvlzPf8W6bk8dxQ0NPbxAALgCgg2JkaQuhzQau/El0zbmUA7U0Es8v2CiYmKQJHGO1QICCLoqilMhkmurDAyapKgqItezi/USRdJqEYY4D5jCy03ht2yMkkvL91jTTX10qzyyu2hruPRN7jgbH+EOsXcMLgYiThEgAMhABW85oqy1DXdRIdvP1AHJ2acQXvDIrVHcdQNrEKNYSVMSZGMjEzIIAwDXIo+6G/FxcGnzkC3T2oMhLjre49sBB+RRcHLqdafK6sYdE/GGBwU1VpFNj0aN8pJbe+BkZyevUrvLl6Xmm0W9IuTc0DxrDNAJd5oEvI/KRsNC3bQyNjPO9yQ1YHcfj2QvfQc/5TUhJTBc2iM0U7AWDQtc1nJHvD/cfO2s7jaGkiTEfa/Ep8coLu7zmNmh8+dc5lZDuUeFAGUNA/OY6JVaypQ0vjr7XYjUvJM37vt+j1vuTK5DgVfVUoTjVe+y3/LxMxY2GgU+CSLy4cpfsYorRXuXIOi0Vt40h67uZFTdIo6nLaZcwUJWAzwNS0tBnqqKzQDnjdG/iPyZxo46HaKUpbvYkj8qYRTZsBhge+JHhZyh0x9b95JqjVJkT084kZIPwu/mPWqPgfQ5jXh2+92Ay7HedfAgwA6KDWafb4w3cAAAAASUVORK5CYII=\");background-repeat: no-repeat;background-position: 2px center;}.ace_gutter-cell.ace_warning {background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QUM2OEZDQTg4RTU0MTFFMUEzM0VFRTM2RUY1M0RBMjYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QUM2OEZDQTk4RTU0MTFFMUEzM0VFRTM2RUY1M0RBMjYiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpBQzY4RkNBNjhFNTQxMUUxQTMzRUVFMzZFRjUzREEyNiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpBQzY4RkNBNzhFNTQxMUUxQTMzRUVFMzZFRjUzREEyNiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pgd7PfIAAAGmSURBVHjaYvr//z8DJZiJgUIANoCRkREb9gLiSVAaQx4OQM7AAkwd7XU2/v++/rOttdYGEB9dASEvOMydGKfH8Gv/p4XTkvRBfLxeQAP+1cUhXopyvzhP7P/IoSj7g7Mw09cNKO6J1QQ0L4gICPIv/veg/8W+JdFvQNLHVsW9/nmn9zk7B+cCkDwhL7gt6knSZnx9/LuCEOcvkIAMP+cvto9nfqyZmmUAksfnBUtbM60gX/3/kgyv3/xSFOL5DZT+L8vP+Yfh5cvfPvp/xUHyQHXGyAYwgpwBjZYFT3Y1OEl/OfCH4ffv3wzc4iwMvNIsDJ+f/mH4+vIPAxsb631WW0Yln6ZpQLXdMK/DXGDflh+sIv37EivD5x//Gb7+YWT4y86sl7BCCkSD+Z++/1dkvsFRl+HnD1Rvje4F8whjMXmGj58YGf5zsDMwcnAwfPvKcml62DsQDeaDxN+/Y0qwlpEHqrdB94IRNIDUgfgfKJChGK4OikEW3gTiXUB950ASLFAF54AC94A0G9QAfOnmF9DCDzABFqS08IHYDIScdijOjQABBgC+/9awBH96jwAAAABJRU5ErkJggg==\");background-position: 2px center;}.ace_gutter-cell.ace_info {background-image: url(\"data:image/gif;base64,R0lGODlhEAAQAMQAAAAAAEFBQVJSUl5eXmRkZGtra39/f4WFhYmJiZGRkaampry8vMPDw8zMzNXV1dzc3OTk5Orq6vDw8P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABQALAAAAAAQABAAAAUuICWOZGmeaBml5XGwFCQSBGyXRSAwtqQIiRuiwIM5BoYVbEFIyGCQoeJGrVptIQA7\");background-position: 2px center;}.ace_dark .ace_gutter-cell.ace_info {background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpGRTk5MTVGREIxNDkxMUUxOTc5Q0FFREQyMTNGMjBFQyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpGRTk5MTVGRUIxNDkxMUUxOTc5Q0FFREQyMTNGMjBFQyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkZFOTkxNUZCQjE0OTExRTE5NzlDQUVERDIxM0YyMEVDIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkZFOTkxNUZDQjE0OTExRTE5NzlDQUVERDIxM0YyMEVDIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+SIDkjAAAAJ1JREFUeNpi/P//PwMlgImBQkB7A6qrq/+DMC55FkIGKCoq4pVnpFkgTp069f/+/fv/r1u37r+tre1/kg0A+ptn9uzZYLaRkRHpLvjw4cNXWVlZhufPnzOcO3eOdAO0tbVPAjHDmzdvGA4fPsxIsgGSkpJmv379Ynj37h2DjIyMCMkG3LhxQ/T27dsMampqDHZ2dq/pH41DxwCAAAMAFdc68dUsFZgAAAAASUVORK5CYII=\");}.ace_scrollbar {position: absolute;overflow-x: hidden;overflow-y: scroll;right: 0;}.ace_scrollbar-inner {position: absolute;width: 1px;left: 0;}.ace_print-margin {position: absolute;height: 100%;}.ace_text-input {position: absolute;z-index: 0;width: 0.5em;height: 1em;opacity: 0;background: transparent;-moz-appearance: none;appearance: none;border: none;resize: none;outline: none;overflow: hidden;}.ace_text-input.ace_composition {background: #fff;color: #000;z-index: 1000;opacity: 1;border: solid lightgray 1px;margin: -1px}.ace_layer {z-index: 1;position: absolute;overflow: hidden;white-space: nowrap;height: 100%;width: 100%;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;/* setting pointer-events: auto; on node under the mouse, which changesduring scroll, will break mouse wheel scrolling in Safari */pointer-events: none;}.ace_gutter-layer {position: relative;width: auto;text-align: right;pointer-events: auto;}.ace_text-layer {color: black;font: inherit !important;}.ace_cjk {display: inline-block;text-align: center;}.ace_cursor-layer {z-index: 4;}.ace_cursor {z-index: 4;position: absolute;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;}.ace_hidden-cursors .ace_cursor {opacity: 0.2;}.ace_smooth-blinking .ace_cursor {-moz-transition: opacity 0.18s;-webkit-transition: opacity 0.18s;-o-transition: opacity 0.18s;-ms-transition: opacity 0.18s;transition: opacity 0.18s;}.ace_cursor[style*=\"opacity: 0\"]{-ms-filter: \"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)\";}.ace_editor.ace_multiselect .ace_cursor {border-left-width: 1px;}.ace_line {white-space: nowrap;}.ace_marker-layer .ace_step {position: absolute;z-index: 3;}.ace_marker-layer .ace_selection {position: absolute;z-index: 5;}.ace_marker-layer .ace_bracket {position: absolute;z-index: 6;}.ace_marker-layer .ace_active-line {position: absolute;z-index: 2;}.ace_marker-layer .ace_selected-word {position: absolute;z-index: 4;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;}.ace_line .ace_fold {-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;display: inline-block;height: 11px;margin-top: -2px;vertical-align: middle;background-image:url(\"data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%11%00%00%00%09%08%06%00%00%00%D4%E8%C7%0C%00%00%03%1EiCCPICC%20Profile%00%00x%01%85T%DFk%D3P%14%FE%DAe%9D%B0%E1%8B%3Ag%11%09%3Eh%91ndStC%9C%B6kW%BA%CDZ%EA6%B7!H%9B%A6m%5C%9A%C6%24%ED~%B0%07%D9%8Bo%3A%C5w%F1%07%3E%F9%07%0C%D9%83o%7B%92%0D%C6%14a%F8%AC%88%22L%F6%22%B3%9E%9B4M'S%03%B9%F7%BB%DF%F9%EE9'%E7%E4%5E%A0%F9qZ%D3%14%2F%0F%14USO%C5%C2%FC%C4%E4%14%DF%F2%01%5E%1CC%2B%FChM%8B%86%16J%26G%40%0F%D3%B2y%EF%B3%F3%0E%1E%C6lt%EEo%DF%AB%FEc%D5%9A%95%0C%11%F0%1C%20%BE%945%C4%22%E1Y%A0i%5C%D4t%13%E0%D6%89%EF%9D15%C2%CDLsX%A7%04%09%1Fg8oc%81%E1%8C%8D%23%96f45%40%9A%09%C2%07%C5B%3AK%B8%408%98i%E0%F3%0D%D8%CE%81%14%E4'%26%A9%92.%8B%3C%ABER%2F%E5dE%B2%0C%F6%F0%1Fs%83%F2_%B0%A8%94%E9%9B%AD%E7%10%8Dm%9A%19N%D1%7C%8A%DE%1F9%7Dp%8C%E6%00%D5%C1%3F_%18%BDA%B8%9DpX6%E3%A35~B%CD%24%AE%11%26%BD%E7%EEti%98%EDe%9A%97Y)%12%25%1C%24%BCbT%AE3li%E6%0B%03%89%9A%E6%D3%ED%F4P%92%B0%9F4%BF43Y%F3%E3%EDP%95%04%EB1%C5%F5%F6KF%F4%BA%BD%D7%DB%91%93%07%E35%3E%A7)%D6%7F%40%FE%BD%F7%F5r%8A%E5y%92%F0%EB%B4%1E%8D%D5%F4%5B%92%3AV%DB%DB%E4%CD%A6%23%C3%C4wQ%3F%03HB%82%8E%1Cd(%E0%91B%0Ca%9Ac%C4%AA%F8L%16%19%22J%A4%D2itTy%B28%D6%3B(%93%96%ED%1CGx%C9_%0E%B8%5E%16%F5%5B%B2%B8%F6%E0%FB%9E%DD%25%D7%8E%BC%15%85%C5%B7%A3%D8Q%ED%B5%81%E9%BA%B2%13%9A%1B%7Fua%A5%A3n%E17%B9%E5%9B%1Bm%AB%0B%08Q%FE%8A%E5%B1H%5Ee%CAO%82Q%D7u6%E6%90S%97%FCu%0B%CF2%94%EE%25v%12X%0C%BA%AC%F0%5E%F8*l%0AO%85%17%C2%97%BF%D4%C8%CE%DE%AD%11%CB%80q%2C%3E%AB%9ES%CD%C6%EC%25%D2L%D2%EBd%B8%BF%8A%F5B%C6%18%F9%901CZ%9D%BE%24M%9C%8A9%F2%DAP%0B'%06w%82%EB%E6%E2%5C%2F%D7%07%9E%BB%CC%5D%E1%FA%B9%08%AD.r%23%8E%C2%17%F5E%7C!%F0%BE3%BE%3E_%B7o%88a%A7%DB%BE%D3d%EB%A31Z%EB%BB%D3%91%BA%A2%B1z%94%8F%DB'%F6%3D%8E%AA%13%19%B2%B1%BE%B1~V%08%2B%B4%A2cjJ%B3tO%00%03%25mN%97%F3%05%93%EF%11%84%0B%7C%88%AE-%89%8F%ABbW%90O%2B%0Ao%99%0C%5E%97%0CI%AFH%D9.%B0%3B%8F%ED%03%B6S%D6%5D%E6i_s9%F3*p%E9%1B%FD%C3%EB.7U%06%5E%19%C0%D1s.%17%A03u%E4%09%B0%7C%5E%2C%EB%15%DB%1F%3C%9E%B7%80%91%3B%DBc%AD%3Dma%BA%8B%3EV%AB%DBt.%5B%1E%01%BB%0F%AB%D5%9F%CF%AA%D5%DD%E7%E4%7F%0Bx%A3%FC%06%A9%23%0A%D6%C2%A1_2%00%00%00%09pHYs%00%00%0B%13%00%00%0B%13%01%00%9A%9C%18%00%00%00%B5IDAT(%15%A5%91%3D%0E%02!%10%85ac%E1%05%D6%CE%D6%C6%CE%D2%E8%ED%CD%DE%C0%C6%D6N.%E0V%F8%3D%9Ca%891XH%C2%BE%D9y%3F%90!%E6%9C%C3%BFk%E5%011%C6-%F5%C8N%04%DF%BD%FF%89%DFt%83DN%60%3E%F3%AB%A0%DE%1A%5Dg%BE%10Q%97%1B%40%9C%A8o%10%8F%5E%828%B4%1B%60%87%F6%02%26%85%1Ch%1E%C1%2B%5Bk%FF%86%EE%B7j%09%9A%DA%9B%ACe%A3%F9%EC%DA!9%B4%D5%A6%81%86%86%98%CC%3C%5B%40%FA%81%B3%E9%CB%23%94%C16Azo%05%D4%E1%C1%95a%3B%8A'%A0%E8%CC%17%22%85%1D%BA%00%A2%FA%DC%0A%94%D1%D1%8D%8B%3A%84%17B%C7%60%1A%25Z%FC%8D%00%00%00%00IEND%AEB%60%82\"),url(\"data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%05%00%00%007%08%06%00%00%00%C4%DD%80C%00%00%03%1EiCCPICC%20Profile%00%00x%01%85T%DFk%D3P%14%FE%DAe%9D%B0%E1%8B%3Ag%11%09%3Eh%91ndStC%9C%B6kW%BA%CDZ%EA6%B7!H%9B%A6m%5C%9A%C6%24%ED~%B0%07%D9%8Bo%3A%C5w%F1%07%3E%F9%07%0C%D9%83o%7B%92%0D%C6%14a%F8%AC%88%22L%F6%22%B3%9E%9B4M'S%03%B9%F7%BB%DF%F9%EE9'%E7%E4%5E%A0%F9qZ%D3%14%2F%0F%14USO%C5%C2%FC%C4%E4%14%DF%F2%01%5E%1CC%2B%FChM%8B%86%16J%26G%40%0F%D3%B2y%EF%B3%F3%0E%1E%C6lt%EEo%DF%AB%FEc%D5%9A%95%0C%11%F0%1C%20%BE%945%C4%22%E1Y%A0i%5C%D4t%13%E0%D6%89%EF%9D15%C2%CDLsX%A7%04%09%1Fg8oc%81%E1%8C%8D%23%96f45%40%9A%09%C2%07%C5B%3AK%B8%408%98i%E0%F3%0D%D8%CE%81%14%E4'%26%A9%92.%8B%3C%ABER%2F%E5dE%B2%0C%F6%F0%1Fs%83%F2_%B0%A8%94%E9%9B%AD%E7%10%8Dm%9A%19N%D1%7C%8A%DE%1F9%7Dp%8C%E6%00%D5%C1%3F_%18%BDA%B8%9DpX6%E3%A35~B%CD%24%AE%11%26%BD%E7%EEti%98%EDe%9A%97Y)%12%25%1C%24%BCbT%AE3li%E6%0B%03%89%9A%E6%D3%ED%F4P%92%B0%9F4%BF43Y%F3%E3%EDP%95%04%EB1%C5%F5%F6KF%F4%BA%BD%D7%DB%91%93%07%E35%3E%A7)%D6%7F%40%FE%BD%F7%F5r%8A%E5y%92%F0%EB%B4%1E%8D%D5%F4%5B%92%3AV%DB%DB%E4%CD%A6%23%C3%C4wQ%3F%03HB%82%8E%1Cd(%E0%91B%0Ca%9Ac%C4%AA%F8L%16%19%22J%A4%D2itTy%B28%D6%3B(%93%96%ED%1CGx%C9_%0E%B8%5E%16%F5%5B%B2%B8%F6%E0%FB%9E%DD%25%D7%8E%BC%15%85%C5%B7%A3%D8Q%ED%B5%81%E9%BA%B2%13%9A%1B%7Fua%A5%A3n%E17%B9%E5%9B%1Bm%AB%0B%08Q%FE%8A%E5%B1H%5Ee%CAO%82Q%D7u6%E6%90S%97%FCu%0B%CF2%94%EE%25v%12X%0C%BA%AC%F0%5E%F8*l%0AO%85%17%C2%97%BF%D4%C8%CE%DE%AD%11%CB%80q%2C%3E%AB%9ES%CD%C6%EC%25%D2L%D2%EBd%B8%BF%8A%F5B%C6%18%F9%901CZ%9D%BE%24M%9C%8A9%F2%DAP%0B'%06w%82%EB%E6%E2%5C%2F%D7%07%9E%BB%CC%5D%E1%FA%B9%08%AD.r%23%8E%C2%17%F5E%7C!%F0%BE3%BE%3E_%B7o%88a%A7%DB%BE%D3d%EB%A31Z%EB%BB%D3%91%BA%A2%B1z%94%8F%DB'%F6%3D%8E%AA%13%19%B2%B1%BE%B1~V%08%2B%B4%A2cjJ%B3tO%00%03%25mN%97%F3%05%93%EF%11%84%0B%7C%88%AE-%89%8F%ABbW%90O%2B%0Ao%99%0C%5E%97%0CI%AFH%D9.%B0%3B%8F%ED%03%B6S%D6%5D%E6i_s9%F3*p%E9%1B%FD%C3%EB.7U%06%5E%19%C0%D1s.%17%A03u%E4%09%B0%7C%5E%2C%EB%15%DB%1F%3C%9E%B7%80%91%3B%DBc%AD%3Dma%BA%8B%3EV%AB%DBt.%5B%1E%01%BB%0F%AB%D5%9F%CF%AA%D5%DD%E7%E4%7F%0Bx%A3%FC%06%A9%23%0A%D6%C2%A1_2%00%00%00%09pHYs%00%00%0B%13%00%00%0B%13%01%00%9A%9C%18%00%00%00%3AIDAT8%11c%FC%FF%FF%7F%18%03%1A%60%01%F2%3F%A0%891%80%04%FF%11-%F8%17%9BJ%E2%05%B1ZD%81v%26t%E7%80%F8%A3%82h%A12%1A%20%A3%01%02%0F%01%BA%25%06%00%19%C0%0D%AEF%D5%3ES%00%00%00%00IEND%AEB%60%82\");background-repeat: no-repeat, repeat-x;background-position: center center, top left;color: transparent;border: 1px solid black;-moz-border-radius: 2px;-webkit-border-radius: 2px;border-radius: 2px;cursor: pointer;pointer-events: auto;}.ace_dark .ace_fold {}.ace_fold:hover{background-image:url(\"data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%11%00%00%00%09%08%06%00%00%00%D4%E8%C7%0C%00%00%03%1EiCCPICC%20Profile%00%00x%01%85T%DFk%D3P%14%FE%DAe%9D%B0%E1%8B%3Ag%11%09%3Eh%91ndStC%9C%B6kW%BA%CDZ%EA6%B7!H%9B%A6m%5C%9A%C6%24%ED~%B0%07%D9%8Bo%3A%C5w%F1%07%3E%F9%07%0C%D9%83o%7B%92%0D%C6%14a%F8%AC%88%22L%F6%22%B3%9E%9B4M'S%03%B9%F7%BB%DF%F9%EE9'%E7%E4%5E%A0%F9qZ%D3%14%2F%0F%14USO%C5%C2%FC%C4%E4%14%DF%F2%01%5E%1CC%2B%FChM%8B%86%16J%26G%40%0F%D3%B2y%EF%B3%F3%0E%1E%C6lt%EEo%DF%AB%FEc%D5%9A%95%0C%11%F0%1C%20%BE%945%C4%22%E1Y%A0i%5C%D4t%13%E0%D6%89%EF%9D15%C2%CDLsX%A7%04%09%1Fg8oc%81%E1%8C%8D%23%96f45%40%9A%09%C2%07%C5B%3AK%B8%408%98i%E0%F3%0D%D8%CE%81%14%E4'%26%A9%92.%8B%3C%ABER%2F%E5dE%B2%0C%F6%F0%1Fs%83%F2_%B0%A8%94%E9%9B%AD%E7%10%8Dm%9A%19N%D1%7C%8A%DE%1F9%7Dp%8C%E6%00%D5%C1%3F_%18%BDA%B8%9DpX6%E3%A35~B%CD%24%AE%11%26%BD%E7%EEti%98%EDe%9A%97Y)%12%25%1C%24%BCbT%AE3li%E6%0B%03%89%9A%E6%D3%ED%F4P%92%B0%9F4%BF43Y%F3%E3%EDP%95%04%EB1%C5%F5%F6KF%F4%BA%BD%D7%DB%91%93%07%E35%3E%A7)%D6%7F%40%FE%BD%F7%F5r%8A%E5y%92%F0%EB%B4%1E%8D%D5%F4%5B%92%3AV%DB%DB%E4%CD%A6%23%C3%C4wQ%3F%03HB%82%8E%1Cd(%E0%91B%0Ca%9Ac%C4%AA%F8L%16%19%22J%A4%D2itTy%B28%D6%3B(%93%96%ED%1CGx%C9_%0E%B8%5E%16%F5%5B%B2%B8%F6%E0%FB%9E%DD%25%D7%8E%BC%15%85%C5%B7%A3%D8Q%ED%B5%81%E9%BA%B2%13%9A%1B%7Fua%A5%A3n%E17%B9%E5%9B%1Bm%AB%0B%08Q%FE%8A%E5%B1H%5Ee%CAO%82Q%D7u6%E6%90S%97%FCu%0B%CF2%94%EE%25v%12X%0C%BA%AC%F0%5E%F8*l%0AO%85%17%C2%97%BF%D4%C8%CE%DE%AD%11%CB%80q%2C%3E%AB%9ES%CD%C6%EC%25%D2L%D2%EBd%B8%BF%8A%F5B%C6%18%F9%901CZ%9D%BE%24M%9C%8A9%F2%DAP%0B'%06w%82%EB%E6%E2%5C%2F%D7%07%9E%BB%CC%5D%E1%FA%B9%08%AD.r%23%8E%C2%17%F5E%7C!%F0%BE3%BE%3E_%B7o%88a%A7%DB%BE%D3d%EB%A31Z%EB%BB%D3%91%BA%A2%B1z%94%8F%DB'%F6%3D%8E%AA%13%19%B2%B1%BE%B1~V%08%2B%B4%A2cjJ%B3tO%00%03%25mN%97%F3%05%93%EF%11%84%0B%7C%88%AE-%89%8F%ABbW%90O%2B%0Ao%99%0C%5E%97%0CI%AFH%D9.%B0%3B%8F%ED%03%B6S%D6%5D%E6i_s9%F3*p%E9%1B%FD%C3%EB.7U%06%5E%19%C0%D1s.%17%A03u%E4%09%B0%7C%5E%2C%EB%15%DB%1F%3C%9E%B7%80%91%3B%DBc%AD%3Dma%BA%8B%3EV%AB%DBt.%5B%1E%01%BB%0F%AB%D5%9F%CF%AA%D5%DD%E7%E4%7F%0Bx%A3%FC%06%A9%23%0A%D6%C2%A1_2%00%00%00%09pHYs%00%00%0B%13%00%00%0B%13%01%00%9A%9C%18%00%00%00%B5IDAT(%15%A5%91%3D%0E%02!%10%85ac%E1%05%D6%CE%D6%C6%CE%D2%E8%ED%CD%DE%C0%C6%D6N.%E0V%F8%3D%9Ca%891XH%C2%BE%D9y%3F%90!%E6%9C%C3%BFk%E5%011%C6-%F5%C8N%04%DF%BD%FF%89%DFt%83DN%60%3E%F3%AB%A0%DE%1A%5Dg%BE%10Q%97%1B%40%9C%A8o%10%8F%5E%828%B4%1B%60%87%F6%02%26%85%1Ch%1E%C1%2B%5Bk%FF%86%EE%B7j%09%9A%DA%9B%ACe%A3%F9%EC%DA!9%B4%D5%A6%81%86%86%98%CC%3C%5B%40%FA%81%B3%E9%CB%23%94%C16Azo%05%D4%E1%C1%95a%3B%8A'%A0%E8%CC%17%22%85%1D%BA%00%A2%FA%DC%0A%94%D1%D1%8D%8B%3A%84%17B%C7%60%1A%25Z%FC%8D%00%00%00%00IEND%AEB%60%82\"),url(\"data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%05%00%00%007%08%06%00%00%00%C4%DD%80C%00%00%03%1EiCCPICC%20Profile%00%00x%01%85T%DFk%D3P%14%FE%DAe%9D%B0%E1%8B%3Ag%11%09%3Eh%91ndStC%9C%B6kW%BA%CDZ%EA6%B7!H%9B%A6m%5C%9A%C6%24%ED~%B0%07%D9%8Bo%3A%C5w%F1%07%3E%F9%07%0C%D9%83o%7B%92%0D%C6%14a%F8%AC%88%22L%F6%22%B3%9E%9B4M'S%03%B9%F7%BB%DF%F9%EE9'%E7%E4%5E%A0%F9qZ%D3%14%2F%0F%14USO%C5%C2%FC%C4%E4%14%DF%F2%01%5E%1CC%2B%FChM%8B%86%16J%26G%40%0F%D3%B2y%EF%B3%F3%0E%1E%C6lt%EEo%DF%AB%FEc%D5%9A%95%0C%11%F0%1C%20%BE%945%C4%22%E1Y%A0i%5C%D4t%13%E0%D6%89%EF%9D15%C2%CDLsX%A7%04%09%1Fg8oc%81%E1%8C%8D%23%96f45%40%9A%09%C2%07%C5B%3AK%B8%408%98i%E0%F3%0D%D8%CE%81%14%E4'%26%A9%92.%8B%3C%ABER%2F%E5dE%B2%0C%F6%F0%1Fs%83%F2_%B0%A8%94%E9%9B%AD%E7%10%8Dm%9A%19N%D1%7C%8A%DE%1F9%7Dp%8C%E6%00%D5%C1%3F_%18%BDA%B8%9DpX6%E3%A35~B%CD%24%AE%11%26%BD%E7%EEti%98%EDe%9A%97Y)%12%25%1C%24%BCbT%AE3li%E6%0B%03%89%9A%E6%D3%ED%F4P%92%B0%9F4%BF43Y%F3%E3%EDP%95%04%EB1%C5%F5%F6KF%F4%BA%BD%D7%DB%91%93%07%E35%3E%A7)%D6%7F%40%FE%BD%F7%F5r%8A%E5y%92%F0%EB%B4%1E%8D%D5%F4%5B%92%3AV%DB%DB%E4%CD%A6%23%C3%C4wQ%3F%03HB%82%8E%1Cd(%E0%91B%0Ca%9Ac%C4%AA%F8L%16%19%22J%A4%D2itTy%B28%D6%3B(%93%96%ED%1CGx%C9_%0E%B8%5E%16%F5%5B%B2%B8%F6%E0%FB%9E%DD%25%D7%8E%BC%15%85%C5%B7%A3%D8Q%ED%B5%81%E9%BA%B2%13%9A%1B%7Fua%A5%A3n%E17%B9%E5%9B%1Bm%AB%0B%08Q%FE%8A%E5%B1H%5Ee%CAO%82Q%D7u6%E6%90S%97%FCu%0B%CF2%94%EE%25v%12X%0C%BA%AC%F0%5E%F8*l%0AO%85%17%C2%97%BF%D4%C8%CE%DE%AD%11%CB%80q%2C%3E%AB%9ES%CD%C6%EC%25%D2L%D2%EBd%B8%BF%8A%F5B%C6%18%F9%901CZ%9D%BE%24M%9C%8A9%F2%DAP%0B'%06w%82%EB%E6%E2%5C%2F%D7%07%9E%BB%CC%5D%E1%FA%B9%08%AD.r%23%8E%C2%17%F5E%7C!%F0%BE3%BE%3E_%B7o%88a%A7%DB%BE%D3d%EB%A31Z%EB%BB%D3%91%BA%A2%B1z%94%8F%DB'%F6%3D%8E%AA%13%19%B2%B1%BE%B1~V%08%2B%B4%A2cjJ%B3tO%00%03%25mN%97%F3%05%93%EF%11%84%0B%7C%88%AE-%89%8F%ABbW%90O%2B%0Ao%99%0C%5E%97%0CI%AFH%D9.%B0%3B%8F%ED%03%B6S%D6%5D%E6i_s9%F3*p%E9%1B%FD%C3%EB.7U%06%5E%19%C0%D1s.%17%A03u%E4%09%B0%7C%5E%2C%EB%15%DB%1F%3C%9E%B7%80%91%3B%DBc%AD%3Dma%BA%8B%3EV%AB%DBt.%5B%1E%01%BB%0F%AB%D5%9F%CF%AA%D5%DD%E7%E4%7F%0Bx%A3%FC%06%A9%23%0A%D6%C2%A1_2%00%00%00%09pHYs%00%00%0B%13%00%00%0B%13%01%00%9A%9C%18%00%00%003IDAT8%11c%FC%FF%FF%7F%3E%03%1A%60%01%F2%3F%A3%891%80%04%FFQ%26%F8w%C0%B43%A1%DB%0C%E2%8F%0A%A2%85%CAh%80%8C%06%08%3C%04%E8%96%18%00%A3S%0D%CD%CF%D8%C1%9D%00%00%00%00IEND%AEB%60%82\");background-repeat: no-repeat, repeat-x;background-position: center center, top left;}.ace_editor.ace_dragging .ace_content {cursor: move;}.ace_gutter-tooltip {background-color: #FFFFD5;border: 1px solid gray;box-shadow: 0 1px 1px rgba(0, 0, 0, 0.4);color: black;display: inline-block;padding: 4px;position: absolute;z-index: 300;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;cursor: default;white-space: pre-line;word-wrap: break-word;}.ace_folding-enabled > .ace_gutter-cell {padding-right: 13px;}.ace_fold-widget {-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;margin: 0 -12px 0 1px;display: inline-block;width: 11px;vertical-align: top;background-image: url(\"data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%05%00%00%00%05%08%06%00%00%00%8Do%26%E5%00%00%004IDATx%DAe%8A%B1%0D%000%0C%C2%F2%2CK%96%BC%D0%8F9%81%88H%E9%D0%0E%96%C0%10%92%3E%02%80%5E%82%E4%A9*-%EEsw%C8%CC%11%EE%96w%D8%DC%E9*Eh%0C%151(%00%00%00%00IEND%AEB%60%82\");background-repeat: no-repeat;background-position: center;border-radius: 3px;border: 1px solid transparent;}.ace_fold-widget.ace_end {background-image: url(\"data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%05%00%00%00%05%08%06%00%00%00%8Do%26%E5%00%00%004IDATx%DAm%C7%C1%09%000%08C%D1%8C%ECE%C8E(%8E%EC%02)%1EZJ%F1%C1'%04%07I%E1%E5%EE%CAL%F5%A2%99%99%22%E2%D6%1FU%B5%FE0%D9x%A7%26Wz5%0E%D5%00%00%00%00IEND%AEB%60%82\");}.ace_fold-widget.ace_closed {background-image: url(\"data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%03%00%00%00%06%08%06%00%00%00%06%E5%24%0C%00%00%009IDATx%DA5%CA%C1%09%000%08%03%C0%AC*(%3E%04%C1%0D%BA%B1%23%A4Uh%E0%20%81%C0%CC%F8%82%81%AA%A2%AArGfr%88%08%11%11%1C%DD%7D%E0%EE%5B%F6%F6%CB%B8%05Q%2F%E9tai%D9%00%00%00%00IEND%AEB%60%82\");}.ace_fold-widget:hover {border: 1px solid rgba(0, 0, 0, 0.3);background-color: rgba(255, 255, 255, 0.2);-moz-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);-webkit-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);}.ace_fold-widget:active {border: 1px solid rgba(0, 0, 0, 0.4);background-color: rgba(0, 0, 0, 0.05);-moz-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);-webkit-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);}/*** Dark version for fold widgets*/.ace_dark .ace_fold-widget {background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHklEQVQIW2P4//8/AzoGEQ7oGCaLLAhWiSwB146BAQCSTPYocqT0AAAAAElFTkSuQmCC\");}.ace_dark .ace_fold-widget.ace_end {background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAH0lEQVQIW2P4//8/AxQ7wNjIAjDMgC4AxjCVKBirIAAF0kz2rlhxpAAAAABJRU5ErkJggg==\");}.ace_dark .ace_fold-widget.ace_closed {background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAHElEQVQIW2P4//+/AxAzgDADlOOAznHAKgPWAwARji8UIDTfQQAAAABJRU5ErkJggg==\");}.ace_dark .ace_fold-widget:hover {box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);background-color: rgba(255, 255, 255, 0.1);}.ace_dark .ace_fold-widget:active {-moz-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);-webkit-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);}.ace_fold-widget.ace_invalid {background-color: #FFB4B4;border-color: #DE5555;}.ace_fade-fold-widgets .ace_fold-widget {-moz-transition: opacity 0.4s ease 0.05s;-webkit-transition: opacity 0.4s ease 0.05s;-o-transition: opacity 0.4s ease 0.05s;-ms-transition: opacity 0.4s ease 0.05s;transition: opacity 0.4s ease 0.05s;opacity: 0;}.ace_fade-fold-widgets:hover .ace_fold-widget {-moz-transition: opacity 0.05s ease 0.05s;-webkit-transition: opacity 0.05s ease 0.05s;-o-transition: opacity 0.05s ease 0.05s;-ms-transition: opacity 0.05s ease 0.05s;transition: opacity 0.05s ease 0.05s;opacity:1;}.ace_underline {text-decoration: underline;}.ace_bold {font-weight: bold;}.ace_nobold .ace_bold {font-weight: normal;}.ace_italic {font-style: italic;}";i.importCssString(m,"ace_editor");var g=function(e,t){var n=this;this.container=e,this.$keepTextAreaAtCursor=!o.isIE,i.addCssClass(e,"ace_editor"),this.setTheme(t),this.$gutter=i.createElement("div"),this.$gutter.className="ace_gutter",this.container.appendChild(this.$gutter),this.scroller=i.createElement("div"),this.scroller.className="ace_scroller",this.container.appendChild(this.scroller),this.content=i.createElement("div"),this.content.className="ace_content",this.scroller.appendChild(this.content),this.setHighlightGutterLine(!0),this.$gutterLayer=new f(this.$gutter),this.$gutterLayer.on("changeGutterWidth",this.onGutterResize.bind(this)),this.$markerBack=new l(this.content);var r=this.$textLayer=new c(this.content);this.canvas=r.element,this.$markerFront=new l(this.content),this.$cursorLayer=new h(this.content),this.$horizScroll=!1,this.$horizScrollAlwaysVisible=!1,this.$animatedScroll=!1,this.scrollBar=new p(e),this.scrollBar.addEventListener("scroll",function(e){n.$inScrollAnimation||n.session.setScrollTop(e.data)}),this.scrollTop=0,this.scrollLeft=0,s.addListener(this.scroller,"scroll",function(){var e=n.scroller.scrollLeft;n.scrollLeft=e,n.session.setScrollLeft(e)}),this.cursorPos={row:0,column:0},this.$textLayer.addEventListener("changeCharacterSize",function(){n.updateCharacterSize(),n.onResize(!0)}),this.$size={width:0,height:0,scrollerHeight:0,scrollerWidth:0},this.layerConfig={width:1,padding:0,firstRow:0,firstRowScreen:0,lastRow:0,lineHeight:1,characterWidth:1,minHeight:1,maxHeight:1,offset:0,height:1},this.$loop=new d(this.$renderChanges.bind(this),this.container.ownerDocument.defaultView),this.$loop.schedule(this.CHANGE_FULL),this.updateCharacterSize(),this.setPadding(4)};(function(){this.showGutter=!0,this.CHANGE_CURSOR=1,this.CHANGE_MARKER=2,this.CHANGE_GUTTER=4,this.CHANGE_SCROLL=8,this.CHANGE_LINES=16,this.CHANGE_TEXT=32,this.CHANGE_SIZE=64,this.CHANGE_MARKER_BACK=128,this.CHANGE_MARKER_FRONT=256,this.CHANGE_FULL=512,this.CHANGE_H_SCROLL=1024,r.implement(this,v),this.updateCharacterSize=function(){this.$textLayer.allowBoldFonts!=this.$allowBoldFonts&&(this.$allowBoldFonts=this.$textLayer.allowBoldFonts,this.setStyle("ace_nobold",!this.$allowBoldFonts)),this.characterWidth=this.$textLayer.getCharacterWidth(),this.lineHeight=this.$textLayer.getLineHeight(),this.$updatePrintMargin()},this.setSession=function(e){this.session=e,this.scroller.className="ace_scroller",this.$cursorLayer.setSession(e),this.$markerBack.setSession(e),this.$markerFront.setSession(e),this.$gutterLayer.setSession(e),this.$textLayer.setSession(e),this.$loop.schedule(this.CHANGE_FULL)},this.updateLines=function(e,t){t===undefined&&(t=Infinity),this.$changedLines?(this.$changedLines.firstRow>e&&(this.$changedLines.firstRow=e),this.$changedLines.lastRow<t&&(this.$changedLines.lastRow=t)):this.$changedLines={firstRow:e,lastRow:t};if(this.$changedLines.firstRow>this.layerConfig.lastRow||this.$changedLines.lastRow<this.layerConfig.firstRow)return;this.$loop.schedule(this.CHANGE_LINES)},this.onChangeTabSize=function(){this.$loop.schedule(this.CHANGE_TEXT|this.CHANGE_MARKER),this.$textLayer.onChangeTabSize()},this.updateText=function(){this.$loop.schedule(this.CHANGE_TEXT)},this.updateFull=function(e){e?this.$renderChanges(this.CHANGE_FULL,!0):this.$loop.schedule(this.CHANGE_FULL)},this.updateFontSize=function(){this.$textLayer.checkForSizeChanges()},this.onResize=function(e,t,n,r){var s=this.CHANGE_SIZE,o=this.$size;if(this.resizing>2)return;this.resizing>1?this.resizing++:this.resizing=e?1:0,r||(r=i.getInnerHeight(this.container));if(e||o.height!=r)o.height=r,this.scroller.style.height=r+"px",o.scrollerHeight=this.scroller.clientHeight,this.scrollBar.setHeight(o.scrollerHeight),this.session&&(this.session.setScrollTop(this.getScrollTop()),s|=this.CHANGE_FULL);n||(n=i.getInnerWidth(this.container));if(e||this.resizing>1||o.width!=n){o.width=n;var t=this.showGutter?this.$gutter.offsetWidth:0;this.scroller.style.left=t+"px",o.scrollerWidth=Math.max(0,n-t-this.scrollBar.getWidth()),this.scroller.style.right=this.scrollBar.getWidth()+"px";if(this.session.getUseWrapMode()&&this.adjustWrapLimit()||e)s|=this.CHANGE_FULL}e?this.$renderChanges(s,!0):this.$loop.schedule(s),e&&delete this.resizing},this.onGutterResize=function(){var e=this.$size.width,t=this.showGutter?this.$gutter.offsetWidth:0;this.scroller.style.left=t+"px",this.$size.scrollerWidth=Math.max(0,e-t-this.scrollBar.getWidth()),this.session.getUseWrapMode()&&this.adjustWrapLimit()&&this.$loop.schedule(this.CHANGE_FULL)},this.adjustWrapLimit=function(){var e=this.$size.scrollerWidth-this.$padding*2,t=Math.floor(e/this.characterWidth);return this.session.adjustWrapLimit(t)},this.setAnimatedScroll=function(e){this.$animatedScroll=e},this.getAnimatedScroll=function(){return this.$animatedScroll},this.setShowInvisibles=function(e){this.$textLayer.setShowInvisibles(e)&&this.$loop.schedule(this.CHANGE_TEXT)},this.getShowInvisibles=function(){return this.$textLayer.showInvisibles},this.getDisplayIndentGuides=function(){return this.$textLayer.displayIndentGuides},this.setDisplayIndentGuides=function(e){this.$textLayer.setDisplayIndentGuides(e)&&this.$loop.schedule(this.CHANGE_TEXT)},this.$showPrintMargin=!0,this.setShowPrintMargin=function(e){this.$showPrintMargin=e,this.$updatePrintMargin()},this.getShowPrintMargin=function(){return this.$showPrintMargin},this.$printMarginColumn=80,this.setPrintMarginColumn=function(e){this.$printMarginColumn=e,this.$updatePrintMargin()},this.getPrintMarginColumn=function(){return this.$printMarginColumn},this.getShowGutter=function(){return this.showGutter},this.setShowGutter=function(e){if(this.showGutter===e)return;this.$gutter.style.display=e?"block":"none",this.showGutter=e,this.onResize(!0)},this.getFadeFoldWidgets=function(){return i.hasCssClass(this.$gutter,"ace_fade-fold-widgets")},this.setFadeFoldWidgets=function(e){e?i.addCssClass(this.$gutter,"ace_fade-fold-widgets"):i.removeCssClass(this.$gutter,"ace_fade-fold-widgets")},this.$highlightGutterLine=!1,this.setHighlightGutterLine=function(e){if(this.$highlightGutterLine==e)return;this.$highlightGutterLine=e;if(!this.$gutterLineHighlight){this.$gutterLineHighlight=i.createElement("div"),this.$gutterLineHighlight.className="ace_gutter-active-line",this.$gutter.appendChild(this.$gutterLineHighlight);return}this.$gutterLineHighlight.style.display=e?"":"none",this.$cursorLayer.$pixelPos&&this.$updateGutterLineHighlight()},this.getHighlightGutterLine=function(){return this.$highlightGutterLine},this.$updateGutterLineHighlight=function(){this.$gutterLineHighlight.style.top=this.$cursorLayer.$pixelPos.top-this.layerConfig.offset+"px",this.$gutterLineHighlight.style.height=this.layerConfig.lineHeight+"px"},this.$updatePrintMargin=function(){if(!this.$showPrintMargin&&!this.$printMarginEl)return;if(!this.$printMarginEl){var e=i.createElement("div");e.className="ace_layer ace_print-margin-layer",this.$printMarginEl=i.createElement("div"),this.$printMarginEl.className="ace_print-margin",e.appendChild(this.$printMarginEl),this.content.insertBefore(e,this.content.firstChild)}var t=this.$printMarginEl.style;t.left=this.characterWidth*this.$printMarginColumn+this.$padding+"px",t.visibility=this.$showPrintMargin?"visible":"hidden"},this.getContainerElement=function(){return this.container},this.getMouseEventTarget=function(){return this.content},this.getTextAreaContainer=function(){return this.container},this.$moveTextAreaToCursor=function(){if(!this.$keepTextAreaAtCursor)return;var e=this.$cursorLayer.$pixelPos.top,t=this.$cursorLayer.$pixelPos.left;e-=this.layerConfig.offset;if(e<0||e>this.layerConfig.height-this.lineHeight)return;var n=this.characterWidth;this.$composition&&(n+=this.textarea.scrollWidth),t-=this.scrollLeft,t>this.$size.scrollerWidth-n&&(t=this.$size.scrollerWidth-n),this.showGutter&&(t+=this.$gutterLayer.gutterWidth),this.textarea.style.height=this.lineHeight+"px",this.textarea.style.width=n+"px",this.textarea.style.left=t+"px",this.textarea.style.top=e-1+"px"},this.getFirstVisibleRow=function(){return this.layerConfig.firstRow},this.getFirstFullyVisibleRow=function(){return this.layerConfig.firstRow+(this.layerConfig.offset===0?0:1)},this.getLastFullyVisibleRow=function(){var e=Math.floor((this.layerConfig.height+this.layerConfig.offset)/this.layerConfig.lineHeight);return this.layerConfig.firstRow-1+e},this.getLastVisibleRow=function(){return this.layerConfig.lastRow},this.$padding=null,this.setPadding=function(e){this.$padding=e,this.$textLayer.setPadding(e),this.$cursorLayer.setPadding(e),this.$markerFront.setPadding(e),this.$markerBack.setPadding(e),this.$loop.schedule(this.CHANGE_FULL),this.$updatePrintMargin()},this.getHScrollBarAlwaysVisible=function(){return this.$horizScrollAlwaysVisible},this.setHScrollBarAlwaysVisible=function(e){this.$horizScrollAlwaysVisible!=e&&(this.$horizScrollAlwaysVisible=e,(!this.$horizScrollAlwaysVisible||!this.$horizScroll)&&this.$loop.schedule(this.CHANGE_SCROLL))},this.$updateScrollBar=function(){this.scrollBar.setInnerHeight(this.layerConfig.maxHeight),this.scrollBar.setScrollTop(this.scrollTop)},this.$renderChanges=function(e,t){if(!t&&(!e||!this.session||!this.container.offsetWidth))return;(e&this.CHANGE_FULL||e&this.CHANGE_SIZE||e&this.CHANGE_TEXT||e&this.CHANGE_LINES||e&this.CHANGE_SCROLL)&&this.$computeLayerConfig();if(e&this.CHANGE_H_SCROLL){this.scroller.scrollLeft=this.scrollLeft;var n=this.scroller.scrollLeft;this.scrollLeft=n,this.session.setScrollLeft(n),this.scroller.className=this.scrollLeft==0?"ace_scroller":"ace_scroller ace_scroll-left"}if(e&this.CHANGE_FULL){this.$textLayer.checkForSizeChanges(),this.$updateScrollBar(),this.$textLayer.update(this.layerConfig),this.showGutter&&this.$gutterLayer.update(this.layerConfig),this.$markerBack.update(this.layerConfig),this.$markerFront.update(this.layerConfig),this.$cursorLayer.update(this.layerConfig),this.$moveTextAreaToCursor(),this.$highlightGutterLine&&this.$updateGutterLineHighlight();return}if(e&this.CHANGE_SCROLL){this.$updateScrollBar(),e&this.CHANGE_TEXT||e&this.CHANGE_LINES?this.$textLayer.update(this.layerConfig):this.$textLayer.scrollLines(this.layerConfig),this.showGutter&&this.$gutterLayer.update(this.layerConfig),this.$markerBack.update(this.layerConfig),this.$markerFront.update(this.layerConfig),this.$cursorLayer.update(this.layerConfig),this.$moveTextAreaToCursor(),this.$highlightGutterLine&&this.$updateGutterLineHighlight();return}e&this.CHANGE_TEXT?(this.$textLayer.update(this.layerConfig),this.showGutter&&this.$gutterLayer.update(this.layerConfig)):e&this.CHANGE_LINES?(this.$updateLines()||e&this.CHANGE_GUTTER&&this.showGutter)&&this.$gutterLayer.update(this.layerConfig):(e&this.CHANGE_TEXT||e&this.CHANGE_GUTTER)&&this.showGutter&&this.$gutterLayer.update(this.layerConfig),e&this.CHANGE_CURSOR&&(this.$cursorLayer.update(this.layerConfig),this.$moveTextAreaToCursor(),this.$highlightGutterLine&&this.$updateGutterLineHighlight()),e&(this.CHANGE_MARKER|this.CHANGE_MARKER_FRONT)&&this.$markerFront.update(this.layerConfig),e&(this.CHANGE_MARKER|this.CHANGE_MARKER_BACK)&&this.$markerBack.update(this.layerConfig),e&this.CHANGE_SIZE&&this.$updateScrollBar()},this.$computeLayerConfig=function(){var e=this.session,t=this.scrollTop%this.lineHeight,n=this.$size.scrollerHeight+this.lineHeight,r=this.$getLongestLine(),i=this.$horizScrollAlwaysVisible||this.$size.scrollerWidth-r<0,s=this.$horizScroll!==i;this.$horizScroll=i,s&&(this.scroller.style.overflowX=i?"scroll":"hidden",i||this.session.setScrollLeft(0));var o=this.session.getScreenLength()*this.lineHeight;this.session.setScrollTop(Math.max(0,Math.min(this.scrollTop,o-this.$size.scrollerHeight)));var u=Math.ceil(n/this.lineHeight)-1,a=Math.max(0,Math.round((this.scrollTop-t)/this.lineHeight)),f=a+u,l,c,h=this.lineHeight;a=e.screenToDocumentRow(a,0);var p=e.getFoldLine(a);p&&(a=p.start.row),l=e.documentToScreenRow(a,0),c=e.getRowLength(a)*h,f=Math.min(e.screenToDocumentRow(f,0),e.getLength()-1),n=this.$size.scrollerHeight+e.getRowLength(f)*h+c,t=this.scrollTop-l*h,this.layerConfig={width:r,padding:this.$padding,firstRow:a,firstRowScreen:l,lastRow:f,lineHeight:h,characterWidth:this.characterWidth,minHeight:n,maxHeight:o,offset:t,height:this.$size.scrollerHeight},this.$gutterLayer.element.style.marginTop=-t+"px",this.content.style.marginTop=-t+"px",this.content.style.width=r+2*this.$padding+"px",this.content.style.height=n+"px",s&&this.onResize(!0)},this.$updateLines=function(){var e=this.$changedLines.firstRow,t=this.$changedLines.lastRow;this.$changedLines=null;var n=this.layerConfig;if(e>n.lastRow+1)return;if(t<n.firstRow)return;if(t===Infinity){this.showGutter&&this.$gutterLayer.update(n),this.$textLayer.update(n);return}return this.$textLayer.updateLines(n,e,t),!0},this.$getLongestLine=function(){var e=this.session.getScreenWidth();return this.$textLayer.showInvisibles&&(e+=1),Math.max(this.$size.scrollerWidth-2*this.$padding,Math.round(e*this.characterWidth))},this.updateFrontMarkers=function(){this.$markerFront.setMarkers(this.session.getMarkers(!0)),this.$loop.schedule(this.CHANGE_MARKER_FRONT)},this.updateBackMarkers=function(){this.$markerBack.setMarkers(this.session.getMarkers()),this.$loop.schedule(this.CHANGE_MARKER_BACK)},this.addGutterDecoration=function(e,t){this.$gutterLayer.addGutterDecoration(e,t)},this.removeGutterDecoration=function(e,t){this.$gutterLayer.removeGutterDecoration(e,t)},this.updateBreakpoints=function(e){this.$loop.schedule(this.CHANGE_GUTTER)},this.setAnnotations=function(e){this.$gutterLayer.setAnnotations(e),this.$loop.schedule(this.CHANGE_GUTTER)},this.updateCursor=function(){this.$loop.schedule(this.CHANGE_CURSOR)},this.hideCursor=function(){this.$cursorLayer.hideCursor()},this.showCursor=function(){this.$cursorLayer.showCursor()},this.scrollSelectionIntoView=function(e,t,n){this.scrollCursorIntoView(e,n),this.scrollCursorIntoView(t,n)},this.scrollCursorIntoView=function(e,t){if(this.$size.scrollerHeight===0)return;var n=this.$cursorLayer.getPixelPosition(e),r=n.left,i=n.top;this.scrollTop>i?(t&&(i-=t*this.$size.scrollerHeight),this.session.setScrollTop(i)):this.scrollTop+this.$size.scrollerHeight<i+this.lineHeight&&(t&&(i+=t*this.$size.scrollerHeight),this.session.setScrollTop(i+this.lineHeight-this.$size.scrollerHeight));var s=this.scrollLeft;s>r?(r<this.$padding+2*this.layerConfig.characterWidth&&(r=0),this.session.setScrollLeft(r)):s+this.$size.scrollerWidth<r+this.characterWidth&&this.session.setScrollLeft(Math.round(r+this.characterWidth-this.$size.scrollerWidth))},this.getScrollTop=function(){return this.session.getScrollTop()},this.getScrollLeft=function(){return this.session.getScrollLeft()},this.getScrollTopRow=function(){return this.scrollTop/this.lineHeight},this.getScrollBottomRow=function(){return Math.max(0,Math.floor((this.scrollTop+this.$size.scrollerHeight)/this.lineHeight)-1)},this.scrollToRow=function(e){this.session.setScrollTop(e*this.lineHeight)},this.alignCursor=function(e,t){typeof e=="number"&&(e={row:e,column:0});var n=this.$cursorLayer.getPixelPosition(e),r=this.$size.scrollerHeight-this.lineHeight,i=n.top-r*(t||0);return this.session.setScrollTop(i),i},this.STEPS=8,this.$calcSteps=function(e,t){var n=0,r=this.STEPS,i=[],s=function(e,t,n){return n*(Math.pow(e-1,3)+1)+t};for(n=0;n<r;++n)i.push(s(n/this.STEPS,e,t-e));return i},this.scrollToLine=function(e,t,n,r){var i=this.$cursorLayer.getPixelPosition({row:e,column:0}),s=i.top;t&&(s-=this.$size.scrollerHeight/2);var o=this.scrollTop;this.session.setScrollTop(s),n!==!1&&this.animateScrolling(o,r)},this.animateScrolling=function(e,t){var n=this.scrollTop;if(this.$animatedScroll&&Math.abs(e-n)<1e5){var r=this,i=r.$calcSteps(e,n);this.$inScrollAnimation=!0,clearInterval(this.$timer),r.session.setScrollTop(i.shift()),this.$timer=setInterval(function(){i.length?(r.session.setScrollTop(i.shift()),r.session.$scrollTop=n):n!=null?(r.session.$scrollTop=-1,r.session.setScrollTop(n),n=null):(r.$timer=clearInterval(r.$timer),r.$inScrollAnimation=!1,t&&t())},10)}},this.scrollToY=function(e){this.scrollTop!==e&&(this.$loop.schedule(this.CHANGE_SCROLL),this.scrollTop=e)},this.scrollToX=function(e){e<0&&(e=0),this.scrollLeft!==e&&(this.scrollLeft=e),this.$loop.schedule(this.CHANGE_H_SCROLL)},this.scrollBy=function(e,t){t&&this.session.setScrollTop(this.session.getScrollTop()+t),e&&this.session.setScrollLeft(this.session.getScrollLeft()+e)},this.isScrollableBy=function(e,t){if(t<0&&this.session.getScrollTop()>0)return!0;if(t>0&&this.session.getScrollTop()+this.$size.scrollerHeight<this.layerConfig.maxHeight)return!0},this.pixelToScreenCoordinates=function(e,t){var n=this.scroller.getBoundingClientRect(),r=(e+this.scrollLeft-n.left-this.$padding)/this.characterWidth,i=Math.floor((t+this.scrollTop-n.top)/this.lineHeight),s=Math.round(r);return{row:i,column:s,side:r-s>0?1:-1}},this.screenToTextCoordinates=function(e,t){var n=this.scroller.getBoundingClientRect(),r=Math.round((e+this.scrollLeft-n.left-this.$padding)/this.characterWidth),i=Math.floor((t+this.scrollTop-n.top)/this.lineHeight);return this.session.screenToDocumentPosition(i,Math.max(r,0))},this.textToScreenCoordinates=function(e,t){var n=this.scroller.getBoundingClientRect(),r=this.session.documentToScreenPosition(e,t),i=this.$padding+Math.round(r.column*this.characterWidth),s=r.row*this.lineHeight;return{pageX:n.left+i-this.scrollLeft,pageY:n.top+s-this.scrollTop}},this.visualizeFocus=function(){i.addCssClass(this.container,"ace_focus")},this.visualizeBlur=function(){i.removeCssClass(this.container,"ace_focus")},this.showComposition=function(e){this.$composition||(this.$composition={keepTextAreaAtCursor:this.$keepTextAreaAtCursor,cssText:this.textarea.style.cssText}),this.$keepTextAreaAtCursor=!0,i.addCssClass(this.textarea,"ace_composition"),this.textarea.style.cssText="",this.$moveTextAreaToCursor()},this.setCompositionText=function(e){this.$moveTextAreaToCursor()},this.hideComposition=function(){if(!this.$composition)return;i.removeCssClass(this.textarea,"ace_composition"),this.$keepTextAreaAtCursor=this.$composition.keepTextAreaAtCursor,this.textarea.style.cssText=this.$composition.cssText,this.$composition=null},this._loadTheme=function(e,t){if(!u.get("packaged"))return t();a.loadScript(u.moduleUrl(e,"theme"),t)},this.setTheme=function(t){function u(e){i.importCssString(e.cssText,e.cssClass,n.container.ownerDocument),n.theme&&i.removeCssClass(n.container,n.theme.cssClass),n.$theme=e.cssClass,n.theme=e,i.addCssClass(n.container,e.cssClass),i.setCssClass(n.container,"ace_dark",e.isDark);var t=e.padding||4;n.$padding&&t!=n.$padding&&n.setPadding(t),n.$size&&(n.$size.width=0,n.onResize()),n._dispatchEvent("themeLoaded",{theme:e})}var n=this;this.$themeValue=t,n._dispatchEvent("themeChange",{theme:t});if(!t||typeof t=="string"){var r=t||"ace/theme/textmate",s;try{s=e(r)}catch(o){}if(s)return u(s);n._loadTheme(r,function(){e([r],function(e){if(n.$themeValue!==t)return;u(e)})})}else u(t)},this.getTheme=function(){return this.$themeValue},this.setStyle=function(t,n){i.setCssClass(this.container,t,n!=0)},this.unsetStyle=function(t){i.removeCssClass(this.container,t)},this.destroy=function(){this.$textLayer.destroy(),this.$cursorLayer.destroy()}}).call(g.prototype),t.VirtualRenderer=g}),ace.define("ace/layer/gutter",["require","exports","module","ace/lib/dom","ace/lib/oop","ace/lib/lang","ace/lib/event_emitter"],function(e,t,n){var r=e("../lib/dom"),i=e("../lib/oop"),s=e("../lib/lang"),o=e("../lib/event_emitter").EventEmitter,u=function(e){this.element=r.createElement("div"),this.element.className="ace_layer ace_gutter-layer",e.appendChild(this.element),this.setShowFoldWidgets(this.$showFoldWidgets),this.gutterWidth=0,this.$annotations=[],this.$updateAnnotations=this.$updateAnnotations.bind(this)};(function(){i.implement(this,o),this.setSession=function(e){this.session&&this.session.removeEventListener("change",this.$updateAnnotations),this.session=e,e.on("change",this.$updateAnnotations)},this.addGutterDecoration=function(e,t){window.console&&console.warn&&console.warn("deprecated use session.addGutterDecoration"),this.session.addGutterDecoration(e,t)},this.removeGutterDecoration=function(e,t){window.console&&console.warn&&console.warn("deprecated use session.removeGutterDecoration"),this.session.removeGutterDecoration(e,t)},this.setAnnotations=function(e){this.$annotations=[];var t,n;for(var r=0;r<e.length;r++){var i=e[r],n=i.row,t=this.$annotations[n];t||(t=this.$annotations[n]={text:[]});var o=i.text;o=o?s.escapeHTML(o):i.html||"",t.text.indexOf(o)===-1&&t.text.push(o);var u=i.type;u=="error"?t.className=" ace_error":u=="warning"&&t.className!=" ace_error"?t.className=" ace_warning":u=="info"&&!t.className&&(t.className=" ace_info")}},this.$updateAnnotations=function(e){if(!this.$annotations.length)return;var t=e.data,n=t.range,r=n.start.row,i=n.end.row-r;if(i!==0)if(t.action=="removeText"||t.action=="removeLines")this.$annotations.splice(r,i+1,null);else{var s=Array(i+1);s.unshift(r,1),this.$annotations.splice.apply(this.$annotations,s)}},this.update=function(e){var t={className:""},n=[],i=e.firstRow,s=e.lastRow,o=this.session.getNextFoldLine(i),u=o?o.start.row:Infinity,a=this.$showFoldWidgets&&this.session.foldWidgets,f=this.session.$breakpoints,l=this.session.$decorations,c=0;for(;;){i>u&&(i=o.end.row+1,o=this.session.getNextFoldLine(i,o),u=o?o.start.row:Infinity);if(i>s)break;var h=this.$annotations[i]||t;n.push("<div class='ace_gutter-cell ",f[i]||"",l[i]||"",h.className,"' style='height:",this.session.getRowLength(i)*e.lineHeight,"px;'>",c=i+1);if(a){var p=a[i];p==null&&(p=a[i]=this.session.getFoldWidget(i)),p&&n.push("<span class='ace_fold-widget ace_",p,p=="start"&&i==u&&i<o.end.row?" ace_closed":" ace_open","' style='height:",e.lineHeight,"px","'></span>")}n.push("</div>"),i++}this.element=r.setInnerHtml(this.element,n.join("")),this.element.style.height=e.minHeight+"px",this.session.$useWrapMode&&(c=this.session.getLength());var d=(""+c).length*e.characterWidth,v=this.$padding||this.$computePadding();d+=v.left+v.right,d!==this.gutterWidth&&(this.gutterWidth=d,this.element.style.width=Math.ceil(this.gutterWidth)+"px",this._emit("changeGutterWidth",d))},this.$showFoldWidgets=!0,this.setShowFoldWidgets=function(e){e?r.addCssClass(this.element,"ace_folding-enabled"):r.removeCssClass(this.element,"ace_folding-enabled"),this.$showFoldWidgets=e,this.$padding=null},this.getShowFoldWidgets=function(){return this.$showFoldWidgets},this.$computePadding=function(){if(!this.element.firstChild)return{left:0,right:0};var e=r.computedStyle(this.element.firstChild);return this.$padding={},this.$padding.left=parseInt(e.paddingLeft)+1,this.$padding.right=parseInt(e.paddingRight),this.$padding},this.getRegion=function(e){var t=this.$padding||this.$computePadding(),n=this.element.getBoundingClientRect();if(e.x<t.left+n.left)return"markers";if(this.$showFoldWidgets&&e.x>n.right-t.right)return"foldWidgets"}}).call(u.prototype),t.Gutter=u}),ace.define("ace/layer/marker",["require","exports","module","ace/range","ace/lib/dom"],function(e,t,n){var r=e("../range").Range,i=e("../lib/dom"),s=function(e){this.element=i.createElement("div"),this.element.className="ace_layer ace_marker-layer",e.appendChild(this.element)};(function(){this.$padding=0,this.setPadding=function(e){this.$padding=e},this.setSession=function(e){this.session=e},this.setMarkers=function(e){this.markers=e},this.update=function(e){var e=e||this.config;if(!e)return;this.config=e;var t=[];for(var n in this.markers){var r=this.markers[n];if(!r.range){r.update(t,this,this.session,e);continue}var s=r.range.clipRows(e.firstRow,e.lastRow);if(s.isEmpty())continue;s=s.toScreenRange(this.session);if(r.renderer){var o=this.$getTop(s.start.row,e),u=this.$padding+s.start.column*e.characterWidth;r.renderer(t,s,u,o,e)}else r.type=="fullLine"?this.drawFullLineMarker(t,s,r.clazz,e):s.isMultiLine()?r.type=="text"?this.drawTextMarker(t,s,r.clazz,e):this.drawMultiLineMarker(t,s,r.clazz,e):this.drawSingleLineMarker(t,s,r.clazz+" ace_start",e)}this.element=i.setInnerHtml(this.element,t.join(""))},this.$getTop=function(e,t){return(e-t.firstRowScreen)*t.lineHeight},this.drawTextMarker=function(e,t,n,i){var s=t.start.row,o=new r(s,t.start.column,s,this.session.getScreenLastRowColumn(s));this.drawSingleLineMarker(e,o,n+" ace_start",i,1,"text"),s=t.end.row,o=new r(s,0,s,t.end.column),this.drawSingleLineMarker(e,o,n,i,0,"text");for(s=t.start.row+1;s<t.end.row;s++)o.start.row=s,o.end.row=s,o.end.column=this.session.getScreenLastRowColumn(s),this.drawSingleLineMarker(e,o,n,i,1,"text")},this.drawMultiLineMarker=function(e,t,n,r,i){var s=this.$padding,o=r.lineHeight,u=this.$getTop(t.start.row,r),a=s+t.start.column*r.characterWidth;e.push("<div class='",n," ace_start' style='","height:",o,"px;","right:0;","top:",u,"px;","left:",a,"px;'></div>"),u=this.$getTop(t.end.row,r);var f=t.end.column*r.characterWidth;e.push("<div class='",n,"' style='","height:",o,"px;","width:",f,"px;","top:",u,"px;","left:",s,"px;'></div>"),o=(t.end.row-t.start.row-1)*r.lineHeight;if(o<0)return;u=this.$getTop(t.start.row+1,r),e.push("<div class='",n,"' style='","height:",o,"px;","right:0;","top:",u,"px;","left:",s,"px;'></div>")},this.drawSingleLineMarker=function(e,t,n,r,i){var s=r.lineHeight,o=(t.end.column+(i||0)-t.start.column)*r.characterWidth,u=this.$getTop(t.start.row,r),a=this.$padding+t.start.column*r.characterWidth;e.push("<div class='",n,"' style='","height:",s,"px;","width:",o,"px;","top:",u,"px;","left:",a,"px;'></div>")},this.drawFullLineMarker=function(e,t,n,r){var i=this.$getTop(t.start.row,r),s=r.lineHeight;t.start.row!=t.end.row&&(s+=this.$getTop(t.end.row,r)-i),e.push("<div class='",n,"' style='","height:",s,"px;","top:",i,"px;","left:0;right:0;'></div>")}}).call(s.prototype),t.Marker=s}),ace.define("ace/layer/text",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/lang","ace/lib/useragent","ace/lib/event_emitter"],function(e,t,n){var r=e("../lib/oop"),i=e("../lib/dom"),s=e("../lib/lang"),o=e("../lib/useragent"),u=e("../lib/event_emitter").EventEmitter,a=function(e){this.element=i.createElement("div"),this.element.className="ace_layer ace_text-layer",e.appendChild(this.element),this.$characterSize={width:0,height:0},this.checkForSizeChanges(),this.$pollSizeChanges()};(function(){r.implement(this,u),this.EOF_CHAR="¶",this.EOL_CHAR="¬",this.TAB_CHAR="→",this.SPACE_CHAR="·",this.$padding=0,this.setPadding=function(e){this.$padding=e,this.element.style.padding="0 "+e+"px"},this.getLineHeight=function(){return this.$characterSize.height||1},this.getCharacterWidth=function(){return this.$characterSize.width||1},this.checkForSizeChanges=function(){var e=this.$measureSizes();if(e&&(this.$characterSize.width!==e.width||this.$characterSize.height!==e.height)){this.$measureNode.style.fontWeight="bold";var t=this.$measureSizes();this.$measureNode.style.fontWeight="",this.$characterSize=e,this.allowBoldFonts=t&&t.width===e.width&&t.height===e.height,this._emit("changeCharacterSize",{data:e})}},this.$pollSizeChanges=function(){var e=this;this.$pollSizeChangesTimer=setInterval(function(){e.checkForSizeChanges()},500)},this.$fontStyles={fontFamily:1,fontSize:1,fontWeight:1,fontStyle:1,lineHeight:1},this.$measureSizes=o.isIE||o.isOldGecko?function(){var e=1e3;if(!this.$measureNode){var t=this.$measureNode=i.createElement("div"),n=t.style;n.width=n.height="auto",n.left=n.top=-e*40+"px",n.visibility="hidden",n.position="fixed",n.overflow="visible",n.whiteSpace="nowrap",t.innerHTML=s.stringRepeat("Xy",e);if(this.element.ownerDocument.body)this.element.ownerDocument.body.appendChild(t);else{var r=this.element.parentNode;while(!i.hasCssClass(r,"ace_editor"))r=r.parentNode;r.appendChild(t)}}if(!this.element.offsetWidth)return null;var n=this.$measureNode.style,o=i.computedStyle(this.element);for(var u in this.$fontStyles)n[u]=o[u];var a={height:this.$measureNode.offsetHeight,width:this.$measureNode.offsetWidth/(e*2)};return a.width==0||a.height==0?null:a}:function(){if(!this.$measureNode){var e=this.$measureNode=i.createElement("div"),t=e.style;t.width=t.height="auto",t.left=t.top="-100px",t.visibility="hidden",t.position="fixed",t.overflow="visible",t.whiteSpace="nowrap",e.innerHTML="X";var n=this.element.parentNode;while(n&&!i.hasCssClass(n,"ace_editor"))n=n.parentNode;if(!n)return this.$measureNode=null;n.appendChild(e)}var r=this.$measureNode.getBoundingClientRect(),s={height:r.height,width:r.width};return s.width==0||s.height==0?null:s},this.setSession=function(e){this.session=e,this.$computeTabString()},this.showInvisibles=!1,this.setShowInvisibles=function(e){return this.showInvisibles==e?!1:(this.showInvisibles=e,this.$computeTabString(),!0)},this.displayIndentGuides=!0,this.setDisplayIndentGuides=function(e){return this.displayIndentGuides==e?!1:(this.displayIndentGuides=e,this.$computeTabString(),!0)},this.$tabStrings=[],this.onChangeTabSize=this.$computeTabString=function(){var e=this.session.getTabSize();this.tabSize=e;var t=this.$tabStrings=[0];for(var n=1;n<e+1;n++)this.showInvisibles?t.push("<span class='ace_invisible'>"+this.TAB_CHAR+Array(n).join("&#160;")+"</span>"):t.push((new Array(n+1)).join("&#160;"));if(this.displayIndentGuides){this.$indentGuideRe=/\s\S| \t|\t |\s$/;var r="ace_indent-guide",i=Array(this.tabSize+1).join("&#160;"),s=i;this.showInvisibles&&(r+=" ace_invisible",s=this.TAB_CHAR+i.substr(6)),this.$tabStrings[" "]="<span class='"+r+"'>"+i+"</span>",this.$tabStrings[" "]="<span class='"+r+"'>"+s+"</span>"}},this.updateLines=function(e,t,n){(this.config.lastRow!=e.lastRow||this.config.firstRow!=e.firstRow)&&this.scrollLines(e),this.config=e;var r=Math.max(t,e.firstRow),s=Math.min(n,e.lastRow),o=this.element.childNodes,u=0;for(var a=e.firstRow;a<r;a++){var f=this.session.getFoldLine(a);if(f){if(f.containsRow(r)){r=f.start.row;break}a=f.end.row}u++}var a=r,f=this.session.getNextFoldLine(a),l=f?f.start.row:Infinity;for(;;){a>l&&(a=f.end.row+1,f=this.session.getNextFoldLine(a,f),l=f?f.start.row:Infinity);if(a>s)break;var c=o[u++];if(c){var h=[];this.$renderLine(h,a,!this.$useLineGroups(),a==l?f:!1),i.setInnerHtml(c,h.join(""))}a++}},this.scrollLines=function(e){var t=this.config;this.config=e;if(!t||t.lastRow<e.firstRow)return this.update(e);if(e.lastRow<t.firstRow)return this.update(e);var n=this.element;if(t.firstRow<e.firstRow)for(var r=this.session.getFoldedRowCount(t.firstRow,e.firstRow-1);r>0;r--)n.removeChild(n.firstChild);if(t.lastRow>e.lastRow)for(var r=this.session.getFoldedRowCount(e.lastRow+1,t.lastRow);r>0;r--)n.removeChild(n.lastChild);if(e.firstRow<t.firstRow){var i=this.$renderLinesFragment(e,e.firstRow,t.firstRow-1);n.firstChild?n.insertBefore(i,n.firstChild):n.appendChild(i)}if(e.lastRow>t.lastRow){var i=this.$renderLinesFragment(e,t.lastRow+1,e.lastRow);n.appendChild(i)}},this.$renderLinesFragment=function(e,t,n){var r=this.element.ownerDocument.createDocumentFragment(),s=t,o=this.session.getNextFoldLine(s),u=o?o.start.row:Infinity;for(;;){s>u&&(s=o.end.row+1,o=this.session.getNextFoldLine(s,o),u=o?o.start.row:Infinity);if(s>n)break;var a=i.createElement("div"),f=[];this.$renderLine(f,s,!1,s==u?o:!1),a.innerHTML=f.join("");if(this.$useLineGroups())a.className="ace_line_group",r.appendChild(a);else{var l=a.childNodes;while(l.length)r.appendChild(l[0])}s++}return r},this.update=function(e){this.config=e;var t=[],n=e.firstRow,r=e.lastRow,s=n,o=this.session.getNextFoldLine(s),u=o?o.start.row:Infinity;for(;;){s>u&&(s=o.end.row+1,o=this.session.getNextFoldLine(s,o),u=o?o.start.row:Infinity);if(s>r)break;this.$useLineGroups()&&t.push("<div class='ace_line_group'>"),this.$renderLine(t,s,!1,s==u?o:!1),this.$useLineGroups()&&t.push("</div>"),s++}this.element=i.setInnerHtml(this.element,t.join(""))},this.$textToken={text:!0,rparen:!0,lparen:!0},this.$renderToken=function(e,t,n,r){var i=this,s=/\t|&|<|( +)|([\x00-\x1f\x80-\xa0\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\u3000\uFEFF])|[\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3000-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]/g,o=function(e,n,r,s,o){if(n)return(new Array(e.length+1)).join("&#160;");if(e=="&")return"&#38;";if(e=="<")return"&#60;";if(e==" "){var u=i.session.getScreenTabSize(t+s);return t+=u-1,i.$tabStrings[u]}if(e==" "){var a=i.showInvisibles?"ace_cjk ace_invisible":"ace_cjk",f=i.showInvisibles?i.SPACE_CHAR:"";return t+=1,"<span class='"+a+"' style='width:"+i.config.characterWidth*2+"px'>"+f+"</span>"}return r?"<span class='ace_invisible ace_invalid'>"+i.SPACE_CHAR+"</span>":(t+=1,"<span class='ace_cjk' style='width:"+i.config.characterWidth*2+"px'>"+e+"</span>")},u=r.replace(s,o);if(!this.$textToken[n.type]){var a="ace_"+n.type.replace(/\./g," ace_"),f="";n.type=="fold"&&(f=" style='width:"+n.value.length*this.config.characterWidth+"px;' "),e.push("<span class='",a,"'",f,">",u,"</span>")}else e.push(u);return t+r.length},this.renderIndentGuide=function(e,t){var n=t.search(this.$indentGuideRe);return n<=0?t:t[0]==" "?(n-=n%this.tabSize,e.push(Array(n/this.tabSize+1).join(this.$tabStrings[" "])),t.substr(n)):t[0]==" "?(e.push(Array(n+1).join(this.$tabStrings[" "])),t.substr(n)):t},this.$renderWrappedLine=function(e,t,n,r){var i=0,s=0,o=n[0],u=0;for(var a=0;a<t.length;a++){var f=t[a],l=f.value;if(a==0&&this.displayIndentGuides){i=l.length,l=this.renderIndentGuide(e,l);if(!l)continue;i-=l.length}if(i+l.length<o)u=this.$renderToken(e,u,f,l),i+=l.length;else{while(i+l.length>=o)u=this.$renderToken(e,u,f,l.substring(0,o-i)),l=l.substring(o-i),i=o,r||e.push("</div>","<div class='ace_line' style='height:",this.config.lineHeight,"px'>"),s++,u=0,o=n[s]||Number.MAX_VALUE;l.length!=0&&(i+=l.length,u=this.$renderToken(e,u,f,l))}}},this.$renderSimpleLine=function(e,t){var n=0,r=t[0],i=r.value;this.displayIndentGuides&&(i=this.renderIndentGuide(e,i)),i&&(n=this.$renderToken(e,n,r,i));for(var s=1;s<t.length;s++)r=t[s],i=r.value,n=this.$renderToken(e,n,r,i)},this.$renderLine=function(e,t,n,r){!r&&r!=0&&(r=this.session.getFoldLine(t));if(r)var i=this.$getFoldLineTokens(t,r);else var i=this.session.getTokens(t);n||e.push("<div class='ace_line' style='height:",this.config.lineHeight,"px'>");if(i.length){var s=this.session.getRowSplitData(t);s&&s.length?this.$renderWrappedLine(e,i,s,n):this.$renderSimpleLine(e,i)}this.showInvisibles&&(r&&(t=r.end.row),e.push("<span class='ace_invisible'>",t==this.session.getLength()-1?this.EOF_CHAR:this.EOL_CHAR,"</span>")),n||e.push("</div>")},this.$getFoldLineTokens=function(e,t){function i(e,t,n){var i=0,s=0;while(s+e[i].value.length<t){s+=e[i].value.length,i++;if(i==e.length)return}if(s!=t){var o=e[i].value.substring(t-s);o.length>n-t&&(o=o.substring(0,n-t)),r.push({type:e[i].type,value:o}),s=t+o.length,i+=1}while(s<n&&i<e.length){var o=e[i].value;o.length+s>n?r.push({type:e[i].type,value:o.substring(0,n-s)}):r.push(e[i]),s+=o.length,i+=1}}var n=this.session,r=[],s=n.getTokens(e);return t.walk(function(e,t,o,u,a){e!=null?r.push({type:"fold",value:e}):(a&&(s=n.getTokens(t)),s.length&&i(s,u,o))},t.end.row,this.session.getLine(t.end.row).length),r},this.$useLineGroups=function(){return this.session.getUseWrapMode()},this.destroy=function(){clearInterval(this.$pollSizeChangesTimer),this.$measureNode&&this.$measureNode.parentNode.removeChild(this.$measureNode),delete this.$measureNode}}).call(a.prototype),t.Text=a}),ace.define("ace/layer/cursor",["require","exports","module","ace/lib/dom"],function(e,t,n){var r=e("../lib/dom"),i=function(e){this.element=r.createElement("div"),this.element.className="ace_layer ace_cursor-layer",e.appendChild(this.element),this.isVisible=!1,this.isBlinking=!0,this.blinkInterval=1e3,this.smoothBlinking=!1,this.cursors=[],this.cursor=this.addCursor(),r.addCssClass(this.element,"ace_hidden-cursors")};(function(){this.$padding=0,this.setPadding=function(e){this.$padding=e},this.setSession=function(e){this.session=e},this.setBlinking=function(e){e!=this.isBlinking&&(this.isBlinking=e,this.restartTimer())},this.setBlinkInterval=function(e){e!=this.blinkInterval&&(this.blinkInterval=e,this.restartTimer())},this.setSmoothBlinking=function(e){e!=this.smoothBlinking&&(this.smoothBlinking=e,e?r.addCssClass(this.element,"ace_smooth-blinking"):r.removeCssClass(this.element,"ace_smooth-blinking"),this.restartTimer())},this.addCursor=function(){var e=r.createElement("div");return e.className="ace_cursor",this.element.appendChild(e),this.cursors.push(e),e},this.removeCursor=function(){if(this.cursors.length>1){var e=this.cursors.pop();return e.parentNode.removeChild(e),e}},this.hideCursor=function(){this.isVisible=!1,r.addCssClass(this.element,"ace_hidden-cursors"),this.restartTimer()},this.showCursor=function(){this.isVisible=!0,r.removeCssClass(this.element,"ace_hidden-cursors"),this.restartTimer()},this.restartTimer=function(){clearInterval(this.intervalId),clearTimeout(this.timeoutId),this.smoothBlinking&&r.removeCssClass(this.element,"ace_smooth-blinking");for(var e=this.cursors.length;e--;)this.cursors[e].style.opacity="";if(!this.isBlinking||!this.blinkInterval||!this.isVisible)return;this.smoothBlinking&&setTimeout(function(){r.addCssClass(this.element,"ace_smooth-blinking")}.bind(this));var t=function(){this.timeoutId=setTimeout(function(){for(var e=this.cursors.length;e--;)this.cursors[e].style.opacity=0}.bind(this),.6*this.blinkInterval)}.bind(this);this.intervalId=setInterval(function(){for(var e=this.cursors.length;e--;)this.cursors[e].style.opacity="";t()}.bind(this),this.blinkInterval),t()},this.getPixelPosition=function(e,t){if(!this.config||!this.session)return{left:0,top:0};e||(e=this.session.selection.getCursor());var n=this.session.documentToScreenPosition(e),r=this.$padding+n.column*this.config.characterWidth,i=(n.row-(t?this.config.firstRowScreen:0))*this.config.lineHeight;return{left:r,top:i}},this.update=function(e){this.config=e;var t=this.session.$selectionMarkers,n=0,r=0;if(t===undefined||t.length===0)t=[{cursor:null}];for(var n=t.length;n--;){var i=this.getPixelPosition(t[n].cursor,!0);if((i.top>e.height+e.offset||i.top<-e.offset)&&n>1)continue;var s=(this.cursors[r++]||this.addCursor()).style;s.left=i.left+"px",s.top=i.top+"px",s.width=e.characterWidth+"px",s.height=e.lineHeight+"px"}while(this.cursors.length>r)this.removeCursor();var o=this.session.getOverwrite();this.$setOverwrite(o),this.$pixelPos=i,this.restartTimer()},this.$setOverwrite=function(e){e!=this.overwrite&&(this.overwrite=e,e?r.addCssClass(this.element,"ace_overwrite-cursors"):r.removeCssClass(this.element,"ace_overwrite-cursors"))},this.destroy=function(){clearInterval(this.intervalId),clearTimeout(this.timeoutId)}}).call(i.prototype),t.Cursor=i}),ace.define("ace/scrollbar",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/event","ace/lib/event_emitter"],function(e,t,n){var r=e("./lib/oop"),i=e("./lib/dom"),s=e("./lib/event"),o=e("./lib/event_emitter").EventEmitter,u=function(e){this.element=i.createElement("div"),this.element.className="ace_scrollbar",this.inner=i.createElement("div"),this.inner.className="ace_scrollbar-inner",this.element.appendChild(this.inner),e.appendChild(this.element),this.width=i.scrollbarWidth(e.ownerDocument),this.element.style.width=(this.width||15)+5+"px",s.addListener(this.element,"scroll",this.onScroll.bind(this))};(function(){r.implement(this,o),this.onScroll=function(){this.skipEvent||(this.scrollTop=this.element.scrollTop,this._emit("scroll",{data:this.scrollTop})),this.skipEvent=!1},this.getWidth=function(){return this.width},this.setHeight=function(e){this.element.style.height=e+"px"},this.setInnerHeight=function(e){this.inner.style.height=e+"px"},this.setScrollTop=function(e){this.scrollTop!=e&&(this.skipEvent=!0,this.scrollTop=this.element.scrollTop=e)}}).call(u.prototype),t.ScrollBar=u}),ace.define("ace/renderloop",["require","exports","module","ace/lib/event"],function(e,t,n){var r=e("./lib/event"),i=function(e,t){this.onRender=e,this.pending=!1,this.changes=0,this.window=t||window};(function(){this.schedule=function(e){this.changes=this.changes|e;if(!this.pending){this.pending=!0;var t=this;r.nextFrame(function(){t.pending=!1;var e;while(e=t.changes)t.changes=0,t.onRender(e)},this.window)}}}).call(i.prototype),t.RenderLoop=i}),ace.define("ace/multi_select",["require","exports","module","ace/range_list","ace/range","ace/selection","ace/mouse/multi_select_handler","ace/lib/event","ace/lib/lang","ace/commands/multi_select_commands","ace/search","ace/edit_session","ace/editor"],function(e,t,n){function h(e,t,n){return c.$options.wrap=!0,c.$options.needle=t,c.$options.backwards=n==-1,c.find(e)}function v(e,t){return e.row==t.row&&e.column==t.column}function m(e){e.$onAddRange=e.$onAddRange.bind(e),e.$onRemoveRange=e.$onRemoveRange.bind(e),e.$onMultiSelect=e.$onMultiSelect.bind(e),e.$onSingleSelect=e.$onSingleSelect.bind(e),t.onSessionChange.call(e,e),e.on("changeSession",t.onSessionChange.bind(e)),e.on("mousedown",o),e.commands.addCommands(f.defaultCommands),g(e)}function g(e){function i(){n&&(r.style.cursor="",n=!1)}var t=e.textInput.getElement(),n=!1,r=e.renderer.content;u.addListener(t,"keydown",function(e){e.keyCode==18&&!(e.ctrlKey||e.shiftKey||e.metaKey)?n||(r.style.cursor="crosshair",n=!0):n&&(r.style.cursor="")}),u.addListener(t,"keyup",i),u.addListener(t,"blur",i)}var r=e("./range_list").RangeList,i=e("./range").Range,s=e("./selection").Selection,o=e("./mouse/multi_select_handler").onMouseDown,u=e("./lib/event"),a=e("./lib/lang"),f=e("./commands/multi_select_commands");t.commands=f.defaultCommands.concat(f.multiSelectCommands);var l=e("./search").Search,c=new l,p=e("./edit_session").EditSession;(function(){this.getSelectionMarkers=function(){return this.$selectionMarkers}}).call(p.prototype),function(){this.ranges=null,this.rangeList=null,this.addRange=function(e,t){if(!e)return;if(!this.inMultiSelectMode&&this.rangeCount==0){var n=this.toOrientedRange();if(e.intersects(n))return t||this.fromOrientedRange(e);this.rangeList.add(n),this.$onAddRange(n)}e.cursor||(e.cursor=e.end);var r=this.rangeList.add(e);return this.$onAddRange(e),r.length&&this.$onRemoveRange(r),this.rangeCount>1&&!this.inMultiSelectMode&&(this._emit("multiSelect"),this.inMultiSelectMode=!0,this.session.$undoSelect=!1,this.rangeList.attach(this.session)),t||this.fromOrientedRange(e)},this.toSingleRange=function(e){e=e||this.ranges[0];var t=this.rangeList.removeAll();t.length&&this.$onRemoveRange(t),e&&this.fromOrientedRange(e)},this.substractPoint=function(e){var t=this.rangeList.substractPoint(e);if(t)return this.$onRemoveRange(t),t[0]},this.mergeOverlappingRanges=function(){var e=this.rangeList.merge();e.length?this.$onRemoveRange(e):this.ranges[0]&&this.fromOrientedRange(this.ranges[0])},this.$onAddRange=function(e){this.rangeCount=this.rangeList.ranges.length,this.ranges.unshift(e),this._emit("addRange",{range:e})},this.$onRemoveRange=function(e){this.rangeCount=this.rangeList.ranges.length;if(this.rangeCount==1&&this.inMultiSelectMode){var t=this.rangeList.ranges.pop();e.push(t),this.rangeCount=0}for(var n=e.length;n--;){var r=this.ranges.indexOf(e[n]);this.ranges.splice(r,1)}this._emit("removeRange",{ranges:e}),this.rangeCount==0&&this.inMultiSelectMode&&(this.inMultiSelectMode=!1,this._emit("singleSelect"),this.session.$undoSelect=!0,this.rangeList.detach(this.session)),t=t||this.ranges[0],t&&!t.isEqual(this.getRange())&&this.fromOrientedRange(t)},this.$initRangeList=function(){if(this.rangeList)return;this.rangeList=new r,this.ranges=[],this.rangeCount=0},this.getAllRanges=function(){return this.rangeList.ranges.concat()},this.splitIntoLines=function(){if(this.rangeCount>1){var e=this.rangeList.ranges,t=e[e.length-1],n=i.fromPoints(e[0].start,t.end);this.toSingleRange(),this.setSelectionRange(n,t.cursor==t.start)}else{var n=this.getRange(),r=this.isBackwards(),s=n.start.row,o=n.end.row;if(s==o){if(r)var u=n.end,a=n.start;else var u=n.start,a=n.end;this.addRange(i.fromPoints(a,a)),this.addRange(i.fromPoints(u,u));return}var f=[],l=this.getLineRange(s,!0);l.start.column=n.start.column,f.push(l);for(var c=s+1;c<o;c++)f.push(this.getLineRange(c,!0));l=this.getLineRange(o,!0),l.end.column=n.end.column,f.push(l),f.forEach(this.addRange,this)}},this.toggleBlockSelection=function(){if(this.rangeCount>1){var e=this.rangeList.ranges,t=e[e.length-1],n=i.fromPoints(e[0].start,t.end);this.toSingleRange(),this.setSelectionRange(n,t.cursor==t.start)}else{var r=this.session.documentToScreenPosition(this.selectionLead),s=this.session.documentToScreenPosition(this.selectionAnchor),o=this.rectangularRangeBlock(r,s);o.forEach(this.addRange,this)}},this.rectangularRangeBlock=function(e,t,n){var r=[],s=e.column<t.column;if(s)var o=e.column,u=t.column;else var o=t.column,u=e.column;var a=e.row<t.row;if(a)var f=e.row,l=t.row;else var f=t.row,l=e.row;o<0&&(o=0),f<0&&(f=0),f==l&&(n=!0);for(var c=f;c<=l;c++){var h=i.fromPoints(this.session.screenToDocumentPosition(c,o),this.session.screenToDocumentPosition(c,u));if(h.isEmpty()){if(p&&v(h.end,p))break;var p=h.end}h.cursor=s?h.start:h.end,r.push(h)}a&&r.reverse();if(!n){var d=r.length-1;while(r[d].isEmpty()&&d>0)d--;if(d>0){var m=0;while(r[m].isEmpty())m++}for(var g=d;g>=m;g--)r[g].isEmpty()&&r.splice(g,1)}return r}}.call(s.prototype);var d=e("./editor").Editor;(function(){this.updateSelectionMarkers=function(){this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.addSelectionMarker=function(e){e.cursor||(e.cursor=e.end);var t=this.getSelectionStyle();return e.marker=this.session.addMarker(e,"ace_selection",t),this.session.$selectionMarkers.push(e),this.session.selectionMarkerCount=this.session.$selectionMarkers.length,e},this.removeSelectionMarker=function(e){if(!e.marker)return;this.session.removeMarker(e.marker);var t=this.session.$selectionMarkers.indexOf(e);t!=-1&&this.session.$selectionMarkers.splice(t,1),this.session.selectionMarkerCount=this.session.$selectionMarkers.length},this.removeSelectionMarkers=function(e){var t=this.session.$selectionMarkers;for(var n=e.length;n--;){var r=e[n];if(!r.marker)continue;this.session.removeMarker(r.marker);var i=t.indexOf(r);i!=-1&&t.splice(i,1)}this.session.selectionMarkerCount=t.length},this.$onAddRange=function(e){this.addSelectionMarker(e.range),this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.$onRemoveRange=function(e){this.removeSelectionMarkers(e.ranges),this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.$onMultiSelect=function(e){if(this.inMultiSelectMode)return;this.inMultiSelectMode=!0,this.setStyle("ace_multiselect"),this.keyBinding.addKeyboardHandler(f.keyboardHandler),this.commands.on("exec",this.$onMultiSelectExec),this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.$onSingleSelect=function(e){if(this.session.multiSelect.inVirtualMode)return;this.inMultiSelectMode=!1,this.unsetStyle("ace_multiselect"),this.keyBinding.removeKeyboardHandler(f.keyboardHandler),this.commands.removeEventListener("exec",this.$onMultiSelectExec),this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.$onMultiSelectExec=function(e){var t=e.command,n=e.editor;if(!n.multiSelect)return;t.multiSelectAction?t.multiSelectAction=="forEach"?n.forEachSelection(t,e.args):t.multiSelectAction=="single"?(n.exitMultiSelectMode(),t.exec(n,e.args||{})):t.multiSelectAction(n,e.args||{}):(t.exec(n,e.args||{}),n.multiSelect.addRange(n.multiSelect.toOrientedRange()),n.multiSelect.mergeOverlappingRanges()),e.preventDefault()},this.forEachSelection=function(e,t){if(this.inVirtualSelectionMode)return;var n=this.session,r=this.selection,i=r.rangeList,o=r._eventRegistry;r._eventRegistry={};var u=new s(n);this.inVirtualSelectionMode=!0;for(var a=i.ranges.length;a--;)u.fromOrientedRange(i.ranges[a]),this.selection=n.selection=u,e.exec(this,t||{}),u.toOrientedRange(i.ranges[a]);u.detach(),this.selection=n.selection=r,this.inVirtualSelectionMode=!1,r._eventRegistry=o,r.mergeOverlappingRanges(),this.onCursorChange(),this.onSelectionChange()},this.exitMultiSelectMode=function(){if(this.inVirtualSelectionMode)return;this.multiSelect.toSingleRange()},this.getCopyText=function(){var e="";if(this.inMultiSelectMode){var t=this.multiSelect.rangeList.ranges;e=[];for(var n=0;n<t.length;n++)e.push(this.session.getTextRange(t[n]));e=e.join(this.session.getDocument().getNewLineCharacter())}else this.selection.isEmpty()||(e=this.session.getTextRange(this.getSelectionRange()));return e},this.onPaste=function(e){if(this.$readOnly)return;this._emit("paste",e);if(!this.inMultiSelectMode)return this.insert(e);var t=e.split(/\r\n|\r|\n/),n=this.selection.rangeList.ranges;if(t.length>n.length||t.length<=2||!t[1])return this.commands.exec("insertstring",this,e);for(var r=n.length;r--;){var i=n[r];i.isEmpty()||this.session.remove(i),this.session.insert(i.start,t[r])}},this.findAll=function(e,t,n){t=t||{},t.needle=e||t.needle,this.$search.set(t);var r=this.$search.findAll(this.session);if(!r.length)return 0;this.$blockScrolling+=1;var i=this.multiSelect;n||i.toSingleRange(r[0]);for(var s=r.length;s--;)i.addRange(r[s],!0);return this.$blockScrolling-=1,r.length},this.selectMoreLines=function(e,t){var n=this.selection.toOrientedRange(),r=n.cursor==n.end,s=this.session.documentToScreenPosition(n.cursor);this.selection.$desiredColumn&&(s.column=this.selection.$desiredColumn);var o=this.session.screenToDocumentPosition(s.row+e,s.column);if(!n.isEmpty())var u=this.session.documentToScreenPosition(r?n.end:n.start),a=this.session.screenToDocumentPosition(u.row+e,u.column);else var a=o;if(r){var f=i.fromPoints(o,a);f.cursor=f.start}else{var f=i.fromPoints(a,o);f.cursor=f.end}f.desiredColumn=s.column;if(!this.selection.inMultiSelectMode)this.selection.addRange(n);else if(t)var l=n.cursor;this.selection.addRange(f),l&&this.selection.substractPoint(l)},this.transposeSelections=function(e){var t=this.session,n=t.multiSelect,r=n.ranges;for(var i=r.length;i--;){var s=r[i];if(s.isEmpty()){var o=t.getWordRange(s.start.row,s.start.column);s.start.row=o.start.row,s.start.column=o.start.column,s.end.row=o.end.row,s.end.column=o.end.column}}n.mergeOverlappingRanges();var u=[];for(var i=r.length;i--;){var s=r[i];u.unshift(t.getTextRange(s))}e<0?u.unshift(u.pop()):u.push(u.shift());for(var i=r.length;i--;){var s=r[i],o=s.clone();t.replace(s,u[i]),s.start.row=o.start.row,s.start.column=o.start.column}},this.selectMore=function(e,t){var n=this.session,r=n.multiSelect,i=r.toOrientedRange();if(i.isEmpty()){var i=n.getWordRange(i.start.row,i.start.column);i.cursor=i.end,this.multiSelect.addRange(i)}var s=n.getTextRange(i),o=h(n,s,e);o&&(o.cursor=e==-1?o.start:o.end,this.multiSelect.addRange(o)),t&&this.multiSelect.substractPoint(i.cursor)},this.alignCursors=function(){var e=this.session,t=e.multiSelect,n=t.ranges;if(!n.length){var r=this.selection.getRange(),s=r.start.row,o=r.end.row,u=this.session.doc.removeLines(s,o);u=this.$reAlignText(u),this.session.doc.insertLines(s,u),r.start.column=0,r.end.column=u[u.length-1].length,this.selection.setRange(r)}else{var f=-1,l=n.filter(function(e){if(e.cursor.row==f)return!0;f=e.cursor.row});t.$onRemoveRange(l);var c=0,h=Infinity,p=n.map(function(t){var n=t.cursor,r=e.getLine(n.row),i=r.substr(n.column).search(/\S/g);return i==-1&&(i=0),n.column>c&&(c=n.column),i<h&&(h=i),i});n.forEach(function(t,n){var r=t.cursor,s=c-r.column,o=p[n]-h;s>o?e.insert(r,a.stringRepeat(" ",s-o)):e.remove(new i(r.row,r.column,r.row,r.column-s+o)),t.start.column=t.end.column=c,t.start.row=t.end.row=r.row,t.cursor=t.end}),t.fromOrientedRange(n[0]),this.renderer.updateCursor(),this.renderer.updateBackMarkers()}},this.$reAlignText=function(e){function o(e,t){return Array(e+1).join(t)}function u(e){return e[2]?o(r," ")+e[2]+o(i-e[2].length+s," ")+e[4].replace(/^([=:])\s+/,"$1 "):e[0]}function a(e){return e[2]?o(r+i-e[2].length," ")+e[2]+o(s," ")+e[4].replace(/^([=:])\s+/,"$1 "):e[0]}function f(e){return e[2]?o(r," ")+e[2]+o(s," ")+e[4].replace(/^([=:])\s+/,"$1 "):e[0]}var t=!0,n=!0,r,i,s;return e.map(function(e){var o=e.match(/(\s*)(.*?)(\s*)([=:].*)/);return o?r==null?(r=o[1].length,i=o[2].length,s=o[3].length,o):(r+i+s!=o[1].length+o[2].length+o[3].length&&(n=!1),r!=o[1].length&&(t=!1),r>o[1].length&&(r=o[1].length),i<o[2].length&&(i=o[2].length),s>o[3].length&&(s=o[3].length),o):[e]}).map(t?n?a:u:f)}}).call(d.prototype),t.onSessionChange=function(e){var t=e.session;t.multiSelect||(t.$selectionMarkers=[],t.selection.$initRangeList(),t.multiSelect=t.selection),this.multiSelect=t.multiSelect;var n=e.oldSession;n&&(n.multiSelect&&n.multiSelect.editor==this&&(n.multiSelect.editor=null),t.multiSelect.removeEventListener("addRange",this.$onAddRange),t.multiSelect.removeEventListener("removeRange",this.$onRemoveRange),t.multiSelect.removeEventListener("multiSelect",this.$onMultiSelect),t.multiSelect.removeEventListener("singleSelect",this.$onSingleSelect)),t.multiSelect.on("addRange",this.$onAddRange),t.multiSelect.on("removeRange",this.$onRemoveRange),t.multiSelect.on("multiSelect",this.$onMultiSelect),t.multiSelect.on("singleSelect",this.$onSingleSelect),this.inMultiSelectMode!=t.selection.inMultiSelectMode&&(t.selection.inMultiSelectMode?this.$onMultiSelect():this.$onSingleSelect())},t.MultiSelect=m}),ace.define("ace/range_list",["require","exports","module"],function(e,t,n){var r=function(){this.ranges=[]};(function(){this.comparePoints=function(e,t){return e.row-t.row||e.column-t.column},this.pointIndex=function(e,t){var n=this.ranges;for(var r=t||0;r<n.length;r++){var i=n[r],s=this.comparePoints(e,i.end);if(s>0)continue;return s==0?r:(s=this.comparePoints(e,i.start),s>=0?r:-r-1)}return-r-1},this.add=function(e){var t=this.pointIndex(e.start);t<0&&(t=-t-1);var n=this.pointIndex(e.end,t);return n<0?n=-n-1:n++,this.ranges.splice(t,n-t,e)},this.addList=function(e){var t=[];for(var n=e.length;n--;)t.push.call(t,this.add(e[n]));return t},this.substractPoint=function(e){var t=this.pointIndex(e);if(t>=0)return this.ranges.splice(t,1)},this.merge=function(){var e=[],t=this.ranges,n=t[0],r;for(var i=1;i<t.length;i++){r=n,n=t[i];var s=this.comparePoints(r.end,n.start);if(s<0)continue;if(s==0&&!r.isEmpty()&&!n.isEmpty())continue;this.comparePoints(r.end,n.end)<0&&(r.end.row=n.end.row,r.end.column=n.end.column),t.splice(i,1),e.push(n),n=r,i--}return e},this.contains=function(e,t){return this.pointIndex({row:e,column:t})>=0},this.containsPoint=function(e){return this.pointIndex(e)>=0},this.rangeAtPoint=function(e){var t=this.pointIndex(e);if(t>=0)return this.ranges[t]},this.clipRows=function(e,t){var n=this.ranges;if(n[0].start.row>t||n[n.length-1].start.row<e)return[];var r=this.pointIndex({row:e,column:0});r<0&&(r=-r-1);var i=this.pointIndex({row:t,column:0},r);i<0&&(i=-i-1);var s=[];for(var o=r;o<i;o++)s.push(n[o]);return s},this.removeAll=function(){return this.ranges.splice(0,this.ranges.length)},this.attach=function(e){this.session&&this.detach(),this.session=e,this.onChange=this.$onChange.bind(this),this.session.on("change",this.onChange)},this.detach=function(){if(!this.session)return;this.session.removeListener("change",this.onChange),this.session=null},this.$onChange=function(e){var t=e.data.range;if(e.data.action[0]=="i")var n=t.start,r=t.end;else var r=t.start,n=t.end;var i=n.row,s=r.row,o=s-i,u=-n.column+r.column,a=this.ranges;for(var f=0,l=a.length;f<l;f++){var c=a[f];if(c.end.row<i)continue;if(c.start.row>i)break;c.start.row==i&&c.start.column>=n.column&&(c.start.column+=u,c.start.row+=o),c.end.row==i&&c.end.column>=n.column&&(c.end.column+=u,c.end.row+=o)}if(o!=0&&f<l)for(;f<l;f++){var c=a[f];c.start.row+=o,c.end.row+=o}}}).call(r.prototype),t.RangeList=r}),ace.define("ace/mouse/multi_select_handler",["require","exports","module","ace/lib/event"],function(e,t,n){function i(e,t){return e.row==t.row&&e.column==t.column}function s(e){var t=e.domEvent,n=t.altKey,s=t.shiftKey,o=e.getAccelKey(),u=e.getButton();if(e.editor.inMultiSelectMode&&u==2){e.editor.textInput.onContextMenu(e.domEvent);return}if(!o&&!n){u==0&&e.editor.inMultiSelectMode&&e.editor.exitMultiSelectMode();return}var a=e.editor,f=a.selection,l=a.inMultiSelectMode,c=e.getDocumentPosition(),h=f.getCursor(),p=e.inSelection()||f.isEmpty()&&i(c,h),d=e.x,v=e.y,m=function(e){d=e.clientX,v=e.clientY},g=function(){var e=a.renderer.pixelToScreenCoordinates(d,v),t=y.screenToDocumentPosition(e.row,e.column);if(i(w,e)&&i(t,f.selectionLead))return;w=e,a.selection.moveCursorToPosition(t),a.selection.clearSelection(),a.renderer.scrollCursorIntoView(),a.removeSelectionMarkers(x),x=f.rectangularRangeBlock(w,b),x.forEach(a.addSelectionMarker,a),a.updateSelectionMarkers()},y=a.session,b=a.renderer.pixelToScreenCoordinates(d,v),w=b;if(o&&!s&&!n&&u==0){if(!l&&p)return;if(!l){var E=f.toOrientedRange();a.addSelectionMarker(E)}var S=f.rangeList.rangeAtPoint(c);r.capture(a.container,function(){},function(){var e=f.toOrientedRange();S&&e.isEmpty()&&i(S.cursor,e.cursor)?f.substractPoint(e.cursor):(E&&(a.removeSelectionMarker(E),f.addRange(E)),f.addRange(e))})}else if(!s&&n&&u==0){e.stop(),l&&!o?f.toSingleRange():!l&&o&&f.addRange(),f.moveCursorToPosition(c),f.clearSelection();var x=[],T=function(e){clearInterval(C),a.removeSelectionMarkers(x);for(var t=0;t<x.length;t++)f.addRange(x[t])},N=g;r.capture(a.container,m,T);var C=setInterval(function(){N()},20);return e.preventDefault()}}var r=e("../lib/event");t.onMouseDown=s}),ace.define("ace/commands/multi_select_commands",["require","exports","module","ace/keyboard/hash_handler"],function(e,t,n){t.defaultCommands=[{name:"addCursorAbove",exec:function(e){e.selectMoreLines(-1)},bindKey:{win:"Ctrl-Alt-Up",mac:"Ctrl-Alt-Up"},readonly:!0},{name:"addCursorBelow",exec:function(e){e.selectMoreLines(1)},bindKey:{win:"Ctrl-Alt-Down",mac:"Ctrl-Alt-Down"},readonly:!0},{name:"addCursorAboveSkipCurrent",exec:function(e){e.selectMoreLines(-1,!0)},bindKey:{win:"Ctrl-Alt-Shift-Up",mac:"Ctrl-Alt-Shift-Up"},readonly:!0},{name:"addCursorBelowSkipCurrent",exec:function(e){e.selectMoreLines(1,!0)},bindKey:{win:"Ctrl-Alt-Shift-Down",mac:"Ctrl-Alt-Shift-Down"},readonly:!0},{name:"selectMoreBefore",exec:function(e){e.selectMore(-1)},bindKey:{win:"Ctrl-Alt-Left",mac:"Ctrl-Alt-Left"},readonly:!0},{name:"selectMoreAfter",exec:function(e){e.selectMore(1)},bindKey:{win:"Ctrl-Alt-Right",mac:"Ctrl-Alt-Right"},readonly:!0},{name:"selectNextBefore",exec:function(e){e.selectMore(-1,!0)},bindKey:{win:"Ctrl-Alt-Shift-Left",mac:"Ctrl-Alt-Shift-Left"},readonly:!0},{name:"selectNextAfter",exec:function(e){e.selectMore(1,!0)},bindKey:{win:"Ctrl-Alt-Shift-Right",mac:"Ctrl-Alt-Shift-Right"},readonly:!0},{name:"splitIntoLines",exec:function(e){e.multiSelect.splitIntoLines()},bindKey:{win:"Ctrl-Alt-L",mac:"Ctrl-Alt-L"},readonly:!0},{name:"alignCursors",exec:function(e){e.alignCursors()},bindKey:{win:"Ctrl-Alt-A",mac:"Ctrl-Alt-A"}}],t.multiSelectCommands=[{name:"singleSelection",bindKey:"esc",exec:function(e){e.exitMultiSelectMode()},readonly:!0,isAvailable:function(e){return e&&e.inMultiSelectMode}}];var r=e("../keyboard/hash_handler").HashHandler;t.keyboardHandler=new r(t.multiSelectCommands)}),ace.define("ace/worker/worker_client",["require","exports","module","ace/lib/oop","ace/lib/event_emitter","ace/config"],function(e,t,n){var r=e("../lib/oop"),i=e("../lib/event_emitter").EventEmitter,s=e("../config"),o=function(t,n,r){this.changeListener=this.changeListener.bind(this),this.onMessage=this.onMessage.bind(this),this.onError=this.onError.bind(this);var i;if(s.get("packaged"))i=s.moduleUrl(n,"worker");else{var o=this.$normalizePath;typeof e.supports!="undefined"&&e.supports.indexOf("ucjs2-pinf-0")>=0?i=e.nameToUrl("ace/worker/worker_sourcemint"):(e.nameToUrl&&!e.toUrl&&(e.toUrl=e.nameToUrl),i=o(e.toUrl("ace/worker/worker",null,"_")));var u={};t.forEach(function(t){u[t]=o(e.toUrl(t,null,"_").replace(/.js(\?.*)?$/,""))})}this.$worker=new Worker(i),this.$worker.postMessage({init:!0,tlns:u,module:n,classname:r}),this.callbackId=1,this.callbacks={},this.$worker.onerror=this.onError,this.$worker.onmessage=this.onMessage};(function(){r.implement(this,i),this.onError=function(e){throw window.console&&console.log&&console.log(e),e},this.onMessage=function(e){var t=e.data;switch(t.type){case"log":window.console&&console.log&&console.log.apply(console,t.data);break;case"event":this._emit(t.name,{data:t.data});break;case"call":var n=this.callbacks[t.id];n&&(n(t.data),delete this.callbacks[t.id])}},this.$normalizePath=function(e){return location.host?(e=e.replace(/^[a-z]+:\/\/[^\/]+/,""),e=location.protocol+"//"+location.host+(e.charAt(0)=="/"?"":location.pathname.replace(/\/[^\/]*$/,""))+"/"+e.replace(/^[\/]+/,""),e):e},this.terminate=function(){this._emit("terminate",{}),this.$worker.terminate(),this.$worker=null,this.$doc.removeEventListener("change",this.changeListener),this.$doc=null},this.send=function(e,t){this.$worker.postMessage({command:e,args:t})},this.call=function(e,t,n){if(n){var r=this.callbackId++;this.callbacks[r]=n,t.push(r)}this.send(e,t)},this.emit=function(e,t){try{this.$worker.postMessage({event:e,data:{data:t.data}})}catch(n){}},this.attachToDocument=function(e){this.$doc&&this.terminate(),this.$doc=e,this.call("setValue",[e.getValue()]),e.on("change",this.changeListener)},this.changeListener=function(e){e.range={start:e.data.range.start,end:e.data.range.end},this.emit("change",e)}}).call(o.prototype);var u=function(t,n,r){this.changeListener=this.changeListener.bind(this),this.callbackId=1,this.callbacks={},this.messageBuffer=[];var s=null,o=Object.create(i),u=this;this.$worker={},this.$worker.postMessage=function(e){u.messageBuffer.push(e),s&&setTimeout(a)};var a=function(){var e=u.messageBuffer.shift();e.command?s[e.command].apply(s,e.args):e.event&&o._emit(e.event,e.data)};o.postMessage=function(e){u.onMessage({data:e})},o.callback=function(e,t){this.postMessage({type:"call",id:t,data:e})},o.emit=function(e,t){this.postMessage({type:"event",name:e,data:t})},e([n],function(e){s=new e[r](o);while(u.messageBuffer.length)a()})};u.prototype=o.prototype,t.UIWorkerClient=u,t.WorkerClient=o}),ace.define("ace/placeholder",["require","exports","module","ace/range","ace/lib/event_emitter","ace/lib/oop"],function(e,t,n){var r=e("./range").Range,i=e("./lib/event_emitter").EventEmitter,s=e("./lib/oop"),o=function(e,t,n,r,i,s){var o=this;this.length=t,this.session=e,this.doc=e.getDocument(),this.mainClass=i,this.othersClass=s,this.$onUpdate=this.onUpdate.bind(this),this.doc.on("change",this.$onUpdate),this.$others=r,this.$onCursorChange=function(){setTimeout(function(){o.onCursorChange()})},this.$pos=n;var u=e.getUndoManager().$undoStack||e.getUndoManager().$undostack||{length:-1};this.$undoStackDepth=u.length,this.setup(),e.selection.on("changeCursor",this.$onCursorChange)};(function(){s.implement(this,i),this.setup=function(){var e=this,t=this.doc,n=this.session,i=this.$pos;this.pos=t.createAnchor(i.row,i.column),this.markerId=n.addMarker(new r(i.row,i.column,i.row,i.column+this.length),this.mainClass,null,!1),this.pos.on("change",function(t){n.removeMarker(e.markerId),e.markerId=n.addMarker(new r(t.value.row,t.value.column,t.value.row,t.value.column+e.length),e.mainClass,null,!1)}),this.others=[],this.$others.forEach(function(n){var r=t.createAnchor(n.row,n.column);e.others.push(r)}),n.setUndoSelect(!1)},this.showOtherMarkers=function(){if(this.othersActive)return;var e=this.session,t=this;this.othersActive=!0,this.others.forEach(function(n){n.markerId=e.addMarker(new r(n.row,n.column,n.row,n.column+t.length),t.othersClass,null,!1),n.on("change",function(i){e.removeMarker(n.markerId),n.markerId=e.addMarker(new r(i.value.row,i.value.column,i.value.row,i.value.column+t.length),t.othersClass,null,!1)})})},this.hideOtherMarkers=function(){if(!this.othersActive)return;this.othersActive=!1;for(var e=0;e<this.others.length;e++)this.session.removeMarker(this.others[e].markerId)},this.onUpdate=function(e){var t=e.data,n=t.range;if(n.start.row!==n.end.row)return;if(n.start.row!==this.pos.row)return;if(this.$updating)return;this.$updating=!0;var i=t.action==="insertText"?n.end.column-n.start.column:n.start.column-n.end.column;if(n.start.column>=this.pos.column&&n.start.column<=this.pos.column+this.length+1){var s=n.start.column-this.pos.column;this.length+=i;if(!this.session.$fromUndo){if(t.action==="insertText")for(var o=this.others.length-1;o>=0;o--){var u=this.others[o],a={row:u.row,column:u.column+s};u.row===n.start.row&&n.start.column<u.column&&(a.column+=i),this.doc.insert(a,t.text)}else if(t.action==="removeText")for(var o=this.others.length-1;o>=0;o--){var u=this.others[o],a={row:u.row,column:u.column+s};u.row===n.start.row&&n.start.column<u.column&&(a.column+=i),this.doc.remove(new r(a.row,a.column,a.row,a.column-i))}n.start.column===this.pos.column&&t.action==="insertText"?setTimeout(function(){this.pos.setPosition(this.pos.row,this.pos.column-i);for(var e=0;e<this.others.length;e++){var t=this.others[e],r={row:t.row,column:t.column-i};t.row===n.start.row&&n.start.column<t.column&&(r.column+=i),t.setPosition(r.row,r.column)}}.bind(this),0):n.start.column===this.pos.column&&t.action==="removeText"&&setTimeout(function(){for(var e=0;e<this.others.length;e++){var t=this.others[e];t.row===n.start.row&&n.start.column<t.column&&t.setPosition(t.row,t.column-i)}}.bind(this),0)}this.pos._emit("change",{value:this.pos});for(var o=0;o<this.others.length;o++)this.others[o]._emit("change",{value:this.others[o]})}this.$updating=!1},this.onCursorChange=function(e){if(this.$updating)return;var t=this.session.selection.getCursor();t.row===this.pos.row&&t.column>=this.pos.column&&t.column<=this.pos.column+this.length?(this.showOtherMarkers(),this._emit("cursorEnter",e)):(this.hideOtherMarkers(),this._emit("cursorLeave",e))},this.detach=function(){this.session.removeMarker(this.markerId),this.hideOtherMarkers(),this.doc.removeEventListener("change",this.$onUpdate),this.session.selection.removeEventListener("changeCursor",this.$onCursorChange),this.pos.detach();for(var e=0;e<this.others.length;e++)this.others[e].detach();this.session.setUndoSelect(!0)},this.cancel=function(){if(this.$undoStackDepth===-1)throw Error("Canceling placeholders only supported with undo manager attached to session.");var e=this.session.getUndoManager(),t=(e.$undoStack||e.$undostack).length-this.$undoStackDepth;for(var n=0;n<t;n++)e.undo(!0)}}).call(o.prototype),t.PlaceHolder=o}),ace.define("ace/mode/folding/fold_mode",["require","exports","module","ace/range"],function(e,t,n){var r=e("../../range").Range,i=t.FoldMode=function(){};(function(){this.foldingStartMarker=null,this.foldingStopMarker=null,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);return this.foldingStartMarker.test(r)?"start":t=="markbeginend"&&this.foldingStopMarker&&this.foldingStopMarker.test(r)?"end":""},this.getFoldWidgetRange=function(e,t,n){return null},this.indentationBlock=function(e,t,n){var i=/\S/,s=e.getLine(t),o=s.search(i);if(o==-1)return;var u=n||s.length,a=e.getLength(),f=t,l=t;while(++t<a){var c=e.getLine(t).search(i);if(c==-1)continue;if(c<=o)break;l=t}if(l>f){var h=e.getLine(l).length;return new r(f,u,l,h)}},this.openingBracketBlock=function(e,t,n,i,s){var o={row:n,column:i+1},u=e.$findClosingBracket(t,o,s);if(!u)return;var a=e.foldWidgets[u.row];return a==null&&(a=this.getFoldWidget(e,u.row)),a=="start"&&u.row>o.row&&(u.row--,u.column=e.getLine(u.row).length),r.fromPoints(o,u)},this.closingBracketBlock=function(e,t,n,i,s){var o={row:n,column:i},u=e.$findOpeningBracket(t,o);if(!u)return;return u.column++,o.column--,r.fromPoints(u,o)}}).call(i.prototype)});
- (function() {
- ace.require(["ace/ace"], function(a) {
- a && a.config.init();
- if (!window.ace)
- window.ace = {};
- for (var key in a) if (a.hasOwnProperty(key))
- ace[key] = a[key];
- });
- })();
diff --git a/plugins/jetpack/modules/custom-css/custom-css/js/ace/mode-css.js b/plugins/jetpack/modules/custom-css/custom-css/js/ace/mode-css.js
deleted file mode 100644
index 20155551..00000000
--- a/plugins/jetpack/modules/custom-css/custom-css/js/ace/mode-css.js
+++ /dev/null
@@ -1 +0,0 @@
-ace.define("ace/mode/css",["require","exports","module","ace/lib/oop","ace/mode/text","ace/tokenizer","ace/mode/css_highlight_rules","ace/mode/matching_brace_outdent","ace/worker/worker_client","ace/mode/behaviour/cstyle","ace/mode/folding/cstyle"],function(e,t,n){var r=e("../lib/oop"),i=e("./text").Mode,s=e("../tokenizer").Tokenizer,o=e("./css_highlight_rules").CssHighlightRules,u=e("./matching_brace_outdent").MatchingBraceOutdent,a=e("../worker/worker_client").WorkerClient,f=e("./behaviour/cstyle").CstyleBehaviour,l=e("./folding/cstyle").FoldMode,c=function(){this.$tokenizer=new s((new o).getRules(),"i"),this.$outdent=new u,this.$behaviour=new f,this.foldingRules=new l};r.inherits(c,i),function(){this.foldingRules="cStyle",this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t),i=this.$tokenizer.getLineTokens(t,e).tokens;if(i.length&&i[i.length-1].type=="comment")return r;var s=t.match(/^.*\{\s*$/);return s&&(r+=n),r},this.checkOutdent=function(e,t,n){return this.$outdent.checkOutdent(t,n)},this.autoOutdent=function(e,t,n){this.$outdent.autoOutdent(t,n)},this.createWorker=function(e){var t=new a(["ace"],"ace/mode/css_worker","Worker");return t.attachToDocument(e.getDocument()),t.on("csslint",function(t){e.setAnnotations(t.data)}),t.on("terminate",function(){e.clearAnnotations()}),t}}.call(c.prototype),t.Mode=c}),ace.define("ace/mode/css_highlight_rules",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/mode/text_highlight_rules"],function(e,t,n){var r=e("../lib/oop"),i=e("../lib/lang"),s=e("./text_highlight_rules").TextHighlightRules,o=t.supportType="animation-fill-mode|alignment-adjust|alignment-baseline|animation-delay|animation-direction|animation-duration|animation-iteration-count|animation-name|animation-play-state|animation-timing-function|animation|appearance|azimuth|backface-visibility|background-attachment|background-break|background-clip|background-color|background-image|background-origin|background-position|background-repeat|background-size|background|baseline-shift|binding|bleed|bookmark-label|bookmark-level|bookmark-state|bookmark-target|border-bottom|border-bottom-color|border-bottom-left-radius|border-bottom-right-radius|border-bottom-style|border-bottom-width|border-collapse|border-color|border-image|border-image-outset|border-image-repeat|border-image-slice|border-image-source|border-image-width|border-left|border-left-color|border-left-style|border-left-width|border-radius|border-right|border-right-color|border-right-style|border-right-width|border-spacing|border-style|border-top|border-top-color|border-top-left-radius|border-top-right-radius|border-top-style|border-top-width|border-width|border|bottom|box-align|box-decoration-break|box-direction|box-flex-group|box-flex|box-lines|box-ordinal-group|box-orient|box-pack|box-shadow|box-sizing|break-after|break-before|break-inside|caption-side|clear|clip|color-profile|color|column-count|column-fill|column-gap|column-rule|column-rule-color|column-rule-style|column-rule-width|column-span|column-width|columns|content|counter-increment|counter-reset|crop|cue-after|cue-before|cue|cursor|direction|display|dominant-baseline|drop-initial-after-adjust|drop-initial-after-align|drop-initial-before-adjust|drop-initial-before-align|drop-initial-size|drop-initial-value|elevation|empty-cells|fit|fit-position|float-offset|float|font-family|font-size|font-size-adjust|font-stretch|font-style|font-variant|font-weight|font|grid-columns|grid-rows|hanging-punctuation|height|hyphenate-after|hyphenate-before|hyphenate-character|hyphenate-lines|hyphenate-resource|hyphens|icon|image-orientation|image-rendering|image-resolution|inline-box-align|left|letter-spacing|line-height|line-stacking-ruby|line-stacking-shift|line-stacking-strategy|line-stacking|list-style-image|list-style-position|list-style-type|list-style|margin-bottom|margin-left|margin-right|margin-top|margin|mark-after|mark-before|mark|marks|marquee-direction|marquee-play-count|marquee-speed|marquee-style|max-height|max-width|min-height|min-width|move-to|nav-down|nav-index|nav-left|nav-right|nav-up|opacity|orphans|outline-color|outline-offset|outline-style|outline-width|outline|overflow-style|overflow-x|overflow-y|overflow|padding-bottom|padding-left|padding-right|padding-top|padding|page-break-after|page-break-before|page-break-inside|page-policy|page|pause-after|pause-before|pause|perspective-origin|perspective|phonemes|pitch-range|pitch|play-during|position|presentation-level|punctuation-trim|quotes|rendering-intent|resize|rest-after|rest-before|rest|richness|right|rotation-point|rotation|ruby-align|ruby-overhang|ruby-position|ruby-span|size|speak-header|speak-numeral|speak-punctuation|speak|speech-rate|stress|string-set|table-layout|target-name|target-new|target-position|target|text-align-last|text-align|text-decoration|text-emphasis|text-height|text-indent|text-justify|text-outline|text-shadow|text-transform|text-wrap|top|transform-origin|transform-style|transform|transition-delay|transition-duration|transition-property|transition-timing-function|transition|unicode-bidi|vertical-align|visibility|voice-balance|voice-duration|voice-family|voice-pitch-range|voice-pitch|voice-rate|voice-stress|voice-volume|volume|white-space-collapse|white-space|widows|width|word-break|word-spacing|word-wrap|z-index",u=t.supportFunction="rgb|rgba|url|attr|counter|counters",a=t.supportConstant="absolute|after-edge|after|all-scroll|all|alphabetic|always|antialiased|armenian|auto|avoid-column|avoid-page|avoid|balance|baseline|before-edge|before|below|bidi-override|block-line-height|block|bold|bolder|border-box|both|bottom|box|break-all|break-word|capitalize|caps-height|caption|center|central|char|circle|cjk-ideographic|clone|close-quote|col-resize|collapse|column|consider-shifts|contain|content-box|cover|crosshair|cubic-bezier|dashed|decimal-leading-zero|decimal|default|disabled|disc|disregard-shifts|distribute-all-lines|distribute-letter|distribute-space|distribute|dotted|double|e-resize|ease-in|ease-in-out|ease-out|ease|ellipsis|end|exclude-ruby|fill|fixed|georgian|glyphs|grid-height|groove|hand|hanging|hebrew|help|hidden|hiragana-iroha|hiragana|horizontal|icon|ideograph-alpha|ideograph-numeric|ideograph-parenthesis|ideograph-space|ideographic|inactive|include-ruby|inherit|initial|inline-block|inline-box|inline-line-height|inline-table|inline|inset|inside|inter-ideograph|inter-word|invert|italic|justify|katakana-iroha|katakana|keep-all|last|left|lighter|line-edge|line-through|line|linear|list-item|local|loose|lower-alpha|lower-greek|lower-latin|lower-roman|lowercase|lr-tb|ltr|mathematical|max-height|max-size|medium|menu|message-box|middle|move|n-resize|ne-resize|newspaper|no-change|no-close-quote|no-drop|no-open-quote|no-repeat|none|normal|not-allowed|nowrap|nw-resize|oblique|open-quote|outset|outside|overline|padding-box|page|pointer|pre-line|pre-wrap|pre|preserve-3d|progress|relative|repeat-x|repeat-y|repeat|replaced|reset-size|ridge|right|round|row-resize|rtl|s-resize|scroll|se-resize|separate|slice|small-caps|small-caption|solid|space|square|start|static|status-bar|step-end|step-start|steps|stretch|strict|sub|super|sw-resize|table-caption|table-cell|table-column-group|table-column|table-footer-group|table-header-group|table-row-group|table-row|table|tb-rl|text-after-edge|text-before-edge|text-bottom|text-size|text-top|text|thick|thin|transparent|underline|upper-alpha|upper-latin|upper-roman|uppercase|use-script|vertical-ideographic|vertical-text|visible|w-resize|wait|whitespace|z-index|zero",f=t.supportConstantColor="aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow",l=t.supportConstantFonts="arial|century|comic|courier|garamond|georgia|helvetica|impact|lucida|symbol|system|tahoma|times|trebuchet|utopia|verdana|webdings|sans-serif|serif|monospace",c=t.numRe="\\-?(?:(?:[0-9]+)|(?:[0-9]*\\.[0-9]+))",h=t.pseudoElements="(\\:+)\\b(after|before|first-letter|first-line|moz-selection|selection)\\b",p=t.pseudoClasses="(:)\\b(active|checked|disabled|empty|enabled|first-child|first-of-type|focus|hover|indeterminate|invalid|last-child|last-of-type|link|not|nth-child|nth-last-child|nth-last-of-type|nth-of-type|only-child|only-of-type|required|root|target|valid|visited)\\b",d=function(){var e=this.createKeywordMapper({"support.function":u,"support.constant":a,"support.type":o,"support.constant.color":f,"support.constant.fonts":l},"text",!0),t=[{token:"comment",merge:!0,regex:"\\/\\*",next:"ruleset_comment"},{token:"string",regex:'["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'},{token:"string",regex:"['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"},{token:["constant.numeric","keyword"],regex:"("+c+")(ch|cm|deg|em|ex|fr|gd|grad|Hz|in|kHz|mm|ms|pc|pt|px|rad|rem|s|turn|vh|vm|vw|%)"},{token:"constant.numeric",regex:c},{token:"constant.numeric",regex:"#[a-f0-9]{6}"},{token:"constant.numeric",regex:"#[a-f0-9]{3}"},{token:["punctuation","entity.other.attribute-name.pseudo-element.css"],regex:h},{token:["punctuation","entity.other.attribute-name.pseudo-class.css"],regex:p},{token:e,regex:"\\-?[a-zA-Z_][a-zA-Z0-9_\\-]*"}],n=i.copyArray(t);n.unshift({token:"paren.rparen",regex:"\\}",next:"start"});var r=i.copyArray(t);r.unshift({token:"paren.rparen",regex:"\\}",next:"media"});var s=[{token:"comment",merge:!0,regex:".+"}],d=i.copyArray(s);d.unshift({token:"comment",regex:".*?\\*\\/",next:"start"});var v=i.copyArray(s);v.unshift({token:"comment",regex:".*?\\*\\/",next:"media"});var m=i.copyArray(s);m.unshift({token:"comment",regex:".*?\\*\\/",next:"ruleset"}),this.$rules={start:[{token:"comment",merge:!0,regex:"\\/\\*",next:"comment"},{token:"paren.lparen",regex:"\\{",next:"ruleset"},{token:"string",regex:"@.*?{",next:"media"},{token:"keyword",regex:"#[a-z0-9-_]+"},{token:"variable",regex:"\\.[a-z0-9-_]+"},{token:"string",regex:":[a-z0-9-_]+"},{token:"constant",regex:"[a-z0-9-_]+"}],media:[{token:"comment",merge:!0,regex:"\\/\\*",next:"media_comment"},{token:"paren.lparen",regex:"\\{",next:"media_ruleset"},{token:"string",regex:"\\}",next:"start"},{token:"keyword",regex:"#[a-z0-9-_]+"},{token:"variable",regex:"\\.[a-z0-9-_]+"},{token:"string",regex:":[a-z0-9-_]+"},{token:"constant",regex:"[a-z0-9-_]+"}],comment:d,ruleset:n,ruleset_comment:m,media_ruleset:r,media_comment:v}};r.inherits(d,s),t.CssHighlightRules=d}),ace.define("ace/mode/matching_brace_outdent",["require","exports","module","ace/range"],function(e,t,n){var r=e("../range").Range,i=function(){};(function(){this.checkOutdent=function(e,t){return/^\s+$/.test(e)?/^\s*\}/.test(t):!1},this.autoOutdent=function(e,t){var n=e.getLine(t),i=n.match(/^(\s*\})/);if(!i)return 0;var s=i[1].length,o=e.findMatchingBracket({row:t,column:s});if(!o||o.row==t)return 0;var u=this.$getIndent(e.getLine(o.row));e.replace(new r(t,0,t,s-1),u)},this.$getIndent=function(e){var t=e.match(/^(\s+)/);return t?t[1]:""}}).call(i.prototype),t.MatchingBraceOutdent=i}),ace.define("ace/mode/behaviour/cstyle",["require","exports","module","ace/lib/oop","ace/mode/behaviour","ace/token_iterator","ace/lib/lang"],function(e,t,n){var r=e("../../lib/oop"),i=e("../behaviour").Behaviour,s=e("../../token_iterator").TokenIterator,o=e("../../lib/lang"),u=["text","paren.rparen","punctuation.operator"],a=["text","paren.rparen","punctuation.operator","comment"],f=0,l=-1,c="",h=0,p=-1,d="",v="",m=function(){m.isSaneInsertion=function(e,t){var n=e.getCursorPosition(),r=new s(t,n.row,n.column);if(!this.$matchTokenType(r.getCurrentToken()||"text",u)){var i=new s(t,n.row,n.column+1);if(!this.$matchTokenType(i.getCurrentToken()||"text",u))return!1}return r.stepForward(),r.getCurrentTokenRow()!==n.row||this.$matchTokenType(r.getCurrentToken()||"text",a)},m.$matchTokenType=function(e,t){return t.indexOf(e.type||e)>-1},m.recordAutoInsert=function(e,t,n){var r=e.getCursorPosition(),i=t.doc.getLine(r.row);this.isAutoInsertedClosing(r,i,c[0])||(f=0),l=r.row,c=n+i.substr(r.column),f++},m.recordMaybeInsert=function(e,t,n){var r=e.getCursorPosition(),i=t.doc.getLine(r.row);this.isMaybeInsertedClosing(r,i)||(h=0),p=r.row,d=i.substr(0,r.column)+n,v=i.substr(r.column),h++},m.isAutoInsertedClosing=function(e,t,n){return f>0&&e.row===l&&n===c[0]&&t.substr(e.column)===c},m.isMaybeInsertedClosing=function(e,t){return h>0&&e.row===p&&t.substr(e.column)===v&&t.substr(0,e.column)==d},m.popAutoInsertedClosing=function(){c=c.substr(1),f--},m.clearMaybeInsertedClosing=function(){h=0,p=-1},this.add("braces","insertion",function(e,t,n,r,i){var s=n.getCursorPosition(),u=r.doc.getLine(s.row);if(i=="{"){var a=n.getSelectionRange(),f=r.doc.getTextRange(a);if(f!==""&&f!=="{"&&n.getWrapBehavioursEnabled())return{text:"{"+f+"}",selection:!1};if(m.isSaneInsertion(n,r))return/[\]\}\)]/.test(u[s.column])?(m.recordAutoInsert(n,r,"}"),{text:"{}",selection:[1,1]}):(m.recordMaybeInsert(n,r,"{"),{text:"{",selection:[1,1]})}else if(i=="}"){var l=u.substring(s.column,s.column+1);if(l=="}"){var c=r.$findOpeningBracket("}",{column:s.column+1,row:s.row});if(c!==null&&m.isAutoInsertedClosing(s,u,i))return m.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}else if(i=="\n"||i=="\r\n"){var p="";m.isMaybeInsertedClosing(s,u)&&(p=o.stringRepeat("}",h),m.clearMaybeInsertedClosing());var l=u.substring(s.column,s.column+1);if(l=="}"||p!==""){var d=r.findMatchingBracket({row:s.row,column:s.column},"}");if(!d)return null;var v=this.getNextLineIndent(e,u.substring(0,s.column),r.getTabString()),g=this.$getIndent(u);return{text:"\n"+v+"\n"+g+p,selection:[1,v.length,1,v.length]}}}}),this.add("braces","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="{"){var o=r.doc.getLine(i.start.row),u=o.substring(i.end.column,i.end.column+1);if(u=="}")return i.end.column++,i;h--}}),this.add("parens","insertion",function(e,t,n,r,i){if(i=="("){var s=n.getSelectionRange(),o=r.doc.getTextRange(s);if(o!==""&&n.getWrapBehavioursEnabled())return{text:"("+o+")",selection:!1};if(m.isSaneInsertion(n,r))return m.recordAutoInsert(n,r,")"),{text:"()",selection:[1,1]}}else if(i==")"){var u=n.getCursorPosition(),a=r.doc.getLine(u.row),f=a.substring(u.column,u.column+1);if(f==")"){var l=r.$findOpeningBracket(")",{column:u.column+1,row:u.row});if(l!==null&&m.isAutoInsertedClosing(u,a,i))return m.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}}),this.add("parens","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="("){var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u==")")return i.end.column++,i}}),this.add("brackets","insertion",function(e,t,n,r,i){if(i=="["){var s=n.getSelectionRange(),o=r.doc.getTextRange(s);if(o!==""&&n.getWrapBehavioursEnabled())return{text:"["+o+"]",selection:!1};if(m.isSaneInsertion(n,r))return m.recordAutoInsert(n,r,"]"),{text:"[]",selection:[1,1]}}else if(i=="]"){var u=n.getCursorPosition(),a=r.doc.getLine(u.row),f=a.substring(u.column,u.column+1);if(f=="]"){var l=r.$findOpeningBracket("]",{column:u.column+1,row:u.row});if(l!==null&&m.isAutoInsertedClosing(u,a,i))return m.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}}),this.add("brackets","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="["){var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u=="]")return i.end.column++,i}}),this.add("string_dquotes","insertion",function(e,t,n,r,i){if(i=='"'||i=="'"){var s=i,o=n.getSelectionRange(),u=r.doc.getTextRange(o);if(u!==""&&u!=="'"&&u!='"'&&n.getWrapBehavioursEnabled())return{text:s+u+s,selection:!1};var a=n.getCursorPosition(),f=r.doc.getLine(a.row),l=f.substring(a.column-1,a.column);if(l=="\\")return null;var c=r.getTokens(o.start.row),h=0,p,d=-1;for(var v=0;v<c.length;v++){p=c[v],p.type=="string"?d=-1:d<0&&(d=p.value.indexOf(s));if(p.value.length+h>o.start.column)break;h+=c[v].value.length}if(!p||d<0&&p.type!=="comment"&&(p.type!=="string"||o.start.column!==p.value.length+h-1&&p.value.lastIndexOf(s)===p.value.length-1)){if(!m.isSaneInsertion(n,r))return;return{text:s+s,selection:[1,1]}}if(p&&p.type==="string"){var g=f.substring(a.column,a.column+1);if(g==s)return{text:"",selection:[1,1]}}}}),this.add("string_dquotes","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&(s=='"'||s=="'")){var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u=='"')return i.end.column++,i}})};r.inherits(m,i),t.CstyleBehaviour=m}),ace.define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"],function(e,t,n){var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./fold_mode").FoldMode,o=t.FoldMode=function(){};r.inherits(o,s),function(){this.foldingStartMarker=/(\{|\[)[^\}\]]*$|^\s*(\/\*)/,this.foldingStopMarker=/^[^\[\{]*(\}|\])|^[\s\*]*(\*\/)/,this.getFoldWidgetRange=function(e,t,n){var r=e.getLine(n),i=r.match(this.foldingStartMarker);if(i){var s=i.index;return i[1]?this.openingBracketBlock(e,i[1],n,s):e.getCommentFoldRange(n,s+i[0].length,1)}if(t!=="markbeginend")return;var i=r.match(this.foldingStopMarker);if(i){var s=i.index+i[0].length;return i[1]?this.closingBracketBlock(e,i[1],n,s):e.getCommentFoldRange(n,s,-1)}}}.call(o.prototype)}) \ No newline at end of file
diff --git a/plugins/jetpack/modules/custom-css/custom-css/js/ace/mode-less.js b/plugins/jetpack/modules/custom-css/custom-css/js/ace/mode-less.js
deleted file mode 100644
index 68b4ca74..00000000
--- a/plugins/jetpack/modules/custom-css/custom-css/js/ace/mode-less.js
+++ /dev/null
@@ -1 +0,0 @@
-ace.define("ace/mode/less",["require","exports","module","ace/lib/oop","ace/mode/text","ace/tokenizer","ace/mode/less_highlight_rules","ace/mode/matching_brace_outdent","ace/mode/folding/cstyle"],function(e,t,n){var r=e("../lib/oop"),i=e("./text").Mode,s=e("../tokenizer").Tokenizer,o=e("./less_highlight_rules").LessHighlightRules,u=e("./matching_brace_outdent").MatchingBraceOutdent,a=e("./folding/cstyle").FoldMode,f=function(){this.$tokenizer=new s((new o).getRules(),"i"),this.$outdent=new u,this.foldingRules=new a};r.inherits(f,i),function(){this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t),i=this.$tokenizer.getLineTokens(t,e).tokens;if(i.length&&i[i.length-1].type=="comment")return r;var s=t.match(/^.*\{\s*$/);return s&&(r+=n),r},this.checkOutdent=function(e,t,n){return this.$outdent.checkOutdent(t,n)},this.autoOutdent=function(e,t,n){this.$outdent.autoOutdent(t,n)}}.call(f.prototype),t.Mode=f}),ace.define("ace/mode/less_highlight_rules",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/mode/text_highlight_rules"],function(e,t,n){var r=e("../lib/oop"),i=e("../lib/lang"),s=e("./text_highlight_rules").TextHighlightRules,o=function(){var e=i.arrayToMap(function(){var e="-webkit-|-moz-|-o-|-ms-|-svg-|-pie-|-khtml-".split("|"),t="appearance|background-clip|background-inline-policy|background-origin|background-size|binding|border-bottom-colors|border-left-colors|border-right-colors|border-top-colors|border-end|border-end-color|border-end-style|border-end-width|border-image|border-start|border-start-color|border-start-style|border-start-width|box-align|box-direction|box-flex|box-flexgroup|box-ordinal-group|box-orient|box-pack|box-sizing|column-count|column-gap|column-width|column-rule|column-rule-width|column-rule-style|column-rule-color|float-edge|font-feature-settings|font-language-override|force-broken-image-icon|image-region|margin-end|margin-start|opacity|outline|outline-color|outline-offset|outline-radius|outline-radius-bottomleft|outline-radius-bottomright|outline-radius-topleft|outline-radius-topright|outline-style|outline-width|padding-end|padding-start|stack-sizing|tab-size|text-blink|text-decoration-color|text-decoration-line|text-decoration-style|transform|transform-origin|transition|transition-delay|transition-duration|transition-property|transition-timing-function|user-focus|user-input|user-modify|user-select|window-shadow|border-radius".split("|"),n="azimuth|background-attachment|background-color|background-image|background-position|background-repeat|background|border-bottom-color|border-bottom-style|border-bottom-width|border-bottom|border-collapse|border-color|border-left-color|border-left-style|border-left-width|border-left|border-right-color|border-right-style|border-right-width|border-right|border-spacing|border-style|border-top-color|border-top-style|border-top-width|border-top|border-width|border|bottom|box-sizing|caption-side|clear|clip|color|content|counter-increment|counter-reset|cue-after|cue-before|cue|cursor|direction|display|elevation|empty-cells|float|font-family|font-size-adjust|font-size|font-stretch|font-style|font-variant|font-weight|font|height|left|letter-spacing|line-height|list-style-image|list-style-position|list-style-type|list-style|margin-bottom|margin-left|margin-right|margin-top|marker-offset|margin|marks|max-height|max-width|min-height|min-width|opacity|orphans|outline-color|outline-style|outline-width|outline|overflow|overflow-x|overflow-y|padding-bottom|padding-left|padding-right|padding-top|padding|page-break-after|page-break-before|page-break-inside|page|pause-after|pause-before|pause|pitch-range|pitch|play-during|position|quotes|richness|right|size|speak-header|speak-numeral|speak-punctuation|speech-rate|speak|stress|table-layout|text-align|text-decoration|text-indent|text-shadow|text-transform|top|unicode-bidi|vertical-align|visibility|voice-family|volume|white-space|widows|width|word-spacing|z-index".split("|"),r=[];for(var i=0,s=e.length;i<s;i++)Array.prototype.push.apply(r,(e[i]+t.join("|"+e[i])).split("|"));return Array.prototype.push.apply(r,t),Array.prototype.push.apply(r,n),r}()),t=i.arrayToMap("hsl|hsla|rgb|rgba|url|attr|counter|counters|lighten|darken|saturate|desaturate|fadein|fadeout|fade|spin|mix|hue|saturation|lightness|alpha|round|ceil|floor|percentage|color|iscolor|isnumber|isstring|iskeyword|isurl|ispixel|ispercentage|isem".split("|")),n=i.arrayToMap("absolute|all-scroll|always|armenian|auto|baseline|below|bidi-override|block|bold|bolder|border-box|both|bottom|break-all|break-word|capitalize|center|char|circle|cjk-ideographic|col-resize|collapse|content-box|crosshair|dashed|decimal-leading-zero|decimal|default|disabled|disc|distribute-all-lines|distribute-letter|distribute-space|distribute|dotted|double|e-resize|ellipsis|fixed|georgian|groove|hand|hebrew|help|hidden|hiragana-iroha|hiragana|horizontal|ideograph-alpha|ideograph-numeric|ideograph-parenthesis|ideograph-space|inactive|inherit|inline-block|inline|inset|inside|inter-ideograph|inter-word|italic|justify|katakana-iroha|katakana|keep-all|left|lighter|line-edge|line-through|line|list-item|loose|lower-alpha|lower-greek|lower-latin|lower-roman|lowercase|lr-tb|ltr|medium|middle|move|n-resize|ne-resize|newspaper|no-drop|no-repeat|nw-resize|none|normal|not-allowed|nowrap|oblique|outset|outside|overline|pointer|progress|relative|repeat-x|repeat-y|repeat|right|ridge|row-resize|rtl|s-resize|scroll|se-resize|separate|small-caps|solid|square|static|strict|super|sw-resize|table-footer-group|table-header-group|tb-rl|text-bottom|text-top|text|thick|thin|top|transparent|underline|upper-alpha|upper-latin|upper-roman|uppercase|vertical-ideographic|vertical-text|visible|w-resize|wait|whitespace|zero".split("|")),r=i.arrayToMap("aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow".split("|")),s=i.arrayToMap("@mixin|@extend|@include|@import|@media|@debug|@warn|@if|@for|@each|@while|@else|@font-face|@-webkit-keyframes|if|and|!default|module|def|end|declare|when|not|and".split("|")),o=i.arrayToMap("a|abbr|acronym|address|applet|area|article|aside|audio|b|base|basefont|bdo|big|blockquote|body|br|button|canvas|caption|center|cite|code|col|colgroup|command|datalist|dd|del|details|dfn|dir|div|dl|dt|em|embed|fieldset|figcaption|figure|font|footer|form|frame|frameset|h1|h2|h3|h4|h5|h6|head|header|hgroup|hr|html|i|iframe|img|input|ins|keygen|kbd|label|legend|li|link|map|mark|menu|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|rp|rt|ruby|s|samp|script|section|select|small|source|span|strike|strong|style|sub|summary|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|tt|u|ul|var|video|wbr|xmp".split("|")),u="\\-?(?:(?:[0-9]+)|(?:[0-9]*\\.[0-9]+))";this.$rules={start:[{token:"comment",regex:"\\/\\/.*$"},{token:"comment",merge:!0,regex:"\\/\\*",next:"comment"},{token:"string",regex:'["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'},{token:"string",regex:"['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"},{token:"constant.numeric",regex:u+"(?:em|ex|px|cm|mm|in|pt|pc|deg|rad|grad|ms|s|hz|khz|%)"},{token:"constant.numeric",regex:"#[a-f0-9]{6}"},{token:"constant.numeric",regex:"#[a-f0-9]{3}"},{token:"constant.numeric",regex:u},{token:function(e){return s.hasOwnProperty(e)?"keyword":"variable"},regex:"@[a-z0-9_\\-@]*\\b"},{token:function(i){return e.hasOwnProperty(i.toLowerCase())?"support.type":s.hasOwnProperty(i)?"keyword":n.hasOwnProperty(i)?"constant.language":t.hasOwnProperty(i)?"support.function":r.hasOwnProperty(i.toLowerCase())?"support.constant.color":o.hasOwnProperty(i.toLowerCase())?"variable.language":"text"},regex:"\\-?[@a-z_][@a-z0-9_\\-]*"},{token:"variable.language",regex:"#[a-z0-9-_]+"},{token:"variable.language",regex:"\\.[a-z0-9-_]+"},{token:"variable.language",regex:":[a-z0-9-_]+"},{token:"constant",regex:"[a-z0-9-_]+"},{token:"keyword.operator",regex:"<|>|<=|>=|==|!=|-|%|#|\\+|\\$|\\+|\\*"},{token:"paren.lparen",regex:"[[({]"},{token:"paren.rparen",regex:"[\\])}]"},{token:"text",regex:"\\s+"}],comment:[{token:"comment",regex:".*?\\*\\/",next:"start"},{token:"comment",merge:!0,regex:".+"}]}};r.inherits(o,s),t.LessHighlightRules=o}),ace.define("ace/mode/matching_brace_outdent",["require","exports","module","ace/range"],function(e,t,n){var r=e("../range").Range,i=function(){};(function(){this.checkOutdent=function(e,t){return/^\s+$/.test(e)?/^\s*\}/.test(t):!1},this.autoOutdent=function(e,t){var n=e.getLine(t),i=n.match(/^(\s*\})/);if(!i)return 0;var s=i[1].length,o=e.findMatchingBracket({row:t,column:s});if(!o||o.row==t)return 0;var u=this.$getIndent(e.getLine(o.row));e.replace(new r(t,0,t,s-1),u)},this.$getIndent=function(e){var t=e.match(/^(\s+)/);return t?t[1]:""}}).call(i.prototype),t.MatchingBraceOutdent=i}),ace.define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"],function(e,t,n){var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./fold_mode").FoldMode,o=t.FoldMode=function(){};r.inherits(o,s),function(){this.foldingStartMarker=/(\{|\[)[^\}\]]*$|^\s*(\/\*)/,this.foldingStopMarker=/^[^\[\{]*(\}|\])|^[\s\*]*(\*\/)/,this.getFoldWidgetRange=function(e,t,n){var r=e.getLine(n),i=r.match(this.foldingStartMarker);if(i){var s=i.index;return i[1]?this.openingBracketBlock(e,i[1],n,s):e.getCommentFoldRange(n,s+i[0].length,1)}if(t!=="markbeginend")return;var i=r.match(this.foldingStopMarker);if(i){var s=i.index+i[0].length;return i[1]?this.closingBracketBlock(e,i[1],n,s):e.getCommentFoldRange(n,s,-1)}}}.call(o.prototype)}) \ No newline at end of file
diff --git a/plugins/jetpack/modules/custom-css/custom-css/js/ace/mode-scss.js b/plugins/jetpack/modules/custom-css/custom-css/js/ace/mode-scss.js
deleted file mode 100644
index eca01605..00000000
--- a/plugins/jetpack/modules/custom-css/custom-css/js/ace/mode-scss.js
+++ /dev/null
@@ -1 +0,0 @@
-ace.define("ace/mode/scss",["require","exports","module","ace/lib/oop","ace/mode/text","ace/tokenizer","ace/mode/scss_highlight_rules","ace/mode/matching_brace_outdent","ace/mode/folding/cstyle"],function(e,t,n){var r=e("../lib/oop"),i=e("./text").Mode,s=e("../tokenizer").Tokenizer,o=e("./scss_highlight_rules").ScssHighlightRules,u=e("./matching_brace_outdent").MatchingBraceOutdent,a=e("./folding/cstyle").FoldMode,f=function(){this.$tokenizer=new s((new o).getRules(),"i"),this.$outdent=new u,this.foldingRules=new a};r.inherits(f,i),function(){this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t),i=this.$tokenizer.getLineTokens(t,e).tokens;if(i.length&&i[i.length-1].type=="comment")return r;var s=t.match(/^.*\{\s*$/);return s&&(r+=n),r},this.checkOutdent=function(e,t,n){return this.$outdent.checkOutdent(t,n)},this.autoOutdent=function(e,t,n){this.$outdent.autoOutdent(t,n)}}.call(f.prototype),t.Mode=f}),ace.define("ace/mode/scss_highlight_rules",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/mode/text_highlight_rules"],function(e,t,n){var r=e("../lib/oop"),i=e("../lib/lang"),s=e("./text_highlight_rules").TextHighlightRules,o=function(){var e=i.arrayToMap(function(){var e="-webkit-|-moz-|-o-|-ms-|-svg-|-pie-|-khtml-".split("|"),t="appearance|background-clip|background-inline-policy|background-origin|background-size|binding|border-bottom-colors|border-left-colors|border-right-colors|border-top-colors|border-end|border-end-color|border-end-style|border-end-width|border-image|border-start|border-start-color|border-start-style|border-start-width|box-align|box-direction|box-flex|box-flexgroup|box-ordinal-group|box-orient|box-pack|box-sizing|column-count|column-gap|column-width|column-rule|column-rule-width|column-rule-style|column-rule-color|float-edge|font-feature-settings|font-language-override|force-broken-image-icon|image-region|margin-end|margin-start|opacity|outline|outline-color|outline-offset|outline-radius|outline-radius-bottomleft|outline-radius-bottomright|outline-radius-topleft|outline-radius-topright|outline-style|outline-width|padding-end|padding-start|stack-sizing|tab-size|text-blink|text-decoration-color|text-decoration-line|text-decoration-style|transform|transform-origin|transition|transition-delay|transition-duration|transition-property|transition-timing-function|user-focus|user-input|user-modify|user-select|window-shadow|border-radius".split("|"),n="azimuth|background-attachment|background-color|background-image|background-position|background-repeat|background|border-bottom-color|border-bottom-style|border-bottom-width|border-bottom|border-collapse|border-color|border-left-color|border-left-style|border-left-width|border-left|border-right-color|border-right-style|border-right-width|border-right|border-spacing|border-style|border-top-color|border-top-style|border-top-width|border-top|border-width|border|bottom|box-sizing|caption-side|clear|clip|color|content|counter-increment|counter-reset|cue-after|cue-before|cue|cursor|direction|display|elevation|empty-cells|float|font-family|font-size-adjust|font-size|font-stretch|font-style|font-variant|font-weight|font|height|left|letter-spacing|line-height|list-style-image|list-style-position|list-style-type|list-style|margin-bottom|margin-left|margin-right|margin-top|marker-offset|margin|marks|max-height|max-width|min-height|min-width|opacity|orphans|outline-color|outline-style|outline-width|outline|overflow|overflow-x|overflow-y|padding-bottom|padding-left|padding-right|padding-top|padding|page-break-after|page-break-before|page-break-inside|page|pause-after|pause-before|pause|pitch-range|pitch|play-during|position|quotes|richness|right|size|speak-header|speak-numeral|speak-punctuation|speech-rate|speak|stress|table-layout|text-align|text-decoration|text-indent|text-shadow|text-transform|top|unicode-bidi|vertical-align|visibility|voice-family|volume|white-space|widows|width|word-spacing|z-index".split("|"),r=[];for(var i=0,s=e.length;i<s;i++)Array.prototype.push.apply(r,(e[i]+t.join("|"+e[i])).split("|"));return Array.prototype.push.apply(r,t),Array.prototype.push.apply(r,n),r}()),t=i.arrayToMap("hsl|hsla|rgb|rgba|url|attr|counter|counters|abs|adjust_color|adjust_hue|alpha|join|blue|ceil|change_color|comparable|complement|darken|desaturate|floor|grayscale|green|hue|if|invert|join|length|lighten|lightness|mix|nth|opacify|opacity|percentage|quote|red|round|saturate|saturation|scale_color|transparentize|type_of|unit|unitless|unqoute".split("|")),n=i.arrayToMap("absolute|all-scroll|always|armenian|auto|baseline|below|bidi-override|block|bold|bolder|border-box|both|bottom|break-all|break-word|capitalize|center|char|circle|cjk-ideographic|col-resize|collapse|content-box|crosshair|dashed|decimal-leading-zero|decimal|default|disabled|disc|distribute-all-lines|distribute-letter|distribute-space|distribute|dotted|double|e-resize|ellipsis|fixed|georgian|groove|hand|hebrew|help|hidden|hiragana-iroha|hiragana|horizontal|ideograph-alpha|ideograph-numeric|ideograph-parenthesis|ideograph-space|inactive|inherit|inline-block|inline|inset|inside|inter-ideograph|inter-word|italic|justify|katakana-iroha|katakana|keep-all|left|lighter|line-edge|line-through|line|list-item|loose|lower-alpha|lower-greek|lower-latin|lower-roman|lowercase|lr-tb|ltr|medium|middle|move|n-resize|ne-resize|newspaper|no-drop|no-repeat|nw-resize|none|normal|not-allowed|nowrap|oblique|outset|outside|overline|pointer|progress|relative|repeat-x|repeat-y|repeat|right|ridge|row-resize|rtl|s-resize|scroll|se-resize|separate|small-caps|solid|square|static|strict|super|sw-resize|table-footer-group|table-header-group|tb-rl|text-bottom|text-top|text|thick|thin|top|transparent|underline|upper-alpha|upper-latin|upper-roman|uppercase|vertical-ideographic|vertical-text|visible|w-resize|wait|whitespace|zero".split("|")),r=i.arrayToMap("aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow".split("|")),s=i.arrayToMap("@mixin|@extend|@include|@import|@media|@debug|@warn|@if|@for|@each|@while|@else|@font-face|@-webkit-keyframes|if|and|!default|module|def|end|declare".split("|")),o=i.arrayToMap("a|abbr|acronym|address|applet|area|article|aside|audio|b|base|basefont|bdo|big|blockquote|body|br|button|canvas|caption|center|cite|code|col|colgroup|command|datalist|dd|del|details|dfn|dir|div|dl|dt|em|embed|fieldset|figcaption|figure|font|footer|form|frame|frameset|h1|h2|h3|h4|h5|h6|head|header|hgroup|hr|html|i|iframe|img|input|ins|keygen|kbd|label|legend|li|link|map|mark|menu|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|rp|rt|ruby|s|samp|script|section|select|small|source|span|strike|strong|style|sub|summary|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|tt|u|ul|var|video|wbr|xmp".split("|")),u="\\-?(?:(?:[0-9]+)|(?:[0-9]*\\.[0-9]+))";this.$rules={start:[{token:"comment",regex:"\\/\\/.*$"},{token:"comment",merge:!0,regex:"\\/\\*",next:"comment"},{token:"string",regex:'["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'},{token:"string",merge:!0,regex:'["].*\\\\$',next:"qqstring"},{token:"string",regex:"['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"},{token:"string",merge:!0,regex:"['].*\\\\$",next:"qstring"},{token:"constant.numeric",regex:u+"(?:em|ex|px|cm|mm|in|pt|pc|deg|rad|grad|ms|s|hz|khz|%)"},{token:"constant.numeric",regex:"#[a-f0-9]{6}"},{token:"constant.numeric",regex:"#[a-f0-9]{3}"},{token:"constant.numeric",regex:u},{token:function(i){return e.hasOwnProperty(i.toLowerCase())?"support.type":s.hasOwnProperty(i)?"keyword":n.hasOwnProperty(i)?"constant.language":t.hasOwnProperty(i)?"support.function":r.hasOwnProperty(i.toLowerCase())?"support.constant.color":o.hasOwnProperty(i.toLowerCase())?"variable.language":"text"},regex:"\\-?[@a-z_][@a-z0-9_\\-]*"},{token:"variable",regex:"[a-z_\\-$][a-z0-9_\\-$]*\\b"},{token:"variable.language",regex:"#[a-z0-9-_]+"},{token:"variable.language",regex:"\\.[a-z0-9-_]+"},{token:"variable.language",regex:":[a-z0-9-_]+"},{token:"constant",regex:"[a-z0-9-_]+"},{token:"keyword.operator",regex:"<|>|<=|>=|==|!=|-|%|#|\\+|\\$|\\+|\\*"},{token:"paren.lparen",regex:"[[({]"},{token:"paren.rparen",regex:"[\\])}]"},{token:"text",regex:"\\s+"}],comment:[{token:"comment",regex:".*?\\*\\/",next:"start"},{token:"comment",merge:!0,regex:".+"}],qqstring:[{token:"string",regex:'(?:(?:\\\\.)|(?:[^"\\\\]))*?"',next:"start"},{token:"string",merge:!0,regex:".+"}],qstring:[{token:"string",regex:"(?:(?:\\\\.)|(?:[^'\\\\]))*?'",next:"start"},{token:"string",merge:!0,regex:".+"}]}};r.inherits(o,s),t.ScssHighlightRules=o}),ace.define("ace/mode/matching_brace_outdent",["require","exports","module","ace/range"],function(e,t,n){var r=e("../range").Range,i=function(){};(function(){this.checkOutdent=function(e,t){return/^\s+$/.test(e)?/^\s*\}/.test(t):!1},this.autoOutdent=function(e,t){var n=e.getLine(t),i=n.match(/^(\s*\})/);if(!i)return 0;var s=i[1].length,o=e.findMatchingBracket({row:t,column:s});if(!o||o.row==t)return 0;var u=this.$getIndent(e.getLine(o.row));e.replace(new r(t,0,t,s-1),u)},this.$getIndent=function(e){var t=e.match(/^(\s+)/);return t?t[1]:""}}).call(i.prototype),t.MatchingBraceOutdent=i}),ace.define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"],function(e,t,n){var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./fold_mode").FoldMode,o=t.FoldMode=function(){};r.inherits(o,s),function(){this.foldingStartMarker=/(\{|\[)[^\}\]]*$|^\s*(\/\*)/,this.foldingStopMarker=/^[^\[\{]*(\}|\])|^[\s\*]*(\*\/)/,this.getFoldWidgetRange=function(e,t,n){var r=e.getLine(n),i=r.match(this.foldingStartMarker);if(i){var s=i.index;return i[1]?this.openingBracketBlock(e,i[1],n,s):e.getCommentFoldRange(n,s+i[0].length,1)}if(t!=="markbeginend")return;var i=r.match(this.foldingStopMarker);if(i){var s=i.index+i[0].length;return i[1]?this.closingBracketBlock(e,i[1],n,s):e.getCommentFoldRange(n,s,-1)}}}.call(o.prototype)}) \ No newline at end of file
diff --git a/plugins/jetpack/modules/custom-css/custom-css/js/ace/readme.txt b/plugins/jetpack/modules/custom-css/custom-css/js/ace/readme.txt
deleted file mode 100644
index 6ef94f82..00000000
--- a/plugins/jetpack/modules/custom-css/custom-css/js/ace/readme.txt
+++ /dev/null
@@ -1 +0,0 @@
-The ACE editor files in this directory were pulled from https://github.com/ajaxorg/ace-builds/tree/master/src-min-noconflict, package 12.17.2012. \ No newline at end of file
diff --git a/plugins/jetpack/modules/custom-css/custom-css/js/ace/theme-textmate.js b/plugins/jetpack/modules/custom-css/custom-css/js/ace/theme-textmate.js
deleted file mode 100644
index d8ef4710..00000000
--- a/plugins/jetpack/modules/custom-css/custom-css/js/ace/theme-textmate.js
+++ /dev/null
@@ -1 +0,0 @@
-ace.define("ace/theme/textmate",["require","exports","module","ace/lib/dom"],function(e,t,n){t.isDark=!1,t.cssClass="ace-tm",t.cssText='.ace-tm .ace_gutter {background: #f0f0f0;color: #333;}.ace-tm .ace_print-margin {width: 1px;background: #e8e8e8;}.ace-tm .ace_fold {background-color: #6B72E6;}.ace-tm .ace_scroller {background-color: #FFFFFF;}.ace-tm .ace_cursor {border-left: 2px solid black;}.ace-tm .ace_overwrite-cursors .ace_cursor {border-left: 0px;border-bottom: 1px solid black;}.ace-tm .ace_invisible {color: rgb(191, 191, 191);}.ace-tm .ace_storage,.ace-tm .ace_keyword {color: blue;}.ace-tm .ace_constant {color: rgb(197, 6, 11);}.ace-tm .ace_constant.ace_buildin {color: rgb(88, 72, 246);}.ace-tm .ace_constant.ace_language {color: rgb(88, 92, 246);}.ace-tm .ace_constant.ace_library {color: rgb(6, 150, 14);}.ace-tm .ace_invalid {background-color: rgba(255, 0, 0, 0.1);color: red;}.ace-tm .ace_support.ace_function {color: rgb(60, 76, 114);}.ace-tm .ace_support.ace_constant {color: rgb(6, 150, 14);}.ace-tm .ace_support.ace_type,.ace-tm .ace_support.ace_class {color: rgb(109, 121, 222);}.ace-tm .ace_keyword.ace_operator {color: rgb(104, 118, 135);}.ace-tm .ace_string {color: rgb(3, 106, 7);}.ace-tm .ace_comment {color: rgb(76, 136, 107);}.ace-tm .ace_comment.ace_doc {color: rgb(0, 102, 255);}.ace-tm .ace_comment.ace_doc.ace_tag {color: rgb(128, 159, 191);}.ace-tm .ace_constant.ace_numeric {color: rgb(0, 0, 205);}.ace-tm .ace_variable {color: rgb(49, 132, 149);}.ace-tm .ace_xml-pe {color: rgb(104, 104, 91);}.ace-tm .ace_entity.ace_name.ace_function {color: #0000A2;}.ace-tm .ace_markup.ace_heading {color: rgb(12, 7, 255);}.ace-tm .ace_markup.ace_list {color:rgb(185, 6, 144);}.ace-tm .ace_meta.ace_tag {color:rgb(0, 22, 142);}.ace-tm .ace_string.ace_regex {color: rgb(255, 0, 0)}.ace-tm .ace_marker-layer .ace_selection {background: rgb(181, 213, 255);}.ace-tm.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px white;border-radius: 2px;}.ace-tm .ace_marker-layer .ace_step {background: rgb(252, 255, 0);}.ace-tm .ace_marker-layer .ace_stack {background: rgb(164, 229, 101);}.ace-tm .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgb(192, 192, 192);}.ace-tm .ace_marker-layer .ace_active-line {background: rgba(0, 0, 0, 0.07);}.ace-tm .ace_gutter-active-line {background-color : #dcdcdc;}.ace-tm .ace_marker-layer .ace_selected-word {background: rgb(250, 250, 255);border: 1px solid rgb(200, 200, 250);}.ace-tm .ace_indent-guide {background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==") right repeat-y;}';var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)}) \ No newline at end of file
diff --git a/plugins/jetpack/modules/custom-css/custom-css/js/ace/worker-css.js b/plugins/jetpack/modules/custom-css/custom-css/js/ace/worker-css.js
deleted file mode 100644
index 54c2a3e0..00000000
--- a/plugins/jetpack/modules/custom-css/custom-css/js/ace/worker-css.js
+++ /dev/null
@@ -1,7886 +0,0 @@
-"no use strict";
-
-if (typeof window != "undefined" && window.document)
- throw "atempt to load ace worker into main window instead of webWorker";
-
-var console = {
- log: function() {
- var msgs = Array.prototype.slice.call(arguments, 0);
- postMessage({type: "log", data: msgs});
- },
- error: function() {
- var msgs = Array.prototype.slice.call(arguments, 0);
- postMessage({type: "log", data: msgs});
- }
-};
-var window = {
- console: console
-};
-
-var normalizeModule = function(parentId, moduleName) {
- // normalize plugin requires
- if (moduleName.indexOf("!") !== -1) {
- var chunks = moduleName.split("!");
- return normalizeModule(parentId, chunks[0]) + "!" + normalizeModule(parentId, chunks[1]);
- }
- // normalize relative requires
- if (moduleName.charAt(0) == ".") {
- var base = parentId.split("/").slice(0, -1).join("/");
- moduleName = base + "/" + moduleName;
-
- while(moduleName.indexOf(".") !== -1 && previous != moduleName) {
- var previous = moduleName;
- moduleName = moduleName.replace(/\/\.\//, "/").replace(/[^\/]+\/\.\.\//, "");
- }
- }
-
- return moduleName;
-};
-
-var require = function(parentId, id) {
- if (!id.charAt)
- throw new Error("worker.js require() accepts only (parentId, id) as arguments");
-
- id = normalizeModule(parentId, id);
-
- var module = require.modules[id];
- if (module) {
- if (!module.initialized) {
- module.initialized = true;
- module.exports = module.factory().exports;
- }
- return module.exports;
- }
-
- var chunks = id.split("/");
- chunks[0] = require.tlns[chunks[0]] || chunks[0];
- var path = chunks.join("/") + ".js";
-
- require.id = id;
- importScripts(path);
- return require(parentId, id);
-};
-
-require.modules = {};
-require.tlns = {};
-
-var define = function(id, deps, factory) {
- if (arguments.length == 2) {
- factory = deps;
- if (typeof id != "string") {
- deps = id;
- id = require.id;
- }
- } else if (arguments.length == 1) {
- factory = id;
- id = require.id;
- }
-
- if (id.indexOf("text!") === 0)
- return;
-
- var req = function(deps, factory) {
- return require(id, deps, factory);
- };
-
- require.modules[id] = {
- factory: function() {
- var module = {
- exports: {}
- };
- var returnExports = factory(req, module.exports, module);
- if (returnExports)
- module.exports = returnExports;
- return module;
- }
- };
-};
-
-function initBaseUrls(topLevelNamespaces) {
- require.tlns = topLevelNamespaces;
-}
-
-function initSender() {
-
- var EventEmitter = require(null, "ace/lib/event_emitter").EventEmitter;
- var oop = require(null, "ace/lib/oop");
-
- var Sender = function() {};
-
- (function() {
-
- oop.implement(this, EventEmitter);
-
- this.callback = function(data, callbackId) {
- postMessage({
- type: "call",
- id: callbackId,
- data: data
- });
- };
-
- this.emit = function(name, data) {
- postMessage({
- type: "event",
- name: name,
- data: data
- });
- };
-
- }).call(Sender.prototype);
-
- return new Sender();
-}
-
-var main;
-var sender;
-
-onmessage = function(e) {
- var msg = e.data;
- if (msg.command) {
- if (main[msg.command])
- main[msg.command].apply(main, msg.args);
- else
- throw new Error("Unknown command:" + msg.command);
- }
- else if (msg.init) {
- initBaseUrls(msg.tlns);
- require(null, "ace/lib/fixoldbrowsers");
- sender = initSender();
- var clazz = require(null, msg.module)[msg.classname];
- main = new clazz(sender);
- }
- else if (msg.event && sender) {
- sender._emit(msg.event, msg.data);
- }
-};
-// vim:set ts=4 sts=4 sw=4 st:
-
-define('ace/lib/fixoldbrowsers', ['require', 'exports', 'module' , 'ace/lib/regexp', 'ace/lib/es5-shim'], function(require, exports, module) {
-
-
-require("./regexp");
-require("./es5-shim");
-
-});
-
-define('ace/lib/regexp', ['require', 'exports', 'module' ], function(require, exports, module) {
-
- var real = {
- exec: RegExp.prototype.exec,
- test: RegExp.prototype.test,
- match: String.prototype.match,
- replace: String.prototype.replace,
- split: String.prototype.split
- },
- compliantExecNpcg = real.exec.call(/()??/, "")[1] === undefined, // check `exec` handling of nonparticipating capturing groups
- compliantLastIndexIncrement = function () {
- var x = /^/g;
- real.test.call(x, "");
- return !x.lastIndex;
- }();
-
- if (compliantLastIndexIncrement && compliantExecNpcg)
- return;
- RegExp.prototype.exec = function (str) {
- var match = real.exec.apply(this, arguments),
- name, r2;
- if ( typeof(str) == 'string' && match) {
- if (!compliantExecNpcg && match.length > 1 && indexOf(match, "") > -1) {
- r2 = RegExp(this.source, real.replace.call(getNativeFlags(this), "g", ""));
- real.replace.call(str.slice(match.index), r2, function () {
- for (var i = 1; i < arguments.length - 2; i++) {
- if (arguments[i] === undefined)
- match[i] = undefined;
- }
- });
- }
- if (this._xregexp && this._xregexp.captureNames) {
- for (var i = 1; i < match.length; i++) {
- name = this._xregexp.captureNames[i - 1];
- if (name)
- match[name] = match[i];
- }
- }
- if (!compliantLastIndexIncrement && this.global && !match[0].length && (this.lastIndex > match.index))
- this.lastIndex--;
- }
- return match;
- };
- if (!compliantLastIndexIncrement) {
- RegExp.prototype.test = function (str) {
- var match = real.exec.call(this, str);
- if (match && this.global && !match[0].length && (this.lastIndex > match.index))
- this.lastIndex--;
- return !!match;
- };
- }
-
- function getNativeFlags (regex) {
- return (regex.global ? "g" : "") +
- (regex.ignoreCase ? "i" : "") +
- (regex.multiline ? "m" : "") +
- (regex.extended ? "x" : "") + // Proposed for ES4; included in AS3
- (regex.sticky ? "y" : "");
- }
-
- function indexOf (array, item, from) {
- if (Array.prototype.indexOf) // Use the native array method if available
- return array.indexOf(item, from);
- for (var i = from || 0; i < array.length; i++) {
- if (array[i] === item)
- return i;
- }
- return -1;
- }
-
-});
-
-define('ace/lib/es5-shim', ['require', 'exports', 'module' ], function(require, exports, module) {
-
-function Empty() {}
-
-if (!Function.prototype.bind) {
- Function.prototype.bind = function bind(that) { // .length is 1
- var target = this;
- if (typeof target != "function") {
- throw new TypeError("Function.prototype.bind called on incompatible " + target);
- }
- var args = slice.call(arguments, 1); // for normal call
- var bound = function () {
-
- if (this instanceof bound) {
-
- var result = target.apply(
- this,
- args.concat(slice.call(arguments))
- );
- if (Object(result) === result) {
- return result;
- }
- return this;
-
- } else {
- return target.apply(
- that,
- args.concat(slice.call(arguments))
- );
-
- }
-
- };
- if(target.prototype) {
- Empty.prototype = target.prototype;
- bound.prototype = new Empty();
- Empty.prototype = null;
- }
- return bound;
- };
-}
-var call = Function.prototype.call;
-var prototypeOfArray = Array.prototype;
-var prototypeOfObject = Object.prototype;
-var slice = prototypeOfArray.slice;
-var _toString = call.bind(prototypeOfObject.toString);
-var owns = call.bind(prototypeOfObject.hasOwnProperty);
-var defineGetter;
-var defineSetter;
-var lookupGetter;
-var lookupSetter;
-var supportsAccessors;
-if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) {
- defineGetter = call.bind(prototypeOfObject.__defineGetter__);
- defineSetter = call.bind(prototypeOfObject.__defineSetter__);
- lookupGetter = call.bind(prototypeOfObject.__lookupGetter__);
- lookupSetter = call.bind(prototypeOfObject.__lookupSetter__);
-}
-if ([1,2].splice(0).length != 2) {
- if(function() { // test IE < 9 to splice bug - see issue #138
- function makeArray(l) {
- var a = new Array(l+2);
- a[0] = a[1] = 0;
- return a;
- }
- var array = [], lengthBefore;
-
- array.splice.apply(array, makeArray(20));
- array.splice.apply(array, makeArray(26));
-
- lengthBefore = array.length; //46
- array.splice(5, 0, "XXX"); // add one element
-
- lengthBefore + 1 == array.length
-
- if (lengthBefore + 1 == array.length) {
- return true;// has right splice implementation without bugs
- }
- }()) {//IE 6/7
- var array_splice = Array.prototype.splice;
- Array.prototype.splice = function(start, deleteCount) {
- if (!arguments.length) {
- return [];
- } else {
- return array_splice.apply(this, [
- start === void 0 ? 0 : start,
- deleteCount === void 0 ? (this.length - start) : deleteCount
- ].concat(slice.call(arguments, 2)))
- }
- };
- } else {//IE8
- Array.prototype.splice = function(pos, removeCount){
- var length = this.length;
- if (pos > 0) {
- if (pos > length)
- pos = length;
- } else if (pos == void 0) {
- pos = 0;
- } else if (pos < 0) {
- pos = Math.max(length + pos, 0);
- }
-
- if (!(pos+removeCount < length))
- removeCount = length - pos;
-
- var removed = this.slice(pos, pos+removeCount);
- var insert = slice.call(arguments, 2);
- var add = insert.length;
- if (pos === length) {
- if (add) {
- this.push.apply(this, insert);
- }
- } else {
- var remove = Math.min(removeCount, length - pos);
- var tailOldPos = pos + remove;
- var tailNewPos = tailOldPos + add - remove;
- var tailCount = length - tailOldPos;
- var lengthAfterRemove = length - remove;
-
- if (tailNewPos < tailOldPos) { // case A
- for (var i = 0; i < tailCount; ++i) {
- this[tailNewPos+i] = this[tailOldPos+i];
- }
- } else if (tailNewPos > tailOldPos) { // case B
- for (i = tailCount; i--; ) {
- this[tailNewPos+i] = this[tailOldPos+i];
- }
- } // else, add == remove (nothing to do)
-
- if (add && pos === lengthAfterRemove) {
- this.length = lengthAfterRemove; // truncate array
- this.push.apply(this, insert);
- } else {
- this.length = lengthAfterRemove + add; // reserves space
- for (i = 0; i < add; ++i) {
- this[pos+i] = insert[i];
- }
- }
- }
- return removed;
- };
- }
-}
-if (!Array.isArray) {
- Array.isArray = function isArray(obj) {
- return _toString(obj) == "[object Array]";
- };
-}
-var boxedString = Object("a"),
- splitString = boxedString[0] != "a" || !(0 in boxedString);
-
-if (!Array.prototype.forEach) {
- Array.prototype.forEach = function forEach(fun /*, thisp*/) {
- var object = toObject(this),
- self = splitString && _toString(this) == "[object String]" ?
- this.split("") :
- object,
- thisp = arguments[1],
- i = -1,
- length = self.length >>> 0;
- if (_toString(fun) != "[object Function]") {
- throw new TypeError(); // TODO message
- }
-
- while (++i < length) {
- if (i in self) {
- fun.call(thisp, self[i], i, object);
- }
- }
- };
-}
-if (!Array.prototype.map) {
- Array.prototype.map = function map(fun /*, thisp*/) {
- var object = toObject(this),
- self = splitString && _toString(this) == "[object String]" ?
- this.split("") :
- object,
- length = self.length >>> 0,
- result = Array(length),
- thisp = arguments[1];
- if (_toString(fun) != "[object Function]") {
- throw new TypeError(fun + " is not a function");
- }
-
- for (var i = 0; i < length; i++) {
- if (i in self)
- result[i] = fun.call(thisp, self[i], i, object);
- }
- return result;
- };
-}
-if (!Array.prototype.filter) {
- Array.prototype.filter = function filter(fun /*, thisp */) {
- var object = toObject(this),
- self = splitString && _toString(this) == "[object String]" ?
- this.split("") :
- object,
- length = self.length >>> 0,
- result = [],
- value,
- thisp = arguments[1];
- if (_toString(fun) != "[object Function]") {
- throw new TypeError(fun + " is not a function");
- }
-
- for (var i = 0; i < length; i++) {
- if (i in self) {
- value = self[i];
- if (fun.call(thisp, value, i, object)) {
- result.push(value);
- }
- }
- }
- return result;
- };
-}
-if (!Array.prototype.every) {
- Array.prototype.every = function every(fun /*, thisp */) {
- var object = toObject(this),
- self = splitString && _toString(this) == "[object String]" ?
- this.split("") :
- object,
- length = self.length >>> 0,
- thisp = arguments[1];
- if (_toString(fun) != "[object Function]") {
- throw new TypeError(fun + " is not a function");
- }
-
- for (var i = 0; i < length; i++) {
- if (i in self && !fun.call(thisp, self[i], i, object)) {
- return false;
- }
- }
- return true;
- };
-}
-if (!Array.prototype.some) {
- Array.prototype.some = function some(fun /*, thisp */) {
- var object = toObject(this),
- self = splitString && _toString(this) == "[object String]" ?
- this.split("") :
- object,
- length = self.length >>> 0,
- thisp = arguments[1];
- if (_toString(fun) != "[object Function]") {
- throw new TypeError(fun + " is not a function");
- }
-
- for (var i = 0; i < length; i++) {
- if (i in self && fun.call(thisp, self[i], i, object)) {
- return true;
- }
- }
- return false;
- };
-}
-if (!Array.prototype.reduce) {
- Array.prototype.reduce = function reduce(fun /*, initial*/) {
- var object = toObject(this),
- self = splitString && _toString(this) == "[object String]" ?
- this.split("") :
- object,
- length = self.length >>> 0;
- if (_toString(fun) != "[object Function]") {
- throw new TypeError(fun + " is not a function");
- }
- if (!length && arguments.length == 1) {
- throw new TypeError("reduce of empty array with no initial value");
- }
-
- var i = 0;
- var result;
- if (arguments.length >= 2) {
- result = arguments[1];
- } else {
- do {
- if (i in self) {
- result = self[i++];
- break;
- }
- if (++i >= length) {
- throw new TypeError("reduce of empty array with no initial value");
- }
- } while (true);
- }
-
- for (; i < length; i++) {
- if (i in self) {
- result = fun.call(void 0, result, self[i], i, object);
- }
- }
-
- return result;
- };
-}
-if (!Array.prototype.reduceRight) {
- Array.prototype.reduceRight = function reduceRight(fun /*, initial*/) {
- var object = toObject(this),
- self = splitString && _toString(this) == "[object String]" ?
- this.split("") :
- object,
- length = self.length >>> 0;
- if (_toString(fun) != "[object Function]") {
- throw new TypeError(fun + " is not a function");
- }
- if (!length && arguments.length == 1) {
- throw new TypeError("reduceRight of empty array with no initial value");
- }
-
- var result, i = length - 1;
- if (arguments.length >= 2) {
- result = arguments[1];
- } else {
- do {
- if (i in self) {
- result = self[i--];
- break;
- }
- if (--i < 0) {
- throw new TypeError("reduceRight of empty array with no initial value");
- }
- } while (true);
- }
-
- do {
- if (i in this) {
- result = fun.call(void 0, result, self[i], i, object);
- }
- } while (i--);
-
- return result;
- };
-}
-if (!Array.prototype.indexOf || ([0, 1].indexOf(1, 2) != -1)) {
- Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) {
- var self = splitString && _toString(this) == "[object String]" ?
- this.split("") :
- toObject(this),
- length = self.length >>> 0;
-
- if (!length) {
- return -1;
- }
-
- var i = 0;
- if (arguments.length > 1) {
- i = toInteger(arguments[1]);
- }
- i = i >= 0 ? i : Math.max(0, length + i);
- for (; i < length; i++) {
- if (i in self && self[i] === sought) {
- return i;
- }
- }
- return -1;
- };
-}
-if (!Array.prototype.lastIndexOf || ([0, 1].lastIndexOf(0, -3) != -1)) {
- Array.prototype.lastIndexOf = function lastIndexOf(sought /*, fromIndex */) {
- var self = splitString && _toString(this) == "[object String]" ?
- this.split("") :
- toObject(this),
- length = self.length >>> 0;
-
- if (!length) {
- return -1;
- }
- var i = length - 1;
- if (arguments.length > 1) {
- i = Math.min(i, toInteger(arguments[1]));
- }
- i = i >= 0 ? i : length - Math.abs(i);
- for (; i >= 0; i--) {
- if (i in self && sought === self[i]) {
- return i;
- }
- }
- return -1;
- };
-}
-if (!Object.getPrototypeOf) {
- Object.getPrototypeOf = function getPrototypeOf(object) {
- return object.__proto__ || (
- object.constructor ?
- object.constructor.prototype :
- prototypeOfObject
- );
- };
-}
-if (!Object.getOwnPropertyDescriptor) {
- var ERR_NON_OBJECT = "Object.getOwnPropertyDescriptor called on a " +
- "non-object: ";
- Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) {
- if ((typeof object != "object" && typeof object != "function") || object === null)
- throw new TypeError(ERR_NON_OBJECT + object);
- if (!owns(object, property))
- return;
-
- var descriptor, getter, setter;
- descriptor = { enumerable: true, configurable: true };
- if (supportsAccessors) {
- var prototype = object.__proto__;
- object.__proto__ = prototypeOfObject;
-
- var getter = lookupGetter(object, property);
- var setter = lookupSetter(object, property);
- object.__proto__ = prototype;
-
- if (getter || setter) {
- if (getter) descriptor.get = getter;
- if (setter) descriptor.set = setter;
- return descriptor;
- }
- }
- descriptor.value = object[property];
- return descriptor;
- };
-}
-if (!Object.getOwnPropertyNames) {
- Object.getOwnPropertyNames = function getOwnPropertyNames(object) {
- return Object.keys(object);
- };
-}
-if (!Object.create) {
- var createEmpty;
- if (Object.prototype.__proto__ === null) {
- createEmpty = function () {
- return { "__proto__": null };
- };
- } else {
- createEmpty = function () {
- var empty = {};
- for (var i in empty)
- empty[i] = null;
- empty.constructor =
- empty.hasOwnProperty =
- empty.propertyIsEnumerable =
- empty.isPrototypeOf =
- empty.toLocaleString =
- empty.toString =
- empty.valueOf =
- empty.__proto__ = null;
- return empty;
- }
- }
-
- Object.create = function create(prototype, properties) {
- var object;
- if (prototype === null) {
- object = createEmpty();
- } else {
- if (typeof prototype != "object")
- throw new TypeError("typeof prototype["+(typeof prototype)+"] != 'object'");
- var Type = function () {};
- Type.prototype = prototype;
- object = new Type();
- object.__proto__ = prototype;
- }
- if (properties !== void 0)
- Object.defineProperties(object, properties);
- return object;
- };
-}
-
-function doesDefinePropertyWork(object) {
- try {
- Object.defineProperty(object, "sentinel", {});
- return "sentinel" in object;
- } catch (exception) {
- }
-}
-if (Object.defineProperty) {
- var definePropertyWorksOnObject = doesDefinePropertyWork({});
- var definePropertyWorksOnDom = typeof document == "undefined" ||
- doesDefinePropertyWork(document.createElement("div"));
- if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) {
- var definePropertyFallback = Object.defineProperty;
- }
-}
-
-if (!Object.defineProperty || definePropertyFallback) {
- var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: ";
- var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: "
- var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " +
- "on this javascript engine";
-
- Object.defineProperty = function defineProperty(object, property, descriptor) {
- if ((typeof object != "object" && typeof object != "function") || object === null)
- throw new TypeError(ERR_NON_OBJECT_TARGET + object);
- if ((typeof descriptor != "object" && typeof descriptor != "function") || descriptor === null)
- throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor);
- if (definePropertyFallback) {
- try {
- return definePropertyFallback.call(Object, object, property, descriptor);
- } catch (exception) {
- }
- }
- if (owns(descriptor, "value")) {
-
- if (supportsAccessors && (lookupGetter(object, property) ||
- lookupSetter(object, property)))
- {
- var prototype = object.__proto__;
- object.__proto__ = prototypeOfObject;
- delete object[property];
- object[property] = descriptor.value;
- object.__proto__ = prototype;
- } else {
- object[property] = descriptor.value;
- }
- } else {
- if (!supportsAccessors)
- throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
- if (owns(descriptor, "get"))
- defineGetter(object, property, descriptor.get);
- if (owns(descriptor, "set"))
- defineSetter(object, property, descriptor.set);
- }
-
- return object;
- };
-}
-if (!Object.defineProperties) {
- Object.defineProperties = function defineProperties(object, properties) {
- for (var property in properties) {
- if (owns(properties, property))
- Object.defineProperty(object, property, properties[property]);
- }
- return object;
- };
-}
-if (!Object.seal) {
- Object.seal = function seal(object) {
- return object;
- };
-}
-if (!Object.freeze) {
- Object.freeze = function freeze(object) {
- return object;
- };
-}
-try {
- Object.freeze(function () {});
-} catch (exception) {
- Object.freeze = (function freeze(freezeObject) {
- return function freeze(object) {
- if (typeof object == "function") {
- return object;
- } else {
- return freezeObject(object);
- }
- };
- })(Object.freeze);
-}
-if (!Object.preventExtensions) {
- Object.preventExtensions = function preventExtensions(object) {
- return object;
- };
-}
-if (!Object.isSealed) {
- Object.isSealed = function isSealed(object) {
- return false;
- };
-}
-if (!Object.isFrozen) {
- Object.isFrozen = function isFrozen(object) {
- return false;
- };
-}
-if (!Object.isExtensible) {
- Object.isExtensible = function isExtensible(object) {
- if (Object(object) === object) {
- throw new TypeError(); // TODO message
- }
- var name = '';
- while (owns(object, name)) {
- name += '?';
- }
- object[name] = true;
- var returnValue = owns(object, name);
- delete object[name];
- return returnValue;
- };
-}
-if (!Object.keys) {
- var hasDontEnumBug = true,
- dontEnums = [
- "toString",
- "toLocaleString",
- "valueOf",
- "hasOwnProperty",
- "isPrototypeOf",
- "propertyIsEnumerable",
- "constructor"
- ],
- dontEnumsLength = dontEnums.length;
-
- for (var key in {"toString": null}) {
- hasDontEnumBug = false;
- }
-
- Object.keys = function keys(object) {
-
- if (
- (typeof object != "object" && typeof object != "function") ||
- object === null
- ) {
- throw new TypeError("Object.keys called on a non-object");
- }
-
- var keys = [];
- for (var name in object) {
- if (owns(object, name)) {
- keys.push(name);
- }
- }
-
- if (hasDontEnumBug) {
- for (var i = 0, ii = dontEnumsLength; i < ii; i++) {
- var dontEnum = dontEnums[i];
- if (owns(object, dontEnum)) {
- keys.push(dontEnum);
- }
- }
- }
- return keys;
- };
-
-}
-if (!Date.now) {
- Date.now = function now() {
- return new Date().getTime();
- };
-}
-if("0".split(void 0, 0).length) {
- var string_split = String.prototype.split;
- String.prototype.split = function(separator, limit) {
- if(separator === void 0 && limit === 0)return [];
- return string_split.apply(this, arguments);
- }
-}
-if("".substr && "0b".substr(-1) !== "b") {
- var string_substr = String.prototype.substr;
- String.prototype.substr = function(start, length) {
- return string_substr.call(
- this,
- start < 0 ? (start = this.length + start) < 0 ? 0 : start : start,
- length
- );
- }
-}
-var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" +
- "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" +
- "\u2029\uFEFF";
-if (!String.prototype.trim || ws.trim()) {
- ws = "[" + ws + "]";
- var trimBeginRegexp = new RegExp("^" + ws + ws + "*"),
- trimEndRegexp = new RegExp(ws + ws + "*$");
- String.prototype.trim = function trim() {
- if (this === undefined || this === null) {
- throw new TypeError("can't convert "+this+" to object");
- }
- return String(this)
- .replace(trimBeginRegexp, "")
- .replace(trimEndRegexp, "");
- };
-}
-
-function toInteger(n) {
- n = +n;
- if (n !== n) { // isNaN
- n = 0;
- } else if (n !== 0 && n !== (1/0) && n !== -(1/0)) {
- n = (n > 0 || -1) * Math.floor(Math.abs(n));
- }
- return n;
-}
-
-function isPrimitive(input) {
- var type = typeof input;
- return (
- input === null ||
- type === "undefined" ||
- type === "boolean" ||
- type === "number" ||
- type === "string"
- );
-}
-
-function toPrimitive(input) {
- var val, valueOf, toString;
- if (isPrimitive(input)) {
- return input;
- }
- valueOf = input.valueOf;
- if (typeof valueOf === "function") {
- val = valueOf.call(input);
- if (isPrimitive(val)) {
- return val;
- }
- }
- toString = input.toString;
- if (typeof toString === "function") {
- val = toString.call(input);
- if (isPrimitive(val)) {
- return val;
- }
- }
- throw new TypeError();
-}
-var toObject = function (o) {
- if (o == null) { // this matches both null and undefined
- throw new TypeError("can't convert "+o+" to object");
- }
- return Object(o);
-};
-
-});
-
-define('ace/lib/event_emitter', ['require', 'exports', 'module' ], function(require, exports, module) {
-
-
-var EventEmitter = {};
-
-EventEmitter._emit =
-EventEmitter._dispatchEvent = function(eventName, e) {
- this._eventRegistry = this._eventRegistry || {};
- this._defaultHandlers = this._defaultHandlers || {};
-
- var listeners = this._eventRegistry[eventName] || [];
- var defaultHandler = this._defaultHandlers[eventName];
- if (!listeners.length && !defaultHandler)
- return;
-
- if (typeof e != "object" || !e)
- e = {};
-
- if (!e.type)
- e.type = eventName;
-
- if (!e.stopPropagation) {
- e.stopPropagation = function() {
- this.propagationStopped = true;
- };
- }
-
- if (!e.preventDefault) {
- e.preventDefault = function() {
- this.defaultPrevented = true;
- };
- }
-
- for (var i=0; i<listeners.length; i++) {
- listeners[i](e);
- if (e.propagationStopped)
- break;
- }
-
- if (defaultHandler && !e.defaultPrevented)
- return defaultHandler(e);
-};
-
-EventEmitter.setDefaultHandler = function(eventName, callback) {
- this._defaultHandlers = this._defaultHandlers || {};
-
- if (this._defaultHandlers[eventName])
- throw new Error("The default handler for '" + eventName + "' is already set");
-
- this._defaultHandlers[eventName] = callback;
-};
-
-EventEmitter.on =
-EventEmitter.addEventListener = function(eventName, callback) {
- this._eventRegistry = this._eventRegistry || {};
-
- var listeners = this._eventRegistry[eventName];
- if (!listeners)
- listeners = this._eventRegistry[eventName] = [];
-
- if (listeners.indexOf(callback) == -1)
- listeners.push(callback);
-};
-
-EventEmitter.removeListener =
-EventEmitter.removeEventListener = function(eventName, callback) {
- this._eventRegistry = this._eventRegistry || {};
-
- var listeners = this._eventRegistry[eventName];
- if (!listeners)
- return;
-
- var index = listeners.indexOf(callback);
- if (index !== -1)
- listeners.splice(index, 1);
-};
-
-EventEmitter.removeAllListeners = function(eventName) {
- if (this._eventRegistry) this._eventRegistry[eventName] = [];
-};
-
-exports.EventEmitter = EventEmitter;
-
-});
-
-define('ace/lib/oop', ['require', 'exports', 'module' ], function(require, exports, module) {
-
-
-exports.inherits = (function() {
- var tempCtor = function() {};
- return function(ctor, superCtor) {
- tempCtor.prototype = superCtor.prototype;
- ctor.super_ = superCtor.prototype;
- ctor.prototype = new tempCtor();
- ctor.prototype.constructor = ctor;
- };
-}());
-
-exports.mixin = function(obj, mixin) {
- for (var key in mixin) {
- obj[key] = mixin[key];
- }
-};
-
-exports.implement = function(proto, mixin) {
- exports.mixin(proto, mixin);
-};
-
-});
-
-define('ace/mode/css_worker', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/lang', 'ace/worker/mirror', 'ace/mode/css/csslint'], function(require, exports, module) {
-
-
-var oop = require("../lib/oop");
-var lang = require("../lib/lang");
-var Mirror = require("../worker/mirror").Mirror;
-var CSSLint = require("./css/csslint").CSSLint;
-
-var Worker = exports.Worker = function(sender) {
- Mirror.call(this, sender);
- this.setTimeout(400);
- this.ruleset = null;
- this.setDisabledRules("ids");
- this.setInfoRules("adjoining-classes|qualified-headings|zero-units|gradients|import|outline-none");
-};
-
-oop.inherits(Worker, Mirror);
-
-(function() {
- this.setInfoRules = function(ruleNames) {
- if (typeof ruleNames == "string")
- ruleNames = ruleNames.split("|");
- this.infoRules = lang.arrayToMap(ruleNames);
- this.doc.getValue() && this.deferredUpdate.schedule(100);
- };
-
- this.setDisabledRules = function(ruleNames) {
- if (!ruleNames) {
- this.ruleset = null;
- } else {
- if (typeof ruleNames == "string")
- ruleNames = ruleNames.split("|");
- var all = {};
-
- CSSLint.getRules().forEach(function(x){
- all[x.id] = true;
- });
- ruleNames.forEach(function(x) {
- delete all[x];
- });
-
- this.ruleset = all;
- }
- this.doc.getValue() && this.deferredUpdate.schedule(100);
- };
-
- this.onUpdate = function() {
- var value = this.doc.getValue();
- var infoRules = this.infoRules;
-
- var result = CSSLint.verify(value, this.ruleset);
- this.sender.emit("csslint", result.messages.map(function(msg) {
- return {
- row: msg.line - 1,
- column: msg.col - 1,
- text: msg.message,
- type: infoRules[msg.rule.id] ? "info" : msg.type
- }
- }));
- };
-
-}).call(Worker.prototype);
-
-});
-
-define('ace/lib/lang', ['require', 'exports', 'module' ], function(require, exports, module) {
-
-
-exports.stringReverse = function(string) {
- return string.split("").reverse().join("");
-};
-
-exports.stringRepeat = function (string, count) {
- var result = '';
- while (count > 0) {
- if (count & 1)
- result += string;
-
- if (count >>= 1)
- string += string;
- }
- return result;
-};
-
-var trimBeginRegexp = /^\s\s*/;
-var trimEndRegexp = /\s\s*$/;
-
-exports.stringTrimLeft = function (string) {
- return string.replace(trimBeginRegexp, '');
-};
-
-exports.stringTrimRight = function (string) {
- return string.replace(trimEndRegexp, '');
-};
-
-exports.copyObject = function(obj) {
- var copy = {};
- for (var key in obj) {
- copy[key] = obj[key];
- }
- return copy;
-};
-
-exports.copyArray = function(array){
- var copy = [];
- for (var i=0, l=array.length; i<l; i++) {
- if (array[i] && typeof array[i] == "object")
- copy[i] = this.copyObject( array[i] );
- else
- copy[i] = array[i];
- }
- return copy;
-};
-
-exports.deepCopy = function (obj) {
- if (typeof obj != "object") {
- return obj;
- }
-
- var copy = obj.constructor();
- for (var key in obj) {
- if (typeof obj[key] == "object") {
- copy[key] = this.deepCopy(obj[key]);
- } else {
- copy[key] = obj[key];
- }
- }
- return copy;
-};
-
-exports.arrayToMap = function(arr) {
- var map = {};
- for (var i=0; i<arr.length; i++) {
- map[arr[i]] = 1;
- }
- return map;
-
-};
-
-exports.createMap = function(props) {
- var map = Object.create(null);
- for (var i in props) {
- map[i] = props[i];
- }
- return map;
-};
-exports.arrayRemove = function(array, value) {
- for (var i = 0; i <= array.length; i++) {
- if (value === array[i]) {
- array.splice(i, 1);
- }
- }
-};
-
-exports.escapeRegExp = function(str) {
- return str.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1');
-};
-
-exports.escapeHTML = function(str) {
- return str.replace(/&/g, "&#38;").replace(/"/g, "&#34;").replace(/'/g, "&#39;").replace(/</g, "&#60;");
-};
-
-exports.getMatchOffsets = function(string, regExp) {
- var matches = [];
-
- string.replace(regExp, function(str) {
- matches.push({
- offset: arguments[arguments.length-2],
- length: str.length
- });
- });
-
- return matches;
-};
-exports.deferredCall = function(fcn) {
-
- var timer = null;
- var callback = function() {
- timer = null;
- fcn();
- };
-
- var deferred = function(timeout) {
- deferred.cancel();
- timer = setTimeout(callback, timeout || 0);
- return deferred;
- };
-
- deferred.schedule = deferred;
-
- deferred.call = function() {
- this.cancel();
- fcn();
- return deferred;
- };
-
- deferred.cancel = function() {
- clearTimeout(timer);
- timer = null;
- return deferred;
- };
-
- return deferred;
-};
-
-
-exports.delayedCall = function(fcn, defaultTimeout) {
- var timer = null;
- var callback = function() {
- timer = null;
- fcn();
- };
-
- var _self = function(timeout) {
- timer && clearTimeout(timer);
- timer = setTimeout(callback, timeout || defaultTimeout);
- };
-
- _self.delay = _self;
- _self.schedule = function(timeout) {
- if (timer == null)
- timer = setTimeout(callback, timeout || 0);
- };
-
- _self.call = function() {
- this.cancel();
- fcn();
- };
-
- _self.cancel = function() {
- timer && clearTimeout(timer);
- timer = null;
- };
-
- _self.isPending = function() {
- return timer;
- };
-
- return _self;
-};
-});
-define('ace/worker/mirror', ['require', 'exports', 'module' , 'ace/document', 'ace/lib/lang'], function(require, exports, module) {
-
-
-var Document = require("../document").Document;
-var lang = require("../lib/lang");
-
-var Mirror = exports.Mirror = function(sender) {
- this.sender = sender;
- var doc = this.doc = new Document("");
-
- var deferredUpdate = this.deferredUpdate = lang.deferredCall(this.onUpdate.bind(this));
-
- var _self = this;
- sender.on("change", function(e) {
- doc.applyDeltas([e.data]);
- deferredUpdate.schedule(_self.$timeout);
- });
-};
-
-(function() {
-
- this.$timeout = 500;
-
- this.setTimeout = function(timeout) {
- this.$timeout = timeout;
- };
-
- this.setValue = function(value) {
- this.doc.setValue(value);
- this.deferredUpdate.schedule(this.$timeout);
- };
-
- this.getValue = function(callbackId) {
- this.sender.callback(this.doc.getValue(), callbackId);
- };
-
- this.onUpdate = function() {
- };
-
-}).call(Mirror.prototype);
-
-});
-
-define('ace/document', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter', 'ace/range', 'ace/anchor'], function(require, exports, module) {
-
-
-var oop = require("./lib/oop");
-var EventEmitter = require("./lib/event_emitter").EventEmitter;
-var Range = require("./range").Range;
-var Anchor = require("./anchor").Anchor;
-
-var Document = function(text) {
- this.$lines = [];
- if (text.length == 0) {
- this.$lines = [""];
- } else if (Array.isArray(text)) {
- this.insertLines(0, text);
- } else {
- this.insert({row: 0, column:0}, text);
- }
-};
-
-(function() {
-
- oop.implement(this, EventEmitter);
- this.setValue = function(text) {
- var len = this.getLength();
- this.remove(new Range(0, 0, len, this.getLine(len-1).length));
- this.insert({row: 0, column:0}, text);
- };
- this.getValue = function() {
- return this.getAllLines().join(this.getNewLineCharacter());
- };
- this.createAnchor = function(row, column) {
- return new Anchor(this, row, column);
- };
- if ("aaa".split(/a/).length == 0)
- this.$split = function(text) {
- return text.replace(/\r\n|\r/g, "\n").split("\n");
- }
- else
- this.$split = function(text) {
- return text.split(/\r\n|\r|\n/);
- };
-
-
-
- this.$detectNewLine = function(text) {
- var match = text.match(/^.*?(\r\n|\r|\n)/m);
- if (match) {
- this.$autoNewLine = match[1];
- } else {
- this.$autoNewLine = "\n";
- }
- };
- this.getNewLineCharacter = function() {
- switch (this.$newLineMode) {
- case "windows":
- return "\r\n";
-
- case "unix":
- return "\n";
-
- default:
- return this.$autoNewLine;
- }
- };
-
- this.$autoNewLine = "\n";
- this.$newLineMode = "auto";
- this.setNewLineMode = function(newLineMode) {
- if (this.$newLineMode === newLineMode)
- return;
-
- this.$newLineMode = newLineMode;
- };
- this.getNewLineMode = function() {
- return this.$newLineMode;
- };
- this.isNewLine = function(text) {
- return (text == "\r\n" || text == "\r" || text == "\n");
- };
- this.getLine = function(row) {
- return this.$lines[row] || "";
- };
- this.getLines = function(firstRow, lastRow) {
- return this.$lines.slice(firstRow, lastRow + 1);
- };
- this.getAllLines = function() {
- return this.getLines(0, this.getLength());
- };
- this.getLength = function() {
- return this.$lines.length;
- };
- this.getTextRange = function(range) {
- if (range.start.row == range.end.row) {
- return this.$lines[range.start.row].substring(range.start.column,
- range.end.column);
- }
- else {
- var lines = this.getLines(range.start.row+1, range.end.row-1);
- lines.unshift((this.$lines[range.start.row] || "").substring(range.start.column));
- lines.push((this.$lines[range.end.row] || "").substring(0, range.end.column));
- return lines.join(this.getNewLineCharacter());
- }
- };
-
- this.$clipPosition = function(position) {
- var length = this.getLength();
- if (position.row >= length) {
- position.row = Math.max(0, length - 1);
- position.column = this.getLine(length-1).length;
- }
- return position;
- };
- this.insert = function(position, text) {
- if (!text || text.length === 0)
- return position;
-
- position = this.$clipPosition(position);
- if (this.getLength() <= 1)
- this.$detectNewLine(text);
-
- var lines = this.$split(text);
- var firstLine = lines.splice(0, 1)[0];
- var lastLine = lines.length == 0 ? null : lines.splice(lines.length - 1, 1)[0];
-
- position = this.insertInLine(position, firstLine);
- if (lastLine !== null) {
- position = this.insertNewLine(position); // terminate first line
- position = this.insertLines(position.row, lines);
- position = this.insertInLine(position, lastLine || "");
- }
- return position;
- };
- this.insertLines = function(row, lines) {
- if (lines.length == 0)
- return {row: row, column: 0};
- if (lines.length > 0xFFFF) {
- var end = this.insertLines(row, lines.slice(0xFFFF));
- lines = lines.slice(0, 0xFFFF);
- }
-
- var args = [row, 0];
- args.push.apply(args, lines);
- this.$lines.splice.apply(this.$lines, args);
-
- var range = new Range(row, 0, row + lines.length, 0);
- var delta = {
- action: "insertLines",
- range: range,
- lines: lines
- };
- this._emit("change", { data: delta });
- return end || range.end;
- };
- this.insertNewLine = function(position) {
- position = this.$clipPosition(position);
- var line = this.$lines[position.row] || "";
-
- this.$lines[position.row] = line.substring(0, position.column);
- this.$lines.splice(position.row + 1, 0, line.substring(position.column, line.length));
-
- var end = {
- row : position.row + 1,
- column : 0
- };
-
- var delta = {
- action: "insertText",
- range: Range.fromPoints(position, end),
- text: this.getNewLineCharacter()
- };
- this._emit("change", { data: delta });
-
- return end;
- };
- this.insertInLine = function(position, text) {
- if (text.length == 0)
- return position;
-
- var line = this.$lines[position.row] || "";
-
- this.$lines[position.row] = line.substring(0, position.column) + text
- + line.substring(position.column);
-
- var end = {
- row : position.row,
- column : position.column + text.length
- };
-
- var delta = {
- action: "insertText",
- range: Range.fromPoints(position, end),
- text: text
- };
- this._emit("change", { data: delta });
-
- return end;
- };
- this.remove = function(range) {
- range.start = this.$clipPosition(range.start);
- range.end = this.$clipPosition(range.end);
-
- if (range.isEmpty())
- return range.start;
-
- var firstRow = range.start.row;
- var lastRow = range.end.row;
-
- if (range.isMultiLine()) {
- var firstFullRow = range.start.column == 0 ? firstRow : firstRow + 1;
- var lastFullRow = lastRow - 1;
-
- if (range.end.column > 0)
- this.removeInLine(lastRow, 0, range.end.column);
-
- if (lastFullRow >= firstFullRow)
- this.removeLines(firstFullRow, lastFullRow);
-
- if (firstFullRow != firstRow) {
- this.removeInLine(firstRow, range.start.column, this.getLine(firstRow).length);
- this.removeNewLine(range.start.row);
- }
- }
- else {
- this.removeInLine(firstRow, range.start.column, range.end.column);
- }
- return range.start;
- };
- this.removeInLine = function(row, startColumn, endColumn) {
- if (startColumn == endColumn)
- return;
-
- var range = new Range(row, startColumn, row, endColumn);
- var line = this.getLine(row);
- var removed = line.substring(startColumn, endColumn);
- var newLine = line.substring(0, startColumn) + line.substring(endColumn, line.length);
- this.$lines.splice(row, 1, newLine);
-
- var delta = {
- action: "removeText",
- range: range,
- text: removed
- };
- this._emit("change", { data: delta });
- return range.start;
- };
- this.removeLines = function(firstRow, lastRow) {
- var range = new Range(firstRow, 0, lastRow + 1, 0);
- var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1);
-
- var delta = {
- action: "removeLines",
- range: range,
- nl: this.getNewLineCharacter(),
- lines: removed
- };
- this._emit("change", { data: delta });
- return removed;
- };
- this.removeNewLine = function(row) {
- var firstLine = this.getLine(row);
- var secondLine = this.getLine(row+1);
-
- var range = new Range(row, firstLine.length, row+1, 0);
- var line = firstLine + secondLine;
-
- this.$lines.splice(row, 2, line);
-
- var delta = {
- action: "removeText",
- range: range,
- text: this.getNewLineCharacter()
- };
- this._emit("change", { data: delta });
- };
- this.replace = function(range, text) {
- if (text.length == 0 && range.isEmpty())
- return range.start;
- if (text == this.getTextRange(range))
- return range.end;
-
- this.remove(range);
- if (text) {
- var end = this.insert(range.start, text);
- }
- else {
- end = range.start;
- }
-
- return end;
- };
- this.applyDeltas = function(deltas) {
- for (var i=0; i<deltas.length; i++) {
- var delta = deltas[i];
- var range = Range.fromPoints(delta.range.start, delta.range.end);
-
- if (delta.action == "insertLines")
- this.insertLines(range.start.row, delta.lines);
- else if (delta.action == "insertText")
- this.insert(range.start, delta.text);
- else if (delta.action == "removeLines")
- this.removeLines(range.start.row, range.end.row - 1);
- else if (delta.action == "removeText")
- this.remove(range);
- }
- };
- this.revertDeltas = function(deltas) {
- for (var i=deltas.length-1; i>=0; i--) {
- var delta = deltas[i];
-
- var range = Range.fromPoints(delta.range.start, delta.range.end);
-
- if (delta.action == "insertLines")
- this.removeLines(range.start.row, range.end.row - 1);
- else if (delta.action == "insertText")
- this.remove(range);
- else if (delta.action == "removeLines")
- this.insertLines(range.start.row, delta.lines);
- else if (delta.action == "removeText")
- this.insert(range.start, delta.text);
- }
- };
- this.indexToPosition = function(index, startRow) {
- var lines = this.$lines || this.getAllLines();
- var newlineLength = this.getNewLineCharacter().length;
- for (var i = startRow || 0, l = lines.length; i < l; i++) {
- index -= lines[i].length + newlineLength;
- if (index < 0)
- return {row: i, column: index + lines[i].length + newlineLength};
- }
- return {row: l-1, column: lines[l-1].length};
- };
- this.positionToIndex = function(pos, startRow) {
- var lines = this.$lines || this.getAllLines();
- var newlineLength = this.getNewLineCharacter().length;
- var index = 0;
- var row = Math.min(pos.row, lines.length);
- for (var i = startRow || 0; i < row; ++i)
- index += lines[i].length;
-
- return index + newlineLength * i + pos.column;
- };
-
-}).call(Document.prototype);
-
-exports.Document = Document;
-});
-
-define('ace/range', ['require', 'exports', 'module' ], function(require, exports, module) {
-var Range = function(startRow, startColumn, endRow, endColumn) {
- this.start = {
- row: startRow,
- column: startColumn
- };
-
- this.end = {
- row: endRow,
- column: endColumn
- };
-};
-
-(function() {
- this.isEqual = function(range) {
- return this.start.row == range.start.row &&
- this.end.row == range.end.row &&
- this.start.column == range.start.column &&
- this.end.column == range.end.column
- };
- this.toString = function() {
- return ("Range: [" + this.start.row + "/" + this.start.column +
- "] -> [" + this.end.row + "/" + this.end.column + "]");
- };
-
- this.contains = function(row, column) {
- return this.compare(row, column) == 0;
- };
- this.compareRange = function(range) {
- var cmp,
- end = range.end,
- start = range.start;
-
- cmp = this.compare(end.row, end.column);
- if (cmp == 1) {
- cmp = this.compare(start.row, start.column);
- if (cmp == 1) {
- return 2;
- } else if (cmp == 0) {
- return 1;
- } else {
- return 0;
- }
- } else if (cmp == -1) {
- return -2;
- } else {
- cmp = this.compare(start.row, start.column);
- if (cmp == -1) {
- return -1;
- } else if (cmp == 1) {
- return 42;
- } else {
- return 0;
- }
- }
- };
- this.comparePoint = function(p) {
- return this.compare(p.row, p.column);
- };
- this.containsRange = function(range) {
- return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0;
- };
- this.intersects = function(range) {
- var cmp = this.compareRange(range);
- return (cmp == -1 || cmp == 0 || cmp == 1);
- };
- this.isEnd = function(row, column) {
- return this.end.row == row && this.end.column == column;
- };
- this.isStart = function(row, column) {
- return this.start.row == row && this.start.column == column;
- };
- this.setStart = function(row, column) {
- if (typeof row == "object") {
- this.start.column = row.column;
- this.start.row = row.row;
- } else {
- this.start.row = row;
- this.start.column = column;
- }
- };
- this.setEnd = function(row, column) {
- if (typeof row == "object") {
- this.end.column = row.column;
- this.end.row = row.row;
- } else {
- this.end.row = row;
- this.end.column = column;
- }
- };
- this.inside = function(row, column) {
- if (this.compare(row, column) == 0) {
- if (this.isEnd(row, column) || this.isStart(row, column)) {
- return false;
- } else {
- return true;
- }
- }
- return false;
- };
- this.insideStart = function(row, column) {
- if (this.compare(row, column) == 0) {
- if (this.isEnd(row, column)) {
- return false;
- } else {
- return true;
- }
- }
- return false;
- };
- this.insideEnd = function(row, column) {
- if (this.compare(row, column) == 0) {
- if (this.isStart(row, column)) {
- return false;
- } else {
- return true;
- }
- }
- return false;
- };
- this.compare = function(row, column) {
- if (!this.isMultiLine()) {
- if (row === this.start.row) {
- return column < this.start.column ? -1 : (column > this.end.column ? 1 : 0);
- };
- }
-
- if (row < this.start.row)
- return -1;
-
- if (row > this.end.row)
- return 1;
-
- if (this.start.row === row)
- return column >= this.start.column ? 0 : -1;
-
- if (this.end.row === row)
- return column <= this.end.column ? 0 : 1;
-
- return 0;
- };
- this.compareStart = function(row, column) {
- if (this.start.row == row && this.start.column == column) {
- return -1;
- } else {
- return this.compare(row, column);
- }
- };
- this.compareEnd = function(row, column) {
- if (this.end.row == row && this.end.column == column) {
- return 1;
- } else {
- return this.compare(row, column);
- }
- };
- this.compareInside = function(row, column) {
- if (this.end.row == row && this.end.column == column) {
- return 1;
- } else if (this.start.row == row && this.start.column == column) {
- return -1;
- } else {
- return this.compare(row, column);
- }
- };
- this.clipRows = function(firstRow, lastRow) {
- if (this.end.row > lastRow) {
- var end = {
- row: lastRow+1,
- column: 0
- };
- }
-
- if (this.start.row > lastRow) {
- var start = {
- row: lastRow+1,
- column: 0
- };
- }
-
- if (this.start.row < firstRow) {
- var start = {
- row: firstRow,
- column: 0
- };
- }
-
- if (this.end.row < firstRow) {
- var end = {
- row: firstRow,
- column: 0
- };
- }
- return Range.fromPoints(start || this.start, end || this.end);
- };
- this.extend = function(row, column) {
- var cmp = this.compare(row, column);
-
- if (cmp == 0)
- return this;
- else if (cmp == -1)
- var start = {row: row, column: column};
- else
- var end = {row: row, column: column};
-
- return Range.fromPoints(start || this.start, end || this.end);
- };
-
- this.isEmpty = function() {
- return (this.start.row == this.end.row && this.start.column == this.end.column);
- };
- this.isMultiLine = function() {
- return (this.start.row !== this.end.row);
- };
- this.clone = function() {
- return Range.fromPoints(this.start, this.end);
- };
- this.collapseRows = function() {
- if (this.end.column == 0)
- return new Range(this.start.row, 0, Math.max(this.start.row, this.end.row-1), 0)
- else
- return new Range(this.start.row, 0, this.end.row, 0)
- };
- this.toScreenRange = function(session) {
- var screenPosStart =
- session.documentToScreenPosition(this.start);
- var screenPosEnd =
- session.documentToScreenPosition(this.end);
-
- return new Range(
- screenPosStart.row, screenPosStart.column,
- screenPosEnd.row, screenPosEnd.column
- );
- };
-
-}).call(Range.prototype);
-Range.fromPoints = function(start, end) {
- return new Range(start.row, start.column, end.row, end.column);
-};
-
-exports.Range = Range;
-});
-
-define('ace/anchor', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter'], function(require, exports, module) {
-
-
-var oop = require("./lib/oop");
-var EventEmitter = require("./lib/event_emitter").EventEmitter;
-
-var Anchor = exports.Anchor = function(doc, row, column) {
- this.document = doc;
-
- if (typeof column == "undefined")
- this.setPosition(row.row, row.column);
- else
- this.setPosition(row, column);
-
- this.$onChange = this.onChange.bind(this);
- doc.on("change", this.$onChange);
-};
-
-(function() {
-
- oop.implement(this, EventEmitter);
-
- this.getPosition = function() {
- return this.$clipPositionToDocument(this.row, this.column);
- };
-
- this.getDocument = function() {
- return this.document;
- };
-
- this.onChange = function(e) {
- var delta = e.data;
- var range = delta.range;
-
- if (range.start.row == range.end.row && range.start.row != this.row)
- return;
-
- if (range.start.row > this.row)
- return;
-
- if (range.start.row == this.row && range.start.column > this.column)
- return;
-
- var row = this.row;
- var column = this.column;
-
- if (delta.action === "insertText") {
- if (range.start.row === row && range.start.column <= column) {
- if (range.start.row === range.end.row) {
- column += range.end.column - range.start.column;
- }
- else {
- column -= range.start.column;
- row += range.end.row - range.start.row;
- }
- }
- else if (range.start.row !== range.end.row && range.start.row < row) {
- row += range.end.row - range.start.row;
- }
- } else if (delta.action === "insertLines") {
- if (range.start.row <= row) {
- row += range.end.row - range.start.row;
- }
- }
- else if (delta.action == "removeText") {
- if (range.start.row == row && range.start.column < column) {
- if (range.end.column >= column)
- column = range.start.column;
- else
- column = Math.max(0, column - (range.end.column - range.start.column));
-
- } else if (range.start.row !== range.end.row && range.start.row < row) {
- if (range.end.row == row) {
- column = Math.max(0, column - range.end.column) + range.start.column;
- }
- row -= (range.end.row - range.start.row);
- }
- else if (range.end.row == row) {
- row -= range.end.row - range.start.row;
- column = Math.max(0, column - range.end.column) + range.start.column;
- }
- } else if (delta.action == "removeLines") {
- if (range.start.row <= row) {
- if (range.end.row <= row)
- row -= range.end.row - range.start.row;
- else {
- row = range.start.row;
- column = 0;
- }
- }
- }
-
- this.setPosition(row, column, true);
- };
-
- this.setPosition = function(row, column, noClip) {
- var pos;
- if (noClip) {
- pos = {
- row: row,
- column: column
- };
- }
- else {
- pos = this.$clipPositionToDocument(row, column);
- }
-
- if (this.row == pos.row && this.column == pos.column)
- return;
-
- var old = {
- row: this.row,
- column: this.column
- };
-
- this.row = pos.row;
- this.column = pos.column;
- this._emit("change", {
- old: old,
- value: pos
- });
- };
-
- this.detach = function() {
- this.document.removeEventListener("change", this.$onChange);
- };
- this.$clipPositionToDocument = function(row, column) {
- var pos = {};
-
- if (row >= this.document.getLength()) {
- pos.row = Math.max(0, this.document.getLength() - 1);
- pos.column = this.document.getLine(pos.row).length;
- }
- else if (row < 0) {
- pos.row = 0;
- pos.column = 0;
- }
- else {
- pos.row = row;
- pos.column = Math.min(this.document.getLine(pos.row).length, Math.max(0, column));
- }
-
- if (column < 0)
- pos.column = 0;
-
- return pos;
- };
-
-}).call(Anchor.prototype);
-
-});
-define('ace/mode/css/csslint', ['require', 'exports', 'module' ], function(require, exports, module) {
-var parserlib = {};
-(function(){
-function EventTarget(){
- this._listeners = {};
-}
-
-EventTarget.prototype = {
- constructor: EventTarget,
- addListener: function(type, listener){
- if (!this._listeners[type]){
- this._listeners[type] = [];
- }
-
- this._listeners[type].push(listener);
- },
- fire: function(event){
- if (typeof event == "string"){
- event = { type: event };
- }
- if (typeof event.target != "undefined"){
- event.target = this;
- }
-
- if (typeof event.type == "undefined"){
- throw new Error("Event object missing 'type' property.");
- }
-
- if (this._listeners[event.type]){
- var listeners = this._listeners[event.type].concat();
- for (var i=0, len=listeners.length; i < len; i++){
- listeners[i].call(this, event);
- }
- }
- },
- removeListener: function(type, listener){
- if (this._listeners[type]){
- var listeners = this._listeners[type];
- for (var i=0, len=listeners.length; i < len; i++){
- if (listeners[i] === listener){
- listeners.splice(i, 1);
- break;
- }
- }
-
-
- }
- }
-};
-function StringReader(text){
- this._input = text.replace(/\n\r?/g, "\n");
- this._line = 1;
- this._col = 1;
- this._cursor = 0;
-}
-
-StringReader.prototype = {
- constructor: StringReader,
- getCol: function(){
- return this._col;
- },
- getLine: function(){
- return this._line ;
- },
- eof: function(){
- return (this._cursor == this._input.length);
- },
- peek: function(count){
- var c = null;
- count = (typeof count == "undefined" ? 1 : count);
- if (this._cursor < this._input.length){
- c = this._input.charAt(this._cursor + count - 1);
- }
-
- return c;
- },
- read: function(){
- var c = null;
- if (this._cursor < this._input.length){
- if (this._input.charAt(this._cursor) == "\n"){
- this._line++;
- this._col=1;
- } else {
- this._col++;
- }
- c = this._input.charAt(this._cursor++);
- }
-
- return c;
- },
- mark: function(){
- this._bookmark = {
- cursor: this._cursor,
- line: this._line,
- col: this._col
- };
- },
-
- reset: function(){
- if (this._bookmark){
- this._cursor = this._bookmark.cursor;
- this._line = this._bookmark.line;
- this._col = this._bookmark.col;
- delete this._bookmark;
- }
- },
- readTo: function(pattern){
-
- var buffer = "",
- c;
- while (buffer.length < pattern.length || buffer.lastIndexOf(pattern) != buffer.length - pattern.length){
- c = this.read();
- if (c){
- buffer += c;
- } else {
- throw new Error("Expected \"" + pattern + "\" at line " + this._line + ", col " + this._col + ".");
- }
- }
-
- return buffer;
-
- },
- readWhile: function(filter){
-
- var buffer = "",
- c = this.read();
-
- while(c !== null && filter(c)){
- buffer += c;
- c = this.read();
- }
-
- return buffer;
-
- },
- readMatch: function(matcher){
-
- var source = this._input.substring(this._cursor),
- value = null;
- if (typeof matcher == "string"){
- if (source.indexOf(matcher) === 0){
- value = this.readCount(matcher.length);
- }
- } else if (matcher instanceof RegExp){
- if (matcher.test(source)){
- value = this.readCount(RegExp.lastMatch.length);
- }
- }
-
- return value;
- },
- readCount: function(count){
- var buffer = "";
-
- while(count--){
- buffer += this.read();
- }
-
- return buffer;
- }
-
-};
-function SyntaxError(message, line, col){
- this.col = col;
- this.line = line;
- this.message = message;
-
-}
-SyntaxError.prototype = new Error();
-function SyntaxUnit(text, line, col, type){
- this.col = col;
- this.line = line;
- this.text = text;
- this.type = type;
-}
-SyntaxUnit.fromToken = function(token){
- return new SyntaxUnit(token.value, token.startLine, token.startCol);
-};
-
-SyntaxUnit.prototype = {
- constructor: SyntaxUnit,
- valueOf: function(){
- return this.toString();
- },
- toString: function(){
- return this.text;
- }
-
-};
-function TokenStreamBase(input, tokenData){
- this._reader = input ? new StringReader(input.toString()) : null;
- this._token = null;
- this._tokenData = tokenData;
- this._lt = [];
- this._ltIndex = 0;
-
- this._ltIndexCache = [];
-}
-TokenStreamBase.createTokenData = function(tokens){
-
- var nameMap = [],
- typeMap = {},
- tokenData = tokens.concat([]),
- i = 0,
- len = tokenData.length+1;
-
- tokenData.UNKNOWN = -1;
- tokenData.unshift({name:"EOF"});
-
- for (; i < len; i++){
- nameMap.push(tokenData[i].name);
- tokenData[tokenData[i].name] = i;
- if (tokenData[i].text){
- typeMap[tokenData[i].text] = i;
- }
- }
-
- tokenData.name = function(tt){
- return nameMap[tt];
- };
-
- tokenData.type = function(c){
- return typeMap[c];
- };
-
- return tokenData;
-};
-
-TokenStreamBase.prototype = {
- constructor: TokenStreamBase,
- match: function(tokenTypes, channel){
- if (!(tokenTypes instanceof Array)){
- tokenTypes = [tokenTypes];
- }
-
- var tt = this.get(channel),
- i = 0,
- len = tokenTypes.length;
-
- while(i < len){
- if (tt == tokenTypes[i++]){
- return true;
- }
- }
- this.unget();
- return false;
- },
- mustMatch: function(tokenTypes, channel){
-
- var token;
- if (!(tokenTypes instanceof Array)){
- tokenTypes = [tokenTypes];
- }
-
- if (!this.match.apply(this, arguments)){
- token = this.LT(1);
- throw new SyntaxError("Expected " + this._tokenData[tokenTypes[0]].name +
- " at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol);
- }
- },
- advance: function(tokenTypes, channel){
-
- while(this.LA(0) !== 0 && !this.match(tokenTypes, channel)){
- this.get();
- }
-
- return this.LA(0);
- },
- get: function(channel){
-
- var tokenInfo = this._tokenData,
- reader = this._reader,
- value,
- i =0,
- len = tokenInfo.length,
- found = false,
- token,
- info;
- if (this._lt.length && this._ltIndex >= 0 && this._ltIndex < this._lt.length){
-
- i++;
- this._token = this._lt[this._ltIndex++];
- info = tokenInfo[this._token.type];
- while((info.channel !== undefined && channel !== info.channel) &&
- this._ltIndex < this._lt.length){
- this._token = this._lt[this._ltIndex++];
- info = tokenInfo[this._token.type];
- i++;
- }
- if ((info.channel === undefined || channel === info.channel) &&
- this._ltIndex <= this._lt.length){
- this._ltIndexCache.push(i);
- return this._token.type;
- }
- }
- token = this._getToken();
- if (token.type > -1 && !tokenInfo[token.type].hide){
- token.channel = tokenInfo[token.type].channel;
- this._token = token;
- this._lt.push(token);
- this._ltIndexCache.push(this._lt.length - this._ltIndex + i);
- if (this._lt.length > 5){
- this._lt.shift();
- }
- if (this._ltIndexCache.length > 5){
- this._ltIndexCache.shift();
- }
- this._ltIndex = this._lt.length;
- }
- info = tokenInfo[token.type];
- if (info &&
- (info.hide ||
- (info.channel !== undefined && channel !== info.channel))){
- return this.get(channel);
- } else {
- return token.type;
- }
- },
- LA: function(index){
- var total = index,
- tt;
- if (index > 0){
- if (index > 5){
- throw new Error("Too much lookahead.");
- }
- while(total){
- tt = this.get();
- total--;
- }
- while(total < index){
- this.unget();
- total++;
- }
- } else if (index < 0){
-
- if(this._lt[this._ltIndex+index]){
- tt = this._lt[this._ltIndex+index].type;
- } else {
- throw new Error("Too much lookbehind.");
- }
-
- } else {
- tt = this._token.type;
- }
-
- return tt;
-
- },
- LT: function(index){
- this.LA(index);
- return this._lt[this._ltIndex+index-1];
- },
- peek: function(){
- return this.LA(1);
- },
- token: function(){
- return this._token;
- },
- tokenName: function(tokenType){
- if (tokenType < 0 || tokenType > this._tokenData.length){
- return "UNKNOWN_TOKEN";
- } else {
- return this._tokenData[tokenType].name;
- }
- },
- tokenType: function(tokenName){
- return this._tokenData[tokenName] || -1;
- },
- unget: function(){
- if (this._ltIndexCache.length){
- this._ltIndex -= this._ltIndexCache.pop();//--;
- this._token = this._lt[this._ltIndex - 1];
- } else {
- throw new Error("Too much lookahead.");
- }
- }
-
-};
-
-
-
-
-parserlib.util = {
-StringReader: StringReader,
-SyntaxError : SyntaxError,
-SyntaxUnit : SyntaxUnit,
-EventTarget : EventTarget,
-TokenStreamBase : TokenStreamBase
-};
-})();
-(function(){
-var EventTarget = parserlib.util.EventTarget,
-TokenStreamBase = parserlib.util.TokenStreamBase,
-StringReader = parserlib.util.StringReader,
-SyntaxError = parserlib.util.SyntaxError,
-SyntaxUnit = parserlib.util.SyntaxUnit;
-
-
-var Colors = {
- aliceblue :"#f0f8ff",
- antiquewhite :"#faebd7",
- aqua :"#00ffff",
- aquamarine :"#7fffd4",
- azure :"#f0ffff",
- beige :"#f5f5dc",
- bisque :"#ffe4c4",
- black :"#000000",
- blanchedalmond :"#ffebcd",
- blue :"#0000ff",
- blueviolet :"#8a2be2",
- brown :"#a52a2a",
- burlywood :"#deb887",
- cadetblue :"#5f9ea0",
- chartreuse :"#7fff00",
- chocolate :"#d2691e",
- coral :"#ff7f50",
- cornflowerblue :"#6495ed",
- cornsilk :"#fff8dc",
- crimson :"#dc143c",
- cyan :"#00ffff",
- darkblue :"#00008b",
- darkcyan :"#008b8b",
- darkgoldenrod :"#b8860b",
- darkgray :"#a9a9a9",
- darkgreen :"#006400",
- darkkhaki :"#bdb76b",
- darkmagenta :"#8b008b",
- darkolivegreen :"#556b2f",
- darkorange :"#ff8c00",
- darkorchid :"#9932cc",
- darkred :"#8b0000",
- darksalmon :"#e9967a",
- darkseagreen :"#8fbc8f",
- darkslateblue :"#483d8b",
- darkslategray :"#2f4f4f",
- darkturquoise :"#00ced1",
- darkviolet :"#9400d3",
- deeppink :"#ff1493",
- deepskyblue :"#00bfff",
- dimgray :"#696969",
- dodgerblue :"#1e90ff",
- firebrick :"#b22222",
- floralwhite :"#fffaf0",
- forestgreen :"#228b22",
- fuchsia :"#ff00ff",
- gainsboro :"#dcdcdc",
- ghostwhite :"#f8f8ff",
- gold :"#ffd700",
- goldenrod :"#daa520",
- gray :"#808080",
- green :"#008000",
- greenyellow :"#adff2f",
- honeydew :"#f0fff0",
- hotpink :"#ff69b4",
- indianred :"#cd5c5c",
- indigo :"#4b0082",
- ivory :"#fffff0",
- khaki :"#f0e68c",
- lavender :"#e6e6fa",
- lavenderblush :"#fff0f5",
- lawngreen :"#7cfc00",
- lemonchiffon :"#fffacd",
- lightblue :"#add8e6",
- lightcoral :"#f08080",
- lightcyan :"#e0ffff",
- lightgoldenrodyellow :"#fafad2",
- lightgray :"#d3d3d3",
- lightgreen :"#90ee90",
- lightpink :"#ffb6c1",
- lightsalmon :"#ffa07a",
- lightseagreen :"#20b2aa",
- lightskyblue :"#87cefa",
- lightslategray :"#778899",
- lightsteelblue :"#b0c4de",
- lightyellow :"#ffffe0",
- lime :"#00ff00",
- limegreen :"#32cd32",
- linen :"#faf0e6",
- magenta :"#ff00ff",
- maroon :"#800000",
- mediumaquamarine:"#66cdaa",
- mediumblue :"#0000cd",
- mediumorchid :"#ba55d3",
- mediumpurple :"#9370d8",
- mediumseagreen :"#3cb371",
- mediumslateblue :"#7b68ee",
- mediumspringgreen :"#00fa9a",
- mediumturquoise :"#48d1cc",
- mediumvioletred :"#c71585",
- midnightblue :"#191970",
- mintcream :"#f5fffa",
- mistyrose :"#ffe4e1",
- moccasin :"#ffe4b5",
- navajowhite :"#ffdead",
- navy :"#000080",
- oldlace :"#fdf5e6",
- olive :"#808000",
- olivedrab :"#6b8e23",
- orange :"#ffa500",
- orangered :"#ff4500",
- orchid :"#da70d6",
- palegoldenrod :"#eee8aa",
- palegreen :"#98fb98",
- paleturquoise :"#afeeee",
- palevioletred :"#d87093",
- papayawhip :"#ffefd5",
- peachpuff :"#ffdab9",
- peru :"#cd853f",
- pink :"#ffc0cb",
- plum :"#dda0dd",
- powderblue :"#b0e0e6",
- purple :"#800080",
- red :"#ff0000",
- rosybrown :"#bc8f8f",
- royalblue :"#4169e1",
- saddlebrown :"#8b4513",
- salmon :"#fa8072",
- sandybrown :"#f4a460",
- seagreen :"#2e8b57",
- seashell :"#fff5ee",
- sienna :"#a0522d",
- silver :"#c0c0c0",
- skyblue :"#87ceeb",
- slateblue :"#6a5acd",
- slategray :"#708090",
- snow :"#fffafa",
- springgreen :"#00ff7f",
- steelblue :"#4682b4",
- tan :"#d2b48c",
- teal :"#008080",
- thistle :"#d8bfd8",
- tomato :"#ff6347",
- turquoise :"#40e0d0",
- violet :"#ee82ee",
- wheat :"#f5deb3",
- white :"#ffffff",
- whitesmoke :"#f5f5f5",
- yellow :"#ffff00",
- yellowgreen :"#9acd32"
-};
-function Combinator(text, line, col){
-
- SyntaxUnit.call(this, text, line, col, Parser.COMBINATOR_TYPE);
- this.type = "unknown";
- if (/^\s+$/.test(text)){
- this.type = "descendant";
- } else if (text == ">"){
- this.type = "child";
- } else if (text == "+"){
- this.type = "adjacent-sibling";
- } else if (text == "~"){
- this.type = "sibling";
- }
-
-}
-
-Combinator.prototype = new SyntaxUnit();
-Combinator.prototype.constructor = Combinator;
-function MediaFeature(name, value){
-
- SyntaxUnit.call(this, "(" + name + (value !== null ? ":" + value : "") + ")", name.startLine, name.startCol, Parser.MEDIA_FEATURE_TYPE);
- this.name = name;
- this.value = value;
-}
-
-MediaFeature.prototype = new SyntaxUnit();
-MediaFeature.prototype.constructor = MediaFeature;
-function MediaQuery(modifier, mediaType, features, line, col){
-
- SyntaxUnit.call(this, (modifier ? modifier + " ": "") + (mediaType ? mediaType + " " : "") + features.join(" and "), line, col, Parser.MEDIA_QUERY_TYPE);
- this.modifier = modifier;
- this.mediaType = mediaType;
- this.features = features;
-
-}
-
-MediaQuery.prototype = new SyntaxUnit();
-MediaQuery.prototype.constructor = MediaQuery;
-function Parser(options){
- EventTarget.call(this);
-
-
- this.options = options || {};
-
- this._tokenStream = null;
-}
-Parser.DEFAULT_TYPE = 0;
-Parser.COMBINATOR_TYPE = 1;
-Parser.MEDIA_FEATURE_TYPE = 2;
-Parser.MEDIA_QUERY_TYPE = 3;
-Parser.PROPERTY_NAME_TYPE = 4;
-Parser.PROPERTY_VALUE_TYPE = 5;
-Parser.PROPERTY_VALUE_PART_TYPE = 6;
-Parser.SELECTOR_TYPE = 7;
-Parser.SELECTOR_PART_TYPE = 8;
-Parser.SELECTOR_SUB_PART_TYPE = 9;
-
-Parser.prototype = function(){
-
- var proto = new EventTarget(), //new prototype
- prop,
- additions = {
- constructor: Parser,
- DEFAULT_TYPE : 0,
- COMBINATOR_TYPE : 1,
- MEDIA_FEATURE_TYPE : 2,
- MEDIA_QUERY_TYPE : 3,
- PROPERTY_NAME_TYPE : 4,
- PROPERTY_VALUE_TYPE : 5,
- PROPERTY_VALUE_PART_TYPE : 6,
- SELECTOR_TYPE : 7,
- SELECTOR_PART_TYPE : 8,
- SELECTOR_SUB_PART_TYPE : 9,
-
- _stylesheet: function(){
-
- var tokenStream = this._tokenStream,
- charset = null,
- count,
- token,
- tt;
-
- this.fire("startstylesheet");
- this._charset();
-
- this._skipCruft();
- while (tokenStream.peek() == Tokens.IMPORT_SYM){
- this._import();
- this._skipCruft();
- }
- while (tokenStream.peek() == Tokens.NAMESPACE_SYM){
- this._namespace();
- this._skipCruft();
- }
- tt = tokenStream.peek();
- while(tt > Tokens.EOF){
-
- try {
-
- switch(tt){
- case Tokens.MEDIA_SYM:
- this._media();
- this._skipCruft();
- break;
- case Tokens.PAGE_SYM:
- this._page();
- this._skipCruft();
- break;
- case Tokens.FONT_FACE_SYM:
- this._font_face();
- this._skipCruft();
- break;
- case Tokens.KEYFRAMES_SYM:
- this._keyframes();
- this._skipCruft();
- break;
- case Tokens.UNKNOWN_SYM: //unknown @ rule
- tokenStream.get();
- if (!this.options.strict){
- this.fire({
- type: "error",
- error: null,
- message: "Unknown @ rule: " + tokenStream.LT(0).value + ".",
- line: tokenStream.LT(0).startLine,
- col: tokenStream.LT(0).startCol
- });
- count=0;
- while (tokenStream.advance([Tokens.LBRACE, Tokens.RBRACE]) == Tokens.LBRACE){
- count++; //keep track of nesting depth
- }
-
- while(count){
- tokenStream.advance([Tokens.RBRACE]);
- count--;
- }
-
- } else {
- throw new SyntaxError("Unknown @ rule.", tokenStream.LT(0).startLine, tokenStream.LT(0).startCol);
- }
- break;
- case Tokens.S:
- this._readWhitespace();
- break;
- default:
- if(!this._ruleset()){
- switch(tt){
- case Tokens.CHARSET_SYM:
- token = tokenStream.LT(1);
- this._charset(false);
- throw new SyntaxError("@charset not allowed here.", token.startLine, token.startCol);
- case Tokens.IMPORT_SYM:
- token = tokenStream.LT(1);
- this._import(false);
- throw new SyntaxError("@import not allowed here.", token.startLine, token.startCol);
- case Tokens.NAMESPACE_SYM:
- token = tokenStream.LT(1);
- this._namespace(false);
- throw new SyntaxError("@namespace not allowed here.", token.startLine, token.startCol);
- default:
- tokenStream.get(); //get the last token
- this._unexpectedToken(tokenStream.token());
- }
-
- }
- }
- } catch(ex) {
- if (ex instanceof SyntaxError && !this.options.strict){
- this.fire({
- type: "error",
- error: ex,
- message: ex.message,
- line: ex.line,
- col: ex.col
- });
- } else {
- throw ex;
- }
- }
-
- tt = tokenStream.peek();
- }
-
- if (tt != Tokens.EOF){
- this._unexpectedToken(tokenStream.token());
- }
-
- this.fire("endstylesheet");
- },
-
- _charset: function(emit){
- var tokenStream = this._tokenStream,
- charset,
- token,
- line,
- col;
-
- if (tokenStream.match(Tokens.CHARSET_SYM)){
- line = tokenStream.token().startLine;
- col = tokenStream.token().startCol;
-
- this._readWhitespace();
- tokenStream.mustMatch(Tokens.STRING);
-
- token = tokenStream.token();
- charset = token.value;
-
- this._readWhitespace();
- tokenStream.mustMatch(Tokens.SEMICOLON);
-
- if (emit !== false){
- this.fire({
- type: "charset",
- charset:charset,
- line: line,
- col: col
- });
- }
- }
- },
-
- _import: function(emit){
-
- var tokenStream = this._tokenStream,
- tt,
- uri,
- importToken,
- mediaList = [];
- tokenStream.mustMatch(Tokens.IMPORT_SYM);
- importToken = tokenStream.token();
- this._readWhitespace();
-
- tokenStream.mustMatch([Tokens.STRING, Tokens.URI]);
- uri = tokenStream.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/, "$1");
-
- this._readWhitespace();
-
- mediaList = this._media_query_list();
- tokenStream.mustMatch(Tokens.SEMICOLON);
- this._readWhitespace();
-
- if (emit !== false){
- this.fire({
- type: "import",
- uri: uri,
- media: mediaList,
- line: importToken.startLine,
- col: importToken.startCol
- });
- }
-
- },
-
- _namespace: function(emit){
-
- var tokenStream = this._tokenStream,
- line,
- col,
- prefix,
- uri;
- tokenStream.mustMatch(Tokens.NAMESPACE_SYM);
- line = tokenStream.token().startLine;
- col = tokenStream.token().startCol;
- this._readWhitespace();
- if (tokenStream.match(Tokens.IDENT)){
- prefix = tokenStream.token().value;
- this._readWhitespace();
- }
-
- tokenStream.mustMatch([Tokens.STRING, Tokens.URI]);
- uri = tokenStream.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/, "$1");
-
- this._readWhitespace();
- tokenStream.mustMatch(Tokens.SEMICOLON);
- this._readWhitespace();
-
- if (emit !== false){
- this.fire({
- type: "namespace",
- prefix: prefix,
- uri: uri,
- line: line,
- col: col
- });
- }
-
- },
-
- _media: function(){
- var tokenStream = this._tokenStream,
- line,
- col,
- mediaList;// = [];
- tokenStream.mustMatch(Tokens.MEDIA_SYM);
- line = tokenStream.token().startLine;
- col = tokenStream.token().startCol;
-
- this._readWhitespace();
-
- mediaList = this._media_query_list();
-
- tokenStream.mustMatch(Tokens.LBRACE);
- this._readWhitespace();
-
- this.fire({
- type: "startmedia",
- media: mediaList,
- line: line,
- col: col
- });
-
- while(true) {
- if (tokenStream.peek() == Tokens.PAGE_SYM){
- this._page();
- } else if (!this._ruleset()){
- break;
- }
- }
-
- tokenStream.mustMatch(Tokens.RBRACE);
- this._readWhitespace();
-
- this.fire({
- type: "endmedia",
- media: mediaList,
- line: line,
- col: col
- });
- },
- _media_query_list: function(){
- var tokenStream = this._tokenStream,
- mediaList = [];
-
-
- this._readWhitespace();
-
- if (tokenStream.peek() == Tokens.IDENT || tokenStream.peek() == Tokens.LPAREN){
- mediaList.push(this._media_query());
- }
-
- while(tokenStream.match(Tokens.COMMA)){
- this._readWhitespace();
- mediaList.push(this._media_query());
- }
-
- return mediaList;
- },
- _media_query: function(){
- var tokenStream = this._tokenStream,
- type = null,
- ident = null,
- token = null,
- expressions = [];
-
- if (tokenStream.match(Tokens.IDENT)){
- ident = tokenStream.token().value.toLowerCase();
- if (ident != "only" && ident != "not"){
- tokenStream.unget();
- ident = null;
- } else {
- token = tokenStream.token();
- }
- }
-
- this._readWhitespace();
-
- if (tokenStream.peek() == Tokens.IDENT){
- type = this._media_type();
- if (token === null){
- token = tokenStream.token();
- }
- } else if (tokenStream.peek() == Tokens.LPAREN){
- if (token === null){
- token = tokenStream.LT(1);
- }
- expressions.push(this._media_expression());
- }
-
- if (type === null && expressions.length === 0){
- return null;
- } else {
- this._readWhitespace();
- while (tokenStream.match(Tokens.IDENT)){
- if (tokenStream.token().value.toLowerCase() != "and"){
- this._unexpectedToken(tokenStream.token());
- }
-
- this._readWhitespace();
- expressions.push(this._media_expression());
- }
- }
-
- return new MediaQuery(ident, type, expressions, token.startLine, token.startCol);
- },
- _media_type: function(){
- return this._media_feature();
- },
- _media_expression: function(){
- var tokenStream = this._tokenStream,
- feature = null,
- token,
- expression = null;
-
- tokenStream.mustMatch(Tokens.LPAREN);
-
- feature = this._media_feature();
- this._readWhitespace();
-
- if (tokenStream.match(Tokens.COLON)){
- this._readWhitespace();
- token = tokenStream.LT(1);
- expression = this._expression();
- }
-
- tokenStream.mustMatch(Tokens.RPAREN);
- this._readWhitespace();
-
- return new MediaFeature(feature, (expression ? new SyntaxUnit(expression, token.startLine, token.startCol) : null));
- },
- _media_feature: function(){
- var tokenStream = this._tokenStream;
-
- tokenStream.mustMatch(Tokens.IDENT);
-
- return SyntaxUnit.fromToken(tokenStream.token());
- },
- _page: function(){
- var tokenStream = this._tokenStream,
- line,
- col,
- identifier = null,
- pseudoPage = null;
- tokenStream.mustMatch(Tokens.PAGE_SYM);
- line = tokenStream.token().startLine;
- col = tokenStream.token().startCol;
-
- this._readWhitespace();
-
- if (tokenStream.match(Tokens.IDENT)){
- identifier = tokenStream.token().value;
- if (identifier.toLowerCase() === "auto"){
- this._unexpectedToken(tokenStream.token());
- }
- }
- if (tokenStream.peek() == Tokens.COLON){
- pseudoPage = this._pseudo_page();
- }
-
- this._readWhitespace();
-
- this.fire({
- type: "startpage",
- id: identifier,
- pseudo: pseudoPage,
- line: line,
- col: col
- });
-
- this._readDeclarations(true, true);
-
- this.fire({
- type: "endpage",
- id: identifier,
- pseudo: pseudoPage,
- line: line,
- col: col
- });
-
- },
- _margin: function(){
- var tokenStream = this._tokenStream,
- line,
- col,
- marginSym = this._margin_sym();
-
- if (marginSym){
- line = tokenStream.token().startLine;
- col = tokenStream.token().startCol;
-
- this.fire({
- type: "startpagemargin",
- margin: marginSym,
- line: line,
- col: col
- });
-
- this._readDeclarations(true);
-
- this.fire({
- type: "endpagemargin",
- margin: marginSym,
- line: line,
- col: col
- });
- return true;
- } else {
- return false;
- }
- },
- _margin_sym: function(){
-
- var tokenStream = this._tokenStream;
-
- if(tokenStream.match([Tokens.TOPLEFTCORNER_SYM, Tokens.TOPLEFT_SYM,
- Tokens.TOPCENTER_SYM, Tokens.TOPRIGHT_SYM, Tokens.TOPRIGHTCORNER_SYM,
- Tokens.BOTTOMLEFTCORNER_SYM, Tokens.BOTTOMLEFT_SYM,
- Tokens.BOTTOMCENTER_SYM, Tokens.BOTTOMRIGHT_SYM,
- Tokens.BOTTOMRIGHTCORNER_SYM, Tokens.LEFTTOP_SYM,
- Tokens.LEFTMIDDLE_SYM, Tokens.LEFTBOTTOM_SYM, Tokens.RIGHTTOP_SYM,
- Tokens.RIGHTMIDDLE_SYM, Tokens.RIGHTBOTTOM_SYM]))
- {
- return SyntaxUnit.fromToken(tokenStream.token());
- } else {
- return null;
- }
-
- },
-
- _pseudo_page: function(){
-
- var tokenStream = this._tokenStream;
-
- tokenStream.mustMatch(Tokens.COLON);
- tokenStream.mustMatch(Tokens.IDENT);
-
- return tokenStream.token().value;
- },
-
- _font_face: function(){
- var tokenStream = this._tokenStream,
- line,
- col;
- tokenStream.mustMatch(Tokens.FONT_FACE_SYM);
- line = tokenStream.token().startLine;
- col = tokenStream.token().startCol;
-
- this._readWhitespace();
-
- this.fire({
- type: "startfontface",
- line: line,
- col: col
- });
-
- this._readDeclarations(true);
-
- this.fire({
- type: "endfontface",
- line: line,
- col: col
- });
- },
-
- _operator: function(){
-
- var tokenStream = this._tokenStream,
- token = null;
-
- if (tokenStream.match([Tokens.SLASH, Tokens.COMMA])){
- token = tokenStream.token();
- this._readWhitespace();
- }
- return token ? PropertyValuePart.fromToken(token) : null;
-
- },
-
- _combinator: function(){
-
- var tokenStream = this._tokenStream,
- value = null,
- token;
-
- if(tokenStream.match([Tokens.PLUS, Tokens.GREATER, Tokens.TILDE])){
- token = tokenStream.token();
- value = new Combinator(token.value, token.startLine, token.startCol);
- this._readWhitespace();
- }
-
- return value;
- },
-
- _unary_operator: function(){
-
- var tokenStream = this._tokenStream;
-
- if (tokenStream.match([Tokens.MINUS, Tokens.PLUS])){
- return tokenStream.token().value;
- } else {
- return null;
- }
- },
-
- _property: function(){
-
- var tokenStream = this._tokenStream,
- value = null,
- hack = null,
- tokenValue,
- token,
- line,
- col;
- if (tokenStream.peek() == Tokens.STAR && this.options.starHack){
- tokenStream.get();
- token = tokenStream.token();
- hack = token.value;
- line = token.startLine;
- col = token.startCol;
- }
-
- if(tokenStream.match(Tokens.IDENT)){
- token = tokenStream.token();
- tokenValue = token.value;
- if (tokenValue.charAt(0) == "_" && this.options.underscoreHack){
- hack = "_";
- tokenValue = tokenValue.substring(1);
- }
-
- value = new PropertyName(tokenValue, hack, (line||token.startLine), (col||token.startCol));
- this._readWhitespace();
- }
-
- return value;
- },
- _ruleset: function(){
-
- var tokenStream = this._tokenStream,
- tt,
- selectors;
- try {
- selectors = this._selectors_group();
- } catch (ex){
- if (ex instanceof SyntaxError && !this.options.strict){
- this.fire({
- type: "error",
- error: ex,
- message: ex.message,
- line: ex.line,
- col: ex.col
- });
- tt = tokenStream.advance([Tokens.RBRACE]);
- if (tt == Tokens.RBRACE){
- } else {
- throw ex;
- }
-
- } else {
- throw ex;
- }
- return true;
- }
- if (selectors){
-
- this.fire({
- type: "startrule",
- selectors: selectors,
- line: selectors[0].line,
- col: selectors[0].col
- });
-
- this._readDeclarations(true);
-
- this.fire({
- type: "endrule",
- selectors: selectors,
- line: selectors[0].line,
- col: selectors[0].col
- });
-
- }
-
- return selectors;
-
- },
- _selectors_group: function(){
- var tokenStream = this._tokenStream,
- selectors = [],
- selector;
-
- selector = this._selector();
- if (selector !== null){
-
- selectors.push(selector);
- while(tokenStream.match(Tokens.COMMA)){
- this._readWhitespace();
- selector = this._selector();
- if (selector !== null){
- selectors.push(selector);
- } else {
- this._unexpectedToken(tokenStream.LT(1));
- }
- }
- }
-
- return selectors.length ? selectors : null;
- },
- _selector: function(){
-
- var tokenStream = this._tokenStream,
- selector = [],
- nextSelector = null,
- combinator = null,
- ws = null;
- nextSelector = this._simple_selector_sequence();
- if (nextSelector === null){
- return null;
- }
-
- selector.push(nextSelector);
-
- do {
- combinator = this._combinator();
-
- if (combinator !== null){
- selector.push(combinator);
- nextSelector = this._simple_selector_sequence();
- if (nextSelector === null){
- this._unexpectedToken(tokenStream.LT(1));
- } else {
- selector.push(nextSelector);
- }
- } else {
- if (this._readWhitespace()){
- ws = new Combinator(tokenStream.token().value, tokenStream.token().startLine, tokenStream.token().startCol);
- combinator = this._combinator();
- nextSelector = this._simple_selector_sequence();
- if (nextSelector === null){
- if (combinator !== null){
- this._unexpectedToken(tokenStream.LT(1));
- }
- } else {
-
- if (combinator !== null){
- selector.push(combinator);
- } else {
- selector.push(ws);
- }
-
- selector.push(nextSelector);
- }
- } else {
- break;
- }
-
- }
- } while(true);
-
- return new Selector(selector, selector[0].line, selector[0].col);
- },
- _simple_selector_sequence: function(){
-
- var tokenStream = this._tokenStream,
- elementName = null,
- modifiers = [],
- selectorText= "",
- components = [
- function(){
- return tokenStream.match(Tokens.HASH) ?
- new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) :
- null;
- },
- this._class,
- this._attrib,
- this._pseudo,
- this._negation
- ],
- i = 0,
- len = components.length,
- component = null,
- found = false,
- line,
- col;
- line = tokenStream.LT(1).startLine;
- col = tokenStream.LT(1).startCol;
-
- elementName = this._type_selector();
- if (!elementName){
- elementName = this._universal();
- }
-
- if (elementName !== null){
- selectorText += elementName;
- }
-
- while(true){
- if (tokenStream.peek() === Tokens.S){
- break;
- }
- while(i < len && component === null){
- component = components[i++].call(this);
- }
-
- if (component === null){
- if (selectorText === ""){
- return null;
- } else {
- break;
- }
- } else {
- i = 0;
- modifiers.push(component);
- selectorText += component.toString();
- component = null;
- }
- }
-
-
- return selectorText !== "" ?
- new SelectorPart(elementName, modifiers, selectorText, line, col) :
- null;
- },
- _type_selector: function(){
-
- var tokenStream = this._tokenStream,
- ns = this._namespace_prefix(),
- elementName = this._element_name();
-
- if (!elementName){
- if (ns){
- tokenStream.unget();
- if (ns.length > 1){
- tokenStream.unget();
- }
- }
-
- return null;
- } else {
- if (ns){
- elementName.text = ns + elementName.text;
- elementName.col -= ns.length;
- }
- return elementName;
- }
- },
- _class: function(){
-
- var tokenStream = this._tokenStream,
- token;
-
- if (tokenStream.match(Tokens.DOT)){
- tokenStream.mustMatch(Tokens.IDENT);
- token = tokenStream.token();
- return new SelectorSubPart("." + token.value, "class", token.startLine, token.startCol - 1);
- } else {
- return null;
- }
-
- },
- _element_name: function(){
-
- var tokenStream = this._tokenStream,
- token;
-
- if (tokenStream.match(Tokens.IDENT)){
- token = tokenStream.token();
- return new SelectorSubPart(token.value, "elementName", token.startLine, token.startCol);
-
- } else {
- return null;
- }
- },
- _namespace_prefix: function(){
- var tokenStream = this._tokenStream,
- value = "";
- if (tokenStream.LA(1) === Tokens.PIPE || tokenStream.LA(2) === Tokens.PIPE){
-
- if(tokenStream.match([Tokens.IDENT, Tokens.STAR])){
- value += tokenStream.token().value;
- }
-
- tokenStream.mustMatch(Tokens.PIPE);
- value += "|";
-
- }
-
- return value.length ? value : null;
- },
- _universal: function(){
- var tokenStream = this._tokenStream,
- value = "",
- ns;
-
- ns = this._namespace_prefix();
- if(ns){
- value += ns;
- }
-
- if(tokenStream.match(Tokens.STAR)){
- value += "*";
- }
-
- return value.length ? value : null;
-
- },
- _attrib: function(){
-
- var tokenStream = this._tokenStream,
- value = null,
- ns,
- token;
-
- if (tokenStream.match(Tokens.LBRACKET)){
- token = tokenStream.token();
- value = token.value;
- value += this._readWhitespace();
-
- ns = this._namespace_prefix();
-
- if (ns){
- value += ns;
- }
-
- tokenStream.mustMatch(Tokens.IDENT);
- value += tokenStream.token().value;
- value += this._readWhitespace();
-
- if(tokenStream.match([Tokens.PREFIXMATCH, Tokens.SUFFIXMATCH, Tokens.SUBSTRINGMATCH,
- Tokens.EQUALS, Tokens.INCLUDES, Tokens.DASHMATCH])){
-
- value += tokenStream.token().value;
- value += this._readWhitespace();
-
- tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]);
- value += tokenStream.token().value;
- value += this._readWhitespace();
- }
-
- tokenStream.mustMatch(Tokens.RBRACKET);
-
- return new SelectorSubPart(value + "]", "attribute", token.startLine, token.startCol);
- } else {
- return null;
- }
- },
- _pseudo: function(){
-
- var tokenStream = this._tokenStream,
- pseudo = null,
- colons = ":",
- line,
- col;
-
- if (tokenStream.match(Tokens.COLON)){
-
- if (tokenStream.match(Tokens.COLON)){
- colons += ":";
- }
-
- if (tokenStream.match(Tokens.IDENT)){
- pseudo = tokenStream.token().value;
- line = tokenStream.token().startLine;
- col = tokenStream.token().startCol - colons.length;
- } else if (tokenStream.peek() == Tokens.FUNCTION){
- line = tokenStream.LT(1).startLine;
- col = tokenStream.LT(1).startCol - colons.length;
- pseudo = this._functional_pseudo();
- }
-
- if (pseudo){
- pseudo = new SelectorSubPart(colons + pseudo, "pseudo", line, col);
- }
- }
-
- return pseudo;
- },
- _functional_pseudo: function(){
-
- var tokenStream = this._tokenStream,
- value = null;
-
- if(tokenStream.match(Tokens.FUNCTION)){
- value = tokenStream.token().value;
- value += this._readWhitespace();
- value += this._expression();
- tokenStream.mustMatch(Tokens.RPAREN);
- value += ")";
- }
-
- return value;
- },
- _expression: function(){
-
- var tokenStream = this._tokenStream,
- value = "";
-
- while(tokenStream.match([Tokens.PLUS, Tokens.MINUS, Tokens.DIMENSION,
- Tokens.NUMBER, Tokens.STRING, Tokens.IDENT, Tokens.LENGTH,
- Tokens.FREQ, Tokens.ANGLE, Tokens.TIME,
- Tokens.RESOLUTION])){
-
- value += tokenStream.token().value;
- value += this._readWhitespace();
- }
-
- return value.length ? value : null;
-
- },
- _negation: function(){
-
- var tokenStream = this._tokenStream,
- line,
- col,
- value = "",
- arg,
- subpart = null;
-
- if (tokenStream.match(Tokens.NOT)){
- value = tokenStream.token().value;
- line = tokenStream.token().startLine;
- col = tokenStream.token().startCol;
- value += this._readWhitespace();
- arg = this._negation_arg();
- value += arg;
- value += this._readWhitespace();
- tokenStream.match(Tokens.RPAREN);
- value += tokenStream.token().value;
-
- subpart = new SelectorSubPart(value, "not", line, col);
- subpart.args.push(arg);
- }
-
- return subpart;
- },
- _negation_arg: function(){
-
- var tokenStream = this._tokenStream,
- args = [
- this._type_selector,
- this._universal,
- function(){
- return tokenStream.match(Tokens.HASH) ?
- new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) :
- null;
- },
- this._class,
- this._attrib,
- this._pseudo
- ],
- arg = null,
- i = 0,
- len = args.length,
- elementName,
- line,
- col,
- part;
-
- line = tokenStream.LT(1).startLine;
- col = tokenStream.LT(1).startCol;
-
- while(i < len && arg === null){
-
- arg = args[i].call(this);
- i++;
- }
- if (arg === null){
- this._unexpectedToken(tokenStream.LT(1));
- }
- if (arg.type == "elementName"){
- part = new SelectorPart(arg, [], arg.toString(), line, col);
- } else {
- part = new SelectorPart(null, [arg], arg.toString(), line, col);
- }
-
- return part;
- },
-
- _declaration: function(){
-
- var tokenStream = this._tokenStream,
- property = null,
- expr = null,
- prio = null,
- error = null,
- invalid = null,
- propertyName= "";
-
- property = this._property();
- if (property !== null){
-
- tokenStream.mustMatch(Tokens.COLON);
- this._readWhitespace();
-
- expr = this._expr();
- if (!expr || expr.length === 0){
- this._unexpectedToken(tokenStream.LT(1));
- }
-
- prio = this._prio();
- propertyName = property.toString();
- if (this.options.starHack && property.hack == "*" ||
- this.options.underscoreHack && property.hack == "_") {
-
- propertyName = property.text;
- }
-
- try {
- this._validateProperty(propertyName, expr);
- } catch (ex) {
- invalid = ex;
- }
-
- this.fire({
- type: "property",
- property: property,
- value: expr,
- important: prio,
- line: property.line,
- col: property.col,
- invalid: invalid
- });
-
- return true;
- } else {
- return false;
- }
- },
-
- _prio: function(){
-
- var tokenStream = this._tokenStream,
- result = tokenStream.match(Tokens.IMPORTANT_SYM);
-
- this._readWhitespace();
- return result;
- },
-
- _expr: function(){
-
- var tokenStream = this._tokenStream,
- values = [],
- value = null,
- operator = null;
-
- value = this._term();
- if (value !== null){
-
- values.push(value);
-
- do {
- operator = this._operator();
- if (operator){
- values.push(operator);
- } /*else {
- values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col));
- valueParts = [];
- }*/
-
- value = this._term();
-
- if (value === null){
- break;
- } else {
- values.push(value);
- }
- } while(true);
- }
-
- return values.length > 0 ? new PropertyValue(values, values[0].line, values[0].col) : null;
- },
-
- _term: function(){
-
- var tokenStream = this._tokenStream,
- unary = null,
- value = null,
- token,
- line,
- col;
- unary = this._unary_operator();
- if (unary !== null){
- line = tokenStream.token().startLine;
- col = tokenStream.token().startCol;
- }
- if (tokenStream.peek() == Tokens.IE_FUNCTION && this.options.ieFilters){
-
- value = this._ie_function();
- if (unary === null){
- line = tokenStream.token().startLine;
- col = tokenStream.token().startCol;
- }
- } else if (tokenStream.match([Tokens.NUMBER, Tokens.PERCENTAGE, Tokens.LENGTH,
- Tokens.ANGLE, Tokens.TIME,
- Tokens.FREQ, Tokens.STRING, Tokens.IDENT, Tokens.URI, Tokens.UNICODE_RANGE])){
-
- value = tokenStream.token().value;
- if (unary === null){
- line = tokenStream.token().startLine;
- col = tokenStream.token().startCol;
- }
- this._readWhitespace();
- } else {
- token = this._hexcolor();
- if (token === null){
- if (unary === null){
- line = tokenStream.LT(1).startLine;
- col = tokenStream.LT(1).startCol;
- }
- if (value === null){
- if (tokenStream.LA(3) == Tokens.EQUALS && this.options.ieFilters){
- value = this._ie_function();
- } else {
- value = this._function();
- }
- }
-
- } else {
- value = token.value;
- if (unary === null){
- line = token.startLine;
- col = token.startCol;
- }
- }
-
- }
-
- return value !== null ?
- new PropertyValuePart(unary !== null ? unary + value : value, line, col) :
- null;
-
- },
-
- _function: function(){
-
- var tokenStream = this._tokenStream,
- functionText = null,
- expr = null,
- lt;
-
- if (tokenStream.match(Tokens.FUNCTION)){
- functionText = tokenStream.token().value;
- this._readWhitespace();
- expr = this._expr();
- functionText += expr;
- if (this.options.ieFilters && tokenStream.peek() == Tokens.EQUALS){
- do {
-
- if (this._readWhitespace()){
- functionText += tokenStream.token().value;
- }
- if (tokenStream.LA(0) == Tokens.COMMA){
- functionText += tokenStream.token().value;
- }
-
- tokenStream.match(Tokens.IDENT);
- functionText += tokenStream.token().value;
-
- tokenStream.match(Tokens.EQUALS);
- functionText += tokenStream.token().value;
- lt = tokenStream.peek();
- while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){
- tokenStream.get();
- functionText += tokenStream.token().value;
- lt = tokenStream.peek();
- }
- } while(tokenStream.match([Tokens.COMMA, Tokens.S]));
- }
-
- tokenStream.match(Tokens.RPAREN);
- functionText += ")";
- this._readWhitespace();
- }
-
- return functionText;
- },
-
- _ie_function: function(){
-
- var tokenStream = this._tokenStream,
- functionText = null,
- expr = null,
- lt;
- if (tokenStream.match([Tokens.IE_FUNCTION, Tokens.FUNCTION])){
- functionText = tokenStream.token().value;
-
- do {
-
- if (this._readWhitespace()){
- functionText += tokenStream.token().value;
- }
- if (tokenStream.LA(0) == Tokens.COMMA){
- functionText += tokenStream.token().value;
- }
-
- tokenStream.match(Tokens.IDENT);
- functionText += tokenStream.token().value;
-
- tokenStream.match(Tokens.EQUALS);
- functionText += tokenStream.token().value;
- lt = tokenStream.peek();
- while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){
- tokenStream.get();
- functionText += tokenStream.token().value;
- lt = tokenStream.peek();
- }
- } while(tokenStream.match([Tokens.COMMA, Tokens.S]));
-
- tokenStream.match(Tokens.RPAREN);
- functionText += ")";
- this._readWhitespace();
- }
-
- return functionText;
- },
-
- _hexcolor: function(){
-
- var tokenStream = this._tokenStream,
- token = null,
- color;
-
- if(tokenStream.match(Tokens.HASH)){
-
- token = tokenStream.token();
- color = token.value;
- if (!/#[a-f0-9]{3,6}/i.test(color)){
- throw new SyntaxError("Expected a hex color but found '" + color + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol);
- }
- this._readWhitespace();
- }
-
- return token;
- },
-
- _keyframes: function(){
- var tokenStream = this._tokenStream,
- token,
- tt,
- name,
- prefix = "";
-
- tokenStream.mustMatch(Tokens.KEYFRAMES_SYM);
- token = tokenStream.token();
- if (/^@\-([^\-]+)\-/.test(token.value)) {
- prefix = RegExp.$1;
- }
-
- this._readWhitespace();
- name = this._keyframe_name();
-
- this._readWhitespace();
- tokenStream.mustMatch(Tokens.LBRACE);
-
- this.fire({
- type: "startkeyframes",
- name: name,
- prefix: prefix,
- line: token.startLine,
- col: token.startCol
- });
-
- this._readWhitespace();
- tt = tokenStream.peek();
- while(tt == Tokens.IDENT || tt == Tokens.PERCENTAGE) {
- this._keyframe_rule();
- this._readWhitespace();
- tt = tokenStream.peek();
- }
-
- this.fire({
- type: "endkeyframes",
- name: name,
- prefix: prefix,
- line: token.startLine,
- col: token.startCol
- });
-
- this._readWhitespace();
- tokenStream.mustMatch(Tokens.RBRACE);
-
- },
-
- _keyframe_name: function(){
- var tokenStream = this._tokenStream,
- token;
-
- tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]);
- return SyntaxUnit.fromToken(tokenStream.token());
- },
-
- _keyframe_rule: function(){
- var tokenStream = this._tokenStream,
- token,
- keyList = this._key_list();
-
- this.fire({
- type: "startkeyframerule",
- keys: keyList,
- line: keyList[0].line,
- col: keyList[0].col
- });
-
- this._readDeclarations(true);
-
- this.fire({
- type: "endkeyframerule",
- keys: keyList,
- line: keyList[0].line,
- col: keyList[0].col
- });
-
- },
-
- _key_list: function(){
- var tokenStream = this._tokenStream,
- token,
- key,
- keyList = [];
- keyList.push(this._key());
-
- this._readWhitespace();
-
- while(tokenStream.match(Tokens.COMMA)){
- this._readWhitespace();
- keyList.push(this._key());
- this._readWhitespace();
- }
-
- return keyList;
- },
-
- _key: function(){
-
- var tokenStream = this._tokenStream,
- token;
-
- if (tokenStream.match(Tokens.PERCENTAGE)){
- return SyntaxUnit.fromToken(tokenStream.token());
- } else if (tokenStream.match(Tokens.IDENT)){
- token = tokenStream.token();
-
- if (/from|to/i.test(token.value)){
- return SyntaxUnit.fromToken(token);
- }
-
- tokenStream.unget();
- }
- this._unexpectedToken(tokenStream.LT(1));
- },
- _skipCruft: function(){
- while(this._tokenStream.match([Tokens.S, Tokens.CDO, Tokens.CDC])){
- }
- },
- _readDeclarations: function(checkStart, readMargins){
- var tokenStream = this._tokenStream,
- tt;
-
-
- this._readWhitespace();
-
- if (checkStart){
- tokenStream.mustMatch(Tokens.LBRACE);
- }
-
- this._readWhitespace();
-
- try {
-
- while(true){
-
- if (tokenStream.match(Tokens.SEMICOLON) || (readMargins && this._margin())){
- } else if (this._declaration()){
- if (!tokenStream.match(Tokens.SEMICOLON)){
- break;
- }
- } else {
- break;
- }
- this._readWhitespace();
- }
-
- tokenStream.mustMatch(Tokens.RBRACE);
- this._readWhitespace();
-
- } catch (ex) {
- if (ex instanceof SyntaxError && !this.options.strict){
- this.fire({
- type: "error",
- error: ex,
- message: ex.message,
- line: ex.line,
- col: ex.col
- });
- tt = tokenStream.advance([Tokens.SEMICOLON, Tokens.RBRACE]);
- if (tt == Tokens.SEMICOLON){
- this._readDeclarations(false, readMargins);
- } else if (tt != Tokens.RBRACE){
- throw ex;
- }
-
- } else {
- throw ex;
- }
- }
-
- },
- _readWhitespace: function(){
-
- var tokenStream = this._tokenStream,
- ws = "";
-
- while(tokenStream.match(Tokens.S)){
- ws += tokenStream.token().value;
- }
-
- return ws;
- },
- _unexpectedToken: function(token){
- throw new SyntaxError("Unexpected token '" + token.value + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol);
- },
- _verifyEnd: function(){
- if (this._tokenStream.LA(1) != Tokens.EOF){
- this._unexpectedToken(this._tokenStream.LT(1));
- }
- },
- _validateProperty: function(property, value){
- Validation.validate(property, value);
- },
-
- parse: function(input){
- this._tokenStream = new TokenStream(input, Tokens);
- this._stylesheet();
- },
-
- parseStyleSheet: function(input){
- return this.parse(input);
- },
-
- parseMediaQuery: function(input){
- this._tokenStream = new TokenStream(input, Tokens);
- var result = this._media_query();
- this._verifyEnd();
- return result;
- },
- parsePropertyValue: function(input){
-
- this._tokenStream = new TokenStream(input, Tokens);
- this._readWhitespace();
-
- var result = this._expr();
- this._readWhitespace();
- this._verifyEnd();
- return result;
- },
- parseRule: function(input){
- this._tokenStream = new TokenStream(input, Tokens);
- this._readWhitespace();
-
- var result = this._ruleset();
- this._readWhitespace();
- this._verifyEnd();
- return result;
- },
- parseSelector: function(input){
-
- this._tokenStream = new TokenStream(input, Tokens);
- this._readWhitespace();
-
- var result = this._selector();
- this._readWhitespace();
- this._verifyEnd();
- return result;
- },
- parseStyleAttribute: function(input){
- input += "}"; // for error recovery in _readDeclarations()
- this._tokenStream = new TokenStream(input, Tokens);
- this._readDeclarations();
- }
- };
- for (prop in additions){
- if (additions.hasOwnProperty(prop)){
- proto[prop] = additions[prop];
- }
- }
-
- return proto;
-}();
-var Properties = {
- "alignment-adjust" : "auto | baseline | before-edge | text-before-edge | middle | central | after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical | <percentage> | <length>",
- "alignment-baseline" : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical",
- "animation" : 1,
- "animation-delay" : { multi: "<time>", comma: true },
- "animation-direction" : { multi: "normal | alternate", comma: true },
- "animation-duration" : { multi: "<time>", comma: true },
- "animation-iteration-count" : { multi: "<number> | infinite", comma: true },
- "animation-name" : { multi: "none | <ident>", comma: true },
- "animation-play-state" : { multi: "running | paused", comma: true },
- "animation-timing-function" : 1,
- "-moz-animation-delay" : { multi: "<time>", comma: true },
- "-moz-animation-direction" : { multi: "normal | alternate", comma: true },
- "-moz-animation-duration" : { multi: "<time>", comma: true },
- "-moz-animation-iteration-count" : { multi: "<number> | infinite", comma: true },
- "-moz-animation-name" : { multi: "none | <ident>", comma: true },
- "-moz-animation-play-state" : { multi: "running | paused", comma: true },
-
- "-ms-animation-delay" : { multi: "<time>", comma: true },
- "-ms-animation-direction" : { multi: "normal | alternate", comma: true },
- "-ms-animation-duration" : { multi: "<time>", comma: true },
- "-ms-animation-iteration-count" : { multi: "<number> | infinite", comma: true },
- "-ms-animation-name" : { multi: "none | <ident>", comma: true },
- "-ms-animation-play-state" : { multi: "running | paused", comma: true },
-
- "-webkit-animation-delay" : { multi: "<time>", comma: true },
- "-webkit-animation-direction" : { multi: "normal | alternate", comma: true },
- "-webkit-animation-duration" : { multi: "<time>", comma: true },
- "-webkit-animation-iteration-count" : { multi: "<number> | infinite", comma: true },
- "-webkit-animation-name" : { multi: "none | <ident>", comma: true },
- "-webkit-animation-play-state" : { multi: "running | paused", comma: true },
-
- "-o-animation-delay" : { multi: "<time>", comma: true },
- "-o-animation-direction" : { multi: "normal | alternate", comma: true },
- "-o-animation-duration" : { multi: "<time>", comma: true },
- "-o-animation-iteration-count" : { multi: "<number> | infinite", comma: true },
- "-o-animation-name" : { multi: "none | <ident>", comma: true },
- "-o-animation-play-state" : { multi: "running | paused", comma: true },
-
- "appearance" : "icon | window | desktop | workspace | document | tooltip | dialog | button | push-button | hyperlink | radio-button | checkbox | menu-item | tab | menu | menubar | pull-down-menu | pop-up-menu | list-menu | radio-group | checkbox-group | outline-tree | range | field | combo-box | signature | password | normal | inherit",
- "azimuth" : function (expression) {
- var simple = "<angle> | leftwards | rightwards | inherit",
- direction = "left-side | far-left | left | center-left | center | center-right | right | far-right | right-side",
- behind = false,
- valid = false,
- part;
-
- if (!ValidationTypes.isAny(expression, simple)) {
- if (ValidationTypes.isAny(expression, "behind")) {
- behind = true;
- valid = true;
- }
-
- if (ValidationTypes.isAny(expression, direction)) {
- valid = true;
- if (!behind) {
- ValidationTypes.isAny(expression, "behind");
- }
- }
- }
-
- if (expression.hasNext()) {
- part = expression.next();
- if (valid) {
- throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
- } else {
- throw new ValidationError("Expected (<'azimuth'>) but found '" + part + "'.", part.line, part.col);
- }
- }
- },
- "backface-visibility" : "visible | hidden",
- "background" : 1,
- "background-attachment" : { multi: "<attachment>", comma: true },
- "background-clip" : { multi: "<box>", comma: true },
- "background-color" : "<color> | inherit",
- "background-image" : { multi: "<bg-image>", comma: true },
- "background-origin" : { multi: "<box>", comma: true },
- "background-position" : { multi: "<bg-position>", comma: true },
- "background-repeat" : { multi: "<repeat-style>" },
- "background-size" : { multi: "<bg-size>", comma: true },
- "baseline-shift" : "baseline | sub | super | <percentage> | <length>",
- "behavior" : 1,
- "binding" : 1,
- "bleed" : "<length>",
- "bookmark-label" : "<content> | <attr> | <string>",
- "bookmark-level" : "none | <integer>",
- "bookmark-state" : "open | closed",
- "bookmark-target" : "none | <uri> | <attr>",
- "border" : "<border-width> || <border-style> || <color>",
- "border-bottom" : "<border-width> || <border-style> || <color>",
- "border-bottom-color" : "<color>",
- "border-bottom-left-radius" : "<x-one-radius>",
- "border-bottom-right-radius" : "<x-one-radius>",
- "border-bottom-style" : "<border-style>",
- "border-bottom-width" : "<border-width>",
- "border-collapse" : "collapse | separate | inherit",
- "border-color" : { multi: "<color> | inherit", max: 4 },
- "border-image" : 1,
- "border-image-outset" : { multi: "<length> | <number>", max: 4 },
- "border-image-repeat" : { multi: "stretch | repeat | round", max: 2 },
- "border-image-slice" : function(expression) {
-
- var valid = false,
- numeric = "<number> | <percentage>",
- fill = false,
- count = 0,
- max = 4,
- part;
-
- if (ValidationTypes.isAny(expression, "fill")) {
- fill = true;
- valid = true;
- }
-
- while (expression.hasNext() && count < max) {
- valid = ValidationTypes.isAny(expression, numeric);
- if (!valid) {
- break;
- }
- count++;
- }
-
-
- if (!fill) {
- ValidationTypes.isAny(expression, "fill");
- } else {
- valid = true;
- }
-
- if (expression.hasNext()) {
- part = expression.next();
- if (valid) {
- throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
- } else {
- throw new ValidationError("Expected ([<number> | <percentage>]{1,4} && fill?) but found '" + part + "'.", part.line, part.col);
- }
- }
- },
- "border-image-source" : "<image> | none",
- "border-image-width" : { multi: "<length> | <percentage> | <number> | auto", max: 4 },
- "border-left" : "<border-width> || <border-style> || <color>",
- "border-left-color" : "<color> | inherit",
- "border-left-style" : "<border-style>",
- "border-left-width" : "<border-width>",
- "border-radius" : function(expression) {
-
- var valid = false,
- numeric = "<length> | <percentage>",
- slash = false,
- fill = false,
- count = 0,
- max = 8,
- part;
-
- while (expression.hasNext() && count < max) {
- valid = ValidationTypes.isAny(expression, numeric);
- if (!valid) {
-
- if (expression.peek() == "/" && count > 1 && !slash) {
- slash = true;
- max = count + 5;
- expression.next();
- } else {
- break;
- }
- }
- count++;
- }
-
- if (expression.hasNext()) {
- part = expression.next();
- if (valid) {
- throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
- } else {
- throw new ValidationError("Expected (<'border-radius'>) but found '" + part + "'.", part.line, part.col);
- }
- }
- },
- "border-right" : "<border-width> || <border-style> || <color>",
- "border-right-color" : "<color> | inherit",
- "border-right-style" : "<border-style>",
- "border-right-width" : "<border-width>",
- "border-spacing" : { multi: "<length> | inherit", max: 2 },
- "border-style" : { multi: "<border-style>", max: 4 },
- "border-top" : "<border-width> || <border-style> || <color>",
- "border-top-color" : "<color> | inherit",
- "border-top-left-radius" : "<x-one-radius>",
- "border-top-right-radius" : "<x-one-radius>",
- "border-top-style" : "<border-style>",
- "border-top-width" : "<border-width>",
- "border-width" : { multi: "<border-width>", max: 4 },
- "bottom" : "<margin-width> | inherit",
- "box-align" : "start | end | center | baseline | stretch", //http://www.w3.org/TR/2009/WD-css3-flexbox-20090723/
- "box-decoration-break" : "slice |clone",
- "box-direction" : "normal | reverse | inherit",
- "box-flex" : "<number>",
- "box-flex-group" : "<integer>",
- "box-lines" : "single | multiple",
- "box-ordinal-group" : "<integer>",
- "box-orient" : "horizontal | vertical | inline-axis | block-axis | inherit",
- "box-pack" : "start | end | center | justify",
- "box-shadow" : function (expression) {
- var result = false,
- part;
-
- if (!ValidationTypes.isAny(expression, "none")) {
- Validation.multiProperty("<shadow>", expression, true, Infinity);
- } else {
- if (expression.hasNext()) {
- part = expression.next();
- throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
- }
- }
- },
- "box-sizing" : "content-box | border-box | inherit",
- "break-after" : "auto | always | avoid | left | right | page | column | avoid-page | avoid-column",
- "break-before" : "auto | always | avoid | left | right | page | column | avoid-page | avoid-column",
- "break-inside" : "auto | avoid | avoid-page | avoid-column",
- "caption-side" : "top | bottom | inherit",
- "clear" : "none | right | left | both | inherit",
- "clip" : 1,
- "color" : "<color> | inherit",
- "color-profile" : 1,
- "column-count" : "<integer> | auto", //http://www.w3.org/TR/css3-multicol/
- "column-fill" : "auto | balance",
- "column-gap" : "<length> | normal",
- "column-rule" : "<border-width> || <border-style> || <color>",
- "column-rule-color" : "<color>",
- "column-rule-style" : "<border-style>",
- "column-rule-width" : "<border-width>",
- "column-span" : "none | all",
- "column-width" : "<length> | auto",
- "columns" : 1,
- "content" : 1,
- "counter-increment" : 1,
- "counter-reset" : 1,
- "crop" : "<shape> | auto",
- "cue" : "cue-after | cue-before | inherit",
- "cue-after" : 1,
- "cue-before" : 1,
- "cursor" : 1,
- "direction" : "ltr | rtl | inherit",
- "display" : "inline | block | list-item | inline-block | table | inline-table | table-row-group | table-header-group | table-footer-group | table-row | table-column-group | table-column | table-cell | table-caption | box | inline-box | grid | inline-grid | none | inherit",
- "dominant-baseline" : 1,
- "drop-initial-after-adjust" : "central | middle | after-edge | text-after-edge | ideographic | alphabetic | mathematical | <percentage> | <length>",
- "drop-initial-after-align" : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical",
- "drop-initial-before-adjust" : "before-edge | text-before-edge | central | middle | hanging | mathematical | <percentage> | <length>",
- "drop-initial-before-align" : "caps-height | baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical",
- "drop-initial-size" : "auto | line | <length> | <percentage>",
- "drop-initial-value" : "initial | <integer>",
- "elevation" : "<angle> | below | level | above | higher | lower | inherit",
- "empty-cells" : "show | hide | inherit",
- "filter" : 1,
- "fit" : "fill | hidden | meet | slice",
- "fit-position" : 1,
- "float" : "left | right | none | inherit",
- "float-offset" : 1,
- "font" : 1,
- "font-family" : 1,
- "font-size" : "<absolute-size> | <relative-size> | <length> | <percentage> | inherit",
- "font-size-adjust" : "<number> | none | inherit",
- "font-stretch" : "normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded | inherit",
- "font-style" : "normal | italic | oblique | inherit",
- "font-variant" : "normal | small-caps | inherit",
- "font-weight" : "normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit",
- "grid-cell-stacking" : "columns | rows | layer",
- "grid-column" : 1,
- "grid-columns" : 1,
- "grid-column-align" : "start | end | center | stretch",
- "grid-column-sizing" : 1,
- "grid-column-span" : "<integer>",
- "grid-flow" : "none | rows | columns",
- "grid-layer" : "<integer>",
- "grid-row" : 1,
- "grid-rows" : 1,
- "grid-row-align" : "start | end | center | stretch",
- "grid-row-span" : "<integer>",
- "grid-row-sizing" : 1,
- "hanging-punctuation" : 1,
- "height" : "<margin-width> | inherit",
- "hyphenate-after" : "<integer> | auto",
- "hyphenate-before" : "<integer> | auto",
- "hyphenate-character" : "<string> | auto",
- "hyphenate-lines" : "no-limit | <integer>",
- "hyphenate-resource" : 1,
- "hyphens" : "none | manual | auto",
- "icon" : 1,
- "image-orientation" : "angle | auto",
- "image-rendering" : 1,
- "image-resolution" : 1,
- "inline-box-align" : "initial | last | <integer>",
- "left" : "<margin-width> | inherit",
- "letter-spacing" : "<length> | normal | inherit",
- "line-height" : "<number> | <length> | <percentage> | normal | inherit",
- "line-break" : "auto | loose | normal | strict",
- "line-stacking" : 1,
- "line-stacking-ruby" : "exclude-ruby | include-ruby",
- "line-stacking-shift" : "consider-shifts | disregard-shifts",
- "line-stacking-strategy" : "inline-line-height | block-line-height | max-height | grid-height",
- "list-style" : 1,
- "list-style-image" : "<uri> | none | inherit",
- "list-style-position" : "inside | outside | inherit",
- "list-style-type" : "disc | circle | square | decimal | decimal-leading-zero | lower-roman | upper-roman | lower-greek | lower-latin | upper-latin | armenian | georgian | lower-alpha | upper-alpha | none | inherit",
- "margin" : { multi: "<margin-width> | inherit", max: 4 },
- "margin-bottom" : "<margin-width> | inherit",
- "margin-left" : "<margin-width> | inherit",
- "margin-right" : "<margin-width> | inherit",
- "margin-top" : "<margin-width> | inherit",
- "mark" : 1,
- "mark-after" : 1,
- "mark-before" : 1,
- "marks" : 1,
- "marquee-direction" : 1,
- "marquee-play-count" : 1,
- "marquee-speed" : 1,
- "marquee-style" : 1,
- "max-height" : "<length> | <percentage> | none | inherit",
- "max-width" : "<length> | <percentage> | none | inherit",
- "min-height" : "<length> | <percentage> | inherit",
- "min-width" : "<length> | <percentage> | inherit",
- "move-to" : 1,
- "nav-down" : 1,
- "nav-index" : 1,
- "nav-left" : 1,
- "nav-right" : 1,
- "nav-up" : 1,
- "opacity" : "<number> | inherit",
- "orphans" : "<integer> | inherit",
- "outline" : 1,
- "outline-color" : "<color> | invert | inherit",
- "outline-offset" : 1,
- "outline-style" : "<border-style> | inherit",
- "outline-width" : "<border-width> | inherit",
- "overflow" : "visible | hidden | scroll | auto | inherit",
- "overflow-style" : 1,
- "overflow-x" : 1,
- "overflow-y" : 1,
- "padding" : { multi: "<padding-width> | inherit", max: 4 },
- "padding-bottom" : "<padding-width> | inherit",
- "padding-left" : "<padding-width> | inherit",
- "padding-right" : "<padding-width> | inherit",
- "padding-top" : "<padding-width> | inherit",
- "page" : 1,
- "page-break-after" : "auto | always | avoid | left | right | inherit",
- "page-break-before" : "auto | always | avoid | left | right | inherit",
- "page-break-inside" : "auto | avoid | inherit",
- "page-policy" : 1,
- "pause" : 1,
- "pause-after" : 1,
- "pause-before" : 1,
- "perspective" : 1,
- "perspective-origin" : 1,
- "phonemes" : 1,
- "pitch" : 1,
- "pitch-range" : 1,
- "play-during" : 1,
- "pointer-events" : "auto | none | visiblePainted | visibleFill | visibleStroke | visible | painted | fill | stroke | all | inherit",
- "position" : "static | relative | absolute | fixed | inherit",
- "presentation-level" : 1,
- "punctuation-trim" : 1,
- "quotes" : 1,
- "rendering-intent" : 1,
- "resize" : 1,
- "rest" : 1,
- "rest-after" : 1,
- "rest-before" : 1,
- "richness" : 1,
- "right" : "<margin-width> | inherit",
- "rotation" : 1,
- "rotation-point" : 1,
- "ruby-align" : 1,
- "ruby-overhang" : 1,
- "ruby-position" : 1,
- "ruby-span" : 1,
- "size" : 1,
- "speak" : "normal | none | spell-out | inherit",
- "speak-header" : "once | always | inherit",
- "speak-numeral" : "digits | continuous | inherit",
- "speak-punctuation" : "code | none | inherit",
- "speech-rate" : 1,
- "src" : 1,
- "stress" : 1,
- "string-set" : 1,
-
- "table-layout" : "auto | fixed | inherit",
- "tab-size" : "<integer> | <length>",
- "target" : 1,
- "target-name" : 1,
- "target-new" : 1,
- "target-position" : 1,
- "text-align" : "left | right | center | justify | inherit" ,
- "text-align-last" : 1,
- "text-decoration" : 1,
- "text-emphasis" : 1,
- "text-height" : 1,
- "text-indent" : "<length> | <percentage> | inherit",
- "text-justify" : "auto | none | inter-word | inter-ideograph | inter-cluster | distribute | kashida",
- "text-outline" : 1,
- "text-overflow" : 1,
- "text-rendering" : "auto | optimizeSpeed | optimizeLegibility | geometricPrecision | inherit",
- "text-shadow" : 1,
- "text-transform" : "capitalize | uppercase | lowercase | none | inherit",
- "text-wrap" : "normal | none | avoid",
- "top" : "<margin-width> | inherit",
- "transform" : 1,
- "transform-origin" : 1,
- "transform-style" : 1,
- "transition" : 1,
- "transition-delay" : 1,
- "transition-duration" : 1,
- "transition-property" : 1,
- "transition-timing-function" : 1,
- "unicode-bidi" : "normal | embed | bidi-override | inherit",
- "user-modify" : "read-only | read-write | write-only | inherit",
- "user-select" : "none | text | toggle | element | elements | all | inherit",
- "vertical-align" : "<percentage> | <length> | baseline | sub | super | top | text-top | middle | bottom | text-bottom | inherit",
- "visibility" : "visible | hidden | collapse | inherit",
- "voice-balance" : 1,
- "voice-duration" : 1,
- "voice-family" : 1,
- "voice-pitch" : 1,
- "voice-pitch-range" : 1,
- "voice-rate" : 1,
- "voice-stress" : 1,
- "voice-volume" : 1,
- "volume" : 1,
- "white-space" : "normal | pre | nowrap | pre-wrap | pre-line | inherit",
- "white-space-collapse" : 1,
- "widows" : "<integer> | inherit",
- "width" : "<length> | <percentage> | auto | inherit" ,
- "word-break" : "normal | keep-all | break-all",
- "word-spacing" : "<length> | normal | inherit",
- "word-wrap" : 1,
- "z-index" : "<integer> | auto | inherit",
- "zoom" : "<number> | <percentage> | normal"
-};
-function PropertyName(text, hack, line, col){
-
- SyntaxUnit.call(this, text, line, col, Parser.PROPERTY_NAME_TYPE);
- this.hack = hack;
-
-}
-
-PropertyName.prototype = new SyntaxUnit();
-PropertyName.prototype.constructor = PropertyName;
-PropertyName.prototype.toString = function(){
- return (this.hack ? this.hack : "") + this.text;
-};
-function PropertyValue(parts, line, col){
-
- SyntaxUnit.call(this, parts.join(" "), line, col, Parser.PROPERTY_VALUE_TYPE);
- this.parts = parts;
-
-}
-
-PropertyValue.prototype = new SyntaxUnit();
-PropertyValue.prototype.constructor = PropertyValue;
-function PropertyValueIterator(value){
- this._i = 0;
- this._parts = value.parts;
- this._marks = [];
- this.value = value;
-
-}
-PropertyValueIterator.prototype.count = function(){
- return this._parts.length;
-};
-PropertyValueIterator.prototype.isFirst = function(){
- return this._i === 0;
-};
-PropertyValueIterator.prototype.hasNext = function(){
- return (this._i < this._parts.length);
-};
-PropertyValueIterator.prototype.mark = function(){
- this._marks.push(this._i);
-};
-PropertyValueIterator.prototype.peek = function(count){
- return this.hasNext() ? this._parts[this._i + (count || 0)] : null;
-};
-PropertyValueIterator.prototype.next = function(){
- return this.hasNext() ? this._parts[this._i++] : null;
-};
-PropertyValueIterator.prototype.previous = function(){
- return this._i > 0 ? this._parts[--this._i] : null;
-};
-PropertyValueIterator.prototype.restore = function(){
- if (this._marks.length){
- this._i = this._marks.pop();
- }
-};
-function PropertyValuePart(text, line, col){
-
- SyntaxUnit.call(this, text, line, col, Parser.PROPERTY_VALUE_PART_TYPE);
- this.type = "unknown";
-
- var temp;
- if (/^([+\-]?[\d\.]+)([a-z]+)$/i.test(text)){ //dimension
- this.type = "dimension";
- this.value = +RegExp.$1;
- this.units = RegExp.$2;
- switch(this.units.toLowerCase()){
-
- case "em":
- case "rem":
- case "ex":
- case "px":
- case "cm":
- case "mm":
- case "in":
- case "pt":
- case "pc":
- case "ch":
- this.type = "length";
- break;
-
- case "deg":
- case "rad":
- case "grad":
- this.type = "angle";
- break;
-
- case "ms":
- case "s":
- this.type = "time";
- break;
-
- case "hz":
- case "khz":
- this.type = "frequency";
- break;
-
- case "dpi":
- case "dpcm":
- this.type = "resolution";
- break;
-
- }
-
- } else if (/^([+\-]?[\d\.]+)%$/i.test(text)){ //percentage
- this.type = "percentage";
- this.value = +RegExp.$1;
- } else if (/^([+\-]?[\d\.]+)%$/i.test(text)){ //percentage
- this.type = "percentage";
- this.value = +RegExp.$1;
- } else if (/^([+\-]?\d+)$/i.test(text)){ //integer
- this.type = "integer";
- this.value = +RegExp.$1;
- } else if (/^([+\-]?[\d\.]+)$/i.test(text)){ //number
- this.type = "number";
- this.value = +RegExp.$1;
-
- } else if (/^#([a-f0-9]{3,6})/i.test(text)){ //hexcolor
- this.type = "color";
- temp = RegExp.$1;
- if (temp.length == 3){
- this.red = parseInt(temp.charAt(0)+temp.charAt(0),16);
- this.green = parseInt(temp.charAt(1)+temp.charAt(1),16);
- this.blue = parseInt(temp.charAt(2)+temp.charAt(2),16);
- } else {
- this.red = parseInt(temp.substring(0,2),16);
- this.green = parseInt(temp.substring(2,4),16);
- this.blue = parseInt(temp.substring(4,6),16);
- }
- } else if (/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/i.test(text)){ //rgb() color with absolute numbers
- this.type = "color";
- this.red = +RegExp.$1;
- this.green = +RegExp.$2;
- this.blue = +RegExp.$3;
- } else if (/^rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i.test(text)){ //rgb() color with percentages
- this.type = "color";
- this.red = +RegExp.$1 * 255 / 100;
- this.green = +RegExp.$2 * 255 / 100;
- this.blue = +RegExp.$3 * 255 / 100;
- } else if (/^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d\.]+)\s*\)/i.test(text)){ //rgba() color with absolute numbers
- this.type = "color";
- this.red = +RegExp.$1;
- this.green = +RegExp.$2;
- this.blue = +RegExp.$3;
- this.alpha = +RegExp.$4;
- } else if (/^rgba\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i.test(text)){ //rgba() color with percentages
- this.type = "color";
- this.red = +RegExp.$1 * 255 / 100;
- this.green = +RegExp.$2 * 255 / 100;
- this.blue = +RegExp.$3 * 255 / 100;
- this.alpha = +RegExp.$4;
- } else if (/^hsl\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i.test(text)){ //hsl()
- this.type = "color";
- this.hue = +RegExp.$1;
- this.saturation = +RegExp.$2 / 100;
- this.lightness = +RegExp.$3 / 100;
- } else if (/^hsla\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i.test(text)){ //hsla() color with percentages
- this.type = "color";
- this.hue = +RegExp.$1;
- this.saturation = +RegExp.$2 / 100;
- this.lightness = +RegExp.$3 / 100;
- this.alpha = +RegExp.$4;
- } else if (/^url\(["']?([^\)"']+)["']?\)/i.test(text)){ //URI
- this.type = "uri";
- this.uri = RegExp.$1;
- } else if (/^([^\(]+)\(/i.test(text)){
- this.type = "function";
- this.name = RegExp.$1;
- this.value = text;
- } else if (/^["'][^"']*["']/.test(text)){ //string
- this.type = "string";
- this.value = eval(text);
- } else if (Colors[text.toLowerCase()]){ //named color
- this.type = "color";
- temp = Colors[text.toLowerCase()].substring(1);
- this.red = parseInt(temp.substring(0,2),16);
- this.green = parseInt(temp.substring(2,4),16);
- this.blue = parseInt(temp.substring(4,6),16);
- } else if (/^[\,\/]$/.test(text)){
- this.type = "operator";
- this.value = text;
- } else if (/^[a-z\-\u0080-\uFFFF][a-z0-9\-\u0080-\uFFFF]*$/i.test(text)){
- this.type = "identifier";
- this.value = text;
- }
-
-}
-
-PropertyValuePart.prototype = new SyntaxUnit();
-PropertyValuePart.prototype.constructor = PropertyValuePart;
-PropertyValuePart.fromToken = function(token){
- return new PropertyValuePart(token.value, token.startLine, token.startCol);
-};
-var Pseudos = {
- ":first-letter": 1,
- ":first-line": 1,
- ":before": 1,
- ":after": 1
-};
-
-Pseudos.ELEMENT = 1;
-Pseudos.CLASS = 2;
-
-Pseudos.isElement = function(pseudo){
- return pseudo.indexOf("::") === 0 || Pseudos[pseudo.toLowerCase()] == Pseudos.ELEMENT;
-};
-function Selector(parts, line, col){
-
- SyntaxUnit.call(this, parts.join(" "), line, col, Parser.SELECTOR_TYPE);
- this.parts = parts;
- this.specificity = Specificity.calculate(this);
-
-}
-
-Selector.prototype = new SyntaxUnit();
-Selector.prototype.constructor = Selector;
-function SelectorPart(elementName, modifiers, text, line, col){
-
- SyntaxUnit.call(this, text, line, col, Parser.SELECTOR_PART_TYPE);
- this.elementName = elementName;
- this.modifiers = modifiers;
-
-}
-
-SelectorPart.prototype = new SyntaxUnit();
-SelectorPart.prototype.constructor = SelectorPart;
-function SelectorSubPart(text, type, line, col){
-
- SyntaxUnit.call(this, text, line, col, Parser.SELECTOR_SUB_PART_TYPE);
- this.type = type;
- this.args = [];
-
-}
-
-SelectorSubPart.prototype = new SyntaxUnit();
-SelectorSubPart.prototype.constructor = SelectorSubPart;
-function Specificity(a, b, c, d){
- this.a = a;
- this.b = b;
- this.c = c;
- this.d = d;
-}
-
-Specificity.prototype = {
- constructor: Specificity,
- compare: function(other){
- var comps = ["a", "b", "c", "d"],
- i, len;
-
- for (i=0, len=comps.length; i < len; i++){
- if (this[comps[i]] < other[comps[i]]){
- return -1;
- } else if (this[comps[i]] > other[comps[i]]){
- return 1;
- }
- }
-
- return 0;
- },
- valueOf: function(){
- return (this.a * 1000) + (this.b * 100) + (this.c * 10) + this.d;
- },
- toString: function(){
- return this.a + "," + this.b + "," + this.c + "," + this.d;
- }
-
-};
-Specificity.calculate = function(selector){
-
- var i, len,
- part,
- b=0, c=0, d=0;
-
- function updateValues(part){
-
- var i, j, len, num,
- elementName = part.elementName ? part.elementName.text : "",
- modifier;
-
- if (elementName && elementName.charAt(elementName.length-1) != "*") {
- d++;
- }
-
- for (i=0, len=part.modifiers.length; i < len; i++){
- modifier = part.modifiers[i];
- switch(modifier.type){
- case "class":
- case "attribute":
- c++;
- break;
-
- case "id":
- b++;
- break;
-
- case "pseudo":
- if (Pseudos.isElement(modifier.text)){
- d++;
- } else {
- c++;
- }
- break;
-
- case "not":
- for (j=0, num=modifier.args.length; j < num; j++){
- updateValues(modifier.args[j]);
- }
- }
- }
- }
-
- for (i=0, len=selector.parts.length; i < len; i++){
- part = selector.parts[i];
-
- if (part instanceof SelectorPart){
- updateValues(part);
- }
- }
-
- return new Specificity(0, b, c, d);
-};
-
-var h = /^[0-9a-fA-F]$/,
- nonascii = /^[\u0080-\uFFFF]$/,
- nl = /\n|\r\n|\r|\f/;
-
-
-function isHexDigit(c){
- return c !== null && h.test(c);
-}
-
-function isDigit(c){
- return c !== null && /\d/.test(c);
-}
-
-function isWhitespace(c){
- return c !== null && /\s/.test(c);
-}
-
-function isNewLine(c){
- return c !== null && nl.test(c);
-}
-
-function isNameStart(c){
- return c !== null && (/[a-z_\u0080-\uFFFF\\]/i.test(c));
-}
-
-function isNameChar(c){
- return c !== null && (isNameStart(c) || /[0-9\-\\]/.test(c));
-}
-
-function isIdentStart(c){
- return c !== null && (isNameStart(c) || /\-\\/.test(c));
-}
-
-function mix(receiver, supplier){
- for (var prop in supplier){
- if (supplier.hasOwnProperty(prop)){
- receiver[prop] = supplier[prop];
- }
- }
- return receiver;
-}
-function TokenStream(input){
- TokenStreamBase.call(this, input, Tokens);
-}
-
-TokenStream.prototype = mix(new TokenStreamBase(), {
- _getToken: function(channel){
-
- var c,
- reader = this._reader,
- token = null,
- startLine = reader.getLine(),
- startCol = reader.getCol();
-
- c = reader.read();
-
-
- while(c){
- switch(c){
- case "/":
-
- if(reader.peek() == "*"){
- token = this.commentToken(c, startLine, startCol);
- } else {
- token = this.charToken(c, startLine, startCol);
- }
- break;
- case "|":
- case "~":
- case "^":
- case "$":
- case "*":
- if(reader.peek() == "="){
- token = this.comparisonToken(c, startLine, startCol);
- } else {
- token = this.charToken(c, startLine, startCol);
- }
- break;
- case "\"":
- case "'":
- token = this.stringToken(c, startLine, startCol);
- break;
- case "#":
- if (isNameChar(reader.peek())){
- token = this.hashToken(c, startLine, startCol);
- } else {
- token = this.charToken(c, startLine, startCol);
- }
- break;
- case ".":
- if (isDigit(reader.peek())){
- token = this.numberToken(c, startLine, startCol);
- } else {
- token = this.charToken(c, startLine, startCol);
- }
- break;
- case "-":
- if (reader.peek() == "-"){ //could be closing HTML-style comment
- token = this.htmlCommentEndToken(c, startLine, startCol);
- } else if (isNameStart(reader.peek())){
- token = this.identOrFunctionToken(c, startLine, startCol);
- } else {
- token = this.charToken(c, startLine, startCol);
- }
- break;
- case "!":
- token = this.importantToken(c, startLine, startCol);
- break;
- case "@":
- token = this.atRuleToken(c, startLine, startCol);
- break;
- case ":":
- token = this.notToken(c, startLine, startCol);
- break;
- case "<":
- token = this.htmlCommentStartToken(c, startLine, startCol);
- break;
- case "U":
- case "u":
- if (reader.peek() == "+"){
- token = this.unicodeRangeToken(c, startLine, startCol);
- break;
- }
- default:
- if (isDigit(c)){
- token = this.numberToken(c, startLine, startCol);
- } else
- if (isWhitespace(c)){
- token = this.whitespaceToken(c, startLine, startCol);
- } else
- if (isIdentStart(c)){
- token = this.identOrFunctionToken(c, startLine, startCol);
- } else
- {
- token = this.charToken(c, startLine, startCol);
- }
-
-
-
-
-
-
- }
- break;
- }
-
- if (!token && c === null){
- token = this.createToken(Tokens.EOF,null,startLine,startCol);
- }
-
- return token;
- },
- createToken: function(tt, value, startLine, startCol, options){
- var reader = this._reader;
- options = options || {};
-
- return {
- value: value,
- type: tt,
- channel: options.channel,
- hide: options.hide || false,
- startLine: startLine,
- startCol: startCol,
- endLine: reader.getLine(),
- endCol: reader.getCol()
- };
- },
- atRuleToken: function(first, startLine, startCol){
- var rule = first,
- reader = this._reader,
- tt = Tokens.CHAR,
- valid = false,
- ident,
- c;
- reader.mark();
- ident = this.readName();
- rule = first + ident;
- tt = Tokens.type(rule.toLowerCase());
- if (tt == Tokens.CHAR || tt == Tokens.UNKNOWN){
- if (rule.length > 1){
- tt = Tokens.UNKNOWN_SYM;
- } else {
- tt = Tokens.CHAR;
- rule = first;
- reader.reset();
- }
- }
-
- return this.createToken(tt, rule, startLine, startCol);
- },
- charToken: function(c, startLine, startCol){
- var tt = Tokens.type(c);
-
- if (tt == -1){
- tt = Tokens.CHAR;
- }
-
- return this.createToken(tt, c, startLine, startCol);
- },
- commentToken: function(first, startLine, startCol){
- var reader = this._reader,
- comment = this.readComment(first);
-
- return this.createToken(Tokens.COMMENT, comment, startLine, startCol);
- },
- comparisonToken: function(c, startLine, startCol){
- var reader = this._reader,
- comparison = c + reader.read(),
- tt = Tokens.type(comparison) || Tokens.CHAR;
-
- return this.createToken(tt, comparison, startLine, startCol);
- },
- hashToken: function(first, startLine, startCol){
- var reader = this._reader,
- name = this.readName(first);
-
- return this.createToken(Tokens.HASH, name, startLine, startCol);
- },
- htmlCommentStartToken: function(first, startLine, startCol){
- var reader = this._reader,
- text = first;
-
- reader.mark();
- text += reader.readCount(3);
-
- if (text == "<!--"){
- return this.createToken(Tokens.CDO, text, startLine, startCol);
- } else {
- reader.reset();
- return this.charToken(first, startLine, startCol);
- }
- },
- htmlCommentEndToken: function(first, startLine, startCol){
- var reader = this._reader,
- text = first;
-
- reader.mark();
- text += reader.readCount(2);
-
- if (text == "-->"){
- return this.createToken(Tokens.CDC, text, startLine, startCol);
- } else {
- reader.reset();
- return this.charToken(first, startLine, startCol);
- }
- },
- identOrFunctionToken: function(first, startLine, startCol){
- var reader = this._reader,
- ident = this.readName(first),
- tt = Tokens.IDENT;
- if (reader.peek() == "("){
- ident += reader.read();
- if (ident.toLowerCase() == "url("){
- tt = Tokens.URI;
- ident = this.readURI(ident);
- if (ident.toLowerCase() == "url("){
- tt = Tokens.FUNCTION;
- }
- } else {
- tt = Tokens.FUNCTION;
- }
- } else if (reader.peek() == ":"){ //might be an IE function
- if (ident.toLowerCase() == "progid"){
- ident += reader.readTo("(");
- tt = Tokens.IE_FUNCTION;
- }
- }
-
- return this.createToken(tt, ident, startLine, startCol);
- },
- importantToken: function(first, startLine, startCol){
- var reader = this._reader,
- important = first,
- tt = Tokens.CHAR,
- temp,
- c;
-
- reader.mark();
- c = reader.read();
-
- while(c){
- if (c == "/"){
- if (reader.peek() != "*"){
- break;
- } else {
- temp = this.readComment(c);
- if (temp === ""){ //broken!
- break;
- }
- }
- } else if (isWhitespace(c)){
- important += c + this.readWhitespace();
- } else if (/i/i.test(c)){
- temp = reader.readCount(8);
- if (/mportant/i.test(temp)){
- important += c + temp;
- tt = Tokens.IMPORTANT_SYM;
-
- }
- break; //we're done
- } else {
- break;
- }
-
- c = reader.read();
- }
-
- if (tt == Tokens.CHAR){
- reader.reset();
- return this.charToken(first, startLine, startCol);
- } else {
- return this.createToken(tt, important, startLine, startCol);
- }
-
-
- },
- notToken: function(first, startLine, startCol){
- var reader = this._reader,
- text = first;
-
- reader.mark();
- text += reader.readCount(4);
-
- if (text.toLowerCase() == ":not("){
- return this.createToken(Tokens.NOT, text, startLine, startCol);
- } else {
- reader.reset();
- return this.charToken(first, startLine, startCol);
- }
- },
- numberToken: function(first, startLine, startCol){
- var reader = this._reader,
- value = this.readNumber(first),
- ident,
- tt = Tokens.NUMBER,
- c = reader.peek();
-
- if (isIdentStart(c)){
- ident = this.readName(reader.read());
- value += ident;
-
- if (/^em$|^ex$|^px$|^gd$|^rem$|^vw$|^vh$|^vm$|^ch$|^cm$|^mm$|^in$|^pt$|^pc$/i.test(ident)){
- tt = Tokens.LENGTH;
- } else if (/^deg|^rad$|^grad$/i.test(ident)){
- tt = Tokens.ANGLE;
- } else if (/^ms$|^s$/i.test(ident)){
- tt = Tokens.TIME;
- } else if (/^hz$|^khz$/i.test(ident)){
- tt = Tokens.FREQ;
- } else if (/^dpi$|^dpcm$/i.test(ident)){
- tt = Tokens.RESOLUTION;
- } else {
- tt = Tokens.DIMENSION;
- }
-
- } else if (c == "%"){
- value += reader.read();
- tt = Tokens.PERCENTAGE;
- }
-
- return this.createToken(tt, value, startLine, startCol);
- },
- stringToken: function(first, startLine, startCol){
- var delim = first,
- string = first,
- reader = this._reader,
- prev = first,
- tt = Tokens.STRING,
- c = reader.read();
-
- while(c){
- string += c;
- if (c == delim && prev != "\\"){
- break;
- }
- if (isNewLine(reader.peek()) && c != "\\"){
- tt = Tokens.INVALID;
- break;
- }
- prev = c;
- c = reader.read();
- }
- if (c === null){
- tt = Tokens.INVALID;
- }
-
- return this.createToken(tt, string, startLine, startCol);
- },
-
- unicodeRangeToken: function(first, startLine, startCol){
- var reader = this._reader,
- value = first,
- temp,
- tt = Tokens.CHAR;
- if (reader.peek() == "+"){
- reader.mark();
- value += reader.read();
- value += this.readUnicodeRangePart(true);
- if (value.length == 2){
- reader.reset();
- } else {
-
- tt = Tokens.UNICODE_RANGE;
- if (value.indexOf("?") == -1){
-
- if (reader.peek() == "-"){
- reader.mark();
- temp = reader.read();
- temp += this.readUnicodeRangePart(false);
- if (temp.length == 1){
- reader.reset();
- } else {
- value += temp;
- }
- }
-
- }
- }
- }
-
- return this.createToken(tt, value, startLine, startCol);
- },
- whitespaceToken: function(first, startLine, startCol){
- var reader = this._reader,
- value = first + this.readWhitespace();
- return this.createToken(Tokens.S, value, startLine, startCol);
- },
-
- readUnicodeRangePart: function(allowQuestionMark){
- var reader = this._reader,
- part = "",
- c = reader.peek();
- while(isHexDigit(c) && part.length < 6){
- reader.read();
- part += c;
- c = reader.peek();
- }
- if (allowQuestionMark){
- while(c == "?" && part.length < 6){
- reader.read();
- part += c;
- c = reader.peek();
- }
- }
-
- return part;
- },
-
- readWhitespace: function(){
- var reader = this._reader,
- whitespace = "",
- c = reader.peek();
-
- while(isWhitespace(c)){
- reader.read();
- whitespace += c;
- c = reader.peek();
- }
-
- return whitespace;
- },
- readNumber: function(first){
- var reader = this._reader,
- number = first,
- hasDot = (first == "."),
- c = reader.peek();
-
-
- while(c){
- if (isDigit(c)){
- number += reader.read();
- } else if (c == "."){
- if (hasDot){
- break;
- } else {
- hasDot = true;
- number += reader.read();
- }
- } else {
- break;
- }
-
- c = reader.peek();
- }
-
- return number;
- },
- readString: function(){
- var reader = this._reader,
- delim = reader.read(),
- string = delim,
- prev = delim,
- c = reader.peek();
-
- while(c){
- c = reader.read();
- string += c;
- if (c == delim && prev != "\\"){
- break;
- }
- if (isNewLine(reader.peek()) && c != "\\"){
- string = "";
- break;
- }
- prev = c;
- c = reader.peek();
- }
- if (c === null){
- string = "";
- }
-
- return string;
- },
- readURI: function(first){
- var reader = this._reader,
- uri = first,
- inner = "",
- c = reader.peek();
-
- reader.mark();
- while(c && isWhitespace(c)){
- reader.read();
- c = reader.peek();
- }
- if (c == "'" || c == "\""){
- inner = this.readString();
- } else {
- inner = this.readURL();
- }
-
- c = reader.peek();
- while(c && isWhitespace(c)){
- reader.read();
- c = reader.peek();
- }
- if (inner === "" || c != ")"){
- uri = first;
- reader.reset();
- } else {
- uri += inner + reader.read();
- }
-
- return uri;
- },
- readURL: function(){
- var reader = this._reader,
- url = "",
- c = reader.peek();
- while (/^[!#$%&\\*-~]$/.test(c)){
- url += reader.read();
- c = reader.peek();
- }
-
- return url;
-
- },
- readName: function(first){
- var reader = this._reader,
- ident = first || "",
- c = reader.peek();
-
- while(true){
- if (c == "\\"){
- ident += this.readEscape(reader.read());
- c = reader.peek();
- } else if(c && isNameChar(c)){
- ident += reader.read();
- c = reader.peek();
- } else {
- break;
- }
- }
-
- return ident;
- },
-
- readEscape: function(first){
- var reader = this._reader,
- cssEscape = first || "",
- i = 0,
- c = reader.peek();
-
- if (isHexDigit(c)){
- do {
- cssEscape += reader.read();
- c = reader.peek();
- } while(c && isHexDigit(c) && ++i < 6);
- }
-
- if (cssEscape.length == 3 && /\s/.test(c) ||
- cssEscape.length == 7 || cssEscape.length == 1){
- reader.read();
- } else {
- c = "";
- }
-
- return cssEscape + c;
- },
-
- readComment: function(first){
- var reader = this._reader,
- comment = first || "",
- c = reader.read();
-
- if (c == "*"){
- while(c){
- comment += c;
- if (comment.length > 2 && c == "*" && reader.peek() == "/"){
- comment += reader.read();
- break;
- }
-
- c = reader.read();
- }
-
- return comment;
- } else {
- return "";
- }
-
- }
-});
-
-
-var Tokens = [
- { name: "CDO"},
- { name: "CDC"},
- { name: "S", whitespace: true/*, channel: "ws"*/},
- { name: "COMMENT", comment: true, hide: true, channel: "comment" },
- { name: "INCLUDES", text: "~="},
- { name: "DASHMATCH", text: "|="},
- { name: "PREFIXMATCH", text: "^="},
- { name: "SUFFIXMATCH", text: "$="},
- { name: "SUBSTRINGMATCH", text: "*="},
- { name: "STRING"},
- { name: "IDENT"},
- { name: "HASH"},
- { name: "IMPORT_SYM", text: "@import"},
- { name: "PAGE_SYM", text: "@page"},
- { name: "MEDIA_SYM", text: "@media"},
- { name: "FONT_FACE_SYM", text: "@font-face"},
- { name: "CHARSET_SYM", text: "@charset"},
- { name: "NAMESPACE_SYM", text: "@namespace"},
- { name: "UNKNOWN_SYM" },
- { name: "KEYFRAMES_SYM", text: [ "@keyframes", "@-webkit-keyframes", "@-moz-keyframes", "@-o-keyframes" ] },
- { name: "IMPORTANT_SYM"},
- { name: "LENGTH"},
- { name: "ANGLE"},
- { name: "TIME"},
- { name: "FREQ"},
- { name: "DIMENSION"},
- { name: "PERCENTAGE"},
- { name: "NUMBER"},
- { name: "URI"},
- { name: "FUNCTION"},
- { name: "UNICODE_RANGE"},
- { name: "INVALID"},
- { name: "PLUS", text: "+" },
- { name: "GREATER", text: ">"},
- { name: "COMMA", text: ","},
- { name: "TILDE", text: "~"},
- { name: "NOT"},
- { name: "TOPLEFTCORNER_SYM", text: "@top-left-corner"},
- { name: "TOPLEFT_SYM", text: "@top-left"},
- { name: "TOPCENTER_SYM", text: "@top-center"},
- { name: "TOPRIGHT_SYM", text: "@top-right"},
- { name: "TOPRIGHTCORNER_SYM", text: "@top-right-corner"},
- { name: "BOTTOMLEFTCORNER_SYM", text: "@bottom-left-corner"},
- { name: "BOTTOMLEFT_SYM", text: "@bottom-left"},
- { name: "BOTTOMCENTER_SYM", text: "@bottom-center"},
- { name: "BOTTOMRIGHT_SYM", text: "@bottom-right"},
- { name: "BOTTOMRIGHTCORNER_SYM", text: "@bottom-right-corner"},
- { name: "LEFTTOP_SYM", text: "@left-top"},
- { name: "LEFTMIDDLE_SYM", text: "@left-middle"},
- { name: "LEFTBOTTOM_SYM", text: "@left-bottom"},
- { name: "RIGHTTOP_SYM", text: "@right-top"},
- { name: "RIGHTMIDDLE_SYM", text: "@right-middle"},
- { name: "RIGHTBOTTOM_SYM", text: "@right-bottom"},
- { name: "RESOLUTION", state: "media"},
- { name: "IE_FUNCTION" },
- { name: "CHAR" },
- {
- name: "PIPE",
- text: "|"
- },
- {
- name: "SLASH",
- text: "/"
- },
- {
- name: "MINUS",
- text: "-"
- },
- {
- name: "STAR",
- text: "*"
- },
-
- {
- name: "LBRACE",
- text: "{"
- },
- {
- name: "RBRACE",
- text: "}"
- },
- {
- name: "LBRACKET",
- text: "["
- },
- {
- name: "RBRACKET",
- text: "]"
- },
- {
- name: "EQUALS",
- text: "="
- },
- {
- name: "COLON",
- text: ":"
- },
- {
- name: "SEMICOLON",
- text: ";"
- },
-
- {
- name: "LPAREN",
- text: "("
- },
- {
- name: "RPAREN",
- text: ")"
- },
- {
- name: "DOT",
- text: "."
- }
-];
-
-(function(){
-
- var nameMap = [],
- typeMap = {};
-
- Tokens.UNKNOWN = -1;
- Tokens.unshift({name:"EOF"});
- for (var i=0, len = Tokens.length; i < len; i++){
- nameMap.push(Tokens[i].name);
- Tokens[Tokens[i].name] = i;
- if (Tokens[i].text){
- if (Tokens[i].text instanceof Array){
- for (var j=0; j < Tokens[i].text.length; j++){
- typeMap[Tokens[i].text[j]] = i;
- }
- } else {
- typeMap[Tokens[i].text] = i;
- }
- }
- }
-
- Tokens.name = function(tt){
- return nameMap[tt];
- };
-
- Tokens.type = function(c){
- return typeMap[c] || -1;
- };
-
-})();
-var Validation = {
-
- validate: function(property, value){
- var name = property.toString().toLowerCase(),
- parts = value.parts,
- expression = new PropertyValueIterator(value),
- spec = Properties[name],
- part,
- valid,
- j, count,
- msg,
- types,
- last,
- literals,
- max, multi, group;
-
- if (!spec) {
- if (name.indexOf("-") !== 0){ //vendor prefixed are ok
- throw new ValidationError("Unknown property '" + property + "'.", property.line, property.col);
- }
- } else if (typeof spec != "number"){
- if (typeof spec == "string"){
- if (spec.indexOf("||") > -1) {
- this.groupProperty(spec, expression);
- } else {
- this.singleProperty(spec, expression, 1);
- }
-
- } else if (spec.multi) {
- this.multiProperty(spec.multi, expression, spec.comma, spec.max || Infinity);
- } else if (typeof spec == "function") {
- spec(expression);
- }
-
- }
-
- },
-
- singleProperty: function(types, expression, max, partial) {
-
- var result = false,
- value = expression.value,
- count = 0,
- part;
-
- while (expression.hasNext() && count < max) {
- result = ValidationTypes.isAny(expression, types);
- if (!result) {
- break;
- }
- count++;
- }
-
- if (!result) {
- if (expression.hasNext() && !expression.isFirst()) {
- part = expression.peek();
- throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
- } else {
- throw new ValidationError("Expected (" + types + ") but found '" + value + "'.", value.line, value.col);
- }
- } else if (expression.hasNext()) {
- part = expression.next();
- throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
- }
-
- },
-
- multiProperty: function (types, expression, comma, max) {
-
- var result = false,
- value = expression.value,
- count = 0,
- sep = false,
- part;
-
- while(expression.hasNext() && !result && count < max) {
- if (ValidationTypes.isAny(expression, types)) {
- count++;
- if (!expression.hasNext()) {
- result = true;
-
- } else if (comma) {
- if (expression.peek() == ",") {
- part = expression.next();
- } else {
- break;
- }
- }
- } else {
- break;
-
- }
- }
-
- if (!result) {
- if (expression.hasNext() && !expression.isFirst()) {
- part = expression.peek();
- throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
- } else {
- part = expression.previous();
- if (comma && part == ",") {
- throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
- } else {
- throw new ValidationError("Expected (" + types + ") but found '" + value + "'.", value.line, value.col);
- }
- }
-
- } else if (expression.hasNext()) {
- part = expression.next();
- throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
- }
-
- },
-
- groupProperty: function (types, expression, comma) {
-
- var result = false,
- value = expression.value,
- typeCount = types.split("||").length,
- groups = { count: 0 },
- partial = false,
- name,
- part;
-
- while(expression.hasNext() && !result) {
- name = ValidationTypes.isAnyOfGroup(expression, types);
- if (name) {
- if (groups[name]) {
- break;
- } else {
- groups[name] = 1;
- groups.count++;
- partial = true;
-
- if (groups.count == typeCount || !expression.hasNext()) {
- result = true;
- }
- }
- } else {
- break;
- }
- }
-
- if (!result) {
- if (partial && expression.hasNext()) {
- part = expression.peek();
- throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
- } else {
- throw new ValidationError("Expected (" + types + ") but found '" + value + "'.", value.line, value.col);
- }
- } else if (expression.hasNext()) {
- part = expression.next();
- throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
- }
- }
-
-
-
-};
-function ValidationError(message, line, col){
- this.col = col;
- this.line = line;
- this.message = message;
-
-}
-ValidationError.prototype = new Error();
-var ValidationTypes = {
-
- isLiteral: function (part, literals) {
- var text = part.text.toString().toLowerCase(),
- args = literals.split(" | "),
- i, len, found = false;
-
- for (i=0,len=args.length; i < len && !found; i++){
- if (text == args[i].toLowerCase()){
- found = true;
- }
- }
-
- return found;
- },
-
- isSimple: function(type) {
- return !!this.simple[type];
- },
-
- isComplex: function(type) {
- return !!this.complex[type];
- },
- isAny: function (expression, types) {
- var args = types.split(" | "),
- i, len, found = false;
-
- for (i=0,len=args.length; i < len && !found && expression.hasNext(); i++){
- found = this.isType(expression, args[i]);
- }
-
- return found;
- },
- isAnyOfGroup: function(expression, types) {
- var args = types.split(" || "),
- i, len, found = false;
-
- for (i=0,len=args.length; i < len && !found; i++){
- found = this.isType(expression, args[i]);
- }
-
- return found ? args[i-1] : false;
- },
- isType: function (expression, type) {
- var part = expression.peek(),
- result = false;
-
- if (type.charAt(0) != "<") {
- result = this.isLiteral(part, type);
- if (result) {
- expression.next();
- }
- } else if (this.simple[type]) {
- result = this.simple[type](part);
- if (result) {
- expression.next();
- }
- } else {
- result = this.complex[type](expression);
- }
-
- return result;
- },
-
-
-
- simple: {
-
- "<absolute-size>": function(part){
- return ValidationTypes.isLiteral(part, "xx-small | x-small | small | medium | large | x-large | xx-large");
- },
-
- "<attachment>": function(part){
- return ValidationTypes.isLiteral(part, "scroll | fixed | local");
- },
-
- "<attr>": function(part){
- return part.type == "function" && part.name == "attr";
- },
-
- "<bg-image>": function(part){
- return this["<image>"](part) || this["<gradient>"](part) || part == "none";
- },
-
- "<gradient>": function(part) {
- return part.type == "function" && /^(?:\-(?:ms|moz|o|webkit)\-)?(?:repeating\-)?(?:radial\-|linear\-)?gradient/i.test(part);
- },
-
- "<box>": function(part){
- return ValidationTypes.isLiteral(part, "padding-box | border-box | content-box");
- },
-
- "<content>": function(part){
- return part.type == "function" && part.name == "content";
- },
-
- "<relative-size>": function(part){
- return ValidationTypes.isLiteral(part, "smaller | larger");
- },
- "<ident>": function(part){
- return part.type == "identifier";
- },
-
- "<length>": function(part){
- return part.type == "length" || part.type == "number" || part.type == "integer" || part == "0";
- },
-
- "<color>": function(part){
- return part.type == "color" || part == "transparent";
- },
-
- "<number>": function(part){
- return part.type == "number" || this["<integer>"](part);
- },
-
- "<integer>": function(part){
- return part.type == "integer";
- },
-
- "<line>": function(part){
- return part.type == "integer";
- },
-
- "<angle>": function(part){
- return part.type == "angle";
- },
-
- "<uri>": function(part){
- return part.type == "uri";
- },
-
- "<image>": function(part){
- return this["<uri>"](part);
- },
-
- "<percentage>": function(part){
- return part.type == "percentage" || part == "0";
- },
-
- "<border-width>": function(part){
- return this["<length>"](part) || ValidationTypes.isLiteral(part, "thin | medium | thick");
- },
-
- "<border-style>": function(part){
- return ValidationTypes.isLiteral(part, "none | hidden | dotted | dashed | solid | double | groove | ridge | inset | outset");
- },
-
- "<margin-width>": function(part){
- return this["<length>"](part) || this["<percentage>"](part) || ValidationTypes.isLiteral(part, "auto");
- },
-
- "<padding-width>": function(part){
- return this["<length>"](part) || this["<percentage>"](part);
- },
-
- "<shape>": function(part){
- return part.type == "function" && (part.name == "rect" || part.name == "inset-rect");
- },
-
- "<time>": function(part) {
- return part.type == "time";
- }
- },
-
- complex: {
-
- "<bg-position>": function(expression){
- var types = this,
- result = false,
- numeric = "<percentage> | <length>",
- xDir = "left | center | right",
- yDir = "top | center | bottom",
- part,
- i, len;
-
- if (ValidationTypes.isAny(expression, "top | bottom")) {
- result = true;
- } else {
- if (ValidationTypes.isAny(expression, numeric)){
- if (expression.hasNext()){
- result = ValidationTypes.isAny(expression, numeric + " | " + yDir);
- }
- } else if (ValidationTypes.isAny(expression, xDir)){
- if (expression.hasNext()){
- if (ValidationTypes.isAny(expression, yDir)){
- result = true;
-
- ValidationTypes.isAny(expression, numeric);
-
- } else if (ValidationTypes.isAny(expression, numeric)){
- if (ValidationTypes.isAny(expression, yDir)){
- ValidationTypes.isAny(expression, numeric);
- }
-
- result = true;
- }
- }
- }
- }
-
-
- return result;
- },
-
- "<bg-size>": function(expression){
- var types = this,
- result = false,
- numeric = "<percentage> | <length> | auto",
- part,
- i, len;
-
- if (ValidationTypes.isAny(expression, "cover | contain")) {
- result = true;
- } else if (ValidationTypes.isAny(expression, numeric)) {
- result = true;
- ValidationTypes.isAny(expression, numeric);
- }
-
- return result;
- },
-
- "<repeat-style>": function(expression){
- var result = false,
- values = "repeat | space | round | no-repeat",
- part;
-
- if (expression.hasNext()){
- part = expression.next();
-
- if (ValidationTypes.isLiteral(part, "repeat-x | repeat-y")) {
- result = true;
- } else if (ValidationTypes.isLiteral(part, values)) {
- result = true;
-
- if (expression.hasNext() && ValidationTypes.isLiteral(expression.peek(), values)) {
- expression.next();
- }
- }
- }
-
- return result;
-
- },
-
- "<shadow>": function(expression) {
- var result = false,
- count = 0,
- inset = false,
- color = false,
- part;
-
- if (expression.hasNext()) {
-
- if (ValidationTypes.isAny(expression, "inset")){
- inset = true;
- }
-
- if (ValidationTypes.isAny(expression, "<color>")) {
- color = true;
- }
-
- while (ValidationTypes.isAny(expression, "<length>") && count < 4) {
- count++;
- }
-
-
- if (expression.hasNext()) {
- if (!color) {
- ValidationTypes.isAny(expression, "<color>");
- }
-
- if (!inset) {
- ValidationTypes.isAny(expression, "inset");
- }
-
- }
-
- result = (count >= 2 && count <= 4);
-
- }
-
- return result;
- },
-
- "<x-one-radius>": function(expression) {
- var result = false,
- count = 0,
- numeric = "<length> | <percentage>",
- part;
-
- if (ValidationTypes.isAny(expression, numeric)){
- result = true;
-
- ValidationTypes.isAny(expression, numeric);
- }
-
- return result;
- }
- }
-};
-
-
-parserlib.css = {
-Colors :Colors,
-Combinator :Combinator,
-Parser :Parser,
-PropertyName :PropertyName,
-PropertyValue :PropertyValue,
-PropertyValuePart :PropertyValuePart,
-MediaFeature :MediaFeature,
-MediaQuery :MediaQuery,
-Selector :Selector,
-SelectorPart :SelectorPart,
-SelectorSubPart :SelectorSubPart,
-Specificity :Specificity,
-TokenStream :TokenStream,
-Tokens :Tokens,
-ValidationError :ValidationError
-};
-})();
-var CSSLint = (function(){
-
- var rules = [],
- formatters = [],
- api = new parserlib.util.EventTarget();
-
- api.version = "0.9.9";
- api.addRule = function(rule){
- rules.push(rule);
- rules[rule.id] = rule;
- };
- api.clearRules = function(){
- rules = [];
- };
- api.getRules = function(){
- return [].concat(rules).sort(function(a,b){
- return a.id > b.id ? 1 : 0;
- });
- };
- api.getRuleset = function() {
- var ruleset = {},
- i = 0,
- len = rules.length;
-
- while (i < len){
- ruleset[rules[i++].id] = 1; //by default, everything is a warning
- }
-
- return ruleset;
- };
- api.addFormatter = function(formatter) {
- formatters[formatter.id] = formatter;
- };
- api.getFormatter = function(formatId){
- return formatters[formatId];
- };
- api.format = function(results, filename, formatId, options) {
- var formatter = this.getFormatter(formatId),
- result = null;
-
- if (formatter){
- result = formatter.startFormat();
- result += formatter.formatResults(results, filename, options || {});
- result += formatter.endFormat();
- }
-
- return result;
- };
- api.hasFormat = function(formatId){
- return formatters.hasOwnProperty(formatId);
- };
- api.verify = function(text, ruleset){
-
- var i = 0,
- len = rules.length,
- reporter,
- lines,
- report,
- parser = new parserlib.css.Parser({ starHack: true, ieFilters: true,
- underscoreHack: true, strict: false });
- lines = text.replace(/\n\r?/g, "$split$").split('$split$');
-
- if (!ruleset){
- ruleset = this.getRuleset();
- }
-
- reporter = new Reporter(lines, ruleset);
-
- ruleset.errors = 2; //always report parsing errors as errors
- for (i in ruleset){
- if(ruleset.hasOwnProperty(i)){
- if (rules[i]){
- rules[i].init(parser, reporter);
- }
- }
- }
- try {
- parser.parse(text);
- } catch (ex) {
- reporter.error("Fatal error, cannot continue: " + ex.message, ex.line, ex.col, {});
- }
-
- report = {
- messages : reporter.messages,
- stats : reporter.stats
- };
- report.messages.sort(function (a, b){
- if (a.rollup && !b.rollup){
- return 1;
- } else if (!a.rollup && b.rollup){
- return -1;
- } else {
- return a.line - b.line;
- }
- });
-
- return report;
- };
-
- return api;
-
-})();
-function Reporter(lines, ruleset){
- this.messages = [];
- this.stats = [];
- this.lines = lines;
- this.ruleset = ruleset;
-}
-
-Reporter.prototype = {
- constructor: Reporter,
- error: function(message, line, col, rule){
- this.messages.push({
- type : "error",
- line : line,
- col : col,
- message : message,
- evidence: this.lines[line-1],
- rule : rule || {}
- });
- },
- warn: function(message, line, col, rule){
- this.report(message, line, col, rule);
- },
- report: function(message, line, col, rule){
- this.messages.push({
- type : this.ruleset[rule.id] == 2 ? "error" : "warning",
- line : line,
- col : col,
- message : message,
- evidence: this.lines[line-1],
- rule : rule
- });
- },
- info: function(message, line, col, rule){
- this.messages.push({
- type : "info",
- line : line,
- col : col,
- message : message,
- evidence: this.lines[line-1],
- rule : rule
- });
- },
- rollupError: function(message, rule){
- this.messages.push({
- type : "error",
- rollup : true,
- message : message,
- rule : rule
- });
- },
- rollupWarn: function(message, rule){
- this.messages.push({
- type : "warning",
- rollup : true,
- message : message,
- rule : rule
- });
- },
- stat: function(name, value){
- this.stats[name] = value;
- }
-};
-CSSLint._Reporter = Reporter;
-CSSLint.Util = {
- mix: function(receiver, supplier){
- var prop;
-
- for (prop in supplier){
- if (supplier.hasOwnProperty(prop)){
- receiver[prop] = supplier[prop];
- }
- }
-
- return prop;
- },
- indexOf: function(values, value){
- if (values.indexOf){
- return values.indexOf(value);
- } else {
- for (var i=0, len=values.length; i < len; i++){
- if (values[i] === value){
- return i;
- }
- }
- return -1;
- }
- },
- forEach: function(values, func) {
- if (values.forEach){
- return values.forEach(func);
- } else {
- for (var i=0, len=values.length; i < len; i++){
- func(values[i], i, values);
- }
- }
- }
-};
-CSSLint.addRule({
- id: "adjoining-classes",
- name: "Disallow adjoining classes",
- desc: "Don't use adjoining classes.",
- browsers: "IE6",
- init: function(parser, reporter){
- var rule = this;
- parser.addListener("startrule", function(event){
- var selectors = event.selectors,
- selector,
- part,
- modifier,
- classCount,
- i, j, k;
-
- for (i=0; i < selectors.length; i++){
- selector = selectors[i];
- for (j=0; j < selector.parts.length; j++){
- part = selector.parts[j];
- if (part.type == parser.SELECTOR_PART_TYPE){
- classCount = 0;
- for (k=0; k < part.modifiers.length; k++){
- modifier = part.modifiers[k];
- if (modifier.type == "class"){
- classCount++;
- }
- if (classCount > 1){
- reporter.report("Don't use adjoining classes.", part.line, part.col, rule);
- }
- }
- }
- }
- }
- });
- }
-
-});
-CSSLint.addRule({
- id: "box-model",
- name: "Beware of broken box size",
- desc: "Don't use width or height when using padding or border.",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this,
- widthProperties = {
- border: 1,
- "border-left": 1,
- "border-right": 1,
- padding: 1,
- "padding-left": 1,
- "padding-right": 1
- },
- heightProperties = {
- border: 1,
- "border-bottom": 1,
- "border-top": 1,
- padding: 1,
- "padding-bottom": 1,
- "padding-top": 1
- },
- properties,
- boxSizing = false;
-
- function startRule(){
- properties = {};
- boxSizing = false;
- }
-
- function endRule(){
- var prop, value;
-
- if (!boxSizing) {
- if (properties.height){
- for (prop in heightProperties){
- if (heightProperties.hasOwnProperty(prop) && properties[prop]){
- value = properties[prop].value;
- if (!(prop == "padding" && value.parts.length === 2 && value.parts[0].value === 0)){
- reporter.report("Using height with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule);
- }
- }
- }
- }
-
- if (properties.width){
- for (prop in widthProperties){
- if (widthProperties.hasOwnProperty(prop) && properties[prop]){
- value = properties[prop].value;
-
- if (!(prop == "padding" && value.parts.length === 2 && value.parts[1].value === 0)){
- reporter.report("Using width with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule);
- }
- }
- }
- }
- }
- }
-
- parser.addListener("startrule", startRule);
- parser.addListener("startfontface", startRule);
- parser.addListener("startpage", startRule);
- parser.addListener("startpagemargin", startRule);
- parser.addListener("startkeyframerule", startRule);
-
- parser.addListener("property", function(event){
- var name = event.property.text.toLowerCase();
-
- if (heightProperties[name] || widthProperties[name]){
- if (!/^0\S*$/.test(event.value) && !(name == "border" && event.value == "none")){
- properties[name] = { line: event.property.line, col: event.property.col, value: event.value };
- }
- } else {
- if (/^(width|height)/i.test(name) && /^(length|percentage)/.test(event.value.parts[0].type)){
- properties[name] = 1;
- } else if (name == "box-sizing") {
- boxSizing = true;
- }
- }
-
- });
-
- parser.addListener("endrule", endRule);
- parser.addListener("endfontface", endRule);
- parser.addListener("endpage", endRule);
- parser.addListener("endpagemargin", endRule);
- parser.addListener("endkeyframerule", endRule);
- }
-
-});
-CSSLint.addRule({
- id: "box-sizing",
- name: "Disallow use of box-sizing",
- desc: "The box-sizing properties isn't supported in IE6 and IE7.",
- browsers: "IE6, IE7",
- tags: ["Compatibility"],
- init: function(parser, reporter){
- var rule = this;
-
- parser.addListener("property", function(event){
- var name = event.property.text.toLowerCase();
-
- if (name == "box-sizing"){
- reporter.report("The box-sizing property isn't supported in IE6 and IE7.", event.line, event.col, rule);
- }
- });
- }
-
-});
-CSSLint.addRule({
- id: "compatible-vendor-prefixes",
- name: "Require compatible vendor prefixes",
- desc: "Include all compatible vendor prefixes to reach a wider range of users.",
- browsers: "All",
- init: function (parser, reporter) {
- var rule = this,
- compatiblePrefixes,
- properties,
- prop,
- variations,
- prefixed,
- i,
- len,
- inKeyFrame = false,
- arrayPush = Array.prototype.push,
- applyTo = [];
- compatiblePrefixes = {
- "animation" : "webkit moz",
- "animation-delay" : "webkit moz",
- "animation-direction" : "webkit moz",
- "animation-duration" : "webkit moz",
- "animation-fill-mode" : "webkit moz",
- "animation-iteration-count" : "webkit moz",
- "animation-name" : "webkit moz",
- "animation-play-state" : "webkit moz",
- "animation-timing-function" : "webkit moz",
- "appearance" : "webkit moz",
- "border-end" : "webkit moz",
- "border-end-color" : "webkit moz",
- "border-end-style" : "webkit moz",
- "border-end-width" : "webkit moz",
- "border-image" : "webkit moz o",
- "border-radius" : "webkit moz",
- "border-start" : "webkit moz",
- "border-start-color" : "webkit moz",
- "border-start-style" : "webkit moz",
- "border-start-width" : "webkit moz",
- "box-align" : "webkit moz ms",
- "box-direction" : "webkit moz ms",
- "box-flex" : "webkit moz ms",
- "box-lines" : "webkit ms",
- "box-ordinal-group" : "webkit moz ms",
- "box-orient" : "webkit moz ms",
- "box-pack" : "webkit moz ms",
- "box-sizing" : "webkit moz",
- "box-shadow" : "webkit moz",
- "column-count" : "webkit moz ms",
- "column-gap" : "webkit moz ms",
- "column-rule" : "webkit moz ms",
- "column-rule-color" : "webkit moz ms",
- "column-rule-style" : "webkit moz ms",
- "column-rule-width" : "webkit moz ms",
- "column-width" : "webkit moz ms",
- "hyphens" : "epub moz",
- "line-break" : "webkit ms",
- "margin-end" : "webkit moz",
- "margin-start" : "webkit moz",
- "marquee-speed" : "webkit wap",
- "marquee-style" : "webkit wap",
- "padding-end" : "webkit moz",
- "padding-start" : "webkit moz",
- "tab-size" : "moz o",
- "text-size-adjust" : "webkit ms",
- "transform" : "webkit moz ms o",
- "transform-origin" : "webkit moz ms o",
- "transition" : "webkit moz o",
- "transition-delay" : "webkit moz o",
- "transition-duration" : "webkit moz o",
- "transition-property" : "webkit moz o",
- "transition-timing-function" : "webkit moz o",
- "user-modify" : "webkit moz",
- "user-select" : "webkit moz ms",
- "word-break" : "epub ms",
- "writing-mode" : "epub ms"
- };
-
-
- for (prop in compatiblePrefixes) {
- if (compatiblePrefixes.hasOwnProperty(prop)) {
- variations = [];
- prefixed = compatiblePrefixes[prop].split(' ');
- for (i = 0, len = prefixed.length; i < len; i++) {
- variations.push('-' + prefixed[i] + '-' + prop);
- }
- compatiblePrefixes[prop] = variations;
- arrayPush.apply(applyTo, variations);
- }
- }
-
- parser.addListener("startrule", function () {
- properties = [];
- });
-
- parser.addListener("startkeyframes", function (event) {
- inKeyFrame = event.prefix || true;
- });
-
- parser.addListener("endkeyframes", function (event) {
- inKeyFrame = false;
- });
-
- parser.addListener("property", function (event) {
- var name = event.property;
- if (CSSLint.Util.indexOf(applyTo, name.text) > -1) {
- if (!inKeyFrame || typeof inKeyFrame != "string" ||
- name.text.indexOf("-" + inKeyFrame + "-") !== 0) {
- properties.push(name);
- }
- }
- });
-
- parser.addListener("endrule", function (event) {
- if (!properties.length) {
- return;
- }
-
- var propertyGroups = {},
- i,
- len,
- name,
- prop,
- variations,
- value,
- full,
- actual,
- item,
- propertiesSpecified;
-
- for (i = 0, len = properties.length; i < len; i++) {
- name = properties[i];
-
- for (prop in compatiblePrefixes) {
- if (compatiblePrefixes.hasOwnProperty(prop)) {
- variations = compatiblePrefixes[prop];
- if (CSSLint.Util.indexOf(variations, name.text) > -1) {
- if (!propertyGroups[prop]) {
- propertyGroups[prop] = {
- full : variations.slice(0),
- actual : [],
- actualNodes: []
- };
- }
- if (CSSLint.Util.indexOf(propertyGroups[prop].actual, name.text) === -1) {
- propertyGroups[prop].actual.push(name.text);
- propertyGroups[prop].actualNodes.push(name);
- }
- }
- }
- }
- }
-
- for (prop in propertyGroups) {
- if (propertyGroups.hasOwnProperty(prop)) {
- value = propertyGroups[prop];
- full = value.full;
- actual = value.actual;
-
- if (full.length > actual.length) {
- for (i = 0, len = full.length; i < len; i++) {
- item = full[i];
- if (CSSLint.Util.indexOf(actual, item) === -1) {
- propertiesSpecified = (actual.length === 1) ? actual[0] : (actual.length == 2) ? actual.join(" and ") : actual.join(", ");
- reporter.report("The property " + item + " is compatible with " + propertiesSpecified + " and should be included as well.", value.actualNodes[0].line, value.actualNodes[0].col, rule);
- }
- }
-
- }
- }
- }
- });
- }
-});
-CSSLint.addRule({
- id: "display-property-grouping",
- name: "Require properties appropriate for display",
- desc: "Certain properties shouldn't be used with certain display property values.",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this;
-
- var propertiesToCheck = {
- display: 1,
- "float": "none",
- height: 1,
- width: 1,
- margin: 1,
- "margin-left": 1,
- "margin-right": 1,
- "margin-bottom": 1,
- "margin-top": 1,
- padding: 1,
- "padding-left": 1,
- "padding-right": 1,
- "padding-bottom": 1,
- "padding-top": 1,
- "vertical-align": 1
- },
- properties;
-
- function reportProperty(name, display, msg){
- if (properties[name]){
- if (typeof propertiesToCheck[name] != "string" || properties[name].value.toLowerCase() != propertiesToCheck[name]){
- reporter.report(msg || name + " can't be used with display: " + display + ".", properties[name].line, properties[name].col, rule);
- }
- }
- }
-
- function startRule(){
- properties = {};
- }
-
- function endRule(){
-
- var display = properties.display ? properties.display.value : null;
- if (display){
- switch(display){
-
- case "inline":
- reportProperty("height", display);
- reportProperty("width", display);
- reportProperty("margin", display);
- reportProperty("margin-top", display);
- reportProperty("margin-bottom", display);
- reportProperty("float", display, "display:inline has no effect on floated elements (but may be used to fix the IE6 double-margin bug).");
- break;
-
- case "block":
- reportProperty("vertical-align", display);
- break;
-
- case "inline-block":
- reportProperty("float", display);
- break;
-
- default:
- if (display.indexOf("table-") === 0){
- reportProperty("margin", display);
- reportProperty("margin-left", display);
- reportProperty("margin-right", display);
- reportProperty("margin-top", display);
- reportProperty("margin-bottom", display);
- reportProperty("float", display);
- }
- }
- }
-
- }
-
- parser.addListener("startrule", startRule);
- parser.addListener("startfontface", startRule);
- parser.addListener("startkeyframerule", startRule);
- parser.addListener("startpagemargin", startRule);
- parser.addListener("startpage", startRule);
-
- parser.addListener("property", function(event){
- var name = event.property.text.toLowerCase();
-
- if (propertiesToCheck[name]){
- properties[name] = { value: event.value.text, line: event.property.line, col: event.property.col };
- }
- });
-
- parser.addListener("endrule", endRule);
- parser.addListener("endfontface", endRule);
- parser.addListener("endkeyframerule", endRule);
- parser.addListener("endpagemargin", endRule);
- parser.addListener("endpage", endRule);
-
- }
-
-});
-CSSLint.addRule({
- id: "duplicate-background-images",
- name: "Disallow duplicate background images",
- desc: "Every background-image should be unique. Use a common class for e.g. sprites.",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this,
- stack = {};
-
- parser.addListener("property", function(event){
- var name = event.property.text,
- value = event.value,
- i, len;
-
- if (name.match(/background/i)) {
- for (i=0, len=value.parts.length; i < len; i++) {
- if (value.parts[i].type == 'uri') {
- if (typeof stack[value.parts[i].uri] === 'undefined') {
- stack[value.parts[i].uri] = event;
- }
- else {
- reporter.report("Background image '" + value.parts[i].uri + "' was used multiple times, first declared at line " + stack[value.parts[i].uri].line + ", col " + stack[value.parts[i].uri].col + ".", event.line, event.col, rule);
- }
- }
- }
- }
- });
- }
-});
-CSSLint.addRule({
- id: "duplicate-properties",
- name: "Disallow duplicate properties",
- desc: "Duplicate properties must appear one after the other.",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this,
- properties,
- lastProperty;
-
- function startRule(event){
- properties = {};
- }
-
- parser.addListener("startrule", startRule);
- parser.addListener("startfontface", startRule);
- parser.addListener("startpage", startRule);
- parser.addListener("startpagemargin", startRule);
- parser.addListener("startkeyframerule", startRule);
-
- parser.addListener("property", function(event){
- var property = event.property,
- name = property.text.toLowerCase();
-
- if (properties[name] && (lastProperty != name || properties[name] == event.value.text)){
- reporter.report("Duplicate property '" + event.property + "' found.", event.line, event.col, rule);
- }
-
- properties[name] = event.value.text;
- lastProperty = name;
-
- });
-
-
- }
-
-});
-CSSLint.addRule({
- id: "empty-rules",
- name: "Disallow empty rules",
- desc: "Rules without any properties specified should be removed.",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this,
- count = 0;
-
- parser.addListener("startrule", function(){
- count=0;
- });
-
- parser.addListener("property", function(){
- count++;
- });
-
- parser.addListener("endrule", function(event){
- var selectors = event.selectors;
- if (count === 0){
- reporter.report("Rule is empty.", selectors[0].line, selectors[0].col, rule);
- }
- });
- }
-
-});
-CSSLint.addRule({
- id: "errors",
- name: "Parsing Errors",
- desc: "This rule looks for recoverable syntax errors.",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this;
-
- parser.addListener("error", function(event){
- reporter.error(event.message, event.line, event.col, rule);
- });
-
- }
-
-});
-CSSLint.addRule({
- id: "fallback-colors",
- name: "Require fallback colors",
- desc: "For older browsers that don't support RGBA, HSL, or HSLA, provide a fallback color.",
- browsers: "IE6,IE7,IE8",
- init: function(parser, reporter){
- var rule = this,
- lastProperty,
- propertiesToCheck = {
- color: 1,
- background: 1,
- "background-color": 1
- },
- properties;
-
- function startRule(event){
- properties = {};
- lastProperty = null;
- }
-
- parser.addListener("startrule", startRule);
- parser.addListener("startfontface", startRule);
- parser.addListener("startpage", startRule);
- parser.addListener("startpagemargin", startRule);
- parser.addListener("startkeyframerule", startRule);
-
- parser.addListener("property", function(event){
- var property = event.property,
- name = property.text.toLowerCase(),
- parts = event.value.parts,
- i = 0,
- colorType = "",
- len = parts.length;
-
- if(propertiesToCheck[name]){
- while(i < len){
- if (parts[i].type == "color"){
- if ("alpha" in parts[i] || "hue" in parts[i]){
-
- if (/([^\)]+)\(/.test(parts[i])){
- colorType = RegExp.$1.toUpperCase();
- }
-
- if (!lastProperty || (lastProperty.property.text.toLowerCase() != name || lastProperty.colorType != "compat")){
- reporter.report("Fallback " + name + " (hex or RGB) should precede " + colorType + " " + name + ".", event.line, event.col, rule);
- }
- } else {
- event.colorType = "compat";
- }
- }
-
- i++;
- }
- }
-
- lastProperty = event;
- });
-
- }
-
-});
-CSSLint.addRule({
- id: "floats",
- name: "Disallow too many floats",
- desc: "This rule tests if the float property is used too many times",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this;
- var count = 0;
- parser.addListener("property", function(event){
- if (event.property.text.toLowerCase() == "float" &&
- event.value.text.toLowerCase() != "none"){
- count++;
- }
- });
- parser.addListener("endstylesheet", function(){
- reporter.stat("floats", count);
- if (count >= 10){
- reporter.rollupWarn("Too many floats (" + count + "), you're probably using them for layout. Consider using a grid system instead.", rule);
- }
- });
- }
-
-});
-CSSLint.addRule({
- id: "font-faces",
- name: "Don't use too many web fonts",
- desc: "Too many different web fonts in the same stylesheet.",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this,
- count = 0;
-
-
- parser.addListener("startfontface", function(){
- count++;
- });
-
- parser.addListener("endstylesheet", function(){
- if (count > 5){
- reporter.rollupWarn("Too many @font-face declarations (" + count + ").", rule);
- }
- });
- }
-
-});
-CSSLint.addRule({
- id: "font-sizes",
- name: "Disallow too many font sizes",
- desc: "Checks the number of font-size declarations.",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this,
- count = 0;
- parser.addListener("property", function(event){
- if (event.property == "font-size"){
- count++;
- }
- });
- parser.addListener("endstylesheet", function(){
- reporter.stat("font-sizes", count);
- if (count >= 10){
- reporter.rollupWarn("Too many font-size declarations (" + count + "), abstraction needed.", rule);
- }
- });
- }
-
-});
-CSSLint.addRule({
- id: "gradients",
- name: "Require all gradient definitions",
- desc: "When using a vendor-prefixed gradient, make sure to use them all.",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this,
- gradients;
-
- parser.addListener("startrule", function(){
- gradients = {
- moz: 0,
- webkit: 0,
- oldWebkit: 0,
- ms: 0,
- o: 0
- };
- });
-
- parser.addListener("property", function(event){
-
- if (/\-(moz|ms|o|webkit)(?:\-(?:linear|radial))\-gradient/i.test(event.value)){
- gradients[RegExp.$1] = 1;
- } else if (/\-webkit\-gradient/i.test(event.value)){
- gradients.oldWebkit = 1;
- }
-
- });
-
- parser.addListener("endrule", function(event){
- var missing = [];
-
- if (!gradients.moz){
- missing.push("Firefox 3.6+");
- }
-
- if (!gradients.webkit){
- missing.push("Webkit (Safari 5+, Chrome)");
- }
-
- if (!gradients.oldWebkit){
- missing.push("Old Webkit (Safari 4+, Chrome)");
- }
-
- if (!gradients.ms){
- missing.push("Internet Explorer 10+");
- }
-
- if (!gradients.o){
- missing.push("Opera 11.1+");
- }
-
- if (missing.length && missing.length < 5){
- reporter.report("Missing vendor-prefixed CSS gradients for " + missing.join(", ") + ".", event.selectors[0].line, event.selectors[0].col, rule);
- }
-
- });
-
- }
-
-});
-CSSLint.addRule({
- id: "ids",
- name: "Disallow IDs in selectors",
- desc: "Selectors should not contain IDs.",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this;
- parser.addListener("startrule", function(event){
- var selectors = event.selectors,
- selector,
- part,
- modifier,
- idCount,
- i, j, k;
-
- for (i=0; i < selectors.length; i++){
- selector = selectors[i];
- idCount = 0;
-
- for (j=0; j < selector.parts.length; j++){
- part = selector.parts[j];
- if (part.type == parser.SELECTOR_PART_TYPE){
- for (k=0; k < part.modifiers.length; k++){
- modifier = part.modifiers[k];
- if (modifier.type == "id"){
- idCount++;
- }
- }
- }
- }
-
- if (idCount == 1){
- reporter.report("Don't use IDs in selectors.", selector.line, selector.col, rule);
- } else if (idCount > 1){
- reporter.report(idCount + " IDs in the selector, really?", selector.line, selector.col, rule);
- }
- }
-
- });
- }
-
-});
-CSSLint.addRule({
- id: "import",
- name: "Disallow @import",
- desc: "Don't use @import, use <link> instead.",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this;
-
- parser.addListener("import", function(event){
- reporter.report("@import prevents parallel downloads, use <link> instead.", event.line, event.col, rule);
- });
-
- }
-
-});
-CSSLint.addRule({
- id: "important",
- name: "Disallow !important",
- desc: "Be careful when using !important declaration",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this,
- count = 0;
- parser.addListener("property", function(event){
- if (event.important === true){
- count++;
- reporter.report("Be careful when using !important declaration", event.line, event.col, rule);
- }
- });
- parser.addListener("endstylesheet", function(){
- reporter.stat("important", count);
- if (count >= 10){
- reporter.rollupWarn("Too many !important declarations (" + count + "), try to use less than 10 to avoid specificity issues.", rule);
- }
- });
- }
-
-});
-CSSLint.addRule({
- id: "known-properties",
- name: "Require use of known properties",
- desc: "Properties should be known (listed in CSS3 specification) or be a vendor-prefixed property.",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this;
-
- parser.addListener("property", function(event){
- var name = event.property.text.toLowerCase();
- if (event.invalid) {
- reporter.report(event.invalid.message, event.line, event.col, rule);
- }
-
- });
- }
-
-});
-CSSLint.addRule({
- id: "outline-none",
- name: "Disallow outline: none",
- desc: "Use of outline: none or outline: 0 should be limited to :focus rules.",
- browsers: "All",
- tags: ["Accessibility"],
- init: function(parser, reporter){
- var rule = this,
- lastRule;
-
- function startRule(event){
- if (event.selectors){
- lastRule = {
- line: event.line,
- col: event.col,
- selectors: event.selectors,
- propCount: 0,
- outline: false
- };
- } else {
- lastRule = null;
- }
- }
-
- function endRule(event){
- if (lastRule){
- if (lastRule.outline){
- if (lastRule.selectors.toString().toLowerCase().indexOf(":focus") == -1){
- reporter.report("Outlines should only be modified using :focus.", lastRule.line, lastRule.col, rule);
- } else if (lastRule.propCount == 1) {
- reporter.report("Outlines shouldn't be hidden unless other visual changes are made.", lastRule.line, lastRule.col, rule);
- }
- }
- }
- }
-
- parser.addListener("startrule", startRule);
- parser.addListener("startfontface", startRule);
- parser.addListener("startpage", startRule);
- parser.addListener("startpagemargin", startRule);
- parser.addListener("startkeyframerule", startRule);
-
- parser.addListener("property", function(event){
- var name = event.property.text.toLowerCase(),
- value = event.value;
-
- if (lastRule){
- lastRule.propCount++;
- if (name == "outline" && (value == "none" || value == "0")){
- lastRule.outline = true;
- }
- }
-
- });
-
- parser.addListener("endrule", endRule);
- parser.addListener("endfontface", endRule);
- parser.addListener("endpage", endRule);
- parser.addListener("endpagemargin", endRule);
- parser.addListener("endkeyframerule", endRule);
-
- }
-
-});
-CSSLint.addRule({
- id: "overqualified-elements",
- name: "Disallow overqualified elements",
- desc: "Don't use IDs with elements (a#foo).",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this,
- classes = {};
-
- parser.addListener("startrule", function(event){
- var selectors = event.selectors,
- selector,
- part,
- modifier,
- i, j, k;
-
- for (i=0; i < selectors.length; i++){
- selector = selectors[i];
-
- for (j=0; j < selector.parts.length; j++){
- part = selector.parts[j];
- if (part.type == parser.SELECTOR_PART_TYPE){
- for (k=0; k < part.modifiers.length; k++){
- modifier = part.modifiers[k];
- if (part.elementName && modifier.type == "id"){
- reporter.report("Element (" + part + ") is overqualified, just use " + modifier + " without element name.", part.line, part.col, rule);
- }
- }
- }
- }
- }
- });
- }
-
-});
-CSSLint.addRule({
- id: "qualified-headings",
- name: "Disallow qualified headings",
- desc: "Headings should not be qualified (namespaced).",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this;
-
- parser.addListener("startrule", function(event){
- var selectors = event.selectors,
- selector,
- part,
- i, j;
-
- for (i=0; i < selectors.length; i++){
- selector = selectors[i];
-
- for (j=0; j < selector.parts.length; j++){
- part = selector.parts[j];
- if (part.type == parser.SELECTOR_PART_TYPE){
- if (part.elementName && /h[1-6]/.test(part.elementName.toString()) && j > 0){
- reporter.report("Heading (" + part.elementName + ") should not be qualified.", part.line, part.col, rule);
- }
- }
- }
- }
- });
- }
-
-});
-CSSLint.addRule({
- id: "regex-selectors",
- name: "Disallow selectors that look like regexs",
- desc: "Selectors that look like regular expressions are slow and should be avoided.",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this;
-
- parser.addListener("startrule", function(event){
- var selectors = event.selectors,
- selector,
- part,
- modifier,
- i, j, k;
-
- for (i=0; i < selectors.length; i++){
- selector = selectors[i];
- for (j=0; j < selector.parts.length; j++){
- part = selector.parts[j];
- if (part.type == parser.SELECTOR_PART_TYPE){
- for (k=0; k < part.modifiers.length; k++){
- modifier = part.modifiers[k];
- if (modifier.type == "attribute"){
- if (/([\~\|\^\$\*]=)/.test(modifier)){
- reporter.report("Attribute selectors with " + RegExp.$1 + " are slow!", modifier.line, modifier.col, rule);
- }
- }
-
- }
- }
- }
- }
- });
- }
-
-});
-CSSLint.addRule({
- id: "rules-count",
- name: "Rules Count",
- desc: "Track how many rules there are.",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this,
- count = 0;
- parser.addListener("startrule", function(){
- count++;
- });
-
- parser.addListener("endstylesheet", function(){
- reporter.stat("rule-count", count);
- });
- }
-
-});
-CSSLint.addRule({
- id: "shorthand",
- name: "Require shorthand properties",
- desc: "Use shorthand properties where possible.",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this,
- prop, i, len,
- propertiesToCheck = {},
- properties,
- mapping = {
- "margin": [
- "margin-top",
- "margin-bottom",
- "margin-left",
- "margin-right"
- ],
- "padding": [
- "padding-top",
- "padding-bottom",
- "padding-left",
- "padding-right"
- ]
- };
- for (prop in mapping){
- if (mapping.hasOwnProperty(prop)){
- for (i=0, len=mapping[prop].length; i < len; i++){
- propertiesToCheck[mapping[prop][i]] = prop;
- }
- }
- }
-
- function startRule(event){
- properties = {};
- }
- function endRule(event){
-
- var prop, i, len, total;
- for (prop in mapping){
- if (mapping.hasOwnProperty(prop)){
- total=0;
-
- for (i=0, len=mapping[prop].length; i < len; i++){
- total += properties[mapping[prop][i]] ? 1 : 0;
- }
-
- if (total == mapping[prop].length){
- reporter.report("The properties " + mapping[prop].join(", ") + " can be replaced by " + prop + ".", event.line, event.col, rule);
- }
- }
- }
- }
-
- parser.addListener("startrule", startRule);
- parser.addListener("startfontface", startRule);
- parser.addListener("property", function(event){
- var name = event.property.toString().toLowerCase(),
- value = event.value.parts[0].value;
-
- if (propertiesToCheck[name]){
- properties[name] = 1;
- }
- });
-
- parser.addListener("endrule", endRule);
- parser.addListener("endfontface", endRule);
-
- }
-
-});
-CSSLint.addRule({
- id: "star-property-hack",
- name: "Disallow properties with a star prefix",
- desc: "Checks for the star property hack (targets IE6/7)",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this;
- parser.addListener("property", function(event){
- var property = event.property;
-
- if (property.hack == "*") {
- reporter.report("Property with star prefix found.", event.property.line, event.property.col, rule);
- }
- });
- }
-});
-CSSLint.addRule({
- id: "text-indent",
- name: "Disallow negative text-indent",
- desc: "Checks for text indent less than -99px",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this,
- textIndent,
- direction;
-
-
- function startRule(event){
- textIndent = false;
- direction = "inherit";
- }
- function endRule(event){
- if (textIndent && direction != "ltr"){
- reporter.report("Negative text-indent doesn't work well with RTL. If you use text-indent for image replacement explicitly set direction for that item to ltr.", textIndent.line, textIndent.col, rule);
- }
- }
-
- parser.addListener("startrule", startRule);
- parser.addListener("startfontface", startRule);
- parser.addListener("property", function(event){
- var name = event.property.toString().toLowerCase(),
- value = event.value;
-
- if (name == "text-indent" && value.parts[0].value < -99){
- textIndent = event.property;
- } else if (name == "direction" && value == "ltr"){
- direction = "ltr";
- }
- });
-
- parser.addListener("endrule", endRule);
- parser.addListener("endfontface", endRule);
-
- }
-
-});
-CSSLint.addRule({
- id: "underscore-property-hack",
- name: "Disallow properties with an underscore prefix",
- desc: "Checks for the underscore property hack (targets IE6)",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this;
- parser.addListener("property", function(event){
- var property = event.property;
-
- if (property.hack == "_") {
- reporter.report("Property with underscore prefix found.", event.property.line, event.property.col, rule);
- }
- });
- }
-});
-CSSLint.addRule({
- id: "unique-headings",
- name: "Headings should only be defined once",
- desc: "Headings should be defined only once.",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this;
-
- var headings = {
- h1: 0,
- h2: 0,
- h3: 0,
- h4: 0,
- h5: 0,
- h6: 0
- };
-
- parser.addListener("startrule", function(event){
- var selectors = event.selectors,
- selector,
- part,
- pseudo,
- i, j;
-
- for (i=0; i < selectors.length; i++){
- selector = selectors[i];
- part = selector.parts[selector.parts.length-1];
-
- if (part.elementName && /(h[1-6])/i.test(part.elementName.toString())){
-
- for (j=0; j < part.modifiers.length; j++){
- if (part.modifiers[j].type == "pseudo"){
- pseudo = true;
- break;
- }
- }
-
- if (!pseudo){
- headings[RegExp.$1]++;
- if (headings[RegExp.$1] > 1) {
- reporter.report("Heading (" + part.elementName + ") has already been defined.", part.line, part.col, rule);
- }
- }
- }
- }
- });
-
- parser.addListener("endstylesheet", function(event){
- var prop,
- messages = [];
-
- for (prop in headings){
- if (headings.hasOwnProperty(prop)){
- if (headings[prop] > 1){
- messages.push(headings[prop] + " " + prop + "s");
- }
- }
- }
-
- if (messages.length){
- reporter.rollupWarn("You have " + messages.join(", ") + " defined in this stylesheet.", rule);
- }
- });
- }
-
-});
-CSSLint.addRule({
- id: "universal-selector",
- name: "Disallow universal selector",
- desc: "The universal selector (*) is known to be slow.",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this;
-
- parser.addListener("startrule", function(event){
- var selectors = event.selectors,
- selector,
- part,
- modifier,
- i, j, k;
-
- for (i=0; i < selectors.length; i++){
- selector = selectors[i];
-
- part = selector.parts[selector.parts.length-1];
- if (part.elementName == "*"){
- reporter.report(rule.desc, part.line, part.col, rule);
- }
- }
- });
- }
-
-});
-CSSLint.addRule({
- id: "unqualified-attributes",
- name: "Disallow unqualified attribute selectors",
- desc: "Unqualified attribute selectors are known to be slow.",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this;
-
- parser.addListener("startrule", function(event){
-
- var selectors = event.selectors,
- selector,
- part,
- modifier,
- i, j, k;
-
- for (i=0; i < selectors.length; i++){
- selector = selectors[i];
-
- part = selector.parts[selector.parts.length-1];
- if (part.type == parser.SELECTOR_PART_TYPE){
- for (k=0; k < part.modifiers.length; k++){
- modifier = part.modifiers[k];
- if (modifier.type == "attribute" && (!part.elementName || part.elementName == "*")){
- reporter.report(rule.desc, part.line, part.col, rule);
- }
- }
- }
-
- }
- });
- }
-
-});
-CSSLint.addRule({
- id: "vendor-prefix",
- name: "Require standard property with vendor prefix",
- desc: "When using a vendor-prefixed property, make sure to include the standard one.",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this,
- properties,
- num,
- propertiesToCheck = {
- "-webkit-border-radius": "border-radius",
- "-webkit-border-top-left-radius": "border-top-left-radius",
- "-webkit-border-top-right-radius": "border-top-right-radius",
- "-webkit-border-bottom-left-radius": "border-bottom-left-radius",
- "-webkit-border-bottom-right-radius": "border-bottom-right-radius",
-
- "-o-border-radius": "border-radius",
- "-o-border-top-left-radius": "border-top-left-radius",
- "-o-border-top-right-radius": "border-top-right-radius",
- "-o-border-bottom-left-radius": "border-bottom-left-radius",
- "-o-border-bottom-right-radius": "border-bottom-right-radius",
-
- "-moz-border-radius": "border-radius",
- "-moz-border-radius-topleft": "border-top-left-radius",
- "-moz-border-radius-topright": "border-top-right-radius",
- "-moz-border-radius-bottomleft": "border-bottom-left-radius",
- "-moz-border-radius-bottomright": "border-bottom-right-radius",
-
- "-moz-column-count": "column-count",
- "-webkit-column-count": "column-count",
-
- "-moz-column-gap": "column-gap",
- "-webkit-column-gap": "column-gap",
-
- "-moz-column-rule": "column-rule",
- "-webkit-column-rule": "column-rule",
-
- "-moz-column-rule-style": "column-rule-style",
- "-webkit-column-rule-style": "column-rule-style",
-
- "-moz-column-rule-color": "column-rule-color",
- "-webkit-column-rule-color": "column-rule-color",
-
- "-moz-column-rule-width": "column-rule-width",
- "-webkit-column-rule-width": "column-rule-width",
-
- "-moz-column-width": "column-width",
- "-webkit-column-width": "column-width",
-
- "-webkit-column-span": "column-span",
- "-webkit-columns": "columns",
-
- "-moz-box-shadow": "box-shadow",
- "-webkit-box-shadow": "box-shadow",
-
- "-moz-transform" : "transform",
- "-webkit-transform" : "transform",
- "-o-transform" : "transform",
- "-ms-transform" : "transform",
-
- "-moz-transform-origin" : "transform-origin",
- "-webkit-transform-origin" : "transform-origin",
- "-o-transform-origin" : "transform-origin",
- "-ms-transform-origin" : "transform-origin",
-
- "-moz-box-sizing" : "box-sizing",
- "-webkit-box-sizing" : "box-sizing",
-
- "-moz-user-select" : "user-select",
- "-khtml-user-select" : "user-select",
- "-webkit-user-select" : "user-select"
- };
- function startRule(){
- properties = {};
- num=1;
- }
- function endRule(event){
- var prop,
- i, len,
- standard,
- needed,
- actual,
- needsStandard = [];
-
- for (prop in properties){
- if (propertiesToCheck[prop]){
- needsStandard.push({ actual: prop, needed: propertiesToCheck[prop]});
- }
- }
-
- for (i=0, len=needsStandard.length; i < len; i++){
- needed = needsStandard[i].needed;
- actual = needsStandard[i].actual;
-
- if (!properties[needed]){
- reporter.report("Missing standard property '" + needed + "' to go along with '" + actual + "'.", properties[actual][0].name.line, properties[actual][0].name.col, rule);
- } else {
- if (properties[needed][0].pos < properties[actual][0].pos){
- reporter.report("Standard property '" + needed + "' should come after vendor-prefixed property '" + actual + "'.", properties[actual][0].name.line, properties[actual][0].name.col, rule);
- }
- }
- }
-
- }
-
- parser.addListener("startrule", startRule);
- parser.addListener("startfontface", startRule);
- parser.addListener("startpage", startRule);
- parser.addListener("startpagemargin", startRule);
- parser.addListener("startkeyframerule", startRule);
-
- parser.addListener("property", function(event){
- var name = event.property.text.toLowerCase();
-
- if (!properties[name]){
- properties[name] = [];
- }
-
- properties[name].push({ name: event.property, value : event.value, pos:num++ });
- });
-
- parser.addListener("endrule", endRule);
- parser.addListener("endfontface", endRule);
- parser.addListener("endpage", endRule);
- parser.addListener("endpagemargin", endRule);
- parser.addListener("endkeyframerule", endRule);
- }
-
-});
-CSSLint.addRule({
- id: "zero-units",
- name: "Disallow units for 0 values",
- desc: "You don't need to specify units when a value is 0.",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this;
- parser.addListener("property", function(event){
- var parts = event.value.parts,
- i = 0,
- len = parts.length;
-
- while(i < len){
- if ((parts[i].units || parts[i].type == "percentage") && parts[i].value === 0 && parts[i].type != "time"){
- reporter.report("Values of 0 shouldn't have units specified.", parts[i].line, parts[i].col, rule);
- }
- i++;
- }
-
- });
-
- }
-
-});
-
-CSSLint.addRule({
- id: "custom-background-class",
- name: "Remember .custom-background",
- desc: "Remind users to use the .custom-background class on the body selector.",
- browsers: "All",
- init: function(parser, reporter){
- var rule = this,
- pending = false,
- report_warning = false;
-
- parser.addListener("property", function(event){
- if (pending && event.property.toString().toLowerCase().indexOf('background') === 0)
- report_warning = true;
- });
-
- parser.addListener("startrule", function (event) {
- var selectors = event.selectors,
- selector,
- part,
- i, j;
-
- for (i=0; i < selectors.length; i++){
- selector = selectors[i];
-
- for (j=0; j < selector.parts.length; j++){
- part = selector.parts[j];
-
- if (part.type == parser.SELECTOR_PART_TYPE){
- if (part.elementName && part.elementName.toString() == 'body' && part.modifiers.length == 0) {
- pending = true;
- }
- }
- }
- }
- });
-
- parser.addListener("endrule", function (event) {
- if (report_warning)
- reporter.report("If you want to override any custom background styles, be sure to add '.custom-background' to your 'body' selector.", event.line, event.col, rule);
-
- report_warning = false;
- pending = false;
- });
- }
-});
-
-exports.CSSLint = CSSLint;
-
-
-});
diff --git a/plugins/jetpack/modules/custom-css/custom-css/js/codemirror.min.js b/plugins/jetpack/modules/custom-css/custom-css/js/codemirror.min.js
new file mode 100644
index 00000000..bc7757c8
--- /dev/null
+++ b/plugins/jetpack/modules/custom-css/custom-css/js/codemirror.min.js
@@ -0,0 +1,11 @@
+/**
+ * http://codemirror.net/
+ * MIT License
+ * Includes CSS & LESS modes.
+ * v3.19.1
+ */
+window.CodeMirror=function(){"use strict";function x(a,c){if(!(this instanceof x))return new x(a,c);this.options=c=c||{};for(var d in _c)!c.hasOwnProperty(d)&&_c.hasOwnProperty(d)&&(c[d]=_c[d]);J(c);var e="string"==typeof c.value?0:c.value.first,f=this.display=y(a,e);f.wrapper.CodeMirror=this,G(this),c.autofocus&&!p&&Nb(this),this.state={keyMaps:[],overlays:[],modeGen:0,overwrite:!1,focused:!1,suppressEdits:!1,pasteIncoming:!1,draggingText:!1,highlight:new Xe},E(this),c.lineWrapping&&(this.display.wrapper.className+=" CodeMirror-wrap");var g=c.value;"string"==typeof g&&(g=new ge(c.value,c.mode)),Fb(this,ke)(this,g),b&&setTimeout(ff(Mb,this,!0),20),Pb(this);var h;try{h=document.activeElement==f.input}catch(i){}h||c.autofocus&&!p?setTimeout(ff(mc,this),20):nc(this),Fb(this,function(){for(var a in $c)$c.propertyIsEnumerable(a)&&$c[a](this,c[a],bd);for(var b=0;b<fd.length;++b)fd[b](this)})()}function y(a,b){var d={},e=d.input=lf("textarea",null,null,"position: absolute; padding: 0; width: 1px; height: 1em; outline: none; font-size: 4px;");return f?e.style.width="1000px":e.setAttribute("wrap","off"),o&&(e.style.border="1px solid black"),e.setAttribute("autocorrect","off"),e.setAttribute("autocapitalize","off"),e.setAttribute("spellcheck","false"),d.inputDiv=lf("div",[e],null,"overflow: hidden; position: relative; width: 3px; height: 0px;"),d.scrollbarH=lf("div",[lf("div",null,null,"height: 1px")],"CodeMirror-hscrollbar"),d.scrollbarV=lf("div",[lf("div",null,null,"width: 1px")],"CodeMirror-vscrollbar"),d.scrollbarFiller=lf("div",null,"CodeMirror-scrollbar-filler"),d.gutterFiller=lf("div",null,"CodeMirror-gutter-filler"),d.lineDiv=lf("div",null,"CodeMirror-code"),d.selectionDiv=lf("div",null,null,"position: relative; z-index: 1"),d.cursor=lf("div","\xa0","CodeMirror-cursor"),d.otherCursor=lf("div","\xa0","CodeMirror-cursor CodeMirror-secondarycursor"),d.measure=lf("div",null,"CodeMirror-measure"),d.lineSpace=lf("div",[d.measure,d.selectionDiv,d.lineDiv,d.cursor,d.otherCursor],null,"position: relative; outline: none"),d.mover=lf("div",[lf("div",[d.lineSpace],"CodeMirror-lines")],null,"position: relative"),d.sizer=lf("div",[d.mover],"CodeMirror-sizer"),d.heightForcer=lf("div",null,null,"position: absolute; height: "+Ve+"px; width: 1px;"),d.gutters=lf("div",null,"CodeMirror-gutters"),d.lineGutter=null,d.scroller=lf("div",[d.sizer,d.heightForcer,d.gutters],"CodeMirror-scroll"),d.scroller.setAttribute("tabIndex","-1"),d.wrapper=lf("div",[d.inputDiv,d.scrollbarH,d.scrollbarV,d.scrollbarFiller,d.gutterFiller,d.scroller],"CodeMirror"),c&&(d.gutters.style.zIndex=-1,d.scroller.style.paddingRight=0),a.appendChild?a.appendChild(d.wrapper):a(d.wrapper),o&&(e.style.width="0px"),f||(d.scroller.draggable=!0),k?(d.inputDiv.style.height="1px",d.inputDiv.style.position="absolute"):c&&(d.scrollbarH.style.minWidth=d.scrollbarV.style.minWidth="18px"),d.viewOffset=d.lastSizeC=0,d.showingFrom=d.showingTo=b,d.lineNumWidth=d.lineNumInnerWidth=d.lineNumChars=null,d.prevInput="",d.alignWidgets=!1,d.pollingFast=!1,d.poll=new Xe,d.cachedCharWidth=d.cachedTextHeight=null,d.measureLineCache=[],d.measureLineCachePos=0,d.inaccurateSelection=!1,d.maxLine=null,d.maxLineLength=0,d.maxLineChanged=!1,d.wheelDX=d.wheelDY=d.wheelStartX=d.wheelStartY=null,d}function z(a){a.doc.mode=x.getMode(a.options,a.doc.modeOption),a.doc.iter(function(a){a.stateAfter&&(a.stateAfter=null),a.styles&&(a.styles=null)}),a.doc.frontier=a.doc.first,bb(a,100),a.state.modeGen++,a.curOp&&Ib(a)}function A(a){a.options.lineWrapping?(a.display.wrapper.className+=" CodeMirror-wrap",a.display.sizer.style.minWidth=""):(a.display.wrapper.className=a.display.wrapper.className.replace(" CodeMirror-wrap",""),I(a)),C(a),Ib(a),pb(a),setTimeout(function(){K(a)},100)}function B(a){var b=Ab(a.display),c=a.options.lineWrapping,d=c&&Math.max(5,a.display.scroller.clientWidth/Bb(a.display)-3);return function(e){return Gd(a.doc,e)?0:c?(Math.ceil(e.text.length/d)||1)*b:b}}function C(a){var b=a.doc,c=B(a);b.iter(function(a){var b=c(a);b!=a.height&&oe(a,b)})}function D(a){var b=kd[a.options.keyMap],c=b.style;a.display.wrapper.className=a.display.wrapper.className.replace(/\s*cm-keymap-\S+/g,"")+(c?" cm-keymap-"+c:""),a.state.disableInput=b.disableInput}function E(a){a.display.wrapper.className=a.display.wrapper.className.replace(/\s*cm-s-\S+/g,"")+a.options.theme.replace(/(^|\s)\s*/g," cm-s-"),pb(a)}function F(a){G(a),Ib(a),setTimeout(function(){M(a)},20)}function G(a){var b=a.display.gutters,c=a.options.gutters;mf(b);for(var d=0;d<c.length;++d){var e=c[d],f=b.appendChild(lf("div",null,"CodeMirror-gutter "+e));"CodeMirror-linenumbers"==e&&(a.display.lineGutter=f,f.style.width=(a.display.lineNumWidth||1)+"px")}b.style.display=d?"":"none"}function H(a,b){if(0==b.height)return 0;for(var d,c=b.text.length,e=b;d=Dd(e);){var f=d.find();e=le(a,f.from.line),c+=f.from.ch-f.to.ch}for(e=b;d=Ed(e);){var f=d.find();c-=e.text.length-f.from.ch,e=le(a,f.to.line),c+=e.text.length-f.to.ch}return c}function I(a){var b=a.display,c=a.doc;b.maxLine=le(c,c.first),b.maxLineLength=H(c,b.maxLine),b.maxLineChanged=!0,c.iter(function(a){var d=H(c,a);d>b.maxLineLength&&(b.maxLineLength=d,b.maxLine=a)})}function J(a){var b=bf(a.gutters,"CodeMirror-linenumbers");-1==b&&a.lineNumbers?a.gutters=a.gutters.concat(["CodeMirror-linenumbers"]):b>-1&&!a.lineNumbers&&(a.gutters=a.gutters.slice(0),a.gutters.splice(b,1))}function K(a){var b=a.display,c=a.doc.height,d=c+gb(b);b.sizer.style.minHeight=b.heightForcer.style.top=d+"px",b.gutters.style.height=Math.max(d,b.scroller.clientHeight-Ve)+"px";var e=Math.max(d,b.scroller.scrollHeight),f=b.scroller.scrollWidth>b.scroller.clientWidth+1,g=e>b.scroller.clientHeight+1;g?(b.scrollbarV.style.display="block",b.scrollbarV.style.bottom=f?tf(b.measure)+"px":"0",b.scrollbarV.firstChild.style.height=e-b.scroller.clientHeight+b.scrollbarV.clientHeight+"px"):(b.scrollbarV.style.display="",b.scrollbarV.firstChild.style.height="0"),f?(b.scrollbarH.style.display="block",b.scrollbarH.style.right=g?tf(b.measure)+"px":"0",b.scrollbarH.firstChild.style.width=b.scroller.scrollWidth-b.scroller.clientWidth+b.scrollbarH.clientWidth+"px"):(b.scrollbarH.style.display="",b.scrollbarH.firstChild.style.width="0"),f&&g?(b.scrollbarFiller.style.display="block",b.scrollbarFiller.style.height=b.scrollbarFiller.style.width=tf(b.measure)+"px"):b.scrollbarFiller.style.display="",f&&a.options.coverGutterNextToScrollbar&&a.options.fixedGutter?(b.gutterFiller.style.display="block",b.gutterFiller.style.height=tf(b.measure)+"px",b.gutterFiller.style.width=b.gutters.offsetWidth+"px"):b.gutterFiller.style.display="",l&&0===tf(b.measure)&&(b.scrollbarV.style.minWidth=b.scrollbarH.style.minHeight=m?"18px":"12px",b.scrollbarV.style.pointerEvents=b.scrollbarH.style.pointerEvents="none")}function L(a,b,c){var d=a.scroller.scrollTop,e=a.wrapper.clientHeight;"number"==typeof c?d=c:c&&(d=c.top,e=c.bottom-c.top),d=Math.floor(d-fb(a));var f=Math.ceil(d+e);return{from:qe(b,d),to:qe(b,f)}}function M(a){var b=a.display;if(b.alignWidgets||b.gutters.firstChild&&a.options.fixedGutter){for(var c=P(b)-b.scroller.scrollLeft+a.doc.scrollLeft,d=b.gutters.offsetWidth,e=c+"px",f=b.lineDiv.firstChild;f;f=f.nextSibling)if(f.alignable)for(var g=0,h=f.alignable;g<h.length;++g)h[g].style.left=e;a.options.fixedGutter&&(b.gutters.style.left=c+d+"px")}}function N(a){if(!a.options.lineNumbers)return!1;var b=a.doc,c=O(a.options,b.first+b.size-1),d=a.display;if(c.length!=d.lineNumChars){var e=d.measure.appendChild(lf("div",[lf("div",c)],"CodeMirror-linenumber CodeMirror-gutter-elt")),f=e.firstChild.offsetWidth,g=e.offsetWidth-f;return d.lineGutter.style.width="",d.lineNumInnerWidth=Math.max(f,d.lineGutter.offsetWidth-g),d.lineNumWidth=d.lineNumInnerWidth+g,d.lineNumChars=d.lineNumInnerWidth?c.length:-1,d.lineGutter.style.width=d.lineNumWidth+"px",!0}return!1}function O(a,b){return String(a.lineNumberFormatter(b+a.firstLineNumber))}function P(a){return pf(a.scroller).left-pf(a.sizer).left}function Q(a,b,c,d){for(var g,e=a.display.showingFrom,f=a.display.showingTo,h=L(a.display,a.doc,c),i=!0;;i=!1){var j=a.display.scroller.clientWidth;if(!R(a,b,h,d))break;if(g=!0,b=[],Z(a),K(a),i&&a.options.lineWrapping&&j!=a.display.scroller.clientWidth)d=!0;else if(d=!1,c&&(c=Math.min(a.display.scroller.scrollHeight-a.display.scroller.clientHeight,"number"==typeof c?c:c.top)),h=L(a.display,a.doc,c),h.from>=a.display.showingFrom&&h.to<=a.display.showingTo)break}return g&&(Qe(a,"update",a),(a.display.showingFrom!=e||a.display.showingTo!=f)&&Qe(a,"viewportChange",a,a.display.showingFrom,a.display.showingTo)),g}function R(a,b,c,d){var e=a.display,f=a.doc;if(!e.wrapper.clientWidth)return e.showingFrom=e.showingTo=f.first,e.viewOffset=0,void 0;if(!(!d&&0==b.length&&c.from>e.showingFrom&&c.to<e.showingTo)){N(a)&&(b=[{from:f.first,to:f.first+f.size}]);var g=e.sizer.style.marginLeft=e.gutters.offsetWidth+"px";e.scrollbarH.style.left=a.options.fixedGutter?g:"0";var h=1/0;if(a.options.lineNumbers)for(var i=0;i<b.length;++i)b[i].diff&&b[i].from<h&&(h=b[i].from);var j=f.first+f.size,k=Math.max(c.from-a.options.viewportMargin,f.first),l=Math.min(j,c.to+a.options.viewportMargin);if(e.showingFrom<k&&k-e.showingFrom<20&&(k=Math.max(f.first,e.showingFrom)),e.showingTo>l&&e.showingTo-l<20&&(l=Math.min(j,e.showingTo)),w)for(k=pe(Fd(f,le(f,k)));j>l&&Gd(f,le(f,l));)++l;var m=[{from:Math.max(e.showingFrom,f.first),to:Math.min(e.showingTo,j)}];if(m=m[0].from>=m[0].to?[]:U(m,b),w)for(var i=0;i<m.length;++i)for(var o,n=m[i];o=Ed(le(f,n.to-1));){var p=o.find().from.line;if(!(p>n.from)){m.splice(i--,1);break}n.to=p}for(var q=0,i=0;i<m.length;++i){var n=m[i];n.from<k&&(n.from=k),n.to>l&&(n.to=l),n.from>=n.to?m.splice(i--,1):q+=n.to-n.from}if(!d&&q==l-k&&k==e.showingFrom&&l==e.showingTo)return T(a),void 0;m.sort(function(a,b){return a.from-b.from});try{var r=document.activeElement}catch(s){}.7*(l-k)>q&&(e.lineDiv.style.display="none"),W(a,k,l,m,h),e.lineDiv.style.display="",r&&document.activeElement!=r&&r.offsetHeight&&r.focus();var t=k!=e.showingFrom||l!=e.showingTo||e.lastSizeC!=e.wrapper.clientHeight;return t&&(e.lastSizeC=e.wrapper.clientHeight,bb(a,400)),e.showingFrom=k,e.showingTo=l,S(a),T(a),!0}}function S(a){for(var f,b=a.display,d=b.lineDiv.offsetTop,e=b.lineDiv.firstChild;e;e=e.nextSibling)if(e.lineObj){if(c){var g=e.offsetTop+e.offsetHeight;f=g-d,d=g}else{var h=pf(e);f=h.bottom-h.top}var i=e.lineObj.height-f;if(2>f&&(f=Ab(b)),i>.001||-.001>i){oe(e.lineObj,f);var j=e.lineObj.widgets;if(j)for(var k=0;k<j.length;++k)j[k].height=j[k].node.offsetHeight}}}function T(a){var b=a.display.viewOffset=re(a,le(a.doc,a.display.showingFrom));a.display.mover.style.top=b+"px"}function U(a,b){for(var c=0,d=b.length||0;d>c;++c){for(var e=b[c],f=[],g=e.diff||0,h=0,i=a.length;i>h;++h){var j=a[h];e.to<=j.from&&e.diff?f.push({from:j.from+g,to:j.to+g}):e.to<=j.from||e.from>=j.to?f.push(j):(e.from>j.from&&f.push({from:j.from,to:e.from}),e.to<j.to&&f.push({from:e.to+g,to:j.to+g}))}a=f}return a}function V(a){for(var b=a.display,c={},d={},e=b.gutters.firstChild,f=0;e;e=e.nextSibling,++f)c[a.options.gutters[f]]=e.offsetLeft,d[a.options.gutters[f]]=e.offsetWidth;return{fixedPos:P(b),gutterTotalWidth:b.gutters.offsetWidth,gutterLeft:c,gutterWidth:d,wrapperWidth:b.wrapper.clientWidth}}function W(a,b,c,d,e){function l(b){var c=b.nextSibling;return f&&q&&a.display.currentWheelTarget==b?(b.style.display="none",b.lineObj=null):b.parentNode.removeChild(b),c}var g=V(a),h=a.display,i=a.options.lineNumbers;d.length||f&&a.display.currentWheelTarget||mf(h.lineDiv);var j=h.lineDiv,k=j.firstChild,m=d.shift(),n=b;for(a.doc.iter(b,c,function(b){if(m&&m.to==n&&(m=d.shift()),Gd(a.doc,b)){if(0!=b.height&&oe(b,0),b.widgets&&k&&k.previousSibling)for(var c=0;c<b.widgets.length;++c){var f=b.widgets[c];if(f.showIfHidden){var h=k.previousSibling;if(/pre/i.test(h.nodeName)){var o=lf("div",null,null,"position: relative");h.parentNode.replaceChild(o,h),o.appendChild(h),h=o}var p=h.appendChild(lf("div",[f.node],"CodeMirror-linewidget"));f.handleMouseEvents||(p.ignoreEvents=!0),Y(f,p,h,g)}}}else if(m&&m.from<=n&&m.to>n){for(;k.lineObj!=b;)k=l(k);i&&n>=e&&k.lineNumber&&of(k.lineNumber,O(a.options,n)),k=k.nextSibling}else{if(b.widgets)for(var s,q=0,r=k;r&&20>q;++q,r=r.nextSibling)if(r.lineObj==b&&/div/i.test(r.nodeName)){s=r;break}var t=X(a,b,n,g,s);if(t!=s)j.insertBefore(t,k);else{for(;k!=s;)k=l(k);k=k.nextSibling}t.lineObj=b}++n});k;)k=l(k)}function X(a,b,d,e,f){var k,g=Xd(a,b),h=g.pre,i=b.gutterMarkers,j=a.display,l=g.bgClass?g.bgClass+" "+(b.bgClass||""):b.bgClass;if(!(a.options.lineNumbers||i||l||b.wrapClass||b.widgets))return h;if(f){f.alignable=null;for(var q,m=!0,n=0,o=null,p=f.firstChild;p;p=q)if(q=p.nextSibling,/\bCodeMirror-linewidget\b/.test(p.className)){for(var r=0;r<b.widgets.length;++r){var s=b.widgets[r];if(s.node==p.firstChild){s.above||o||(o=p),Y(s,p,f,e),++n;break}}if(r==b.widgets.length){m=!1;break}}else f.removeChild(p);f.insertBefore(h,o),m&&n==b.widgets.length&&(k=f,f.className=b.wrapClass||"")}if(k||(k=lf("div",null,b.wrapClass,"position: relative"),k.appendChild(h)),l&&k.insertBefore(lf("div",null,l+" CodeMirror-linebackground"),k.firstChild),a.options.lineNumbers||i){var t=k.insertBefore(lf("div",null,null,"position: absolute; left: "+(a.options.fixedGutter?e.fixedPos:-e.gutterTotalWidth)+"px"),k.firstChild);if(a.options.fixedGutter&&(k.alignable||(k.alignable=[])).push(t),!a.options.lineNumbers||i&&i["CodeMirror-linenumbers"]||(k.lineNumber=t.appendChild(lf("div",O(a.options,d),"CodeMirror-linenumber CodeMirror-gutter-elt","left: "+e.gutterLeft["CodeMirror-linenumbers"]+"px; width: "+j.lineNumInnerWidth+"px"))),i)for(var u=0;u<a.options.gutters.length;++u){var v=a.options.gutters[u],w=i.hasOwnProperty(v)&&i[v];w&&t.appendChild(lf("div",[w],"CodeMirror-gutter-elt","left: "+e.gutterLeft[v]+"px; width: "+e.gutterWidth[v]+"px"))}}if(c&&(k.style.zIndex=2),b.widgets&&k!=f)for(var r=0,x=b.widgets;r<x.length;++r){var s=x[r],y=lf("div",[s.node],"CodeMirror-linewidget");s.handleMouseEvents||(y.ignoreEvents=!0),Y(s,y,k,e),s.above?k.insertBefore(y,a.options.lineNumbers&&0!=b.height?t:h):k.appendChild(y),Qe(s,"redraw")}return k}function Y(a,b,c,d){if(a.noHScroll){(c.alignable||(c.alignable=[])).push(b);var e=d.wrapperWidth;b.style.left=d.fixedPos+"px",a.coverGutter||(e-=d.gutterTotalWidth,b.style.paddingLeft=d.gutterTotalWidth+"px"),b.style.width=e+"px"}a.coverGutter&&(b.style.zIndex=5,b.style.position="relative",a.noHScroll||(b.style.marginLeft=-d.gutterTotalWidth+"px"))}function Z(a){var b=a.display,c=Cc(a.doc.sel.from,a.doc.sel.to);if(c||a.options.showCursorWhenSelecting?$(a):b.cursor.style.display=b.otherCursor.style.display="none",c?b.selectionDiv.style.display="none":_(a),a.options.moveInputWithCursor){var d=vb(a,a.doc.sel.head,"div"),e=pf(b.wrapper),f=pf(b.lineDiv);b.inputDiv.style.top=Math.max(0,Math.min(b.wrapper.clientHeight-10,d.top+f.top-e.top))+"px",b.inputDiv.style.left=Math.max(0,Math.min(b.wrapper.clientWidth-10,d.left+f.left-e.left))+"px"}}function $(a){var b=a.display,c=vb(a,a.doc.sel.head,"div");b.cursor.style.left=c.left+"px",b.cursor.style.top=c.top+"px",b.cursor.style.height=Math.max(0,c.bottom-c.top)*a.options.cursorHeight+"px",b.cursor.style.display="",c.other?(b.otherCursor.style.display="",b.otherCursor.style.left=c.other.left+"px",b.otherCursor.style.top=c.other.top+"px",b.otherCursor.style.height=.85*(c.other.bottom-c.other.top)+"px"):b.otherCursor.style.display="none"}function _(a){function h(a,b,c,d){0>b&&(b=0),e.appendChild(lf("div",null,"CodeMirror-selected","position: absolute; left: "+a+"px; top: "+b+"px; width: "+(null==c?f-a:c)+"px; height: "+(d-b)+"px"))}function i(b,d,e){function m(c,d){return ub(a,Bc(b,c),"div",i,d)}var k,l,i=le(c,b),j=i.text.length;return Af(se(i),d||0,null==e?j:e,function(a,b,c){var n,o,p,i=m(a,"left");if(a==b)n=i,o=p=i.left;else{if(n=m(b-1,"right"),"rtl"==c){var q=i;i=n,n=q}o=i.left,p=n.right}null==d&&0==a&&(o=g),n.top-i.top>3&&(h(o,i.top,null,i.bottom),o=g,i.bottom<n.top&&h(o,i.bottom,null,n.top)),null==e&&b==j&&(p=f),(!k||i.top<k.top||i.top==k.top&&i.left<k.left)&&(k=i),(!l||n.bottom>l.bottom||n.bottom==l.bottom&&n.right>l.right)&&(l=n),g+1>o&&(o=g),h(o,n.top,p-o,n.bottom)}),{start:k,end:l}}var b=a.display,c=a.doc,d=a.doc.sel,e=document.createDocumentFragment(),f=b.lineSpace.offsetWidth,g=hb(a.display);if(d.from.line==d.to.line)i(d.from.line,d.from.ch,d.to.ch);else{var j=le(c,d.from.line),k=le(c,d.to.line),l=Fd(c,j)==Fd(c,k),m=i(d.from.line,d.from.ch,l?j.text.length:null).end,n=i(d.to.line,l?0:null,d.to.ch).start;l&&(m.top<n.top-2?(h(m.right,m.top,null,m.bottom),h(g,n.top,n.left,n.bottom)):h(m.right,m.top,n.left-m.right,m.bottom)),m.bottom<n.top&&h(g,m.bottom,null,n.top)}nf(b.selectionDiv,e),b.selectionDiv.style.display=""}function ab(a){if(a.state.focused){var b=a.display;clearInterval(b.blinker);var c=!0;b.cursor.style.visibility=b.otherCursor.style.visibility="",a.options.cursorBlinkRate>0&&(b.blinker=setInterval(function(){b.cursor.style.visibility=b.otherCursor.style.visibility=(c=!c)?"":"hidden"},a.options.cursorBlinkRate))}}function bb(a,b){a.doc.mode.startState&&a.doc.frontier<a.display.showingTo&&a.state.highlight.set(b,ff(cb,a))}function cb(a){var b=a.doc;if(b.frontier<b.first&&(b.frontier=b.first),!(b.frontier>=a.display.showingTo)){var f,c=+new Date+a.options.workTime,d=hd(b.mode,eb(a,b.frontier)),e=[];b.iter(b.frontier,Math.min(b.first+b.size,a.display.showingTo+500),function(g){if(b.frontier>=a.display.showingFrom){var h=g.styles;g.styles=Sd(a,g,d);for(var i=!h||h.length!=g.styles.length,j=0;!i&&j<h.length;++j)i=h[j]!=g.styles[j];i&&(f&&f.end==b.frontier?f.end++:e.push(f={start:b.frontier,end:b.frontier+1})),g.stateAfter=hd(b.mode,d)}else Ud(a,g,d),g.stateAfter=0==b.frontier%5?hd(b.mode,d):null;return++b.frontier,+new Date>c?(bb(a,a.options.workDelay),!0):void 0}),e.length&&Fb(a,function(){for(var a=0;a<e.length;++a)Ib(this,e[a].start,e[a].end)})()}}function db(a,b,c){for(var d,e,f=a.doc,g=c?-1:b-(a.doc.mode.innerMode?1e3:100),h=b;h>g;--h){if(h<=f.first)return f.first;var i=le(f,h-1);if(i.stateAfter&&(!c||h<=f.frontier))return h;var j=Ye(i.text,null,a.options.tabSize);(null==e||d>j)&&(e=h-1,d=j)}return e}function eb(a,b,c){var d=a.doc,e=a.display;if(!d.mode.startState)return!0;var f=db(a,b,c),g=f>d.first&&le(d,f-1).stateAfter;return g=g?hd(d.mode,g):id(d.mode),d.iter(f,b,function(c){Ud(a,c,g);var h=f==b-1||0==f%5||f>=e.showingFrom&&f<e.showingTo;c.stateAfter=h?hd(d.mode,g):null,++f}),c&&(d.frontier=f),g}function fb(a){return a.lineSpace.offsetTop}function gb(a){return a.mover.offsetHeight-a.lineSpace.offsetHeight}function hb(a){var b=nf(a.measure,lf("pre",null,null,"text-align: left")).appendChild(lf("span","x"));return b.offsetLeft}function ib(a,b,c,d,e){var f=-1;if(d=d||lb(a,b),d.crude){var g=d.left+c*d.width;return{left:g,right:g+d.width,top:d.top,bottom:d.bottom}}for(var h=c;;h+=f){var i=d[h];if(i)break;0>f&&0==h&&(f=1)}return e=h>c?"left":c>h?"right":e,"left"==e&&i.leftSide?i=i.leftSide:"right"==e&&i.rightSide&&(i=i.rightSide),{left:c>h?i.right:i.left,right:h>c?i.left:i.right,top:i.top,bottom:i.bottom}}function jb(a,b){for(var c=a.display.measureLineCache,d=0;d<c.length;++d){var e=c[d];if(e.text==b.text&&e.markedSpans==b.markedSpans&&a.display.scroller.clientWidth==e.width&&e.classes==b.textClass+"|"+b.wrapClass)return e}}function kb(a,b){var c=jb(a,b);c&&(c.text=c.measure=c.markedSpans=null)}function lb(a,b){var c=jb(a,b);if(c)return c.measure;var d=mb(a,b),e=a.display.measureLineCache,f={text:b.text,width:a.display.scroller.clientWidth,markedSpans:b.markedSpans,measure:d,classes:b.textClass+"|"+b.wrapClass};return 16==e.length?e[++a.display.measureLineCachePos%16]=f:e.push(f),d}function mb(a,e){function t(a){var b=a.top-p.top,c=a.bottom-p.top;c>s&&(c=s),0>b&&(b=0);for(var d=q.length-2;d>=0;d-=2){var e=q[d],f=q[d+1];if(!(e>c||b>f)&&(b>=e&&f>=c||e>=b&&c>=f||Math.min(c,f)-Math.max(b,e)>=c-b>>1)){q[d]=Math.min(b,e),q[d+1]=Math.max(c,f);break}}return 0>d&&(d=q.length,q.push(b,c)),{left:a.left-p.left,right:a.right-p.left,top:d,bottom:null}}function u(a){a.bottom=q[a.top+1],a.top=q[a.top]}if(!a.options.lineWrapping&&e.text.length>=a.options.crudeMeasuringFrom)return nb(a,e);var f=a.display,g=ef(e.text.length),h=Xd(a,e,g,!0).pre;if(b&&!c&&!a.options.lineWrapping&&h.childNodes.length>100){for(var i=document.createDocumentFragment(),j=10,k=h.childNodes.length,l=0,m=Math.ceil(k/j);m>l;++l){for(var n=lf("div",null,null,"display: inline-block"),o=0;j>o&&k;++o)n.appendChild(h.firstChild),--k;i.appendChild(n)}h.appendChild(i)}nf(f.measure,h);var p=pf(f.lineDiv),q=[],r=ef(e.text.length),s=h.offsetHeight;d&&f.measure.first!=h&&nf(f.measure,h);for(var v,l=0;l<g.length;++l)if(v=g[l]){var w=v,x=null;if(/\bCodeMirror-widget\b/.test(v.className)&&v.getClientRects){1==v.firstChild.nodeType&&(w=v.firstChild);var y=w.getClientRects();y.length>1&&(x=r[l]=t(y[0]),x.rightSide=t(y[y.length-1]))}x||(x=r[l]=t(pf(w))),v.measureRight&&(x.right=pf(v.measureRight).left),v.leftSide&&(x.leftSide=t(pf(v.leftSide)))}mf(a.display.measure);for(var v,l=0;l<r.length;++l)(v=r[l])&&(u(v),v.leftSide&&u(v.leftSide),v.rightSide&&u(v.rightSide));return r}function nb(a,b){var c=new Od(b.text.slice(0,100),null);b.textClass&&(c.textClass=b.textClass);var d=mb(a,c),e=ib(a,c,0,d,"left"),f=ib(a,c,99,d,"right");return{crude:!0,top:e.top,left:e.left,bottom:e.bottom,width:(f.right-e.left)/100}}function ob(a,b){var c=!1;if(b.markedSpans)for(var d=0;d<b.markedSpans;++d){var e=b.markedSpans[d];!e.collapsed||null!=e.to&&e.to!=b.text.length||(c=!0)}var f=!c&&jb(a,b);if(f||b.text.length>=a.options.crudeMeasuringFrom)return ib(a,b,b.text.length,f&&f.measure,"right").right;var g=Xd(a,b,null,!0).pre,h=g.appendChild(vf(a.display.measure));return nf(a.display.measure,g),pf(h).right-pf(a.display.lineDiv).left}function pb(a){a.display.measureLineCache.length=a.display.measureLineCachePos=0,a.display.cachedCharWidth=a.display.cachedTextHeight=null,a.options.lineWrapping||(a.display.maxLineChanged=!0),a.display.lineNumChars=null}function qb(){return window.pageXOffset||(document.documentElement||document.body).scrollLeft}function rb(){return window.pageYOffset||(document.documentElement||document.body).scrollTop}function sb(a,b,c,d){if(b.widgets)for(var e=0;e<b.widgets.length;++e)if(b.widgets[e].above){var f=Md(b.widgets[e]);c.top+=f,c.bottom+=f}if("line"==d)return c;d||(d="local");var g=re(a,b);if("local"==d?g+=fb(a.display):g-=a.display.viewOffset,"page"==d||"window"==d){var h=pf(a.display.lineSpace);g+=h.top+("window"==d?0:rb());var i=h.left+("window"==d?0:qb());c.left+=i,c.right+=i}return c.top+=g,c.bottom+=g,c}function tb(a,b,c){if("div"==c)return b;var d=b.left,e=b.top;if("page"==c)d-=qb(),e-=rb();else if("local"==c||!c){var f=pf(a.display.sizer);d+=f.left,e+=f.top}var g=pf(a.display.lineSpace);return{left:d-g.left,top:e-g.top}}function ub(a,b,c,d,e){return d||(d=le(a.doc,b.line)),sb(a,d,ib(a,d,b.ch,null,e),c)}function vb(a,b,c,d,e){function f(b,f){var g=ib(a,d,b,e,f?"right":"left");return f?g.left=g.right:g.right=g.left,sb(a,d,g,c)}function g(a,b){var c=h[b],d=c.level%2;return a==Bf(c)&&b&&c.level<h[b-1].level?(c=h[--b],a=Cf(c)-(c.level%2?0:1),d=!0):a==Cf(c)&&b<h.length-1&&c.level<h[b+1].level&&(c=h[++b],a=Bf(c)-c.level%2,d=!1),d&&a==c.to&&a>c.from?f(a-1):f(a,d)}d=d||le(a.doc,b.line),e||(e=lb(a,d));var h=se(d),i=b.ch;if(!h)return f(i);var j=Jf(h,i),k=g(i,j);return null!=If&&(k.other=g(i,If)),k}function wb(a,b,c,d){var e=new Bc(a,b);return e.xRel=d,c&&(e.outside=!0),e}function xb(a,b,c){var d=a.doc;if(c+=a.display.viewOffset,0>c)return wb(d.first,0,!0,-1);var e=qe(d,c),f=d.first+d.size-1;if(e>f)return wb(d.first+d.size-1,le(d,f).text.length,!0,1);for(0>b&&(b=0);;){var g=le(d,e),h=yb(a,g,e,b,c),i=Ed(g),j=i&&i.find();if(!i||!(h.ch>j.from.ch||h.ch==j.from.ch&&h.xRel>0))return h;e=j.to.line}}function yb(a,b,c,d,e){function j(d){var e=vb(a,Bc(c,d),"line",b,i);return g=!0,f>e.bottom?e.left-h:f<e.top?e.left+h:(g=!1,e.left)}var f=e-re(a,b),g=!1,h=2*a.display.wrapper.clientWidth,i=lb(a,b),k=se(b),l=b.text.length,m=Df(b),n=Ef(b),o=j(m),p=g,q=j(n),r=g;if(d>q)return wb(c,n,r,1);for(;;){if(k?n==m||n==Lf(b,m,1):1>=n-m){for(var s=o>d||q-d>=d-o?m:n,t=d-(s==m?o:q);kf.test(b.text.charAt(s));)++s;var u=wb(c,s,s==m?p:r,0>t?-1:t?1:0);return u}var v=Math.ceil(l/2),w=m+v;if(k){w=m;for(var x=0;v>x;++x)w=Lf(b,w,1)}var y=j(w);y>d?(n=w,q=y,(r=g)&&(q+=1e3),l=v):(m=w,o=y,p=g,l-=v)}}function Ab(a){if(null!=a.cachedTextHeight)return a.cachedTextHeight;if(null==zb){zb=lf("pre");for(var b=0;49>b;++b)zb.appendChild(document.createTextNode("x")),zb.appendChild(lf("br"));zb.appendChild(document.createTextNode("x"))}nf(a.measure,zb);var c=zb.offsetHeight/50;return c>3&&(a.cachedTextHeight=c),mf(a.measure),c||1}function Bb(a){if(null!=a.cachedCharWidth)return a.cachedCharWidth;var b=lf("span","x"),c=lf("pre",[b]);nf(a.measure,c);var d=b.offsetWidth;return d>2&&(a.cachedCharWidth=d),d||10}function Db(a){a.curOp={changes:[],forceUpdate:!1,updateInput:null,userSelChange:null,textChanged:null,selectionChanged:!1,cursorActivity:!1,updateMaxLine:!1,updateScrollPos:!1,id:++Cb},Pe++||(Oe=[])}function Eb(a){var b=a.curOp,c=a.doc,d=a.display;if(a.curOp=null,b.updateMaxLine&&I(a),d.maxLineChanged&&!a.options.lineWrapping&&d.maxLine){var e=ob(a,d.maxLine);d.sizer.style.minWidth=Math.max(0,e+3+Ve)+"px",d.maxLineChanged=!1;var f=Math.max(0,d.sizer.offsetLeft+d.sizer.offsetWidth-d.scroller.clientWidth);f<c.scrollLeft&&!b.updateScrollPos&&ac(a,Math.min(d.scroller.scrollLeft,f),!0)}var g,h;if(b.updateScrollPos)g=b.updateScrollPos;else if(b.selectionChanged&&d.scroller.clientHeight){var i=vb(a,c.sel.head);g=Rc(a,i.left,i.top,i.left,i.bottom)}(b.changes.length||b.forceUpdate||g&&null!=g.scrollTop)&&(h=Q(a,b.changes,g&&g.scrollTop,b.forceUpdate),a.display.scroller.offsetHeight&&(a.doc.scrollTop=a.display.scroller.scrollTop)),!h&&b.selectionChanged&&Z(a),b.updateScrollPos?(d.scroller.scrollTop=d.scrollbarV.scrollTop=c.scrollTop=g.scrollTop,d.scroller.scrollLeft=d.scrollbarH.scrollLeft=c.scrollLeft=g.scrollLeft,M(a),b.scrollToPos&&Pc(a,Gc(a.doc,b.scrollToPos.from),Gc(a.doc,b.scrollToPos.to),b.scrollToPos.margin)):g&&Oc(a),b.selectionChanged&&ab(a),a.state.focused&&b.updateInput&&Mb(a,b.userSelChange);var j=b.maybeHiddenMarkers,k=b.maybeUnhiddenMarkers;if(j)for(var l=0;l<j.length;++l)j[l].lines.length||Ne(j[l],"hide");if(k)for(var l=0;l<k.length;++l)k[l].lines.length&&Ne(k[l],"unhide");var m;if(--Pe||(m=Oe,Oe=null),b.textChanged&&Ne(a,"change",a,b.textChanged),b.cursorActivity&&Ne(a,"cursorActivity",a),m)for(var l=0;l<m.length;++l)m[l]()}function Fb(a,b){return function(){var c=a||this,d=!c.curOp;d&&Db(c);try{var e=b.apply(c,arguments)}finally{d&&Eb(c)}return e}}function Gb(a){return function(){var c,b=this.cm&&!this.cm.curOp;b&&Db(this.cm);try{c=a.apply(this,arguments)}finally{b&&Eb(this.cm)}return c}}function Hb(a,b){var d,c=!a.curOp;c&&Db(a);try{d=b()}finally{c&&Eb(a)}return d}function Ib(a,b,c,d){null==b&&(b=a.doc.first),null==c&&(c=a.doc.first+a.doc.size),a.curOp.changes.push({from:b,to:c,diff:d})}function Jb(a){a.display.pollingFast||a.display.poll.set(a.options.pollInterval,function(){Lb(a),a.state.focused&&Jb(a)})}function Kb(a){function c(){var d=Lb(a);d||b?(a.display.pollingFast=!1,Jb(a)):(b=!0,a.display.poll.set(60,c))}var b=!1;a.display.pollingFast=!0,a.display.poll.set(20,c)}function Lb(a){var c=a.display.input,e=a.display.prevInput,f=a.doc,g=f.sel;if(!a.state.focused||xf(c)||Ob(a)||a.state.disableInput)return!1;a.state.pasteIncoming&&a.state.fakedLastChar&&(c.value=c.value.substring(0,c.value.length-1),a.state.fakedLastChar=!1);var h=c.value;if(h==e&&Cc(g.from,g.to))return!1;if(b&&!d&&a.display.inputHasSelection===h)return Mb(a,!0),!1;var i=!a.curOp;i&&Db(a),g.shift=!1;for(var j=0,k=Math.min(e.length,h.length);k>j&&e.charCodeAt(j)==h.charCodeAt(j);)++j;var l=g.from,m=g.to;j<e.length?l=Bc(l.line,l.ch-(e.length-j)):a.state.overwrite&&Cc(l,m)&&!a.state.pasteIncoming&&(m=Bc(m.line,Math.min(le(f,m.line).text.length,m.ch+(h.length-j))));var n=a.curOp.updateInput,o={from:l,to:m,text:wf(h.slice(j)),origin:a.state.pasteIncoming?"paste":"+input"};return uc(a.doc,o,"end"),a.curOp.updateInput=n,Qe(a,"inputRead",a,o),h.length>1e3||h.indexOf("\n")>-1?c.value=a.display.prevInput="":a.display.prevInput=h,i&&Eb(a),a.state.pasteIncoming=!1,!0}function Mb(a,c){var e,f,g=a.doc;if(Cc(g.sel.from,g.sel.to))c&&(a.display.prevInput=a.display.input.value="",b&&!d&&(a.display.inputHasSelection=null));else{a.display.prevInput="",e=yf&&(g.sel.to.line-g.sel.from.line>100||(f=a.getSelection()).length>1e3);var h=e?"-":f||a.getSelection();a.display.input.value=h,a.state.focused&&af(a.display.input),b&&!d&&(a.display.inputHasSelection=h)}a.display.inaccurateSelection=e}function Nb(a){"nocursor"==a.options.readOnly||p&&document.activeElement==a.display.input||a.display.input.focus()}function Ob(a){return a.options.readOnly||a.doc.cantEdit}function Pb(a){function e(){a.state.focused&&setTimeout(ff(Nb,a),0)}function h(){null==g&&(g=setTimeout(function(){g=null,c.cachedCharWidth=c.cachedTextHeight=sf=null,pb(a),Hb(a,ff(Ib,a))},100))}function i(){for(var a=c.wrapper.parentNode;a&&a!=document.body;a=a.parentNode);a?setTimeout(i,5e3):Me(window,"resize",h)}function j(b){Re(a,b)||a.options.onDragEvent&&a.options.onDragEvent(a,Ee(b))||Ie(b)}function l(){c.inaccurateSelection&&(c.prevInput="",c.inaccurateSelection=!1,c.input.value=a.getSelection(),af(c.input))}var c=a.display;Le(c.scroller,"mousedown",Fb(a,Ub)),b?Le(c.scroller,"dblclick",Fb(a,function(b){if(!Re(a,b)){var c=Rb(a,b);if(c&&!Xb(a,b)&&!Qb(a.display,b)){Fe(b);var d=Yc(le(a.doc,c.line).text,c);Jc(a.doc,d.from,d.to)}}})):Le(c.scroller,"dblclick",function(b){Re(a,b)||Fe(b)}),Le(c.lineSpace,"selectstart",function(a){Qb(c,a)||Fe(a)}),u||Le(c.scroller,"contextmenu",function(b){pc(a,b)}),Le(c.scroller,"scroll",function(){c.scroller.clientHeight&&(_b(a,c.scroller.scrollTop),ac(a,c.scroller.scrollLeft,!0),Ne(a,"scroll",a))}),Le(c.scrollbarV,"scroll",function(){c.scroller.clientHeight&&_b(a,c.scrollbarV.scrollTop)}),Le(c.scrollbarH,"scroll",function(){c.scroller.clientHeight&&ac(a,c.scrollbarH.scrollLeft)}),Le(c.scroller,"mousewheel",function(b){dc(a,b)}),Le(c.scroller,"DOMMouseScroll",function(b){dc(a,b)}),Le(c.scrollbarH,"mousedown",e),Le(c.scrollbarV,"mousedown",e),Le(c.wrapper,"scroll",function(){c.wrapper.scrollTop=c.wrapper.scrollLeft=0});var g;Le(window,"resize",h),setTimeout(i,5e3),Le(c.input,"keyup",Fb(a,function(b){Re(a,b)||a.options.onKeyEvent&&a.options.onKeyEvent(a,Ee(b))||16==b.keyCode&&(a.doc.sel.shift=!1)})),Le(c.input,"input",function(){b&&!d&&a.display.inputHasSelection&&(a.display.inputHasSelection=null),Kb(a)}),Le(c.input,"keydown",Fb(a,kc)),Le(c.input,"keypress",Fb(a,lc)),Le(c.input,"focus",ff(mc,a)),Le(c.input,"blur",ff(nc,a)),a.options.dragDrop&&(Le(c.scroller,"dragstart",function(b){$b(a,b)}),Le(c.scroller,"dragenter",j),Le(c.scroller,"dragover",j),Le(c.scroller,"drop",Fb(a,Zb))),Le(c.scroller,"paste",function(b){Qb(c,b)||(Nb(a),Kb(a))}),Le(c.input,"paste",function(){if(f&&!a.state.fakedLastChar&&!(new Date-a.state.lastMiddleDown<200)){var b=c.input.selectionStart,d=c.input.selectionEnd;c.input.value+="$",c.input.selectionStart=b,c.input.selectionEnd=d,a.state.fakedLastChar=!0}a.state.pasteIncoming=!0,Kb(a)}),Le(c.input,"cut",l),Le(c.input,"copy",l),k&&Le(c.sizer,"mouseup",function(){document.activeElement==c.input&&c.input.blur(),Nb(a)})}function Qb(a,b){for(var c=Je(b);c!=a.wrapper;c=c.parentNode)if(!c||c.ignoreEvents||c.parentNode==a.sizer&&c!=a.mover)return!0}function Rb(a,b,c){var d=a.display;if(!c){var e=Je(b);if(e==d.scrollbarH||e==d.scrollbarH.firstChild||e==d.scrollbarV||e==d.scrollbarV.firstChild||e==d.scrollbarFiller||e==d.gutterFiller)return null}var f,g,h=pf(d.lineSpace);try{f=b.clientX,g=b.clientY}catch(b){return null}return xb(a,f-h.left,g-h.top)}function Ub(a){function q(a){if(!Cc(p,a)){if(p=a,"single"==j)return Jc(c.doc,Gc(e,h),a),void 0;if(n=Gc(e,n),o=Gc(e,o),"double"==j){var b=Yc(le(e,a.line).text,a);Dc(a,n)?Jc(c.doc,b.from,o):Jc(c.doc,n,b.to)
+}else"triple"==j&&(Dc(a,n)?Jc(c.doc,o,Gc(e,Bc(a.line,0))):Jc(c.doc,n,Gc(e,Bc(a.line+1,0))))}}function t(a){var b=++s,f=Rb(c,a,!0);if(f)if(Cc(f,l)){var h=a.clientY<r.top?-20:a.clientY>r.bottom?20:0;h&&setTimeout(Fb(c,function(){s==b&&(d.scroller.scrollTop+=h,t(a))}),50)}else{c.state.focused||mc(c),l=f,q(f);var g=L(d,e);(f.line>=g.to||f.line<g.from)&&setTimeout(Fb(c,function(){s==b&&t(a)}),150)}}function v(a){s=1/0,Fe(a),Nb(c),Me(document,"mousemove",w),Me(document,"mouseup",x)}if(!Re(this,a)){var c=this,d=c.display,e=c.doc,g=e.sel;if(g.shift=a.shiftKey,Qb(d,a))return f||(d.scroller.draggable=!1,setTimeout(function(){d.scroller.draggable=!0},100)),void 0;if(!Xb(c,a)){var h=Rb(c,a);switch(Ke(a)){case 3:return u&&pc.call(c,c,a),void 0;case 2:return f&&(c.state.lastMiddleDown=+new Date),h&&Jc(c.doc,h),setTimeout(ff(Nb,c),20),Fe(a),void 0}if(!h)return Je(a)==d.scroller&&Fe(a),void 0;c.state.focused||mc(c);var i=+new Date,j="single";if(Tb&&Tb.time>i-400&&Cc(Tb.pos,h))j="triple",Fe(a),setTimeout(ff(Nb,c),20),Zc(c,h.line);else if(Sb&&Sb.time>i-400&&Cc(Sb.pos,h)){j="double",Tb={time:i,pos:h},Fe(a);var k=Yc(le(e,h.line).text,h);Jc(c.doc,k.from,k.to)}else Sb={time:i,pos:h};var l=h;if(c.options.dragDrop&&qf&&!Ob(c)&&!Cc(g.from,g.to)&&!Dc(h,g.from)&&!Dc(g.to,h)&&"single"==j){var m=Fb(c,function(b){f&&(d.scroller.draggable=!1),c.state.draggingText=!1,Me(document,"mouseup",m),Me(d.scroller,"drop",m),Math.abs(a.clientX-b.clientX)+Math.abs(a.clientY-b.clientY)<10&&(Fe(b),Jc(c.doc,h),Nb(c))});return f&&(d.scroller.draggable=!0),c.state.draggingText=m,d.scroller.dragDrop&&d.scroller.dragDrop(),Le(document,"mouseup",m),Le(d.scroller,"drop",m),void 0}Fe(a),"single"==j&&Jc(c.doc,Gc(e,h));var n=g.from,o=g.to,p=h,r=pf(d.wrapper),s=0,w=Fb(c,function(a){b||Ke(a)?t(a):v(a)}),x=Fb(c,v);Le(document,"mousemove",w),Le(document,"mouseup",x)}}}function Vb(a,b,c,d,e){try{var f=b.clientX,g=b.clientY}catch(b){return!1}if(f>=Math.floor(pf(a.display.gutters).right))return!1;d&&Fe(b);var h=a.display,i=pf(h.lineDiv);if(g>i.bottom||!Te(a,c))return He(b);g-=i.top-h.viewOffset;for(var j=0;j<a.options.gutters.length;++j){var k=h.gutters.childNodes[j];if(k&&pf(k).right>=f){var l=qe(a.doc,g),m=a.options.gutters[j];return e(a,c,a,l,m,b),He(b)}}}function Wb(a,b){return Te(a,"gutterContextMenu")?Vb(a,b,"gutterContextMenu",!1,Ne):!1}function Xb(a,b){return Vb(a,b,"gutterClick",!0,Qe)}function Zb(a){var c=this;if(!(Re(c,a)||Qb(c.display,a)||c.options.onDragEvent&&c.options.onDragEvent(c,Ee(a)))){Fe(a),b&&(Yb=+new Date);var d=Rb(c,a,!0),e=a.dataTransfer.files;if(d&&!Ob(c))if(e&&e.length&&window.FileReader&&window.File)for(var f=e.length,g=Array(f),h=0,i=function(a,b){var e=new FileReader;e.onload=function(){g[b]=e.result,++h==f&&(d=Gc(c.doc,d),uc(c.doc,{from:d,to:d,text:wf(g.join("\n")),origin:"paste"},"around"))},e.readAsText(a)},j=0;f>j;++j)i(e[j],j);else{if(c.state.draggingText&&!Dc(d,c.doc.sel.from)&&!Dc(c.doc.sel.to,d))return c.state.draggingText(a),setTimeout(ff(Nb,c),20),void 0;try{var g=a.dataTransfer.getData("Text");if(g){var k=c.doc.sel.from,l=c.doc.sel.to;Lc(c.doc,d,d),c.state.draggingText&&Ac(c.doc,"",k,l,"paste"),c.replaceSelection(g,null,"paste"),Nb(c),mc(c)}}catch(a){}}}}function $b(a,c){if(b&&(!a.state.draggingText||+new Date-Yb<100))return Ie(c),void 0;if(!Re(a,c)&&!Qb(a.display,c)){var d=a.getSelection();if(c.dataTransfer.setData("Text",d),c.dataTransfer.setDragImage&&!j){var e=lf("img",null,null,"position: fixed; left: 0; top: 0;");e.src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==",i&&(e.width=e.height=1,a.display.wrapper.appendChild(e),e._top=e.offsetTop),c.dataTransfer.setDragImage(e,0,0),i&&e.parentNode.removeChild(e)}}}function _b(b,c){Math.abs(b.doc.scrollTop-c)<2||(b.doc.scrollTop=c,a||Q(b,[],c),b.display.scroller.scrollTop!=c&&(b.display.scroller.scrollTop=c),b.display.scrollbarV.scrollTop!=c&&(b.display.scrollbarV.scrollTop=c),a&&Q(b,[]),bb(b,100))}function ac(a,b,c){(c?b==a.doc.scrollLeft:Math.abs(a.doc.scrollLeft-b)<2)||(b=Math.min(b,a.display.scroller.scrollWidth-a.display.scroller.clientWidth),a.doc.scrollLeft=b,M(a),a.display.scroller.scrollLeft!=b&&(a.display.scroller.scrollLeft=b),a.display.scrollbarH.scrollLeft!=b&&(a.display.scrollbarH.scrollLeft=b))}function dc(b,c){var d=c.wheelDeltaX,e=c.wheelDeltaY;null==d&&c.detail&&c.axis==c.HORIZONTAL_AXIS&&(d=c.detail),null==e&&c.detail&&c.axis==c.VERTICAL_AXIS?e=c.detail:null==e&&(e=c.wheelDelta);var g=b.display,h=g.scroller;if(d&&h.scrollWidth>h.clientWidth||e&&h.scrollHeight>h.clientHeight){if(e&&q&&f)for(var j=c.target;j!=h;j=j.parentNode)if(j.lineObj){b.display.currentWheelTarget=j;break}if(d&&!a&&!i&&null!=cc)return e&&_b(b,Math.max(0,Math.min(h.scrollTop+e*cc,h.scrollHeight-h.clientHeight))),ac(b,Math.max(0,Math.min(h.scrollLeft+d*cc,h.scrollWidth-h.clientWidth))),Fe(c),g.wheelStartX=null,void 0;if(e&&null!=cc){var k=e*cc,l=b.doc.scrollTop,m=l+g.wrapper.clientHeight;0>k?l=Math.max(0,l+k-50):m=Math.min(b.doc.height,m+k+50),Q(b,[],{top:l,bottom:m})}20>bc&&(null==g.wheelStartX?(g.wheelStartX=h.scrollLeft,g.wheelStartY=h.scrollTop,g.wheelDX=d,g.wheelDY=e,setTimeout(function(){if(null!=g.wheelStartX){var a=h.scrollLeft-g.wheelStartX,b=h.scrollTop-g.wheelStartY,c=b&&g.wheelDY&&b/g.wheelDY||a&&g.wheelDX&&a/g.wheelDX;g.wheelStartX=g.wheelStartY=null,c&&(cc=(cc*bc+c)/(bc+1),++bc)}},200)):(g.wheelDX+=d,g.wheelDY+=e))}}function ec(a,b,c){if("string"==typeof b&&(b=jd[b],!b))return!1;a.display.pollingFast&&Lb(a)&&(a.display.pollingFast=!1);var d=a.doc,e=d.sel.shift,f=!1;try{Ob(a)&&(a.state.suppressEdits=!0),c&&(d.sel.shift=!1),f=b(a)!=We}finally{d.sel.shift=e,a.state.suppressEdits=!1}return f}function fc(a){var b=a.state.keyMaps.slice(0);return a.options.extraKeys&&b.push(a.options.extraKeys),b.push(a.options.keyMap),b}function hc(a,b){var c=ld(a.options.keyMap),e=c.auto;clearTimeout(gc),e&&!nd(b)&&(gc=setTimeout(function(){ld(a.options.keyMap)==c&&(a.options.keyMap=e.call?e.call(null,a):e,D(a))},50));var f=od(b,!0),g=!1;if(!f)return!1;var h=fc(a);return g=b.shiftKey?md("Shift-"+f,h,function(b){return ec(a,b,!0)})||md(f,h,function(b){return("string"==typeof b?/^go[A-Z]/.test(b):b.motion)?ec(a,b):void 0}):md(f,h,function(b){return ec(a,b)}),g&&(Fe(b),ab(a),d&&(b.oldKeyCode=b.keyCode,b.keyCode=0),Qe(a,"keyHandled",a,f,b)),g}function ic(a,b,c){var d=md("'"+c+"'",fc(a),function(b){return ec(a,b,!0)});return d&&(Fe(b),ab(a),Qe(a,"keyHandled",a,"'"+c+"'",b)),d}function kc(a){var c=this;if(c.state.focused||mc(c),!(Re(c,a)||c.options.onKeyEvent&&c.options.onKeyEvent(c,Ee(a)))){b&&27==a.keyCode&&(a.returnValue=!1);var d=a.keyCode;c.doc.sel.shift=16==d||a.shiftKey;var e=hc(c,a);i&&(jc=e?d:null,!e&&88==d&&!yf&&(q?a.metaKey:a.ctrlKey)&&c.replaceSelection(""))}}function lc(a){var c=this;if(!(Re(c,a)||c.options.onKeyEvent&&c.options.onKeyEvent(c,Ee(a)))){var e=a.keyCode,f=a.charCode;if(i&&e==jc)return jc=null,Fe(a),void 0;if(!(i&&(!a.which||a.which<10)||k)||!hc(c,a)){var g=String.fromCharCode(null==f?e:f);this.options.electricChars&&this.doc.mode.electricChars&&this.options.smartIndent&&!Ob(this)&&this.doc.mode.electricChars.indexOf(g)>-1&&setTimeout(Fb(c,function(){Uc(c,c.doc.sel.to.line,"smart")}),75),ic(c,a,g)||(b&&!d&&(c.display.inputHasSelection=null),Kb(c))}}}function mc(a){"nocursor"!=a.options.readOnly&&(a.state.focused||(Ne(a,"focus",a),a.state.focused=!0,-1==a.display.wrapper.className.search(/\bCodeMirror-focused\b/)&&(a.display.wrapper.className+=" CodeMirror-focused"),a.curOp||(Mb(a,!0),f&&setTimeout(ff(Mb,a,!0),0))),Jb(a),ab(a))}function nc(a){a.state.focused&&(Ne(a,"blur",a),a.state.focused=!1,a.display.wrapper.className=a.display.wrapper.className.replace(" CodeMirror-focused","")),clearInterval(a.display.blinker),setTimeout(function(){a.state.focused||(a.doc.sel.shift=!1)},150)}function pc(a,c){function l(){if(null!=e.input.selectionStart){var a=e.input.value="\u200b"+(Cc(f.from,f.to)?"":e.input.value);e.prevInput="\u200b",e.input.selectionStart=1,e.input.selectionEnd=a.length}}function m(){if(e.inputDiv.style.position="relative",e.input.style.cssText=k,d&&(e.scrollbarV.scrollTop=e.scroller.scrollTop=h),Jb(a),null!=e.input.selectionStart){(!b||d)&&l(),clearTimeout(oc);var c=0,f=function(){" "==e.prevInput&&0==e.input.selectionStart?Fb(a,jd.selectAll)(a):c++<10?oc=setTimeout(f,500):Mb(a)};oc=setTimeout(f,200)}}if(!Re(a,c,"contextmenu")){var e=a.display,f=a.doc.sel;if(!Qb(e,c)&&!Wb(a,c)){var g=Rb(a,c),h=e.scroller.scrollTop;if(g&&!i){var j=a.options.resetSelectionOnContextMenu;j&&(Cc(f.from,f.to)||Dc(g,f.from)||!Dc(g,f.to))&&Fb(a,Lc)(a.doc,g,g);var k=e.input.style.cssText;if(e.inputDiv.style.position="absolute",e.input.style.cssText="position: fixed; width: 30px; height: 30px; top: "+(c.clientY-5)+"px; left: "+(c.clientX-5)+"px; z-index: 1000; background: white; outline: none;"+"border-width: 0; outline: none; overflow: hidden; opacity: .05; -ms-opacity: .05; filter: alpha(opacity=5);",Nb(a),Mb(a,!0),Cc(f.from,f.to)&&(e.input.value=e.prevInput=" "),b&&!d&&l(),u){Ie(c);var n=function(){Me(window,"mouseup",n),setTimeout(m,20)};Le(window,"mouseup",n)}else setTimeout(m,50)}}}}function rc(a,b,c){if(!Dc(b.from,c))return Gc(a,c);var d=b.text.length-1-(b.to.line-b.from.line);if(c.line>b.to.line+d){var e=c.line-d,f=a.first+a.size-1;return e>f?Bc(f,le(a,f).text.length):Hc(c,le(a,e).text.length)}if(c.line==b.to.line+d)return Hc(c,_e(b.text).length+(1==b.text.length?b.from.ch:0)+le(a,b.to.line).text.length-b.to.ch);var g=c.line-b.from.line;return Hc(c,b.text[g].length+(g?0:b.from.ch))}function sc(a,b,c){if(c&&"object"==typeof c)return{anchor:rc(a,b,c.anchor),head:rc(a,b,c.head)};if("start"==c)return{anchor:b.from,head:b.from};var d=qc(b);if("around"==c)return{anchor:b.from,head:d};if("end"==c)return{anchor:d,head:d};var e=function(a){if(Dc(a,b.from))return a;if(!Dc(b.to,a))return d;var c=a.line+b.text.length-(b.to.line-b.from.line)-1,e=a.ch;return a.line==b.to.line&&(e+=d.ch-b.to.ch),Bc(c,e)};return{anchor:e(a.sel.anchor),head:e(a.sel.head)}}function tc(a,b,c){var d={canceled:!1,from:b.from,to:b.to,text:b.text,origin:b.origin,cancel:function(){this.canceled=!0}};return c&&(d.update=function(b,c,d,e){b&&(this.from=Gc(a,b)),c&&(this.to=Gc(a,c)),d&&(this.text=d),void 0!==e&&(this.origin=e)}),Ne(a,"beforeChange",a,d),a.cm&&Ne(a.cm,"beforeChange",a.cm,d),d.canceled?null:{from:d.from,to:d.to,text:d.text,origin:d.origin}}function uc(a,b,c,d){if(a.cm){if(!a.cm.curOp)return Fb(a.cm,uc)(a,b,c,d);if(a.cm.state.suppressEdits)return}if(!(Te(a,"beforeChange")||a.cm&&Te(a.cm,"beforeChange"))||(b=tc(a,b,!0))){var e=v&&!d&&Bd(a,b.from,b.to);if(e){for(var f=e.length-1;f>=1;--f)vc(a,{from:e[f].from,to:e[f].to,text:[""]});e.length&&vc(a,{from:e[0].from,to:e[0].to,text:b.text},c)}else vc(a,b,c)}}function vc(a,b,c){if(1!=b.text.length||""!=b.text[0]||!Cc(b.from,b.to)){var d=sc(a,b,c);we(a,b,d,a.cm?a.cm.curOp.id:0/0),yc(a,b,d,zd(a,b));var e=[];je(a,function(a,c){c||-1!=bf(e,a.history)||(Ce(a.history,b),e.push(a.history)),yc(a,b,null,zd(a,b))})}}function wc(a,b){if(!a.cm||!a.cm.state.suppressEdits){var c=a.history,d=("undo"==b?c.done:c.undone).pop();if(d){var e={changes:[],anchorBefore:d.anchorAfter,headBefore:d.headAfter,anchorAfter:d.anchorBefore,headAfter:d.headBefore,generation:c.generation};("undo"==b?c.undone:c.done).push(e),c.generation=d.generation||++c.maxGeneration;for(var f=Te(a,"beforeChange")||a.cm&&Te(a.cm,"beforeChange"),g=d.changes.length-1;g>=0;--g){var h=d.changes[g];if(h.origin=b,f&&!tc(a,h,!1))return("undo"==b?c.done:c.undone).length=0,void 0;e.changes.push(ve(a,h));var i=g?sc(a,h,null):{anchor:d.anchorBefore,head:d.headBefore};yc(a,h,i,Ad(a,h));var j=[];je(a,function(a,b){b||-1!=bf(j,a.history)||(Ce(a.history,h),j.push(a.history)),yc(a,h,null,Ad(a,h))})}}}}function xc(a,b){function c(a){return Bc(a.line+b,a.ch)}a.first+=b,a.cm&&Ib(a.cm,a.first,a.first,b),a.sel.head=c(a.sel.head),a.sel.anchor=c(a.sel.anchor),a.sel.from=c(a.sel.from),a.sel.to=c(a.sel.to)}function yc(a,b,c,d){if(a.cm&&!a.cm.curOp)return Fb(a.cm,yc)(a,b,c,d);if(b.to.line<a.first)return xc(a,b.text.length-1-(b.to.line-b.from.line)),void 0;if(!(b.from.line>a.lastLine())){if(b.from.line<a.first){var e=b.text.length-1-(a.first-b.from.line);xc(a,e),b={from:Bc(a.first,0),to:Bc(b.to.line+e,b.to.ch),text:[_e(b.text)],origin:b.origin}}var f=a.lastLine();b.to.line>f&&(b={from:b.from,to:Bc(f,le(a,f).text.length),text:[b.text[0]],origin:b.origin}),b.removed=me(a,b.from,b.to),c||(c=sc(a,b,null)),a.cm?zc(a.cm,b,d,c):ce(a,b,d,c)}}function zc(a,b,c,d){var e=a.doc,f=a.display,g=b.from,h=b.to,i=!1,j=g.line;a.options.lineWrapping||(j=pe(Fd(e,le(e,g.line))),e.iter(j,h.line+1,function(a){return a==f.maxLine?(i=!0,!0):void 0})),Dc(e.sel.head,b.from)||Dc(b.to,e.sel.head)||(a.curOp.cursorActivity=!0),ce(e,b,c,d,B(a)),a.options.lineWrapping||(e.iter(j,g.line+b.text.length,function(a){var b=H(e,a);b>f.maxLineLength&&(f.maxLine=a,f.maxLineLength=b,f.maxLineChanged=!0,i=!1)}),i&&(a.curOp.updateMaxLine=!0)),e.frontier=Math.min(e.frontier,g.line),bb(a,400);var k=b.text.length-(h.line-g.line)-1;if(Ib(a,g.line,h.line+1,k),Te(a,"change")){var l={from:g,to:h,text:b.text,removed:b.removed,origin:b.origin};if(a.curOp.textChanged){for(var m=a.curOp.textChanged;m.next;m=m.next);m.next=l}else a.curOp.textChanged=l}}function Ac(a,b,c,d,e){if(d||(d=c),Dc(d,c)){var f=d;d=c,c=f}"string"==typeof b&&(b=wf(b)),uc(a,{from:c,to:d,text:b,origin:e},null)}function Bc(a,b){return this instanceof Bc?(this.line=a,this.ch=b,void 0):new Bc(a,b)}function Cc(a,b){return a.line==b.line&&a.ch==b.ch}function Dc(a,b){return a.line<b.line||a.line==b.line&&a.ch<b.ch}function Ec(a){return Bc(a.line,a.ch)}function Fc(a,b){return Math.max(a.first,Math.min(b,a.first+a.size-1))}function Gc(a,b){if(b.line<a.first)return Bc(a.first,0);var c=a.first+a.size-1;return b.line>c?Bc(c,le(a,c).text.length):Hc(b,le(a,b.line).text.length)}function Hc(a,b){var c=a.ch;return null==c||c>b?Bc(a.line,b):0>c?Bc(a.line,0):a}function Ic(a,b){return b>=a.first&&b<a.first+a.size}function Jc(a,b,c,d){if(a.sel.shift||a.sel.extend){var e=a.sel.anchor;if(c){var f=Dc(b,e);f!=Dc(c,e)?(e=b,b=c):f!=Dc(b,c)&&(b=c)}Lc(a,e,b,d)}else Lc(a,b,c||b,d);a.cm&&(a.cm.curOp.userSelChange=!0)}function Kc(a,b,c){var d={anchor:b,head:c};return Ne(a,"beforeSelectionChange",a,d),a.cm&&Ne(a.cm,"beforeSelectionChange",a.cm,d),d.anchor=Gc(a,d.anchor),d.head=Gc(a,d.head),d}function Lc(a,b,c,d,e){if(!e&&Te(a,"beforeSelectionChange")||a.cm&&Te(a.cm,"beforeSelectionChange")){var f=Kc(a,b,c);c=f.head,b=f.anchor}var g=a.sel;if(g.goalColumn=null,null==d&&(d=Dc(c,g.head)?-1:1),(e||!Cc(b,g.anchor))&&(b=Nc(a,b,d,"push"!=e)),(e||!Cc(c,g.head))&&(c=Nc(a,c,d,"push"!=e)),!Cc(g.anchor,b)||!Cc(g.head,c)){g.anchor=b,g.head=c;var h=Dc(c,b);g.from=h?c:b,g.to=h?b:c,a.cm&&(a.cm.curOp.updateInput=a.cm.curOp.selectionChanged=a.cm.curOp.cursorActivity=!0),Qe(a,"cursorActivity",a)}}function Mc(a){Lc(a.doc,a.doc.sel.from,a.doc.sel.to,null,"push")}function Nc(a,b,c,d){var e=!1,f=b,g=c||1;a.cantEdit=!1;a:for(;;){var h=le(a,f.line);if(h.markedSpans)for(var i=0;i<h.markedSpans.length;++i){var j=h.markedSpans[i],k=j.marker;if((null==j.from||(k.inclusiveLeft?j.from<=f.ch:j.from<f.ch))&&(null==j.to||(k.inclusiveRight?j.to>=f.ch:j.to>f.ch))){if(d&&(Ne(k,"beforeCursorEnter"),k.explicitlyCleared)){if(h.markedSpans){--i;continue}break}if(!k.atomic)continue;var l=k.find()[0>g?"from":"to"];if(Cc(l,f)&&(l.ch+=g,l.ch<0?l=l.line>a.first?Gc(a,Bc(l.line-1)):null:l.ch>h.text.length&&(l=l.line<a.first+a.size-1?Bc(l.line+1,0):null),!l)){if(e)return d?(a.cantEdit=!0,Bc(a.first,0)):Nc(a,b,c,!0);e=!0,l=b,g=-g}f=l;continue a}}return f}}function Oc(a){var b=Pc(a,a.doc.sel.head,null,a.options.cursorScrollMargin);if(a.state.focused){var c=a.display,d=pf(c.sizer),e=null;if(b.top+d.top<0?e=!0:b.bottom+d.top>(window.innerHeight||document.documentElement.clientHeight)&&(e=!1),null!=e&&!n){var f="none"==c.cursor.style.display;f&&(c.cursor.style.display="",c.cursor.style.left=b.left+"px",c.cursor.style.top=b.top-c.viewOffset+"px"),c.cursor.scrollIntoView(e),f&&(c.cursor.style.display="none")}}}function Pc(a,b,c,d){for(null==d&&(d=0);;){var e=!1,f=vb(a,b),g=c&&c!=b?vb(a,c):f,h=Rc(a,Math.min(f.left,g.left),Math.min(f.top,g.top)-d,Math.max(f.left,g.left),Math.max(f.bottom,g.bottom)+d),i=a.doc.scrollTop,j=a.doc.scrollLeft;if(null!=h.scrollTop&&(_b(a,h.scrollTop),Math.abs(a.doc.scrollTop-i)>1&&(e=!0)),null!=h.scrollLeft&&(ac(a,h.scrollLeft),Math.abs(a.doc.scrollLeft-j)>1&&(e=!0)),!e)return f}}function Qc(a,b,c,d,e){var f=Rc(a,b,c,d,e);null!=f.scrollTop&&_b(a,f.scrollTop),null!=f.scrollLeft&&ac(a,f.scrollLeft)}function Rc(a,b,c,d,e){var f=a.display,g=Ab(a.display);0>c&&(c=0);var h=f.scroller.clientHeight-Ve,i=f.scroller.scrollTop,j={},k=a.doc.height+gb(f),l=g>c,m=e>k-g;if(i>c)j.scrollTop=l?0:c;else if(e>i+h){var n=Math.min(c,(m?k:e)-h);n!=i&&(j.scrollTop=n)}var o=f.scroller.clientWidth-Ve,p=f.scroller.scrollLeft;b+=f.gutters.offsetWidth,d+=f.gutters.offsetWidth;var q=f.gutters.offsetWidth,r=q+10>b;return p+q>b||r?(r&&(b=0),j.scrollLeft=Math.max(0,b-10-q)):d>o+p-3&&(j.scrollLeft=d+10-o),j}function Sc(a,b,c){a.curOp.updateScrollPos={scrollLeft:null==b?a.doc.scrollLeft:b,scrollTop:null==c?a.doc.scrollTop:c}}function Tc(a,b,c){var d=a.curOp.updateScrollPos||(a.curOp.updateScrollPos={scrollLeft:a.doc.scrollLeft,scrollTop:a.doc.scrollTop}),e=a.display.scroller;d.scrollTop=Math.max(0,Math.min(e.scrollHeight-e.clientHeight,d.scrollTop+c)),d.scrollLeft=Math.max(0,Math.min(e.scrollWidth-e.clientWidth,d.scrollLeft+b))}function Uc(a,b,c,d){var e=a.doc;if(null==c&&(c="add"),"smart"==c)if(a.doc.mode.indent)var f=eb(a,b);else c="prev";var k,g=a.options.tabSize,h=le(e,b),i=Ye(h.text,null,g),j=h.text.match(/^\s*/)[0];if("smart"==c&&(k=a.doc.mode.indent(f,h.text.slice(j.length),h.text),k==We)){if(!d)return;c="prev"}"prev"==c?k=b>e.first?Ye(le(e,b-1).text,null,g):0:"add"==c?k=i+a.options.indentUnit:"subtract"==c?k=i-a.options.indentUnit:"number"==typeof c&&(k=i+c),k=Math.max(0,k);var l="",m=0;if(a.options.indentWithTabs)for(var n=Math.floor(k/g);n;--n)m+=g,l+=" ";k>m&&(l+=$e(k-m)),l!=j?Ac(a.doc,l,Bc(b,0),Bc(b,j.length),"+input"):e.sel.head.line==b&&e.sel.head.ch<j.length&&Lc(e,Bc(b,j.length),Bc(b,j.length),1),h.stateAfter=null}function Vc(a,b,c){var d=b,e=b,f=a.doc;return"number"==typeof b?e=le(f,Fc(f,b)):d=pe(b),null==d?null:c(e,d)?(Ib(a,d,d+1),e):null}function Wc(a,b,c,d,e){function k(){var b=f+c;return b<a.first||b>=a.first+a.size?j=!1:(f=b,i=le(a,b))}function l(a){var b=(e?Lf:Mf)(i,g,c,!0);if(null==b){if(a||!k())return j=!1;g=e?(0>c?Ef:Df)(i):0>c?i.text.length:0}else g=b;return!0}var f=b.line,g=b.ch,h=c,i=le(a,f),j=!0;if("char"==d)l();else if("column"==d)l(!0);else if("word"==d||"group"==d)for(var m=null,n="group"==d,o=!0;!(0>c)||l(!o);o=!1){var p=i.text.charAt(g)||"\n",q=hf(p)?"w":n?/\s/.test(p)?null:"p":null;if(m&&m!=q){0>c&&(c=1,l());break}if(q&&(m=q),c>0&&!l(!o))break}var r=Nc(a,Bc(f,g),h,!0);return j||(r.hitSide=!0),r}function Xc(a,b,c,d){var g,e=a.doc,f=b.left;if("page"==d){var h=Math.min(a.display.wrapper.clientHeight,window.innerHeight||document.documentElement.clientHeight);g=b.top+c*(h-(0>c?1.5:.5)*Ab(a.display))}else"line"==d&&(g=c>0?b.bottom+3:b.top-3);for(;;){var i=xb(a,f,g);if(!i.outside)break;if(0>c?0>=g:g>=e.height){i.hitSide=!0;break}g+=5*c}return i}function Yc(a,b){var c=b.ch,d=b.ch;if(a){(b.xRel<0||d==a.length)&&c?--c:++d;for(var e=a.charAt(c),f=hf(e)?hf:/\s/.test(e)?function(a){return/\s/.test(a)}:function(a){return!/\s/.test(a)&&!hf(a)};c>0&&f(a.charAt(c-1));)--c;for(;d<a.length&&f(a.charAt(d));)++d}return{from:Bc(b.line,c),to:Bc(b.line,d)}}function Zc(a,b){Jc(a.doc,Bc(b,0),Gc(a.doc,Bc(b+1,0)))}function ad(a,b,c,d){x.defaults[a]=b,c&&($c[a]=d?function(a,b,d){d!=bd&&c(a,b,d)}:c)}function hd(a,b){if(b===!0)return b;if(a.copyState)return a.copyState(b);var c={};for(var d in b){var e=b[d];e instanceof Array&&(e=e.concat([])),c[d]=e}return c}function id(a,b,c){return a.startState?a.startState(b,c):!0}function ld(a){return"string"==typeof a?kd[a]:a}function md(a,b,c){function d(b){b=ld(b);var e=b[a];if(e===!1)return"stop";if(null!=e&&c(e))return!0;if(b.nofallthrough)return"stop";var f=b.fallthrough;if(null==f)return!1;if("[object Array]"!=Object.prototype.toString.call(f))return d(f);for(var g=0,h=f.length;h>g;++g){var i=d(f[g]);if(i)return i}return!1}for(var e=0;e<b.length;++e){var f=d(b[e]);if(f)return"stop"!=f}}function nd(a){var b=zf[a.keyCode];return"Ctrl"==b||"Alt"==b||"Shift"==b||"Mod"==b}function od(a,b){if(i&&34==a.keyCode&&a["char"])return!1;var c=zf[a.keyCode];return null==c||a.altGraphKey?!1:(a.altKey&&(c="Alt-"+c),(t?a.metaKey:a.ctrlKey)&&(c="Ctrl-"+c),(t?a.ctrlKey:a.metaKey)&&(c="Cmd-"+c),!b&&a.shiftKey&&(c="Shift-"+c),c)}function pd(a,b){this.pos=this.start=0,this.string=a,this.tabSize=b||8,this.lastColumnPos=this.lastColumnValue=0}function qd(a,b){this.lines=[],this.type=b,this.doc=a}function rd(a,b,c,d,e){if(d&&d.shared)return td(a,b,c,d,e);if(a.cm&&!a.cm.curOp)return Fb(a.cm,rd)(a,b,c,d,e);var f=new qd(a,e);if(Dc(c,b)||Cc(b,c)&&"range"==e&&(!d.inclusiveLeft||!d.inclusiveRight))return f;d&&df(d,f),f.replacedWith&&(f.collapsed=!0,f.replacedWith=lf("span",[f.replacedWith],"CodeMirror-widget"),d.handleMouseEvents||(f.replacedWith.ignoreEvents=!0)),f.collapsed&&(w=!0),f.addToHistory&&we(a,{from:b,to:c,origin:"markText"},{head:a.sel.head,anchor:a.sel.anchor},0/0);var i,j,l,g=b.line,h=0,k=a.cm;if(a.iter(g,c.line+1,function(d){k&&f.collapsed&&!k.options.lineWrapping&&Fd(a,d)==k.display.maxLine&&(l=!0);var e={from:null,to:null,marker:f};h+=d.text.length,g==b.line&&(e.from=b.ch,h-=b.ch),g==c.line&&(e.to=c.ch,h-=d.text.length-c.ch),f.collapsed&&(g==c.line&&(j=Cd(d,c.ch)),g==b.line?i=Cd(d,b.ch):oe(d,0)),wd(d,e),++g}),f.collapsed&&a.iter(b.line,c.line+1,function(b){Gd(a,b)&&oe(b,0)}),f.clearOnEnter&&Le(f,"beforeCursorEnter",function(){f.clear()}),f.readOnly&&(v=!0,(a.history.done.length||a.history.undone.length)&&a.clearHistory()),f.collapsed){if(i!=j)throw new Error("Inserting collapsed marker overlapping an existing one");f.size=h,f.atomic=!0}return k&&(l&&(k.curOp.updateMaxLine=!0),(f.className||f.title||f.startStyle||f.endStyle||f.collapsed)&&Ib(k,b.line,c.line+1),f.atomic&&Mc(k)),f}function sd(a,b){this.markers=a,this.primary=b;for(var c=0,d=this;c<a.length;++c)a[c].parent=this,Le(a[c],"clear",function(){d.clear()})}function td(a,b,c,d,e){d=df(d),d.shared=!1;var f=[rd(a,b,c,d,e)],g=f[0],h=d.replacedWith;return je(a,function(a){h&&(d.replacedWith=h.cloneNode(!0)),f.push(rd(a,Gc(a,b),Gc(a,c),d,e));for(var i=0;i<a.linked.length;++i)if(a.linked[i].isParent)return;g=_e(f)}),new sd(f,g)}function ud(a,b){if(a)for(var c=0;c<a.length;++c){var d=a[c];if(d.marker==b)return d}}function vd(a,b){for(var c,d=0;d<a.length;++d)a[d]!=b&&(c||(c=[])).push(a[d]);return c}function wd(a,b){a.markedSpans=a.markedSpans?a.markedSpans.concat([b]):[b],b.marker.attachLine(a)}function xd(a,b,c){if(a)for(var e,d=0;d<a.length;++d){var f=a[d],g=f.marker,h=null==f.from||(g.inclusiveLeft?f.from<=b:f.from<b);if(h||(g.inclusiveLeft&&g.inclusiveRight||"bookmark"==g.type)&&f.from==b&&(!c||!f.marker.insertLeft)){var i=null==f.to||(g.inclusiveRight?f.to>=b:f.to>b);(e||(e=[])).push({from:f.from,to:i?null:f.to,marker:g})}}return e}function yd(a,b,c){if(a)for(var e,d=0;d<a.length;++d){var f=a[d],g=f.marker,h=null==f.to||(g.inclusiveRight?f.to>=b:f.to>b);if(h||"bookmark"==g.type&&f.from==b&&(!c||f.marker.insertLeft)){var i=null==f.from||(g.inclusiveLeft?f.from<=b:f.from<b);(e||(e=[])).push({from:i?null:f.from-b,to:null==f.to?null:f.to-b,marker:g})}}return e}function zd(a,b){var c=Ic(a,b.from.line)&&le(a,b.from.line).markedSpans,d=Ic(a,b.to.line)&&le(a,b.to.line).markedSpans;if(!c&&!d)return null;var e=b.from.ch,f=b.to.ch,g=Cc(b.from,b.to),h=xd(c,e,g),i=yd(d,f,g),j=1==b.text.length,k=_e(b.text).length+(j?e:0);if(h)for(var l=0;l<h.length;++l){var m=h[l];if(null==m.to){var n=ud(i,m.marker);n?j&&(m.to=null==n.to?null:n.to+k):m.to=e}}if(i)for(var l=0;l<i.length;++l){var m=i[l];if(null!=m.to&&(m.to+=k),null==m.from){var n=ud(h,m.marker);n||(m.from=k,j&&(h||(h=[])).push(m))}else m.from+=k,j&&(h||(h=[])).push(m)}if(j&&h){for(var l=0;l<h.length;++l)null!=h[l].from&&h[l].from==h[l].to&&"bookmark"!=h[l].marker.type&&h.splice(l--,1);h.length||(h=null)}var o=[h];if(!j){var q,p=b.text.length-2;if(p>0&&h)for(var l=0;l<h.length;++l)null==h[l].to&&(q||(q=[])).push({from:null,to:null,marker:h[l].marker});for(var l=0;p>l;++l)o.push(q);o.push(i)}return o}function Ad(a,b){var c=ye(a,b),d=zd(a,b);if(!c)return d;if(!d)return c;for(var e=0;e<c.length;++e){var f=c[e],g=d[e];if(f&&g)a:for(var h=0;h<g.length;++h){for(var i=g[h],j=0;j<f.length;++j)if(f[j].marker==i.marker)continue a;f.push(i)}else g&&(c[e]=g)}return c}function Bd(a,b,c){var d=null;if(a.iter(b.line,c.line+1,function(a){if(a.markedSpans)for(var b=0;b<a.markedSpans.length;++b){var c=a.markedSpans[b].marker;!c.readOnly||d&&-1!=bf(d,c)||(d||(d=[])).push(c)}}),!d)return null;for(var e=[{from:b,to:c}],f=0;f<d.length;++f)for(var g=d[f],h=g.find(),i=0;i<e.length;++i){var j=e[i];if(!Dc(j.to,h.from)&&!Dc(h.to,j.from)){var k=[i,1];(Dc(j.from,h.from)||!g.inclusiveLeft&&Cc(j.from,h.from))&&k.push({from:j.from,to:h.from}),(Dc(h.to,j.to)||!g.inclusiveRight&&Cc(j.to,h.to))&&k.push({from:h.to,to:j.to}),e.splice.apply(e,k),i+=k.length-1}}return e}function Cd(a,b){var d,c=w&&a.markedSpans;if(c)for(var e,f=0;f<c.length;++f)e=c[f],e.marker.collapsed&&(null==e.from||e.from<b)&&(null==e.to||e.to>b)&&(!d||d.width<e.marker.width)&&(d=e.marker);return d}function Dd(a){return Cd(a,-1)}function Ed(a){return Cd(a,a.text.length+1)}function Fd(a,b){for(var c;c=Dd(b);)b=le(a,c.find().from.line);return b}function Gd(a,b){var c=w&&b.markedSpans;if(c)for(var d,e=0;e<c.length;++e)if(d=c[e],d.marker.collapsed){if(null==d.from)return!0;if(!d.marker.replacedWith&&0==d.from&&d.marker.inclusiveLeft&&Hd(a,b,d))return!0}}function Hd(a,b,c){if(null==c.to){var d=c.marker.find().to,e=le(a,d.line);return Hd(a,e,ud(e.markedSpans,c.marker))}if(c.marker.inclusiveRight&&c.to==b.text.length)return!0;for(var f,g=0;g<b.markedSpans.length;++g)if(f=b.markedSpans[g],f.marker.collapsed&&!f.marker.replacedWith&&f.from==c.to&&(f.marker.inclusiveLeft||c.marker.inclusiveRight)&&Hd(a,b,f))return!0}function Id(a){var b=a.markedSpans;if(b){for(var c=0;c<b.length;++c)b[c].marker.detachLine(a);a.markedSpans=null}}function Jd(a,b){if(b){for(var c=0;c<b.length;++c)b[c].marker.attachLine(a);a.markedSpans=b}}function Ld(a){return function(){var b=!this.cm.curOp;b&&Db(this.cm);try{var c=a.apply(this,arguments)}finally{b&&Eb(this.cm)}return c}}function Md(a){return null!=a.height?a.height:(a.node.parentNode&&1==a.node.parentNode.nodeType||nf(a.cm.display.measure,lf("div",[a.node],null,"position: relative")),a.height=a.node.offsetHeight)}function Nd(a,b,c,d){var e=new Kd(a,c,d);return e.noHScroll&&(a.display.alignWidgets=!0),Vc(a,b,function(b){var c=b.widgets||(b.widgets=[]);if(null==e.insertAt?c.push(e):c.splice(Math.min(c.length-1,Math.max(0,e.insertAt)),0,e),e.line=b,!Gd(a.doc,b)||e.showIfHidden){var d=re(a,b)<a.doc.scrollTop;oe(b,b.height+Md(e)),d&&Tc(a,0,e.height)}return!0}),e}function Pd(a,b,c,d){a.text=b,a.stateAfter&&(a.stateAfter=null),a.styles&&(a.styles=null),null!=a.order&&(a.order=null),Id(a),Jd(a,c);var e=d?d(a):1;e!=a.height&&oe(a,e)}function Qd(a){a.parent=null,Id(a)}function Rd(a,b,c,d,e){var f=c.flattenSpans;null==f&&(f=a.options.flattenSpans);var j,g=0,h=null,i=new pd(b,a.options.tabSize);for(""==b&&c.blankLine&&c.blankLine(d);!i.eol();)i.pos>a.options.maxHighlightLength?(f=!1,i.pos=b.length,j=null):j=c.token(i,d),f&&h==j||(g<i.start&&e(i.start,h),g=i.start,h=j),i.start=i.pos;for(;g<i.pos;){var k=Math.min(i.pos,g+5e4);e(k,h),g=k}}function Sd(a,b,c){var d=[a.state.modeGen];Rd(a,b.text,a.doc.mode,c,function(a,b){d.push(a,b)});for(var e=0;e<a.state.overlays.length;++e){var f=a.state.overlays[e],g=1,h=0;Rd(a,b.text,f.mode,!0,function(a,b){for(var c=g;a>h;){var e=d[g];e>a&&d.splice(g,1,a,d[g+1],e),g+=2,h=Math.min(a,e)}if(b)if(f.opaque)d.splice(c,g-c,a,b),g=c+2;else for(;g>c;c+=2){var i=d[c+1];d[c+1]=i?i+" "+b:b}})}return d}function Td(a,b){return b.styles&&b.styles[0]==a.state.modeGen||(b.styles=Sd(a,b,b.stateAfter=eb(a,pe(b)))),b.styles}function Ud(a,b,c){var d=a.doc.mode,e=new pd(b.text,a.options.tabSize);for(""==b.text&&d.blankLine&&d.blankLine(c);!e.eol()&&e.pos<=a.options.maxHighlightLength;)d.token(e,c),e.start=e.pos}function Wd(a,b){if(!a)return null;for(;;){var c=a.match(/(?:^|\s)line-(background-)?(\S+)/);if(!c)break;a=a.slice(0,c.index)+a.slice(c.index+c[0].length);var d=c[1]?"bgClass":"textClass";null==b[d]?b[d]=c[2]:new RegExp("(?:^|s)"+c[2]+"(?:$|s)").test(b[d])||(b[d]+=" "+c[2])}return Vd[a]||(Vd[a]="cm-"+a.replace(/ +/g," cm-"))}function Xd(a,c,d,g){for(var h,i=c,j=!0;h=Dd(i);)i=le(a.doc,h.find().from.line);var k={pre:lf("pre"),col:0,pos:0,measure:null,measuredSomething:!1,cm:a,copyWidgets:g};do{i.text&&(j=!1),k.measure=i==c&&d,k.pos=0,k.addToken=k.measure?$d:Zd,(b||f)&&a.getOption("lineWrapping")&&(k.addToken=_d(k.addToken));var l=be(i,k,Td(a,i));d&&i==c&&!k.measuredSomething&&(d[0]=k.pre.appendChild(vf(a.display.measure)),k.measuredSomething=!0),l&&(i=le(a.doc,l.to.line))}while(l);!d||k.measuredSomething||d[0]||(d[0]=k.pre.appendChild(j?lf("span","\xa0"):vf(a.display.measure))),k.pre.firstChild||Gd(a.doc,c)||k.pre.appendChild(document.createTextNode("\xa0"));var m;if(d&&(b||e)&&(m=se(i))){var n=m.length-1;m[n].from==m[n].to&&--n;var o=m[n],p=m[n-1];if(o.from+1==o.to&&p&&o.level<p.level){var q=d[k.pos-1];q&&q.parentNode.insertBefore(q.measureRight=vf(a.display.measure),q.nextSibling)}}var r=k.textClass?k.textClass+" "+(c.textClass||""):c.textClass;return r&&(k.pre.className=r),Ne(a,"renderLine",a,c,k.pre),k}function Zd(a,b,c,d,e,f){if(b){if(Yd.test(b))for(var g=document.createDocumentFragment(),h=0;;){Yd.lastIndex=h;var i=Yd.exec(b),j=i?i.index-h:b.length-h;if(j&&(g.appendChild(document.createTextNode(b.slice(h,h+j))),a.col+=j),!i)break;if(h+=j+1," "==i[0]){var k=a.cm.options.tabSize,l=k-a.col%k;g.appendChild(lf("span",$e(l),"cm-tab")),a.col+=l}else{var m=lf("span","\u2022","cm-invalidchar");m.title="\\u"+i[0].charCodeAt(0).toString(16),g.appendChild(m),a.col+=1}}else{a.col+=b.length;var g=document.createTextNode(b)}if(c||d||e||a.measure){var n=c||"";d&&(n+=d),e&&(n+=e);var m=lf("span",[g],n);return f&&(m.title=f),a.pre.appendChild(m)}a.pre.appendChild(g)}}function $d(a,c,d,e,f){for(var g=a.cm.options.lineWrapping,h=0;h<c.length;++h){var i=c.charAt(h),j=0==h;i>="\ud800"&&"\udbff">i&&h<c.length-1?(i=c.slice(h,h+2),++h):h&&g&&rf(c,h)&&a.pre.appendChild(lf("wbr"));var k=a.measure[a.pos],l=a.measure[a.pos]=Zd(a,i,d,j&&e,h==c.length-1&&f);k&&(l.leftSide=k.leftSide||k),b&&g&&" "==i&&h&&!/\s/.test(c.charAt(h-1))&&h<c.length-1&&!/\s/.test(c.charAt(h+1))&&(l.style.whiteSpace="normal"),a.pos+=i.length}c.length&&(a.measuredSomething=!0)}function _d(a){function b(a){for(var b=" ",c=0;c<a.length-2;++c)b+=c%2?" ":"\xa0";return b+=" "}return function(c,d,e,f,g,h){return a(c,d.replace(/ {3,}/g,b),e,f,g,h)}}function ae(a,b,c,d){var e=!d&&c.replacedWith;if(e&&(a.copyWidgets&&(e=e.cloneNode(!0)),a.pre.appendChild(e),a.measure)){if(b)a.measure[a.pos]=e;else{var f=vf(a.cm.display.measure);if("bookmark"!=c.type||c.insertLeft){if(a.measure[a.pos])return;a.measure[a.pos]=a.pre.insertBefore(f,e)}else a.measure[a.pos]=a.pre.appendChild(f)}a.measuredSomething=!0}a.pos+=b}function be(a,b,c){var d=a.markedSpans,e=a.text,f=0;if(d)for(var k,m,n,o,p,q,h=e.length,i=0,g=1,j="",l=0;;){if(l==i){m=n=o=p="",q=null,l=1/0;for(var r=[],s=0;s<d.length;++s){var t=d[s],u=t.marker;t.from<=i&&(null==t.to||t.to>i)?(null!=t.to&&l>t.to&&(l=t.to,n=""),u.className&&(m+=" "+u.className),u.startStyle&&t.from==i&&(o+=" "+u.startStyle),u.endStyle&&t.to==l&&(n+=" "+u.endStyle),u.title&&!p&&(p=u.title),u.collapsed&&(!q||q.marker.size<u.size)&&(q=t)):t.from>i&&l>t.from&&(l=t.from),"bookmark"==u.type&&t.from==i&&u.replacedWith&&r.push(u)}if(q&&(q.from||0)==i&&(ae(b,(null==q.to?h:q.to)-i,q.marker,null==q.from),null==q.to))return q.marker.find();if(!q&&r.length)for(var s=0;s<r.length;++s)ae(b,0,r[s])
+}if(i>=h)break;for(var v=Math.min(h,l);;){if(j){var w=i+j.length;if(!q){var x=w>v?j.slice(0,v-i):j;b.addToken(b,x,k?k+m:m,o,i+x.length==l?n:"",p)}if(w>=v){j=j.slice(v-i),i=v;break}i=w,o=""}j=e.slice(f,f=c[g++]),k=Wd(c[g++],b)}}else for(var g=1;g<c.length;g+=2)b.addToken(b,e.slice(f,f=c[g]),Wd(c[g+1],b))}function ce(a,b,c,d,e){function f(a){return c?c[a]:null}function g(a,c,d){Pd(a,c,d,e),Qe(a,"change",a,b)}var h=b.from,i=b.to,j=b.text,k=le(a,h.line),l=le(a,i.line),m=_e(j),n=f(j.length-1),o=i.line-h.line;if(0==h.ch&&0==i.ch&&""==m){for(var p=0,q=j.length-1,r=[];q>p;++p)r.push(new Od(j[p],f(p),e));g(l,l.text,n),o&&a.remove(h.line,o),r.length&&a.insert(h.line,r)}else if(k==l)if(1==j.length)g(k,k.text.slice(0,h.ch)+m+k.text.slice(i.ch),n);else{for(var r=[],p=1,q=j.length-1;q>p;++p)r.push(new Od(j[p],f(p),e));r.push(new Od(m+k.text.slice(i.ch),n,e)),g(k,k.text.slice(0,h.ch)+j[0],f(0)),a.insert(h.line+1,r)}else if(1==j.length)g(k,k.text.slice(0,h.ch)+j[0]+l.text.slice(i.ch),f(0)),a.remove(h.line+1,o);else{g(k,k.text.slice(0,h.ch)+j[0],f(0)),g(l,m+l.text.slice(i.ch),n);for(var p=1,q=j.length-1,r=[];q>p;++p)r.push(new Od(j[p],f(p),e));o>1&&a.remove(h.line+1,o-1),a.insert(h.line+1,r)}Qe(a,"change",a,b),Lc(a,d.anchor,d.head,null,!0)}function de(a){this.lines=a,this.parent=null;for(var b=0,c=a.length,d=0;c>b;++b)a[b].parent=this,d+=a[b].height;this.height=d}function ee(a){this.children=a;for(var b=0,c=0,d=0,e=a.length;e>d;++d){var f=a[d];b+=f.chunkSize(),c+=f.height,f.parent=this}this.size=b,this.height=c,this.parent=null}function je(a,b,c){function d(a,e,f){if(a.linked)for(var g=0;g<a.linked.length;++g){var h=a.linked[g];if(h.doc!=e){var i=f&&h.sharedHist;(!c||i)&&(b(h.doc,i),d(h.doc,a,i))}}}d(a,null,!0)}function ke(a,b){if(b.cm)throw new Error("This document is already in use.");a.doc=b,b.cm=a,C(a),z(a),a.options.lineWrapping||I(a),a.options.mode=b.modeOption,Ib(a)}function le(a,b){for(b-=a.first;!a.lines;)for(var c=0;;++c){var d=a.children[c],e=d.chunkSize();if(e>b){a=d;break}b-=e}return a.lines[b]}function me(a,b,c){var d=[],e=b.line;return a.iter(b.line,c.line+1,function(a){var f=a.text;e==c.line&&(f=f.slice(0,c.ch)),e==b.line&&(f=f.slice(b.ch)),d.push(f),++e}),d}function ne(a,b,c){var d=[];return a.iter(b,c,function(a){d.push(a.text)}),d}function oe(a,b){for(var c=b-a.height,d=a;d;d=d.parent)d.height+=c}function pe(a){if(null==a.parent)return null;for(var b=a.parent,c=bf(b.lines,a),d=b.parent;d;b=d,d=d.parent)for(var e=0;d.children[e]!=b;++e)c+=d.children[e].chunkSize();return c+b.first}function qe(a,b){var c=a.first;a:do{for(var d=0,e=a.children.length;e>d;++d){var f=a.children[d],g=f.height;if(g>b){a=f;continue a}b-=g,c+=f.chunkSize()}return c}while(!a.lines);for(var d=0,e=a.lines.length;e>d;++d){var h=a.lines[d],i=h.height;if(i>b)break;b-=i}return c+d}function re(a,b){b=Fd(a.doc,b);for(var c=0,d=b.parent,e=0;e<d.lines.length;++e){var f=d.lines[e];if(f==b)break;c+=f.height}for(var g=d.parent;g;d=g,g=d.parent)for(var e=0;e<g.children.length;++e){var h=g.children[e];if(h==d)break;c+=h.height}return c}function se(a){var b=a.order;return null==b&&(b=a.order=Nf(a.text)),b}function te(a){return{done:[],undone:[],undoDepth:1/0,lastTime:0,lastOp:null,lastOrigin:null,generation:a||1,maxGeneration:a||1}}function ue(a,b,c,d){var e=b["spans_"+a.id],f=0;a.iter(Math.max(a.first,c),Math.min(a.first+a.size,d),function(c){c.markedSpans&&((e||(e=b["spans_"+a.id]={}))[f]=c.markedSpans),++f})}function ve(a,b){var c={line:b.from.line,ch:b.from.ch},d={from:c,to:qc(b),text:me(a,b.from,b.to)};return ue(a,d,b.from.line,b.to.line+1),je(a,function(a){ue(a,d,b.from.line,b.to.line+1)},!0),d}function we(a,b,c,d){var e=a.history;e.undone.length=0;var f=+new Date,g=_e(e.done);if(g&&(e.lastOp==d||e.lastOrigin==b.origin&&b.origin&&("+"==b.origin.charAt(0)&&a.cm&&e.lastTime>f-a.cm.options.historyEventDelay||"*"==b.origin.charAt(0)))){var h=_e(g.changes);Cc(b.from,b.to)&&Cc(b.from,h.to)?h.to=qc(b):g.changes.push(ve(a,b)),g.anchorAfter=c.anchor,g.headAfter=c.head}else for(g={changes:[ve(a,b)],generation:e.generation,anchorBefore:a.sel.anchor,headBefore:a.sel.head,anchorAfter:c.anchor,headAfter:c.head},e.done.push(g),e.generation=++e.maxGeneration;e.done.length>e.undoDepth;)e.done.shift();e.lastTime=f,e.lastOp=d,e.lastOrigin=b.origin}function xe(a){if(!a)return null;for(var c,b=0;b<a.length;++b)a[b].marker.explicitlyCleared?c||(c=a.slice(0,b)):c&&c.push(a[b]);return c?c.length?c:null:a}function ye(a,b){var c=b["spans_"+a.id];if(!c)return null;for(var d=0,e=[];d<b.text.length;++d)e.push(xe(c[d]));return e}function ze(a,b){for(var c=0,d=[];c<a.length;++c){var e=a[c],f=e.changes,g=[];d.push({changes:g,anchorBefore:e.anchorBefore,headBefore:e.headBefore,anchorAfter:e.anchorAfter,headAfter:e.headAfter});for(var h=0;h<f.length;++h){var j,i=f[h];if(g.push({from:i.from,to:i.to,text:i.text}),b)for(var k in i)(j=k.match(/^spans_(\d+)$/))&&bf(b,Number(j[1]))>-1&&(_e(g)[k]=i[k],delete i[k])}}return d}function Ae(a,b,c,d){c<a.line?a.line+=d:b<a.line&&(a.line=b,a.ch=0)}function Be(a,b,c,d){for(var e=0;e<a.length;++e){for(var f=a[e],g=!0,h=0;h<f.changes.length;++h){var i=f.changes[h];if(f.copied||(i.from=Ec(i.from),i.to=Ec(i.to)),c<i.from.line)i.from.line+=d,i.to.line+=d;else if(b<=i.to.line){g=!1;break}}f.copied||(f.anchorBefore=Ec(f.anchorBefore),f.headBefore=Ec(f.headBefore),f.anchorAfter=Ec(f.anchorAfter),f.readAfter=Ec(f.headAfter),f.copied=!0),g?(Ae(f.anchorBefore),Ae(f.headBefore),Ae(f.anchorAfter),Ae(f.headAfter)):(a.splice(0,e+1),e=0)}}function Ce(a,b){var c=b.from.line,d=b.to.line,e=b.text.length-(d-c)-1;Be(a.done,c,d,e),Be(a.undone,c,d,e)}function De(){Ie(this)}function Ee(a){return a.stop||(a.stop=De),a}function Fe(a){a.preventDefault?a.preventDefault():a.returnValue=!1}function Ge(a){a.stopPropagation?a.stopPropagation():a.cancelBubble=!0}function He(a){return null!=a.defaultPrevented?a.defaultPrevented:0==a.returnValue}function Ie(a){Fe(a),Ge(a)}function Je(a){return a.target||a.srcElement}function Ke(a){var b=a.which;return null==b&&(1&a.button?b=1:2&a.button?b=3:4&a.button&&(b=2)),q&&a.ctrlKey&&1==b&&(b=3),b}function Le(a,b,c){if(a.addEventListener)a.addEventListener(b,c,!1);else if(a.attachEvent)a.attachEvent("on"+b,c);else{var d=a._handlers||(a._handlers={}),e=d[b]||(d[b]=[]);e.push(c)}}function Me(a,b,c){if(a.removeEventListener)a.removeEventListener(b,c,!1);else if(a.detachEvent)a.detachEvent("on"+b,c);else{var d=a._handlers&&a._handlers[b];if(!d)return;for(var e=0;e<d.length;++e)if(d[e]==c){d.splice(e,1);break}}}function Ne(a,b){var c=a._handlers&&a._handlers[b];if(c)for(var d=Array.prototype.slice.call(arguments,2),e=0;e<c.length;++e)c[e].apply(null,d)}function Qe(a,b){function e(a){return function(){a.apply(null,d)}}var c=a._handlers&&a._handlers[b];if(c){var d=Array.prototype.slice.call(arguments,2);Oe||(++Pe,Oe=[],setTimeout(Se,0));for(var f=0;f<c.length;++f)Oe.push(e(c[f]))}}function Re(a,b,c){return Ne(a,c||b.type,a,b),He(b)||b.codemirrorIgnore}function Se(){--Pe;var a=Oe;Oe=null;for(var b=0;b<a.length;++b)a[b]()}function Te(a,b){var c=a._handlers&&a._handlers[b];return c&&c.length>0}function Ue(a){a.prototype.on=function(a,b){Le(this,a,b)},a.prototype.off=function(a,b){Me(this,a,b)}}function Xe(){this.id=null}function Ye(a,b,c,d,e){null==b&&(b=a.search(/[^\s\u00a0]/),-1==b&&(b=a.length));for(var f=d||0,g=e||0;b>f;++f)" "==a.charAt(f)?g+=c-g%c:++g;return g}function $e(a){for(;Ze.length<=a;)Ze.push(_e(Ze)+" ");return Ze[a]}function _e(a){return a[a.length-1]}function af(a){if(o)a.selectionStart=0,a.selectionEnd=a.value.length;else try{a.select()}catch(b){}}function bf(a,b){if(a.indexOf)return a.indexOf(b);for(var c=0,d=a.length;d>c;++c)if(a[c]==b)return c;return-1}function cf(a,b){function c(){}c.prototype=a;var d=new c;return b&&df(b,d),d}function df(a,b){b||(b={});for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b}function ef(a){for(var b=[],c=0;a>c;++c)b.push(void 0);return b}function ff(a){var b=Array.prototype.slice.call(arguments,1);return function(){return a.apply(null,b)}}function hf(a){return/\w/.test(a)||a>"\x80"&&(a.toUpperCase()!=a.toLowerCase()||gf.test(a))}function jf(a){for(var b in a)if(a.hasOwnProperty(b)&&a[b])return!1;return!0}function lf(a,b,c,d){var e=document.createElement(a);if(c&&(e.className=c),d&&(e.style.cssText=d),"string"==typeof b)of(e,b);else if(b)for(var f=0;f<b.length;++f)e.appendChild(b[f]);return e}function mf(a){for(var b=a.childNodes.length;b>0;--b)a.removeChild(a.firstChild);return a}function nf(a,b){return mf(a).appendChild(b)}function of(a,b){d?(a.innerHTML="",a.appendChild(document.createTextNode(b))):a.textContent=b}function pf(a){return a.getBoundingClientRect()}function rf(){return!1}function tf(a){if(null!=sf)return sf;var b=lf("div",null,null,"width: 50px; height: 50px; overflow-x: scroll");return nf(a,b),b.offsetWidth&&(sf=b.offsetHeight-b.clientHeight),sf||0}function vf(a){if(null==uf){var b=lf("span","\u200b");nf(a,lf("span",[b,document.createTextNode("x")])),0!=a.firstChild.offsetHeight&&(uf=b.offsetWidth<=1&&b.offsetHeight>2&&!c)}return uf?lf("span","\u200b"):lf("span","\xa0",null,"display: inline-block; width: 1px; margin-right: -1px")}function Af(a,b,c,d){if(!a)return d(b,c,"ltr");for(var e=!1,f=0;f<a.length;++f){var g=a[f];(g.from<c&&g.to>b||b==c&&g.to==b)&&(d(Math.max(g.from,b),Math.min(g.to,c),1==g.level?"rtl":"ltr"),e=!0)}e||d(b,c,"ltr")}function Bf(a){return a.level%2?a.to:a.from}function Cf(a){return a.level%2?a.from:a.to}function Df(a){var b=se(a);return b?Bf(b[0]):0}function Ef(a){var b=se(a);return b?Cf(_e(b)):a.text.length}function Ff(a,b){var c=le(a.doc,b),d=Fd(a.doc,c);d!=c&&(b=pe(d));var e=se(d),f=e?e[0].level%2?Ef(d):Df(d):0;return Bc(b,f)}function Gf(a,b){for(var c,d;c=Ed(d=le(a.doc,b));)b=c.find().to.line;var e=se(d),f=e?e[0].level%2?Df(d):Ef(d):d.text.length;return Bc(b,f)}function Hf(a,b,c){var d=a[0].level;return b==d?!0:c==d?!1:c>b}function Jf(a,b){for(var d,c=0;c<a.length;++c){var e=a[c];if(e.from<b&&e.to>b)return If=null,c;if(e.from==b||e.to==b){if(null!=d)return Hf(a,e.level,a[d].level)?(If=d,c):(If=c,d);d=c}}return If=null,d}function Kf(a,b,c,d){if(!d)return b+c;do b+=c;while(b>0&&kf.test(a.text.charAt(b)));return b}function Lf(a,b,c,d){var e=se(a);if(!e)return Mf(a,b,c,d);for(var f=Jf(e,b),g=e[f],h=Kf(a,b,g.level%2?-c:c,d);;){if(h>g.from&&h<g.to)return h;if(h==g.from||h==g.to)return Jf(e,h)==f?h:(g=e[f+=c],c>0==g.level%2?g.to:g.from);if(g=e[f+=c],!g)return null;h=c>0==g.level%2?Kf(a,g.to,-1,d):Kf(a,g.from,1,d)}}function Mf(a,b,c,d){var e=b+c;if(d)for(;e>0&&kf.test(a.text.charAt(e));)e+=c;return 0>e||e>a.text.length?null:e}var a=/gecko\/\d/i.test(navigator.userAgent),b=/MSIE \d/.test(navigator.userAgent),c=b&&(null==document.documentMode||document.documentMode<8),d=b&&(null==document.documentMode||document.documentMode<9),e=/Trident\/([7-9]|\d{2,})\./,f=/WebKit\//.test(navigator.userAgent),g=f&&/Qt\/\d+\.\d+/.test(navigator.userAgent),h=/Chrome\//.test(navigator.userAgent),i=/Opera\//.test(navigator.userAgent),j=/Apple Computer/.test(navigator.vendor),k=/KHTML\//.test(navigator.userAgent),l=/Mac OS X 1\d\D([7-9]|\d\d)\D/.test(navigator.userAgent),m=/Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent),n=/PhantomJS/.test(navigator.userAgent),o=/AppleWebKit/.test(navigator.userAgent)&&/Mobile\/\w+/.test(navigator.userAgent),p=o||/Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent),q=o||/Mac/.test(navigator.platform),r=/win/i.test(navigator.platform),s=i&&navigator.userAgent.match(/Version\/(\d*\.\d*)/);s&&(s=Number(s[1])),s&&s>=15&&(i=!1,f=!0);var zb,Sb,Tb,t=q&&(g||i&&(null==s||12.11>s)),u=a||b&&!d,v=!1,w=!1,Cb=0,Yb=0,bc=0,cc=null;b?cc=-.53:a?cc=15:h?cc=-.7:j&&(cc=-1/3);var gc,oc,jc=null,qc=x.changeEnd=function(a){return a.text?Bc(a.from.line+a.text.length-1,_e(a.text).length+(1==a.text.length?a.from.ch:0)):a.to};x.Pos=Bc,x.prototype={constructor:x,focus:function(){window.focus(),Nb(this),mc(this),Kb(this)},setOption:function(a,b){var c=this.options,d=c[a];(c[a]!=b||"mode"==a)&&(c[a]=b,$c.hasOwnProperty(a)&&Fb(this,$c[a])(this,b,d))},getOption:function(a){return this.options[a]},getDoc:function(){return this.doc},addKeyMap:function(a,b){this.state.keyMaps[b?"push":"unshift"](a)},removeKeyMap:function(a){for(var b=this.state.keyMaps,c=0;c<b.length;++c)if(b[c]==a||"string"!=typeof b[c]&&b[c].name==a)return b.splice(c,1),!0},addOverlay:Fb(null,function(a,b){var c=a.token?a:x.getMode(this.options,a);if(c.startState)throw new Error("Overlays may not be stateful.");this.state.overlays.push({mode:c,modeSpec:a,opaque:b&&b.opaque}),this.state.modeGen++,Ib(this)}),removeOverlay:Fb(null,function(a){for(var b=this.state.overlays,c=0;c<b.length;++c){var d=b[c].modeSpec;if(d==a||"string"==typeof a&&d.name==a)return b.splice(c,1),this.state.modeGen++,Ib(this),void 0}}),indentLine:Fb(null,function(a,b,c){"string"!=typeof b&&"number"!=typeof b&&(b=null==b?this.options.smartIndent?"smart":"prev":b?"add":"subtract"),Ic(this.doc,a)&&Uc(this,a,b,c)}),indentSelection:Fb(null,function(a){var b=this.doc.sel;if(Cc(b.from,b.to))return Uc(this,b.from.line,a);for(var c=b.to.line-(b.to.ch?0:1),d=b.from.line;c>=d;++d)Uc(this,d,a)}),getTokenAt:function(a,b){var c=this.doc;a=Gc(c,a);for(var d=eb(this,a.line,b),e=this.doc.mode,f=le(c,a.line),g=new pd(f.text,this.options.tabSize);g.pos<a.ch&&!g.eol();){g.start=g.pos;var h=e.token(g,d)}return{start:g.start,end:g.pos,string:g.current(),className:h||null,type:h||null,state:d}},getTokenTypeAt:function(a){a=Gc(this.doc,a);var b=Td(this,le(this.doc,a.line)),c=0,d=(b.length-1)/2,e=a.ch;if(0==e)return b[2];for(;;){var f=c+d>>1;if((f?b[2*f-1]:0)>=e)d=f;else{if(!(b[2*f+1]<e))return b[2*f+2];c=f+1}}},getModeAt:function(a){var b=this.doc.mode;return b.innerMode?x.innerMode(b,this.getTokenAt(a).state).mode:b},getHelper:function(a,b){if(gd.hasOwnProperty(b)){var c=gd[b],d=this.getModeAt(a);return d[b]&&c[d[b]]||d.helperType&&c[d.helperType]||c[d.name]}},getStateAfter:function(a,b){var c=this.doc;return a=Fc(c,null==a?c.first+c.size-1:a),eb(this,a+1,b)},cursorCoords:function(a,b){var c,d=this.doc.sel;return c=null==a?d.head:"object"==typeof a?Gc(this.doc,a):a?d.from:d.to,vb(this,c,b||"page")},charCoords:function(a,b){return ub(this,Gc(this.doc,a),b||"page")},coordsChar:function(a,b){return a=tb(this,a,b||"page"),xb(this,a.left,a.top)},lineAtHeight:function(a,b){return a=tb(this,{top:a,left:0},b||"page").top,qe(this.doc,a+this.display.viewOffset)},heightAtLine:function(a,b){var c=!1,d=this.doc.first+this.doc.size-1;a<this.doc.first?a=this.doc.first:a>d&&(a=d,c=!0);var e=le(this.doc,a);return sb(this,le(this.doc,a),{top:0,left:0},b||"page").top+(c?e.height:0)},defaultTextHeight:function(){return Ab(this.display)},defaultCharWidth:function(){return Bb(this.display)},setGutterMarker:Fb(null,function(a,b,c){return Vc(this,a,function(a){var d=a.gutterMarkers||(a.gutterMarkers={});return d[b]=c,!c&&jf(d)&&(a.gutterMarkers=null),!0})}),clearGutter:Fb(null,function(a){var b=this,c=b.doc,d=c.first;c.iter(function(c){c.gutterMarkers&&c.gutterMarkers[a]&&(c.gutterMarkers[a]=null,Ib(b,d,d+1),jf(c.gutterMarkers)&&(c.gutterMarkers=null)),++d})}),addLineClass:Fb(null,function(a,b,c){return Vc(this,a,function(a){var d="text"==b?"textClass":"background"==b?"bgClass":"wrapClass";if(a[d]){if(new RegExp("(?:^|\\s)"+c+"(?:$|\\s)").test(a[d]))return!1;a[d]+=" "+c}else a[d]=c;return!0})}),removeLineClass:Fb(null,function(a,b,c){return Vc(this,a,function(a){var d="text"==b?"textClass":"background"==b?"bgClass":"wrapClass",e=a[d];if(!e)return!1;if(null==c)a[d]=null;else{var f=e.match(new RegExp("(?:^|\\s+)"+c+"(?:$|\\s+)"));if(!f)return!1;var g=f.index+f[0].length;a[d]=e.slice(0,f.index)+(f.index&&g!=e.length?" ":"")+e.slice(g)||null}return!0})}),addLineWidget:Fb(null,function(a,b,c){return Nd(this,a,b,c)}),removeLineWidget:function(a){a.clear()},lineInfo:function(a){if("number"==typeof a){if(!Ic(this.doc,a))return null;var b=a;if(a=le(this.doc,a),!a)return null}else{var b=pe(a);if(null==b)return null}return{line:b,handle:a,text:a.text,gutterMarkers:a.gutterMarkers,textClass:a.textClass,bgClass:a.bgClass,wrapClass:a.wrapClass,widgets:a.widgets}},getViewport:function(){return{from:this.display.showingFrom,to:this.display.showingTo}},addWidget:function(a,b,c,d,e){var f=this.display;a=vb(this,Gc(this.doc,a));var g=a.bottom,h=a.left;if(b.style.position="absolute",f.sizer.appendChild(b),"over"==d)g=a.top;else if("above"==d||"near"==d){var i=Math.max(f.wrapper.clientHeight,this.doc.height),j=Math.max(f.sizer.clientWidth,f.lineSpace.clientWidth);("above"==d||a.bottom+b.offsetHeight>i)&&a.top>b.offsetHeight?g=a.top-b.offsetHeight:a.bottom+b.offsetHeight<=i&&(g=a.bottom),h+b.offsetWidth>j&&(h=j-b.offsetWidth)}b.style.top=g+"px",b.style.left=b.style.right="","right"==e?(h=f.sizer.clientWidth-b.offsetWidth,b.style.right="0px"):("left"==e?h=0:"middle"==e&&(h=(f.sizer.clientWidth-b.offsetWidth)/2),b.style.left=h+"px"),c&&Qc(this,h,g,h+b.offsetWidth,g+b.offsetHeight)},triggerOnKeyDown:Fb(null,kc),execCommand:function(a){return jd[a](this)},findPosH:function(a,b,c,d){var e=1;0>b&&(e=-1,b=-b);for(var f=0,g=Gc(this.doc,a);b>f&&(g=Wc(this.doc,g,e,c,d),!g.hitSide);++f);return g},moveH:Fb(null,function(a,b){var d,c=this.doc.sel;d=c.shift||c.extend||Cc(c.from,c.to)?Wc(this.doc,c.head,a,b,this.options.rtlMoveVisually):0>a?c.from:c.to,Jc(this.doc,d,d,a)}),deleteH:Fb(null,function(a,b){var c=this.doc.sel;Cc(c.from,c.to)?Ac(this.doc,"",c.from,Wc(this.doc,c.head,a,b,!1),"+delete"):Ac(this.doc,"",c.from,c.to,"+delete"),this.curOp.userSelChange=!0}),findPosV:function(a,b,c,d){var e=1,f=d;0>b&&(e=-1,b=-b);for(var g=0,h=Gc(this.doc,a);b>g;++g){var i=vb(this,h,"div");if(null==f?f=i.left:i.left=f,h=Xc(this,i,e,c),h.hitSide)break}return h},moveV:Fb(null,function(a,b){var c=this.doc.sel,d=vb(this,c.head,"div");null!=c.goalColumn&&(d.left=c.goalColumn);var e=Xc(this,d,a,b);"page"==b&&Tc(this,0,ub(this,e,"div").top-d.top),Jc(this.doc,e,e,a),c.goalColumn=d.left}),toggleOverwrite:function(a){(null==a||a!=this.state.overwrite)&&((this.state.overwrite=!this.state.overwrite)?this.display.cursor.className+=" CodeMirror-overwrite":this.display.cursor.className=this.display.cursor.className.replace(" CodeMirror-overwrite",""))},hasFocus:function(){return this.state.focused},scrollTo:Fb(null,function(a,b){Sc(this,a,b)}),getScrollInfo:function(){var a=this.display.scroller,b=Ve;return{left:a.scrollLeft,top:a.scrollTop,height:a.scrollHeight-b,width:a.scrollWidth-b,clientHeight:a.clientHeight-b,clientWidth:a.clientWidth-b}},scrollIntoView:Fb(null,function(a,b){null==a?a={from:this.doc.sel.head,to:null}:"number"==typeof a?a={from:Bc(a,0),to:null}:null==a.from&&(a={from:a,to:null}),a.to||(a.to=a.from),b||(b=0);var c=a;null!=a.from.line&&(this.curOp.scrollToPos={from:a.from,to:a.to,margin:b},c={from:vb(this,a.from),to:vb(this,a.to)});var d=Rc(this,Math.min(c.from.left,c.to.left),Math.min(c.from.top,c.to.top)-b,Math.max(c.from.right,c.to.right),Math.max(c.from.bottom,c.to.bottom)+b);Sc(this,d.scrollLeft,d.scrollTop)}),setSize:Fb(null,function(a,b){function c(a){return"number"==typeof a||/^\d+$/.test(String(a))?a+"px":a}null!=a&&(this.display.wrapper.style.width=c(a)),null!=b&&(this.display.wrapper.style.height=c(b)),this.options.lineWrapping&&(this.display.measureLineCache.length=this.display.measureLineCachePos=0),this.curOp.forceUpdate=!0}),operation:function(a){return Hb(this,a)},refresh:Fb(null,function(){var a=null==this.display.cachedTextHeight;pb(this),Sc(this,this.doc.scrollLeft,this.doc.scrollTop),Ib(this),a&&C(this)}),swapDoc:Fb(null,function(a){var b=this.doc;return b.cm=null,ke(this,a),pb(this),Mb(this,!0),Sc(this,a.scrollLeft,a.scrollTop),Qe(this,"swapDoc",this,b),b}),getInputField:function(){return this.display.input},getWrapperElement:function(){return this.display.wrapper},getScrollerElement:function(){return this.display.scroller},getGutterElement:function(){return this.display.gutters}},Ue(x);var $c=x.optionHandlers={},_c=x.defaults={},bd=x.Init={toString:function(){return"CodeMirror.Init"}};ad("value","",function(a,b){a.setValue(b)},!0),ad("mode",null,function(a,b){a.doc.modeOption=b,z(a)},!0),ad("indentUnit",2,z,!0),ad("indentWithTabs",!1),ad("smartIndent",!0),ad("tabSize",4,function(a){z(a),pb(a),Ib(a)},!0),ad("electricChars",!0),ad("rtlMoveVisually",!r),ad("theme","default",function(a){E(a),F(a)},!0),ad("keyMap","default",D),ad("extraKeys",null),ad("onKeyEvent",null),ad("onDragEvent",null),ad("lineWrapping",!1,A,!0),ad("gutters",[],function(a){J(a.options),F(a)},!0),ad("fixedGutter",!0,function(a,b){a.display.gutters.style.left=b?P(a.display)+"px":"0",a.refresh()},!0),ad("coverGutterNextToScrollbar",!1,K,!0),ad("lineNumbers",!1,function(a){J(a.options),F(a)},!0),ad("firstLineNumber",1,F,!0),ad("lineNumberFormatter",function(a){return a},F,!0),ad("showCursorWhenSelecting",!1,Z,!0),ad("resetSelectionOnContextMenu",!0),ad("readOnly",!1,function(a,b){"nocursor"==b?(nc(a),a.display.input.blur(),a.display.disabled=!0):(a.display.disabled=!1,b||Mb(a,!0))}),ad("dragDrop",!0),ad("cursorBlinkRate",530),ad("cursorScrollMargin",0),ad("cursorHeight",1),ad("workTime",100),ad("workDelay",100),ad("flattenSpans",!0),ad("pollInterval",100),ad("undoDepth",40,function(a,b){a.doc.history.undoDepth=b}),ad("historyEventDelay",500),ad("viewportMargin",10,function(a){a.refresh()},!0),ad("maxHighlightLength",1e4,function(a){z(a),a.refresh()},!0),ad("crudeMeasuringFrom",1e4),ad("moveInputWithCursor",!0,function(a,b){b||(a.display.inputDiv.style.top=a.display.inputDiv.style.left=0)}),ad("tabindex",null,function(a,b){a.display.input.tabIndex=b||""}),ad("autofocus",null);var cd=x.modes={},dd=x.mimeModes={};x.defineMode=function(a,b){if(x.defaults.mode||"null"==a||(x.defaults.mode=a),arguments.length>2){b.dependencies=[];for(var c=2;c<arguments.length;++c)b.dependencies.push(arguments[c])}cd[a]=b},x.defineMIME=function(a,b){dd[a]=b},x.resolveMode=function(a){if("string"==typeof a&&dd.hasOwnProperty(a))a=dd[a];else if(a&&"string"==typeof a.name&&dd.hasOwnProperty(a.name)){var b=dd[a.name];a=cf(b,a),a.name=b.name}else if("string"==typeof a&&/^[\w\-]+\/[\w\-]+\+xml$/.test(a))return x.resolveMode("application/xml");return"string"==typeof a?{name:a}:a||{name:"null"}},x.getMode=function(a,b){var b=x.resolveMode(b),c=cd[b.name];if(!c)return x.getMode(a,"text/plain");var d=c(a,b);if(ed.hasOwnProperty(b.name)){var e=ed[b.name];for(var f in e)e.hasOwnProperty(f)&&(d.hasOwnProperty(f)&&(d["_"+f]=d[f]),d[f]=e[f])}return d.name=b.name,d},x.defineMode("null",function(){return{token:function(a){a.skipToEnd()}}}),x.defineMIME("text/plain","null");var ed=x.modeExtensions={};x.extendMode=function(a,b){var c=ed.hasOwnProperty(a)?ed[a]:ed[a]={};df(b,c)},x.defineExtension=function(a,b){x.prototype[a]=b},x.defineDocExtension=function(a,b){ge.prototype[a]=b},x.defineOption=ad;var fd=[];x.defineInitHook=function(a){fd.push(a)};var gd=x.helpers={};x.registerHelper=function(a,b,c){gd.hasOwnProperty(a)||(gd[a]=x[a]={}),gd[a][b]=c},x.isWordChar=hf,x.copyState=hd,x.startState=id,x.innerMode=function(a,b){for(;a.innerMode;){var c=a.innerMode(b);if(!c||c.mode==a)break;b=c.state,a=c.mode}return c||{mode:a,state:b}};var jd=x.commands={selectAll:function(a){a.setSelection(Bc(a.firstLine(),0),Bc(a.lastLine()))},killLine:function(a){var b=a.getCursor(!0),c=a.getCursor(!1),d=!Cc(b,c);d||a.getLine(b.line).length!=b.ch?a.replaceRange("",b,d?c:Bc(b.line),"+delete"):a.replaceRange("",b,Bc(b.line+1,0),"+delete")},deleteLine:function(a){var b=a.getCursor().line;a.replaceRange("",Bc(b,0),Bc(b),"+delete")},delLineLeft:function(a){var b=a.getCursor();a.replaceRange("",Bc(b.line,0),b,"+delete")},undo:function(a){a.undo()},redo:function(a){a.redo()},goDocStart:function(a){a.extendSelection(Bc(a.firstLine(),0))},goDocEnd:function(a){a.extendSelection(Bc(a.lastLine()))},goLineStart:function(a){a.extendSelection(Ff(a,a.getCursor().line))},goLineStartSmart:function(a){var b=a.getCursor(),c=Ff(a,b.line),d=a.getLineHandle(c.line),e=se(d);if(e&&0!=e[0].level)a.extendSelection(c);else{var f=Math.max(0,d.text.search(/\S/)),g=b.line==c.line&&b.ch<=f&&b.ch;a.extendSelection(Bc(c.line,g?0:f))}},goLineEnd:function(a){a.extendSelection(Gf(a,a.getCursor().line))},goLineRight:function(a){var b=a.charCoords(a.getCursor(),"div").top+5;a.extendSelection(a.coordsChar({left:a.display.lineDiv.offsetWidth+100,top:b},"div"))},goLineLeft:function(a){var b=a.charCoords(a.getCursor(),"div").top+5;a.extendSelection(a.coordsChar({left:0,top:b},"div"))},goLineUp:function(a){a.moveV(-1,"line")},goLineDown:function(a){a.moveV(1,"line")},goPageUp:function(a){a.moveV(-1,"page")},goPageDown:function(a){a.moveV(1,"page")},goCharLeft:function(a){a.moveH(-1,"char")},goCharRight:function(a){a.moveH(1,"char")},goColumnLeft:function(a){a.moveH(-1,"column")},goColumnRight:function(a){a.moveH(1,"column")},goWordLeft:function(a){a.moveH(-1,"word")},goGroupRight:function(a){a.moveH(1,"group")},goGroupLeft:function(a){a.moveH(-1,"group")},goWordRight:function(a){a.moveH(1,"word")},delCharBefore:function(a){a.deleteH(-1,"char")},delCharAfter:function(a){a.deleteH(1,"char")},delWordBefore:function(a){a.deleteH(-1,"word")},delWordAfter:function(a){a.deleteH(1,"word")},delGroupBefore:function(a){a.deleteH(-1,"group")},delGroupAfter:function(a){a.deleteH(1,"group")},indentAuto:function(a){a.indentSelection("smart")},indentMore:function(a){a.indentSelection("add")},indentLess:function(a){a.indentSelection("subtract")},insertTab:function(a){a.replaceSelection(" ","end","+input")},defaultTab:function(a){a.somethingSelected()?a.indentSelection("add"):a.replaceSelection(" ","end","+input")},transposeChars:function(a){var b=a.getCursor(),c=a.getLine(b.line);b.ch>0&&b.ch<c.length-1&&a.replaceRange(c.charAt(b.ch)+c.charAt(b.ch-1),Bc(b.line,b.ch-1),Bc(b.line,b.ch+1))},newlineAndIndent:function(a){Fb(a,function(){a.replaceSelection("\n","end","+input"),a.indentLine(a.getCursor().line,null,!0)})()},toggleOverwrite:function(a){a.toggleOverwrite()}},kd=x.keyMap={};kd.basic={Left:"goCharLeft",Right:"goCharRight",Up:"goLineUp",Down:"goLineDown",End:"goLineEnd",Home:"goLineStartSmart",PageUp:"goPageUp",PageDown:"goPageDown",Delete:"delCharAfter",Backspace:"delCharBefore","Shift-Backspace":"delCharBefore",Tab:"defaultTab","Shift-Tab":"indentAuto",Enter:"newlineAndIndent",Insert:"toggleOverwrite"},kd.pcDefault={"Ctrl-A":"selectAll","Ctrl-D":"deleteLine","Ctrl-Z":"undo","Shift-Ctrl-Z":"redo","Ctrl-Y":"redo","Ctrl-Home":"goDocStart","Alt-Up":"goDocStart","Ctrl-End":"goDocEnd","Ctrl-Down":"goDocEnd","Ctrl-Left":"goGroupLeft","Ctrl-Right":"goGroupRight","Alt-Left":"goLineStart","Alt-Right":"goLineEnd","Ctrl-Backspace":"delGroupBefore","Ctrl-Delete":"delGroupAfter","Ctrl-S":"save","Ctrl-F":"find","Ctrl-G":"findNext","Shift-Ctrl-G":"findPrev","Shift-Ctrl-F":"replace","Shift-Ctrl-R":"replaceAll","Ctrl-[":"indentLess","Ctrl-]":"indentMore",fallthrough:"basic"},kd.macDefault={"Cmd-A":"selectAll","Cmd-D":"deleteLine","Cmd-Z":"undo","Shift-Cmd-Z":"redo","Cmd-Y":"redo","Cmd-Up":"goDocStart","Cmd-End":"goDocEnd","Cmd-Down":"goDocEnd","Alt-Left":"goGroupLeft","Alt-Right":"goGroupRight","Cmd-Left":"goLineStart","Cmd-Right":"goLineEnd","Alt-Backspace":"delGroupBefore","Ctrl-Alt-Backspace":"delGroupAfter","Alt-Delete":"delGroupAfter","Cmd-S":"save","Cmd-F":"find","Cmd-G":"findNext","Shift-Cmd-G":"findPrev","Cmd-Alt-F":"replace","Shift-Cmd-Alt-F":"replaceAll","Cmd-[":"indentLess","Cmd-]":"indentMore","Cmd-Backspace":"delLineLeft",fallthrough:["basic","emacsy"]},kd["default"]=q?kd.macDefault:kd.pcDefault,kd.emacsy={"Ctrl-F":"goCharRight","Ctrl-B":"goCharLeft","Ctrl-P":"goLineUp","Ctrl-N":"goLineDown","Alt-F":"goWordRight","Alt-B":"goWordLeft","Ctrl-A":"goLineStart","Ctrl-E":"goLineEnd","Ctrl-V":"goPageDown","Shift-Ctrl-V":"goPageUp","Ctrl-D":"delCharAfter","Ctrl-H":"delCharBefore","Alt-D":"delWordAfter","Alt-Backspace":"delWordBefore","Ctrl-K":"killLine","Ctrl-T":"transposeChars"},x.lookupKey=md,x.isModifierKey=nd,x.keyName=od,x.fromTextArea=function(a,b){function e(){a.value=i.getValue()}if(b||(b={}),b.value=a.value,!b.tabindex&&a.tabindex&&(b.tabindex=a.tabindex),!b.placeholder&&a.placeholder&&(b.placeholder=a.placeholder),null==b.autofocus){var c=document.body;try{c=document.activeElement}catch(d){}b.autofocus=c==a||null!=a.getAttribute("autofocus")&&c==document.body}if(a.form&&(Le(a.form,"submit",e),!b.leaveSubmitMethodAlone)){var f=a.form,g=f.submit;try{var h=f.submit=function(){e(),f.submit=g,f.submit(),f.submit=h}}catch(d){}}a.style.display="none";var i=x(function(b){a.parentNode.insertBefore(b,a.nextSibling)},b);return i.save=e,i.getTextArea=function(){return a},i.toTextArea=function(){e(),a.parentNode.removeChild(i.getWrapperElement()),a.style.display="",a.form&&(Me(a.form,"submit",e),"function"==typeof a.form.submit&&(a.form.submit=g))},i},pd.prototype={eol:function(){return this.pos>=this.string.length},sol:function(){return 0==this.pos},peek:function(){return this.string.charAt(this.pos)||void 0},next:function(){return this.pos<this.string.length?this.string.charAt(this.pos++):void 0},eat:function(a){var b=this.string.charAt(this.pos);if("string"==typeof a)var c=b==a;else var c=b&&(a.test?a.test(b):a(b));return c?(++this.pos,b):void 0},eatWhile:function(a){for(var b=this.pos;this.eat(a););return this.pos>b},eatSpace:function(){for(var a=this.pos;/[\s\u00a0]/.test(this.string.charAt(this.pos));)++this.pos;return this.pos>a},skipToEnd:function(){this.pos=this.string.length},skipTo:function(a){var b=this.string.indexOf(a,this.pos);return b>-1?(this.pos=b,!0):void 0},backUp:function(a){this.pos-=a},column:function(){return this.lastColumnPos<this.start&&(this.lastColumnValue=Ye(this.string,this.start,this.tabSize,this.lastColumnPos,this.lastColumnValue),this.lastColumnPos=this.start),this.lastColumnValue},indentation:function(){return Ye(this.string,null,this.tabSize)},match:function(a,b,c){if("string"!=typeof a){var f=this.string.slice(this.pos).match(a);return f&&f.index>0?null:(f&&b!==!1&&(this.pos+=f[0].length),f)}var d=function(a){return c?a.toLowerCase():a},e=this.string.substr(this.pos,a.length);return d(e)==d(a)?(b!==!1&&(this.pos+=a.length),!0):void 0},current:function(){return this.string.slice(this.start,this.pos)}},x.StringStream=pd,x.TextMarker=qd,Ue(qd),qd.prototype.clear=function(){if(!this.explicitlyCleared){var a=this.doc.cm,b=a&&!a.curOp;if(b&&Db(a),Te(this,"clear")){var c=this.find();c&&Qe(this,"clear",c.from,c.to)}for(var d=null,e=null,f=0;f<this.lines.length;++f){var g=this.lines[f],h=ud(g.markedSpans,this);null!=h.to&&(e=pe(g)),g.markedSpans=vd(g.markedSpans,h),null!=h.from?d=pe(g):this.collapsed&&!Gd(this.doc,g)&&a&&oe(g,Ab(a.display))}if(a&&this.collapsed&&!a.options.lineWrapping)for(var f=0;f<this.lines.length;++f){var i=Fd(a.doc,this.lines[f]),j=H(a.doc,i);j>a.display.maxLineLength&&(a.display.maxLine=i,a.display.maxLineLength=j,a.display.maxLineChanged=!0)}null!=d&&a&&Ib(a,d,e+1),this.lines.length=0,this.explicitlyCleared=!0,this.atomic&&this.doc.cantEdit&&(this.doc.cantEdit=!1,a&&Mc(a)),b&&Eb(a)}},qd.prototype.find=function(){for(var a,b,c=0;c<this.lines.length;++c){var d=this.lines[c],e=ud(d.markedSpans,this);if(null!=e.from||null!=e.to){var f=pe(d);null!=e.from&&(a=Bc(f,e.from)),null!=e.to&&(b=Bc(f,e.to))}}return"bookmark"==this.type?a:a&&{from:a,to:b}},qd.prototype.changed=function(){var a=this.find(),b=this.doc.cm;if(a&&b){"bookmark"!=this.type&&(a=a.from);var c=le(this.doc,a.line);if(kb(b,c),a.line>=b.display.showingFrom&&a.line<b.display.showingTo){for(var d=b.display.lineDiv.firstChild;d;d=d.nextSibling)if(d.lineObj==c){d.offsetHeight!=c.height&&oe(c,d.offsetHeight);break}Hb(b,function(){b.curOp.selectionChanged=b.curOp.forceUpdate=b.curOp.updateMaxLine=!0})}}},qd.prototype.attachLine=function(a){if(!this.lines.length&&this.doc.cm){var b=this.doc.cm.curOp;b.maybeHiddenMarkers&&-1!=bf(b.maybeHiddenMarkers,this)||(b.maybeUnhiddenMarkers||(b.maybeUnhiddenMarkers=[])).push(this)}this.lines.push(a)},qd.prototype.detachLine=function(a){if(this.lines.splice(bf(this.lines,a),1),!this.lines.length&&this.doc.cm){var b=this.doc.cm.curOp;
+(b.maybeHiddenMarkers||(b.maybeHiddenMarkers=[])).push(this)}},x.SharedTextMarker=sd,Ue(sd),sd.prototype.clear=function(){if(!this.explicitlyCleared){this.explicitlyCleared=!0;for(var a=0;a<this.markers.length;++a)this.markers[a].clear();Qe(this,"clear")}},sd.prototype.find=function(){return this.primary.find()};var Kd=x.LineWidget=function(a,b,c){if(c)for(var d in c)c.hasOwnProperty(d)&&(this[d]=c[d]);this.cm=a,this.node=b};Ue(Kd),Kd.prototype.clear=Ld(function(){var a=this.line.widgets,b=pe(this.line);if(null!=b&&a){for(var c=0;c<a.length;++c)a[c]==this&&a.splice(c--,1);a.length||(this.line.widgets=null);var d=re(this.cm,this.line)<this.cm.doc.scrollTop;oe(this.line,Math.max(0,this.line.height-Md(this))),d&&Tc(this.cm,0,-this.height),Ib(this.cm,b,b+1)}}),Kd.prototype.changed=Ld(function(){var a=this.height;this.height=null;var b=Md(this)-a;if(b){oe(this.line,this.line.height+b);var c=pe(this.line);Ib(this.cm,c,c+1)}});var Od=x.Line=function(a,b,c){this.text=a,Jd(this,b),this.height=c?c(this):1};Ue(Od);var Vd={},Yd=/[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\uFEFF]/g;de.prototype={chunkSize:function(){return this.lines.length},removeInner:function(a,b){for(var c=a,d=a+b;d>c;++c){var e=this.lines[c];this.height-=e.height,Qd(e),Qe(e,"delete")}this.lines.splice(a,b)},collapse:function(a){a.splice.apply(a,[a.length,0].concat(this.lines))},insertInner:function(a,b,c){this.height+=c,this.lines=this.lines.slice(0,a).concat(b).concat(this.lines.slice(a));for(var d=0,e=b.length;e>d;++d)b[d].parent=this},iterN:function(a,b,c){for(var d=a+b;d>a;++a)if(c(this.lines[a]))return!0}},ee.prototype={chunkSize:function(){return this.size},removeInner:function(a,b){this.size-=b;for(var c=0;c<this.children.length;++c){var d=this.children[c],e=d.chunkSize();if(e>a){var f=Math.min(b,e-a),g=d.height;if(d.removeInner(a,f),this.height-=g-d.height,e==f&&(this.children.splice(c--,1),d.parent=null),0==(b-=f))break;a=0}else a-=e}if(this.size-b<25){var h=[];this.collapse(h),this.children=[new de(h)],this.children[0].parent=this}},collapse:function(a){for(var b=0,c=this.children.length;c>b;++b)this.children[b].collapse(a)},insertInner:function(a,b,c){this.size+=b.length,this.height+=c;for(var d=0,e=this.children.length;e>d;++d){var f=this.children[d],g=f.chunkSize();if(g>=a){if(f.insertInner(a,b,c),f.lines&&f.lines.length>50){for(;f.lines.length>50;){var h=f.lines.splice(f.lines.length-25,25),i=new de(h);f.height-=i.height,this.children.splice(d+1,0,i),i.parent=this}this.maybeSpill()}break}a-=g}},maybeSpill:function(){if(!(this.children.length<=10)){var a=this;do{var b=a.children.splice(a.children.length-5,5),c=new ee(b);if(a.parent){a.size-=c.size,a.height-=c.height;var e=bf(a.parent.children,a);a.parent.children.splice(e+1,0,c)}else{var d=new ee(a.children);d.parent=a,a.children=[d,c],a=d}c.parent=a.parent}while(a.children.length>10);a.parent.maybeSpill()}},iterN:function(a,b,c){for(var d=0,e=this.children.length;e>d;++d){var f=this.children[d],g=f.chunkSize();if(g>a){var h=Math.min(b,g-a);if(f.iterN(a,h,c))return!0;if(0==(b-=h))break;a=0}else a-=g}}};var fe=0,ge=x.Doc=function(a,b,c){if(!(this instanceof ge))return new ge(a,b,c);null==c&&(c=0),ee.call(this,[new de([new Od("",null)])]),this.first=c,this.scrollTop=this.scrollLeft=0,this.cantEdit=!1,this.history=te(),this.cleanGeneration=1,this.frontier=c;var d=Bc(c,0);this.sel={from:d,to:d,head:d,anchor:d,shift:!1,extend:!1,goalColumn:null},this.id=++fe,this.modeOption=b,"string"==typeof a&&(a=wf(a)),ce(this,{from:d,to:d,text:a},null,{head:d,anchor:d})};ge.prototype=cf(ee.prototype,{constructor:ge,iter:function(a,b,c){c?this.iterN(a-this.first,b-a,c):this.iterN(this.first,this.first+this.size,a)},insert:function(a,b){for(var c=0,d=0,e=b.length;e>d;++d)c+=b[d].height;this.insertInner(a-this.first,b,c)},remove:function(a,b){this.removeInner(a-this.first,b)},getValue:function(a){var b=ne(this,this.first,this.first+this.size);return a===!1?b:b.join(a||"\n")},setValue:function(a){var b=Bc(this.first,0),c=this.first+this.size-1;uc(this,{from:b,to:Bc(c,le(this,c).text.length),text:wf(a),origin:"setValue"},{head:b,anchor:b},!0)},replaceRange:function(a,b,c,d){b=Gc(this,b),c=c?Gc(this,c):b,Ac(this,a,b,c,d)},getRange:function(a,b,c){var d=me(this,Gc(this,a),Gc(this,b));return c===!1?d:d.join(c||"\n")},getLine:function(a){var b=this.getLineHandle(a);return b&&b.text},setLine:function(a,b){Ic(this,a)&&Ac(this,b,Bc(a,0),Gc(this,Bc(a)))},removeLine:function(a){a?Ac(this,"",Gc(this,Bc(a-1)),Gc(this,Bc(a))):Ac(this,"",Bc(0,0),Gc(this,Bc(1,0)))},getLineHandle:function(a){return Ic(this,a)?le(this,a):void 0},getLineNumber:function(a){return pe(a)},getLineHandleVisualStart:function(a){return"number"==typeof a&&(a=le(this,a)),Fd(this,a)},lineCount:function(){return this.size},firstLine:function(){return this.first},lastLine:function(){return this.first+this.size-1},clipPos:function(a){return Gc(this,a)},getCursor:function(a){var c,b=this.sel;return c=null==a||"head"==a?b.head:"anchor"==a?b.anchor:"end"==a||a===!1?b.to:b.from,Ec(c)},somethingSelected:function(){return!Cc(this.sel.head,this.sel.anchor)},setCursor:Gb(function(a,b,c){var d=Gc(this,"number"==typeof a?Bc(a,b||0):a);c?Jc(this,d):Lc(this,d,d)}),setSelection:Gb(function(a,b,c){Lc(this,Gc(this,a),Gc(this,b||a),c)}),extendSelection:Gb(function(a,b,c){Jc(this,Gc(this,a),b&&Gc(this,b),c)}),getSelection:function(a){return this.getRange(this.sel.from,this.sel.to,a)},replaceSelection:function(a,b,c){uc(this,{from:this.sel.from,to:this.sel.to,text:wf(a),origin:c},b||"around")},undo:Gb(function(){wc(this,"undo")}),redo:Gb(function(){wc(this,"redo")}),setExtending:function(a){this.sel.extend=a},historySize:function(){var a=this.history;return{undo:a.done.length,redo:a.undone.length}},clearHistory:function(){this.history=te(this.history.maxGeneration)},markClean:function(){this.cleanGeneration=this.changeGeneration()},changeGeneration:function(){return this.history.lastOp=this.history.lastOrigin=null,this.history.generation},isClean:function(a){return this.history.generation==(a||this.cleanGeneration)},getHistory:function(){return{done:ze(this.history.done),undone:ze(this.history.undone)}},setHistory:function(a){var b=this.history=te(this.history.maxGeneration);b.done=a.done.slice(0),b.undone=a.undone.slice(0)},markText:function(a,b,c){return rd(this,Gc(this,a),Gc(this,b),c,"range")},setBookmark:function(a,b){var c={replacedWith:b&&(null==b.nodeType?b.widget:b),insertLeft:b&&b.insertLeft};return a=Gc(this,a),rd(this,a,a,c,"bookmark")},findMarksAt:function(a){a=Gc(this,a);var b=[],c=le(this,a.line).markedSpans;if(c)for(var d=0;d<c.length;++d){var e=c[d];(null==e.from||e.from<=a.ch)&&(null==e.to||e.to>=a.ch)&&b.push(e.marker.parent||e.marker)}return b},getAllMarks:function(){var a=[];return this.iter(function(b){var c=b.markedSpans;if(c)for(var d=0;d<c.length;++d)null!=c[d].from&&a.push(c[d].marker)}),a},posFromIndex:function(a){var b,c=this.first;return this.iter(function(d){var e=d.text.length+1;return e>a?(b=a,!0):(a-=e,++c,void 0)}),Gc(this,Bc(c,b))},indexFromPos:function(a){a=Gc(this,a);var b=a.ch;return a.line<this.first||a.ch<0?0:(this.iter(this.first,a.line,function(a){b+=a.text.length+1}),b)},copy:function(a){var b=new ge(ne(this,this.first,this.first+this.size),this.modeOption,this.first);return b.scrollTop=this.scrollTop,b.scrollLeft=this.scrollLeft,b.sel={from:this.sel.from,to:this.sel.to,head:this.sel.head,anchor:this.sel.anchor,shift:this.sel.shift,extend:!1,goalColumn:this.sel.goalColumn},a&&(b.history.undoDepth=this.history.undoDepth,b.setHistory(this.getHistory())),b},linkedDoc:function(a){a||(a={});var b=this.first,c=this.first+this.size;null!=a.from&&a.from>b&&(b=a.from),null!=a.to&&a.to<c&&(c=a.to);var d=new ge(ne(this,b,c),a.mode||this.modeOption,b);return a.sharedHist&&(d.history=this.history),(this.linked||(this.linked=[])).push({doc:d,sharedHist:a.sharedHist}),d.linked=[{doc:this,isParent:!0,sharedHist:a.sharedHist}],d},unlinkDoc:function(a){if(a instanceof x&&(a=a.doc),this.linked)for(var b=0;b<this.linked.length;++b){var c=this.linked[b];if(c.doc==a){this.linked.splice(b,1),a.unlinkDoc(this);break}}if(a.history==this.history){var d=[a.id];je(a,function(a){d.push(a.id)},!0),a.history=te(),a.history.done=ze(this.history.done,d),a.history.undone=ze(this.history.undone,d)}},iterLinkedDocs:function(a){je(this,a)},getMode:function(){return this.mode},getEditor:function(){return this.cm}}),ge.prototype.eachLine=ge.prototype.iter;var he="iter insert remove copy getEditor".split(" ");for(var ie in ge.prototype)ge.prototype.hasOwnProperty(ie)&&bf(he,ie)<0&&(x.prototype[ie]=function(a){return function(){return a.apply(this.doc,arguments)}}(ge.prototype[ie]));Ue(ge),x.e_stop=Ie,x.e_preventDefault=Fe,x.e_stopPropagation=Ge;var Oe,Pe=0;x.on=Le,x.off=Me,x.signal=Ne;var Ve=30,We=x.Pass={toString:function(){return"CodeMirror.Pass"}};Xe.prototype={set:function(a,b){clearTimeout(this.id),this.id=setTimeout(b,a)}},x.countColumn=Ye;var Ze=[""],gf=/[\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/,kf=/[\u0300-\u036F\u0483-\u0487\u0488-\u0489\u0591-\u05BD\u05BF\u05C1-\u05C2\u05C4-\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7-\u06E8\u06EA-\u06ED\uA66F\uA670-\uA672\uA674-\uA67D\uA69F\udc00-\udfff]/;x.replaceGetRect=function(a){pf=a};var qf=function(){if(d)return!1;var a=lf("div");return"draggable"in a||"dragDrop"in a}();a?rf=function(a,b){return 36==a.charCodeAt(b-1)&&39==a.charCodeAt(b)}:j&&!/Version\/([6-9]|\d\d)\b/.test(navigator.userAgent)?rf=function(a,b){return/\-[^ \-?]|\?[^ !\'\"\),.\-\/:;\?\]\}]/.test(a.slice(b-1,b+1))}:f&&/Chrome\/(?:29|[3-9]\d|\d\d\d)\./.test(navigator.userAgent)?rf=function(a,b){var c=a.charCodeAt(b-1);return c>=8208&&8212>=c}:f&&(rf=function(a,b){if(b>1&&45==a.charCodeAt(b-1)){if(/\w/.test(a.charAt(b-2))&&/[^\-?\.]/.test(a.charAt(b)))return!0;if(b>2&&/[\d\.,]/.test(a.charAt(b-2))&&/[\d\.,]/.test(a.charAt(b)))return!1}return/[~!#%&*)=+}\]\\|\"\.>,:;][({[<]|-[^\-?\.\u2010-\u201f\u2026]|\?[\w~`@#$%\^&*(_=+{[|><]|\u2026[\w~`@#$%\^&*(_=+{[><]/.test(a.slice(b-1,b+1))});var sf,uf,wf=3!="\n\nb".split(/\n/).length?function(a){for(var b=0,c=[],d=a.length;d>=b;){var e=a.indexOf("\n",b);-1==e&&(e=a.length);var f=a.slice(b,"\r"==a.charAt(e-1)?e-1:e),g=f.indexOf("\r");-1!=g?(c.push(f.slice(0,g)),b+=g+1):(c.push(f),b=e+1)}return c}:function(a){return a.split(/\r\n?|\n/)};x.splitLines=wf;var xf=window.getSelection?function(a){try{return a.selectionStart!=a.selectionEnd}catch(b){return!1}}:function(a){try{var b=a.ownerDocument.selection.createRange()}catch(c){}return b&&b.parentElement()==a?0!=b.compareEndPoints("StartToEnd",b):!1},yf=function(){var a=lf("div");return"oncopy"in a?!0:(a.setAttribute("oncopy","return;"),"function"==typeof a.oncopy)}(),zf={3:"Enter",8:"Backspace",9:"Tab",13:"Enter",16:"Shift",17:"Ctrl",18:"Alt",19:"Pause",20:"CapsLock",27:"Esc",32:"Space",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"Left",38:"Up",39:"Right",40:"Down",44:"PrintScrn",45:"Insert",46:"Delete",59:";",91:"Mod",92:"Mod",93:"Mod",109:"-",107:"=",127:"Delete",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'",63276:"PageUp",63277:"PageDown",63275:"End",63273:"Home",63234:"Left",63232:"Up",63235:"Right",63233:"Down",63302:"Insert",63272:"Delete"};x.keyNames=zf,function(){for(var a=0;10>a;a++)zf[a+48]=String(a);for(var a=65;90>=a;a++)zf[a]=String.fromCharCode(a);for(var a=1;12>=a;a++)zf[a+111]=zf[a+63235]="F"+a}();var If,Nf=function(){function c(c){return 255>=c?a.charAt(c):c>=1424&&1524>=c?"R":c>=1536&&1791>=c?b.charAt(c-1536):c>=1792&&2220>=c?"r":"L"}var a="bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLL",b="rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmmrrrrrrrrrrrrrrrrrr",d=/[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/,e=/[stwN]/,f=/[LRr]/,g=/[Lb1n]/,h=/[1n]/,i="L";return function(a){if(!d.test(a))return!1;for(var l,b=a.length,j=[],k=0;b>k;++k)j.push(l=c(a.charCodeAt(k)));for(var k=0,m=i;b>k;++k){var l=j[k];"m"==l?j[k]=m:m=l}for(var k=0,n=i;b>k;++k){var l=j[k];"1"==l&&"r"==n?j[k]="n":f.test(l)&&(n=l,"r"==l&&(j[k]="R"))}for(var k=1,m=j[0];b-1>k;++k){var l=j[k];"+"==l&&"1"==m&&"1"==j[k+1]?j[k]="1":","!=l||m!=j[k+1]||"1"!=m&&"n"!=m||(j[k]=m),m=l}for(var k=0;b>k;++k){var l=j[k];if(","==l)j[k]="N";else if("%"==l){for(var o=k+1;b>o&&"%"==j[o];++o);for(var p=k&&"!"==j[k-1]||b-1>o&&"1"==j[o]?"1":"N",q=k;o>q;++q)j[q]=p;k=o-1}}for(var k=0,n=i;b>k;++k){var l=j[k];"L"==n&&"1"==l?j[k]="L":f.test(l)&&(n=l)}for(var k=0;b>k;++k)if(e.test(j[k])){for(var o=k+1;b>o&&e.test(j[o]);++o);for(var r="L"==(k?j[k-1]:i),s="L"==(b-1>o?j[o]:i),p=r||s?"L":"R",q=k;o>q;++q)j[q]=p;k=o-1}for(var u,t=[],k=0;b>k;)if(g.test(j[k])){var v=k;for(++k;b>k&&g.test(j[k]);++k);t.push({from:v,to:k,level:0})}else{var w=k,x=t.length;for(++k;b>k&&"L"!=j[k];++k);for(var q=w;k>q;)if(h.test(j[q])){q>w&&t.splice(x,0,{from:w,to:q,level:1});var y=q;for(++q;k>q&&h.test(j[q]);++q);t.splice(x,0,{from:y,to:q,level:2}),w=q}else++q;k>w&&t.splice(x,0,{from:w,to:k,level:1})}return 1==t[0].level&&(u=a.match(/^\s+/))&&(t[0].from=u[0].length,t.unshift({from:0,to:u[0].length,level:0})),1==_e(t).level&&(u=a.match(/\s+$/))&&(_e(t).to-=u[0].length,t.push({from:b-u[0].length,to:b,level:0})),t[0].level!=_e(t).level&&t.push({from:b,to:b,level:t[0].level}),t}}();return x.version="3.19.1",x}(),CodeMirror.defineMode("css",function(a,b){"use strict";function l(a,b){return k=b,a}function m(a,b){var c=a.next();if(d[c]){var e=d[c](a,b);if(e!==!1)return e}if("@"==c)return a.eatWhile(/[\w\\\-]/),l("def",a.current());if("="==c)l(null,"compare");else{if(("~"==c||"|"==c)&&a.eat("="))return l(null,"compare");if('"'==c||"'"==c)return b.tokenize=n(c),b.tokenize(a,b);if("#"==c)return a.eatWhile(/[\w\\\-]/),l("atom","hash");if("!"==c)return a.match(/^\s*\w*/),l("keyword","important");if(/\d/.test(c)||"."==c&&a.eat(/\d/))return a.eatWhile(/[\w.%]/),l("number","unit");if("-"!==c)return/[,+>*\/]/.test(c)?l(null,"select-op"):"."==c&&a.match(/^-?[_a-z][_a-z0-9-]*/i)?l("qualifier","qualifier"):":"==c?l("operator",c):/[;{}\[\]\(\)]/.test(c)?l(null,c):"u"==c&&a.match("rl(")?(a.backUp(1),b.tokenize=o,l("property","variable")):(a.eatWhile(/[\w\\\-]/),l("property","variable"));if(/\d/.test(a.peek()))return a.eatWhile(/[\w.%]/),l("number","unit");if(a.match(/^[^-]+-/))return l("meta","meta")}}function n(a,b){return function(c,d){for(var f,e=!1;null!=(f=c.next())&&(f!=a||e);)e=!e&&"\\"==f;return e||(b&&c.backUp(1),d.tokenize=m),l("string","string")}}function o(a,b){return a.next(),b.tokenize=a.match(/\s*[\"\']/,!1)?m:n(")",!0),l(null,"(")}b.propertyKeywords||(b=CodeMirror.resolveMode("text/css"));var c=a.indentUnit||a.tabSize||2,d=b.hooks||{},e=b.atMediaTypes||{},f=b.atMediaFeatures||{},g=b.propertyKeywords||{},h=b.colorKeywords||{},i=b.valueKeywords||{},j=!!b.allowNested,k=null;return{startState:function(a){return{tokenize:m,baseIndent:a||0,stack:[],lastToken:null}},token:function(a,b){if(b.tokenize=b.tokenize||m,b.tokenize==m&&a.eatSpace())return null;var c=b.tokenize(a,b);c&&"string"!=typeof c&&(c=l(c[0],c[1]));var d=b.stack[b.stack.length-1];if("variable"==c)return"variable-definition"==k&&b.stack.push("propertyValue"),b.lastToken="variable-2";if("property"==c){var n=a.current().toLowerCase();"propertyValue"==d?c=i.hasOwnProperty(n)?"string-2":h.hasOwnProperty(n)?"keyword":"variable-2":"rule"==d?g.hasOwnProperty(n)||(c+=" error"):"block"==d?c=g.hasOwnProperty(n)?"property":h.hasOwnProperty(n)?"keyword":i.hasOwnProperty(n)?"string-2":"tag":d&&"@media{"!=d?"@media"==d?c=e[a.current()]?"attribute":/^(only|not)$/.test(n)?"keyword":"and"==n?"error":f.hasOwnProperty(n)?"error":"attribute error":"@mediaType"==d?c=e.hasOwnProperty(n)?"attribute":"and"==n?"operator":/^(only|not)$/.test(n)?"error":"error":"@mediaType("==d?g.hasOwnProperty(n)||(e.hasOwnProperty(n)?c="error":"and"==n?c="operator":/^(only|not)$/.test(n)?c="error":c+=" error"):c="@import"==d?"tag":"error":c="tag"}else"atom"==c?d&&"@media{"!=d&&"block"!=d?"propertyValue"==d?/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(a.current())||(c+=" error"):c="error":c="builtin":"@media"==d&&"{"==k&&(c="error");if("{"==k)if("@media"==d||"@mediaType"==d)b.stack[b.stack.length-1]="@media{";else{var o=j?"block":"rule";b.stack.push(o)}else if("}"==k)for("interpolation"==d&&(c="operator");b.stack.length;){var p=b.stack.pop();if(p.indexOf("{")>-1)break}else if("interpolation"==k)b.stack.push("interpolation");else if("@media"==k)b.stack.push("@media");else if("@import"==k)b.stack.push("@import");else if("@media"==d&&/\b(keyword|attribute)\b/.test(c))b.stack[b.stack.length-1]="@mediaType";else if("@mediaType"==d&&","==a.current())b.stack[b.stack.length-1]="@media";else if("("==k)"@media"==d||"@mediaType"==d?(b.stack[b.stack.length-1]="@mediaType",b.stack.push("@mediaType(")):b.stack.push("(");else if(")"==k)for(;b.stack.length;){var p=b.stack.pop();if(p.indexOf("(")>-1)break}else":"==k&&"property"==b.lastToken?b.stack.push("propertyValue"):"propertyValue"==d&&";"==k?b.stack.pop():"@import"==d&&";"==k&&b.stack.pop();return b.lastToken=c},indent:function(a,b){var d=a.stack.length;return/^\}/.test(b)&&(d-="propertyValue"==a.stack[d-1]?2:1),a.baseIndent+d*c},electricChars:"}",blockCommentStart:"/*",blockCommentEnd:"*/",fold:"brace"}}),function(){function a(a){for(var b={},c=0;c<a.length;++c)b[a[c]]=!0;return b}function g(a,b){for(var d,c=!1;null!=(d=a.next());){if(c&&"/"==d){b.tokenize=null;break}c="*"==d}return["comment","comment"]}var b=a(["all","aural","braille","handheld","print","projection","screen","tty","tv","embossed"]),c=a(["width","min-width","max-width","height","min-height","max-height","device-width","min-device-width","max-device-width","device-height","min-device-height","max-device-height","aspect-ratio","min-aspect-ratio","max-aspect-ratio","device-aspect-ratio","min-device-aspect-ratio","max-device-aspect-ratio","color","min-color","max-color","color-index","min-color-index","max-color-index","monochrome","min-monochrome","max-monochrome","resolution","min-resolution","max-resolution","scan","grid"]),d=a(["align-content","align-items","align-self","alignment-adjust","alignment-baseline","anchor-point","animation","animation-delay","animation-direction","animation-duration","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","appearance","azimuth","backface-visibility","background","background-attachment","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","baseline-shift","binding","bleed","bookmark-label","bookmark-level","bookmark-state","bookmark-target","border","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","clear","clip","color","color-profile","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","content","counter-increment","counter-reset","crop","cue","cue-after","cue-before","cursor","direction","display","dominant-baseline","drop-initial-after-adjust","drop-initial-after-align","drop-initial-before-adjust","drop-initial-before-align","drop-initial-size","drop-initial-value","elevation","empty-cells","fit","fit-position","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","float-offset","flow-from","flow-into","font","font-feature-settings","font-family","font-kerning","font-language-override","font-size","font-size-adjust","font-stretch","font-style","font-synthesis","font-variant","font-variant-alternates","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-weight","grid-cell","grid-column","grid-column-align","grid-column-sizing","grid-column-span","grid-columns","grid-flow","grid-row","grid-row-align","grid-row-sizing","grid-row-span","grid-rows","grid-template","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","inline-box-align","justify-content","left","letter-spacing","line-break","line-height","line-stacking","line-stacking-ruby","line-stacking-shift","line-stacking-strategy","list-style","list-style-image","list-style-position","list-style-type","margin","margin-bottom","margin-left","margin-right","margin-top","marker-offset","marks","marquee-direction","marquee-loop","marquee-play-count","marquee-speed","marquee-style","max-height","max-width","min-height","min-width","move-to","nav-down","nav-index","nav-left","nav-right","nav-up","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-style","overflow-wrap","overflow-x","overflow-y","padding","padding-bottom","padding-left","padding-right","padding-top","page","page-break-after","page-break-before","page-break-inside","page-policy","pause","pause-after","pause-before","perspective","perspective-origin","pitch","pitch-range","play-during","position","presentation-level","punctuation-trim","quotes","region-break-after","region-break-before","region-break-inside","region-fragment","rendering-intent","resize","rest","rest-after","rest-before","richness","right","rotation","rotation-point","ruby-align","ruby-overhang","ruby-position","ruby-span","shape-inside","shape-outside","size","speak","speak-as","speak-header","speak-numeral","speak-punctuation","speech-rate","stress","string-set","tab-size","table-layout","target","target-name","target-new","target-position","text-align","text-align-last","text-decoration","text-decoration-color","text-decoration-line","text-decoration-skip","text-decoration-style","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-height","text-indent","text-justify","text-outline","text-overflow","text-shadow","text-size-adjust","text-space-collapse","text-transform","text-underline-position","text-wrap","top","transform","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","volume","white-space","widows","width","word-break","word-spacing","word-wrap","z-index","zoom","clip-path","clip-rule","mask","enable-background","filter","flood-color","flood-opacity","lighting-color","stop-color","stop-opacity","pointer-events","color-interpolation","color-interpolation-filters","color-profile","color-rendering","fill","fill-opacity","fill-rule","image-rendering","marker","marker-end","marker-mid","marker-start","shape-rendering","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","text-rendering","baseline-shift","dominant-baseline","glyph-orientation-horizontal","glyph-orientation-vertical","kerning","text-anchor","writing-mode"]),e=a(["aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","grey","green","greenyellow","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgreen","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","snow","springgreen","steelblue","tan","teal","thistle","tomato","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen"]),f=a(["above","absolute","activeborder","activecaption","afar","after-white-space","ahead","alias","all","all-scroll","alternate","always","amharic","amharic-abegede","antialiased","appworkspace","arabic-indic","armenian","asterisks","auto","avoid","avoid-column","avoid-page","avoid-region","background","backwards","baseline","below","bidi-override","binary","bengali","blink","block","block-axis","bold","bolder","border","border-box","both","bottom","break","break-all","break-word","button","button-bevel","buttonface","buttonhighlight","buttonshadow","buttontext","cambodian","capitalize","caps-lock-indicator","caption","captiontext","caret","cell","center","checkbox","circle","cjk-earthly-branch","cjk-heavenly-stem","cjk-ideographic","clear","clip","close-quote","col-resize","collapse","column","compact","condensed","contain","content","content-box","context-menu","continuous","copy","cover","crop","cross","crosshair","currentcolor","cursive","dashed","decimal","decimal-leading-zero","default","default-button","destination-atop","destination-in","destination-out","destination-over","devanagari","disc","discard","document","dot-dash","dot-dot-dash","dotted","double","down","e-resize","ease","ease-in","ease-in-out","ease-out","element","ellipse","ellipsis","embed","end","ethiopic","ethiopic-abegede","ethiopic-abegede-am-et","ethiopic-abegede-gez","ethiopic-abegede-ti-er","ethiopic-abegede-ti-et","ethiopic-halehame-aa-er","ethiopic-halehame-aa-et","ethiopic-halehame-am-et","ethiopic-halehame-gez","ethiopic-halehame-om-et","ethiopic-halehame-sid-et","ethiopic-halehame-so-et","ethiopic-halehame-ti-er","ethiopic-halehame-ti-et","ethiopic-halehame-tig","ew-resize","expanded","extra-condensed","extra-expanded","fantasy","fast","fill","fixed","flat","footnotes","forwards","from","geometricPrecision","georgian","graytext","groove","gujarati","gurmukhi","hand","hangul","hangul-consonant","hebrew","help","hidden","hide","higher","highlight","highlighttext","hiragana","hiragana-iroha","horizontal","hsl","hsla","icon","ignore","inactiveborder","inactivecaption","inactivecaptiontext","infinite","infobackground","infotext","inherit","initial","inline","inline-axis","inline-block","inline-table","inset","inside","intrinsic","invert","italic","justify","kannada","katakana","katakana-iroha","keep-all","khmer","landscape","lao","large","larger","left","level","lighter","line-through","linear","lines","list-item","listbox","listitem","local","logical","loud","lower","lower-alpha","lower-armenian","lower-greek","lower-hexadecimal","lower-latin","lower-norwegian","lower-roman","lowercase","ltr","malayalam","match","media-controls-background","media-current-time-display","media-fullscreen-button","media-mute-button","media-play-button","media-return-to-realtime-button","media-rewind-button","media-seek-back-button","media-seek-forward-button","media-slider","media-sliderthumb","media-time-remaining-display","media-volume-slider","media-volume-slider-container","media-volume-sliderthumb","medium","menu","menulist","menulist-button","menulist-text","menulist-textfield","menutext","message-box","middle","min-intrinsic","mix","mongolian","monospace","move","multiple","myanmar","n-resize","narrower","ne-resize","nesw-resize","no-close-quote","no-drop","no-open-quote","no-repeat","none","normal","not-allowed","nowrap","ns-resize","nw-resize","nwse-resize","oblique","octal","open-quote","optimizeLegibility","optimizeSpeed","oriya","oromo","outset","outside","outside-shape","overlay","overline","padding","padding-box","painted","page","paused","persian","plus-darker","plus-lighter","pointer","polygon","portrait","pre","pre-line","pre-wrap","preserve-3d","progress","push-button","radio","read-only","read-write","read-write-plaintext-only","rectangle","region","relative","repeat","repeat-x","repeat-y","reset","reverse","rgb","rgba","ridge","right","round","row-resize","rtl","run-in","running","s-resize","sans-serif","scroll","scrollbar","se-resize","searchfield","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","semi-condensed","semi-expanded","separate","serif","show","sidama","single","skip-white-space","slide","slider-horizontal","slider-vertical","sliderthumb-horizontal","sliderthumb-vertical","slow","small","small-caps","small-caption","smaller","solid","somali","source-atop","source-in","source-out","source-over","space","square","square-button","start","static","status-bar","stretch","stroke","sub","subpixel-antialiased","super","sw-resize","table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row","table-row-group","telugu","text","text-bottom","text-top","textarea","textfield","thai","thick","thin","threeddarkshadow","threedface","threedhighlight","threedlightshadow","threedshadow","tibetan","tigre","tigrinya-er","tigrinya-er-abegede","tigrinya-et","tigrinya-et-abegede","to","top","transparent","ultra-condensed","ultra-expanded","underline","up","upper-alpha","upper-armenian","upper-greek","upper-hexadecimal","upper-latin","upper-norwegian","upper-roman","uppercase","urdu","url","vertical","vertical-text","visible","visibleFill","visiblePainted","visibleStroke","visual","w-resize","wait","wave","wider","window","windowframe","windowtext","x-large","x-small","xor","xx-large","xx-small"]);CodeMirror.defineMIME("text/css",{atMediaTypes:b,atMediaFeatures:c,propertyKeywords:d,colorKeywords:e,valueKeywords:f,hooks:{"<":function(a,b){function c(a,b){for(var d,c=0;null!=(d=a.next());){if(c>=2&&">"==d){b.tokenize=null;break}c="-"==d?c+1:0}return["comment","comment"]}return a.eat("!")?(b.tokenize=c,c(a,b)):void 0},"/":function(a,b){return a.eat("*")?(b.tokenize=g,g(a,b)):!1}},name:"css"}),CodeMirror.defineMIME("text/x-scss",{atMediaTypes:b,atMediaFeatures:c,propertyKeywords:d,colorKeywords:e,valueKeywords:f,allowNested:!0,hooks:{":":function(a){return a.match(/\s*{/)?[null,"{"]:!1},$:function(a){return a.match(/^[\w-]+/),":"==a.peek()?["variable","variable-definition"]:["variable","variable"]},",":function(a,b){return"propertyValue"==b.stack[b.stack.length-1]?["operator",";"]:void 0},"/":function(a,b){return a.eat("/")?(a.skipToEnd(),["comment","comment"]):a.eat("*")?(b.tokenize=g,g(a,b)):["operator","operator"]
+},"#":function(a){return a.eat("{")?["operator","interpolation"]:(a.eatWhile(/[\w\\\-]/),["atom","hash"])}},name:"css"})}(),CodeMirror.defineMode("less",function(a){function d(a,b){return c=b,a}function f(a,b){var f=a.next();if("@"==f)return a.eatWhile(/[\w\-]/),d("meta",a.current());if("/"==f&&a.eat("*"))return b.tokenize=h,h(a,b);if("<"==f&&a.eat("!"))return b.tokenize=i,i(a,b);if("="==f)d(null,"compare");else{if("|"==f&&a.eat("="))return d(null,"compare");if('"'==f||"'"==f)return b.tokenize=j(f),b.tokenize(a,b);if("/"==f){if(a.eat("/"))return b.tokenize=g,g(a,b);if("string"==c||"("==c)return d("string","string");if(void 0!==b.stack[b.stack.length-1])return d(null,f);if(a.eatWhile(/[\a-zA-Z0-9\-_.\s]/),/\/|\)|#/.test(a.peek()||a.eatSpace()&&")"===a.peek())||a.eol())return d("string","string")}else{if("!"==f)return a.match(/^\s*\w*/),d("keyword","important");if(/\d/.test(f))return a.eatWhile(/[\w.%]/),d("number","unit");if(/[,+<>*\/]/.test(f))return"="==a.peek()||"a"==c?d("string","string"):","===f?d(null,f):d(null,"select-op");if(/[;{}:\[\]()~\|]/.test(f)){if(":"==f)return a.eatWhile(/[a-z\\\-]/),e.test(a.current())?d("tag","tag"):":"==a.peek()?(a.next(),a.eatWhile(/[a-z\\\-]/),a.current().match(/\:\:\-(o|ms|moz|webkit)\-/)?d("string","string"):e.test(a.current().substring(1))?d("tag","tag"):d(null,f)):d(null,f);if("~"!=f)return d(null,f);if("r"==c)return d("string","string")}else{if("."==f)return"("==c?d("string","string"):(a.eatWhile(/[\a-zA-Z0-9\-_]/)," "===a.peek()&&a.eatSpace(),")"===a.peek()||":"===c?d("number","unit"):a.current().length>1&&"rule"===b.stack[b.stack.length-1]&&null===a.peek().match(/{|,|\+|\(/)?d("number","unit"):d("tag","tag"));if("#"==f)return a.eatWhile(/[A-Za-z0-9]/),4==a.current().length||7==a.current().length?null!=a.current().match(/[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/,!1)?a.current().substring(1)!=a.current().match(/[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/,!1)?d("atom","tag"):(a.eatSpace(),/[\/<>.(){!$%^&*_\-\\?=+\|#'~`]/.test(a.peek())?"select-op"===c?d("number","unit"):d("atom","tag"):"}"==a.peek()?d("number","unit"):/[a-zA-Z\\]/.test(a.peek())?d("atom","tag"):a.eol()?d("atom","tag"):d("number","unit")):(a.eatWhile(/[\w\\\-]/),d("atom",a.current())):(a.eatWhile(/[\w\\\-]/),"rule"===b.stack[b.stack.length-1]?d("atom",a.current()):d("atom",a.current()));if("&"==f)return a.eatWhile(/[\w\-]/),d(null,f);if(a.eatWhile(/[\w\\\-_%.{]/),null===a.current().match(/\\/)){if("string"==c)return"{"===b.stack[b.stack.length-1]&&":"===a.peek()?d("variable","variable"):("/"===a.peek()&&a.eatWhile(/[\w\\\-_%.{:\/]/),d(c,a.current()));if(null!=a.current().match(/(^http$|^https$)/))return a.eatWhile(/[\w\\\-_%.{:\/]/),"/"===a.peek()&&a.eatWhile(/[\w\\\-_%.{:\/]/),d("string","string");if("<"==a.peek()||">"==a.peek()||"+"==a.peek())return"("!==c||"n"!==a.current()&&"-n"!==a.current()?d("tag","tag"):d("string",a.current());if(/\(/.test(a.peek()))return"when"===a.current()?d("variable","variable"):"@media"===b.stack[b.stack.length-1]&&"and"===a.current()?d("variable",a.current()):d(null,f);if("/"==a.peek()&&void 0!==b.stack[b.stack.length-1])return"/"===a.peek()&&a.eatWhile(/[\w\\\-_%.{:\/]/),d("string",a.current());if(a.current().match(/\-\d|\-.\d/))return d("number","unit");if(/\/|[\s\)]/.test(a.peek()||a.eol()||a.eatSpace()&&"/"==a.peek())&&-1!==a.current().indexOf("."))return"{"==a.current().substring(a.current().length-1,a.current().length)?(a.backUp(1),d("tag","tag")):(a.eatSpace(),/[{<>.a-zA-Z\/]/.test(a.peek())||a.eol()?d("tag","tag"):d("string","string"));if(a.eol()||"["==a.peek()||"#"==a.peek()||"tag"==c){if("{"==a.current().substring(a.current().length-1,a.current().length))a.backUp(1);else{if("border-color"===b.stack[b.stack.length-1]||"background-position"===b.stack[b.stack.length-1]||"font-family"===b.stack[b.stack.length-1])return d(null,a.current());if("tag"===c)return d("tag","tag");if((":"===c||"unit"===c)&&"rule"===b.stack[b.stack.length-1])return d(null,a.current());if("rule"===b.stack[b.stack.length-1]&&"tag"===c)return d("string",a.current());if(";"===b.stack[b.stack.length-1]&&":"===c)return d(null,a.current());if("#"===a.peek()&&void 0!==c&&null===c.match(/\+|,|tag|select\-op|}|{|;/g))return d("string",a.current());if("variable"===c)return d(null,a.current());if("{"===b.stack[b.stack.length-1]&&"comment"===c)return d("variable",a.current());if(0===b.stack.length&&(";"===c||"comment"===c))return d("tag",a.current());if(("{"===b.stack[b.stack.length-1]||";"===c)&&"@media{"!==b.stack[b.stack.length-1])return d("variable",a.current());if("{"===b.stack[b.stack.length-2]&&";"===b.stack[b.stack.length-1])return d("variable",a.current())}return d("tag","tag")}if("compare"==c||"a"==c||"("==c)return d("string","string");if("|"==c||"-"==a.current()||"["==c)return"|"==c&&null!==a.peek().match(/\]|=|\~/)?d("number",a.current()):"|"==c?d("tag","tag"):"["==c?(a.eatWhile(/\w\-/),d("number",a.current())):d(null,f);if(":"==a.peek()||a.eatSpace()&&":"==a.peek()){a.next();var k=":"==a.peek()?!0:!1;if(k)a.backUp(1);else{var l=a.pos,m=a.current().length;a.eatWhile(/[a-z\\\-]/);var n=a.pos;if(null!=a.current().substring(m-1).match(e))return a.backUp(n-(l-1)),d("tag","tag");a.backUp(n-(l-1))}return k?d("tag","tag"):d("variable","variable")}return"font-family"===b.stack[b.stack.length-1]||"background-position"===b.stack[b.stack.length-1]||"border-color"===b.stack[b.stack.length-1]?d(null,null):null===b.stack[b.stack.length-1]&&":"===c?d(null,a.current()):/\^|\$/.test(a.current())&&null!==a.peek().match(/\~|=/)?d("string","string"):"unit"===c&&"rule"===b.stack[b.stack.length-1]?d(null,"unit"):"unit"===c&&";"===b.stack[b.stack.length-1]?d(null,"unit"):")"===c&&"rule"===b.stack[b.stack.length-1]?d(null,"unit"):c&&null!==c.match("@")&&"rule"===b.stack[b.stack.length-1]?d(null,"unit"):";"!==c&&"}"!==c&&","!==c||";"!==b.stack[b.stack.length-1]?";"===c&&void 0!==a.peek()&&null===a.peek().match(/{|./)||";"===c&&a.eatSpace()&&null===a.peek().match(/{|./)?d("variable",a.current()):"@media"===c&&"@media"===b.stack[b.stack.length-1]||"@namespace"===c?d("tag",a.current()):"{"===c&&";"===b.stack[b.stack.length-1]&&"{"===a.peek()?d("tag","tag"):"{"!==c&&":"!==c||";"!==b.stack[b.stack.length-1]?"{"===b.stack[b.stack.length-1]&&a.eatSpace()&&null===a.peek().match(/.|#/)||"select-op"===c||"rule"===b.stack[b.stack.length-1]&&","===c?d("tag","tag"):"variable"===c&&"rule"===b.stack[b.stack.length-1]?d("tag","tag"):a.eatSpace()&&"{"===a.peek()||a.eol()||"{"===a.peek()?d("tag","tag"):")"!==c||"and"!=a.current()&&"and "!=a.current()?")"!==c||"when"!=a.current()&&"when "!=a.current()?")"===c||"comment"===c||"{"===c?d("tag","tag"):a.sol()?d("tag","tag"):a.eatSpace()&&"#"===a.peek()||"#"===a.peek()?d("tag","tag"):0===b.stack.length?d("tag","tag"):";"===c&&void 0!==a.peek()&&null!==a.peek().match(/^[.|\#]/g)?d("tag","tag"):":"===c?(a.eatSpace(),d(null,a.current())):"and "===a.current()||"and"===a.current()?d("variable",a.current()):";"===c&&"{"===b.stack[b.stack.length-1]?d("variable",a.current()):"rule"===b.stack[b.stack.length-1]?d(null,a.current()):d("tag",a.current()):d("variable","variable"):d("variable","variable"):d(null,a.current()):d("tag",a.current())}if("\\"===a.current().charAt(a.current().length-1)){for(a.eat(/\'|\"|\)|\(/);a.eatWhile(/[\w\\\-_%.{]/);)a.eat(/\'|\"|\)|\(/);return d("string",a.current())}}}}}function g(a,b){return a.skipToEnd(),b.tokenize=f,d("comment","comment")}function h(a,b){for(var e,c=!1;null!=(e=a.next());){if(c&&"/"==e){b.tokenize=f;break}c="*"==e}return d("comment","comment")}function i(a,b){for(var e,c=0;null!=(e=a.next());){if(c>=2&&">"==e){b.tokenize=f;break}c="-"==e?c+1:0}return d("comment","comment")}function j(a){return function(b,c){for(var g,e=!1;null!=(g=b.next())&&(g!=a||e);)e=!e&&"\\"==g;return e||(c.tokenize=f),d("string","string")}}var c,b=a.indentUnit,e=/(^\:root$|^\:nth\-child$|^\:nth\-last\-child$|^\:nth\-of\-type$|^\:nth\-last\-of\-type$|^\:first\-child$|^\:last\-child$|^\:first\-of\-type$|^\:last\-of\-type$|^\:only\-child$|^\:only\-of\-type$|^\:empty$|^\:link|^\:visited$|^\:active$|^\:hover$|^\:focus$|^\:target$|^\:lang$|^\:enabled^\:disabled$|^\:checked$|^\:first\-line$|^\:first\-letter$|^\:before$|^\:after$|^\:not$|^\:required$|^\:invalid$)/;return{startState:function(a){return{tokenize:f,baseIndent:a||0,stack:[]}},token:function(a,b){if(a.eatSpace())return null;var e=b.tokenize(a,b),f=b.stack[b.stack.length-1];if("hash"==c&&"rule"==f?e="atom":"variable"==e&&("rule"==f?e=null:f&&"@media{"!=f||(e="when"==a.current()?"variable":/[\s,|\s\)|\s]/.test(a.peek())?"tag":c)),"rule"==f&&/^[\{\};]$/.test(c)&&b.stack.pop(),"{"==c?"@media"==f?b.stack[b.stack.length-1]="@media{":b.stack.push("{"):"}"==c?b.stack.pop():"@media"==c?b.stack.push("@media"):"font-family"===a.current()?b.stack[b.stack.length-1]="font-family":"background-position"===a.current()?b.stack[b.stack.length-1]="background-position":"border-color"===a.current()?b.stack[b.stack.length-1]="border-color":"{"==f&&"comment"!=c&&"tag"!==c?b.stack.push("rule"):":"===a.peek()&&null===a.current().match(/@|#/)&&(e=c),";"!==c||"font-family"!=b.stack[b.stack.length-1]&&"background-position"!=b.stack[b.stack.length-1]&&"border-color"!=b.stack[b.stack.length-1]){if("tag"===c&&")"===a.peek()&&null===a.current().match(/\:/))c=null,e=null;else if("variable"===c&&")"===a.peek()||"variable"===c&&a.eatSpace()&&")"===a.peek())return d(null,a.current())}else b.stack[b.stack.length-1]=a.current();return e},indent:function(a,c){var d=a.stack.length;return/^\}/.test(c)?d-="rule"===a.stack[a.stack.length-1]?2:1:"{"===a.stack[a.stack.length-2]&&(d-="rule"===a.stack[a.stack.length-1]?1:0),a.baseIndent+d*b},electricChars:"}",blockCommentStart:"/*",blockCommentEnd:"*/",lineComment:"//"}}),CodeMirror.defineMIME("text/x-less","less"),CodeMirror.mimeModes.hasOwnProperty("text/css")||CodeMirror.defineMIME("text/css","less"); \ No newline at end of file
diff --git a/plugins/jetpack/modules/custom-css/custom-css/js/css-editor.js b/plugins/jetpack/modules/custom-css/custom-css/js/css-editor.js
index 6d4f0824..6da30d9f 100644
--- a/plugins/jetpack/modules/custom-css/custom-css/js/css-editor.js
+++ b/plugins/jetpack/modules/custom-css/custom-css/js/css-editor.js
@@ -1,3 +1,6 @@
+/* jshint onevar: false, smarttabs: true */
+/* global postboxes, addLoadEvent */
+
( function ( $ ) {
var safe, win, safecssResize, safecssInit;
@@ -16,11 +19,11 @@
$( '#safecssform' ).on( 'click', '#preview', function ( e ) {
e.preventDefault();
- document.forms["safecssform"].target = "csspreview";
- document.forms["safecssform"].action.value = 'preview';
- document.forms["safecssform"].submit();
- document.forms["safecssform"].target = "";
- document.forms["safecssform"].action.value = 'save';
+ document.forms.safecssform.target = 'csspreview';
+ document.forms.safecssform.action.value = 'preview';
+ document.forms.safecssform.submit();
+ document.forms.safecssform.target = '';
+ document.forms.safecssform.action.value = 'save';
} );
};
@@ -74,8 +77,8 @@ jQuery( function ( $ ) {
e.preventDefault();
$( '#css-mode-select' ).slideUp();
- $( '#css-mode-display' ).text( $( 'input[name=add_to_existing_display]:checked' ).val() == 'true' ? 'Add-on' : 'Replacement' );
+ $( '#css-mode-display' ).text( $( 'input[name=add_to_existing_display]:checked' ).val() == 'true' ? 'Add-on' : 'Replacement' ); // jshint ignore:line
$( '#add_to_existing' ).val( $( 'input[name=add_to_existing_display]:checked' ).val() );
$( '.edit-css-mode' ).show();
} );
-} ); \ No newline at end of file
+} );
diff --git a/plugins/jetpack/modules/custom-css/custom-css/js/safecss-ace.js b/plugins/jetpack/modules/custom-css/custom-css/js/safecss-ace.js
deleted file mode 100644
index 2fb46191..00000000
--- a/plugins/jetpack/modules/custom-css/custom-css/js/safecss-ace.js
+++ /dev/null
@@ -1,70 +0,0 @@
-(function(global, $){
- // shared scope insied IIFE in case it's needed.
- var editor;
-
- var syncCSS = function () {
- $( "#safecss" ).val( editor.getSession().getValue() );
- };
-
- var loadAce = function() {
- // Set up ACE editor
- ace.config.set( 'modePath', safecssAceSrcPath );
- ace.config.set( 'workerPath', safecssAceSrcPath );
- ace.config.set( 'themePath', safecssAceSrcPath );
-
- editor = ace.edit( 'safecss-ace' );
- // Globalize it so we can access it other places
- global.safecss_editor = editor;
- // Word-wrap, othewise the initial comments are borked.
- editor.getSession().setUseWrapMode(true);
- // This adds an annoying vertical line to the editor; get rid of it.
- editor.setShowPrintMargin( false );
- // Grab straight from the textarea
- editor.getSession().setValue( $("#safecss").val() );
- // kill the spinner
- jQuery.fn.spin && $("#safecss-container").spin( false );
-
- var preprocessorField = $( '#custom_css_preprocessor' );
- function setCSSMode( preprocessor ) {
- switch ( preprocessor ) {
- case 'less':
- var mode = ace.require( 'ace/mode/less' ).Mode;
- break;
- case 'sass':
- var mode = ace.require( 'ace/mode/scss' ).Mode;
- break;
- default:
- var mode = ace.require( 'ace/mode/css' ).Mode;
- break;
- }
-
- editor.getSession().setMode( new mode() );
- }
-
- setCSSMode( preprocessorField.val() );
- preprocessorField.on( 'change', function () {
- setCSSMode( $( this ).val() );
- } );
-
- // When submitting, make sure to include the updated CSS
- // The Ace editor unfortunately doesn't handle this for us
- $( '#safecssform' ).submit(syncCSS);
- }
-
- // exit if we're on IE <= 7
- if ( ( $.browser.msie && parseInt( $.browser.version, 10 ) <= 7 ) || navigator.userAgent.match(/iPad/i) != null ) {
- $("#safecss-container").hide();
- $("#safecss").removeClass('hide-if-js');
- return false;
- }
- // syntaxy goodness.
- else {
- $( '#safecss-ace, #safecss-container' ).css( 'height',
- Math.max( 250, $( window ).height() - $( '#safecss-container' ).offset().top - $( '#wpadminbar' ).height() )
- );
-
- $(global).load(loadAce);
- }
-
- $( '#preview' ).on( 'click', syncCSS );
-})(this, jQuery); \ No newline at end of file
diff --git a/plugins/jetpack/modules/custom-css/custom-css/js/use-codemirror.js b/plugins/jetpack/modules/custom-css/custom-css/js/use-codemirror.js
new file mode 100644
index 00000000..00b5ac7e
--- /dev/null
+++ b/plugins/jetpack/modules/custom-css/custom-css/js/use-codemirror.js
@@ -0,0 +1,47 @@
+/* jshint onevar: false, smarttabs: true */
+
+(function($){
+ var Jetpack_CSS = {
+ modes: {
+ 'default': 'text/css',
+ 'less': 'text/x-less',
+ 'sass': 'text/x-scss'
+ },
+ init: function() {
+ this.$textarea = $( '#safecss' );
+ this.editor = window.CodeMirror.fromTextArea( this.$textarea.get(0),{
+ mode: this.getMode(),
+ lineNumbers: true,
+ tabSize: 2,
+ indentWithTabs: true,
+ lineWrapping: true
+ });
+ this.setEditorHeight();
+ },
+ addListeners: function() {
+ // nice sizing
+ $( window ).on( 'resize', _.bind( _.debounce( this.setEditorHeight, 100 ), this ) );
+ // keep textarea synced up
+ this.editor.on( 'change', _.bind( function( editor ){
+ this.$textarea.val( editor.getValue() );
+ }, this ) );
+ // change mode
+ $( '#preprocessor_choices' ).change( _.bind( function(){
+ this.editor.setOption( 'mode', this.getMode() );
+ }, this ) );
+ },
+ setEditorHeight: function() {
+ var height = $('html').height() - $( this.editor.getWrapperElement() ).offset().top;
+ this.editor.setSize( null, height );
+ },
+ getMode: function() {
+ var mode = $( '#preprocessor_choices' ).val();
+ if ( '' === mode || ! this.modes[ mode ] ) {
+ mode = 'default';
+ }
+ return this.modes[ mode ];
+ }
+ };
+
+ $( document ).ready( _.bind( Jetpack_CSS.init, Jetpack_CSS ) );
+})(jQuery);
diff --git a/plugins/jetpack/modules/custom-css/custom-css/preprocessors/lessc.inc.php b/plugins/jetpack/modules/custom-css/custom-css/preprocessors/lessc.inc.php
index 8bdfa3fb..48e4f82d 100644
--- a/plugins/jetpack/modules/custom-css/custom-css/preprocessors/lessc.inc.php
+++ b/plugins/jetpack/modules/custom-css/custom-css/preprocessors/lessc.inc.php
@@ -537,7 +537,7 @@ class lessc {
return true; // not having enough is handled above
} else {
$numMatched = $i + 1;
- // greater than becuase default values always match
+ // greater than because default values always match
return $numMatched >= count($orderedArgs);
}
}
@@ -2204,7 +2204,7 @@ class lessc_parser {
// regex string to match any of the operators
static protected $operatorString;
- // these properties will supress division unless it's inside parenthases
+ // these properties will suppress division unless it's inside parenthases
static protected $supressDivisionProps =
array('/border-radius$/i', '/^font$/i');
diff --git a/plugins/jetpack/modules/custom-css/custom-css/preprocessors/scss.inc.php b/plugins/jetpack/modules/custom-css/custom-css/preprocessors/scss.inc.php
index ff0493a7..344b55f1 100644
--- a/plugins/jetpack/modules/custom-css/custom-css/preprocessors/scss.inc.php
+++ b/plugins/jetpack/modules/custom-css/custom-css/preprocessors/scss.inc.php
@@ -43,7 +43,7 @@
* @author Leaf Corcoran <leafot@gmail.com>
*/
class scssc {
- static public $VERSION = "v0.0.7";
+ static public $VERSION = "v0.0.9";
static protected $operatorNames = array(
'+' => "add",
@@ -67,7 +67,6 @@ class scssc {
"function" => "^",
);
- static protected $numberPrecision = 5;
static protected $unitTable = array(
"in" => array(
"in" => 1,
@@ -91,9 +90,11 @@ class scssc {
protected $userFunctions = array();
+ protected $numberPrecision = 5;
+
protected $formatter = "scss_formatter_nested";
- function compile($code, $name=null) {
+ public function compile($code, $name=null) {
$this->indentLevel = -1;
$this->commentsSeen = array();
$this->extends = array();
@@ -186,6 +187,13 @@ class scssc {
$rem = array_diff($single, $target);
foreach ($origin as $j => $new) {
+ // prevent infinite loop when target extends itself
+ foreach ($new as $new_selector) {
+ if (!array_diff($single, $new_selector)) {
+ continue 2;
+ }
+ }
+
$origin[$j][count($origin[$j]) - 1] = $this->combineSelectorSingle(end($new), $rem);
}
@@ -732,8 +740,9 @@ class scssc {
$this->throwError("Expected @content inside of mixin");
}
+ $strongTypes = array('include', 'block', 'for', 'while');
foreach ($content->children as $child) {
- $this->storeEnv = ($child[0] == 'include' || $child[0] == 'block')
+ $this->storeEnv = (in_array($child[0], $strongTypes))
? null
: $content->scope;
@@ -1131,7 +1140,7 @@ class scssc {
return $this->toBool($left[1] < $right[1]);
}
- protected function toBool($thing) {
+ public function toBool($thing) {
return $thing ? self::$true : self::$false;
}
@@ -1179,7 +1188,7 @@ class scssc {
return $h;
case "number":
- return round($value[1], self::$numberPrecision) . $value[2];
+ return round($value[1], $this->numberPrecision) . $value[2];
case "string":
return $value[1] . $this->compileStringContent($value) . $value[1];
case "function":
@@ -1414,7 +1423,7 @@ class scssc {
} elseif (!empty($default)) {
$val = $default;
} else {
- $this->throwError("Missing argument $$name");
+ $this->throwError("Missing argument $name");
}
$this->set($name, $this->reduce($val, true), true);
@@ -1450,24 +1459,22 @@ class scssc {
}
}
- // todo: this is bugged?
protected function setExisting($name, $value, $env = null) {
if (is_null($env)) $env = $this->getStoreEnv();
- if (isset($env->store[$name])) {
+ if (isset($env->store[$name]) || is_null($env->parent)) {
$env->store[$name] = $value;
- } elseif (!is_null($env->parent)) {
- $this->setExisting($name, $value, $env->parent);
} else {
- $this->env->store[$name] = $value;
+ $this->setExisting($name, $value, $env->parent);
}
}
protected function setRaw($name, $value) {
- $this->env->store[$name] = $value;
+ $env = $this->getStoreEnv();
+ $env->store[$name] = $value;
}
- protected function get($name, $defaultValue = null, $env = null) {
+ public function get($name, $defaultValue = null, $env = null) {
$name = $this->normalizeName($name);
if (is_null($env)) $env = $this->getStoreEnv();
@@ -1500,6 +1507,10 @@ class scssc {
$this->importPaths = (array)$path;
}
+ public function setNumberPrecision($numberPrecision) {
+ $this->numberPrecision = $numberPrecision;
+ }
+
public function setFormatter($formatterName) {
$this->formatter = $formatterName;
}
@@ -1533,7 +1544,7 @@ class scssc {
}
// results the file path for an import url if it exists
- protected function findImport($url) {
+ public function findImport($url) {
$urls = array();
// for "normal" scss imports (ignore vanilla css and external requests)
@@ -1668,8 +1679,10 @@ class scssc {
case "keyword":
$name = $value[1];
if (isset(self::$cssColors[$name])) {
- list($r, $g, $b) = explode(',', self::$cssColors[$name]);
- return array('color', (int) $r, (int) $g, (int) $b);
+ @list($r, $g, $b, $a) = explode(',', self::$cssColors[$name]);
+ return isset($a)
+ ? array('color', (int) $r, (int) $g, (int) $b, (int) $a)
+ : array('color', (int) $r, (int) $g, (int) $b);
}
return null;
}
@@ -1687,18 +1700,18 @@ class scssc {
return null;
}
- protected function assertList($value) {
+ public function assertList($value) {
if ($value[0] != "list")
$this->throwError("expecting list");
return $value;
}
- protected function assertColor($value) {
+ public function assertColor($value) {
if ($color = $this->coerceColor($value)) return $color;
$this->throwError("expecting color");
}
- protected function assertNumber($value) {
+ public function assertNumber($value) {
if ($value[0] != "number")
$this->throwError("expecting number");
return $value[1];
@@ -1724,7 +1737,7 @@ class scssc {
return $c;
}
- function toHSL($red, $green, $blue) {
+ public function toHSL($red, $green, $blue) {
$r = $red / 255;
$g = $green / 255;
$b = $blue / 255;
@@ -1753,7 +1766,7 @@ class scssc {
return array('hsl', fmod($h, 360), $s * 100, $l * 100);
}
- function hueToRGB($m1, $m2, $h) {
+ public function hueToRGB($m1, $m2, $h) {
if ($h < 0)
$h += 1;
elseif ($h > 1)
@@ -1772,7 +1785,7 @@ class scssc {
}
// H from 0 to 360, S and L from 0 to 100
- function toRGB($hue, $saturation, $lightness) {
+ public function toRGB($hue, $saturation, $lightness) {
if ($hue < 0) {
$hue += 360;
}
@@ -1930,19 +1943,19 @@ class scssc {
protected static $lib_red = array("color");
protected function lib_red($args) {
- list($color) = $args;
+ $color = $this->coerceColor($args[0]);
return $color[1];
}
protected static $lib_green = array("color");
protected function lib_green($args) {
- list($color) = $args;
+ $color = $this->coerceColor($args[0]);
return $color[2];
}
protected static $lib_blue = array("color");
protected function lib_blue($args) {
- list($color) = $args;
+ $color = $this->coerceColor($args[0]);
return $color[3];
}
@@ -2188,8 +2201,8 @@ class scssc {
$numbers = $this->getNormalizedNumbers($args);
$min = null;
foreach ($numbers as $key => $number) {
- if (null === $min || $number <= $min[1]) {
- $min = array($key, $number);
+ if (null === $min || $number[1] <= $min[1]) {
+ $min = array($key, $number[1]);
}
}
@@ -2200,8 +2213,8 @@ class scssc {
$numbers = $this->getNormalizedNumbers($args);
$max = null;
foreach ($numbers as $key => $number) {
- if (null === $max || $number >= $max[1]) {
- $max = array($key, $number);
+ if (null === $max || $number[1] >= $max[1]) {
+ $max = array($key, $number[1]);
}
}
@@ -2220,12 +2233,12 @@ class scssc {
if (null === $unit) {
$unit = $number[2];
+ $originalUnit = $item[2];
} elseif ($unit !== $number[2]) {
$this->throwError('Incompatible units: "%s" and "%s".', $originalUnit, $item[2]);
}
- $originalUnit = $item[2];
- $numbers[$key] = $number[1];
+ $numbers[$key] = $number;
}
return $numbers;
@@ -2244,7 +2257,6 @@ class scssc {
return isset($list[2][$n]) ? $list[2][$n] : self::$defaultValue;
}
-
protected function listSeparatorForJoin($list1, $sep) {
if (is_null($sep)) return $list1[1];
switch ($this->compileValue($sep)) {
@@ -2343,7 +2355,17 @@ class scssc {
return $number1[2] == $number2[2] || $number1[2] == "" || $number2[2] == "";
}
- protected function throwError($msg = null) {
+ /**
+ * Workaround IE7's content counter bug.
+ *
+ * @param array $args
+ */
+ protected function lib_counter($args) {
+ $list = array_map(array($this, 'compileValue'), $args);
+ return array('string', '', array('counter(' . implode(',', $list) . ')'));
+ }
+
+ public function throwError($msg = null) {
if (func_num_args() > 1) {
$msg = call_user_func_array("sprintf", func_get_args());
}
@@ -2355,6 +2377,11 @@ class scssc {
throw new Exception($msg);
}
+ /**
+ * CSS Colors
+ *
+ * @see http://www.w3.org/TR/css3-color
+ */
static protected $cssColors = array(
'aliceblue' => '240,248,255',
'antiquewhite' => '250,235,215',
@@ -2496,6 +2523,7 @@ class scssc {
'teal' => '0,128,128',
'thistle' => '216,191,216',
'tomato' => '255,99,71',
+ 'transparent' => '0,0,0,0',
'turquoise' => '64,224,208',
'violet' => '238,130,238',
'wheat' => '245,222,179',
@@ -2542,7 +2570,7 @@ class scss_parser {
static protected $commentMultiLeft = "/*";
static protected $commentMultiRight = "*/";
- function __construct($sourceName = null, $rootParser = true) {
+ public function __construct($sourceName = null, $rootParser = true) {
$this->sourceName = $sourceName;
$this->rootParser = $rootParser;
@@ -2562,7 +2590,7 @@ class scss_parser {
$operators)).')';
}
- function parse($buffer) {
+ public function parse($buffer) {
$this->count = 0;
$this->env = null;
$this->inParens = false;
@@ -3325,7 +3353,7 @@ class scss_parser {
$args[] = array("string", "", array(", "));
}
- if (!$this->literal(")")) {
+ if (!$this->literal(")") || !count($args)) {
$this->seek($s);
return false;
}
@@ -3893,7 +3921,7 @@ class scss_parser {
*
* {@internal This is a workaround for preg_match's 250K string match limit. }}
*
- * @param array $m Matches (passed by reference)
+ * @param array $m Matches (passed by reference)
* @param string $delim Delimeter
*
* @return boolean True if match; false otherwise
@@ -4208,7 +4236,7 @@ class scss_server {
* @return string
*/
protected function findInput() {
- if ($input = $this->inputName()
+ if (($input = $this->inputName())
&& strpos($input, '..') === false
&& substr($input, -5) === '.scss'
) {
@@ -4290,10 +4318,12 @@ class scss_server {
/**
* Compile requested scss and serve css. Outputs HTTP response.
+ *
+ * @param string $salt Prefix a string to the filename for creating the cache name hash
*/
- public function serve() {
+ public function serve($salt = '') {
if ($input = $this->findInput()) {
- $output = $this->cacheName($input);
+ $output = $this->cacheName($salt . $input);
header('Content-type: text/css');
if ($this->needsCompile($input, $output)) {
@@ -4332,7 +4362,7 @@ class scss_server {
}
$this->cacheDir = $cacheDir;
- if (!is_dir($this->cacheDir)) mkdir($this->cacheDir);
+ if (!is_dir($this->cacheDir)) mkdir($this->cacheDir, 0755, true);
if (is_null($scss)) {
$scss = new scssc();
diff --git a/plugins/jetpack/modules/custom-post-types/comics.php b/plugins/jetpack/modules/custom-post-types/comics.php
index a91b7e56..0170512b 100644
--- a/plugins/jetpack/modules/custom-post-types/comics.php
+++ b/plugins/jetpack/modules/custom-post-types/comics.php
@@ -1,5 +1,5 @@
<?php
-
+
class Jetpack_Comic {
const POST_TYPE = 'jetpack-comic';
@@ -22,6 +22,15 @@ class Jetpack_Comic {
* WordPress. We'll just return early instead.
*/
function __construct() {
+ // Make sure the post types are loaded for imports
+ add_action( 'import_start', array( $this, 'register_post_types' ) );
+
+ // Add to REST API post type whitelist
+ add_filter( 'rest_api_allowed_post_types', array( $this, 'allow_rest_api_type' ) );
+
+ // If called via REST API, we need to register later in lifecycle
+ add_action( 'restapi_theme_init', array( $this, 'maybe_register_post_types' ) );
+
// Return early if theme does not support Jetpack Comic.
if ( ! ( $this->site_supports_comics() ) )
return;
@@ -39,7 +48,6 @@ class Jetpack_Comic {
// available.
// Enable Omnisearch for Comic posts.
- // @see http://themedevp2.wordpress.com/2013/06/21/howdy-cainm-id-like-to // @wpcom
if ( class_exists( 'Jetpack_Omnisearch_Posts' ) )
new Jetpack_Omnisearch_Posts( self::POST_TYPE );
@@ -47,8 +55,6 @@ class Jetpack_Comic {
if ( function_exists( 'queue_publish_post' ) ) {
add_action( 'publish_jetpack-comic', 'queue_publish_post', 10, 2 );
- } else {
- add_action( 'publish_jetpack-comic', 'publish_post', 10, 2 );
}
add_action( 'pre_get_posts', array( $this, 'include_in_feeds' ) );
@@ -72,6 +78,7 @@ class Jetpack_Comic {
add_action( 'admin_footer-edit.php', array( $this, 'admin_footer' ) );
add_action( 'load-edit.php', array( $this, 'bulk_edit' ) );
add_action( 'admin_notices', array( $this, 'bulk_edit_notices' ) );
+
}
public function admin_footer() {
@@ -166,7 +173,12 @@ class Jetpack_Comic {
}
public function register_scripts() {
- wp_enqueue_style( 'jetpack-comics-style', plugins_url( 'comics/comics.css', __FILE__ ) );
+ if( is_rtl() ) {
+ wp_enqueue_style( 'jetpack-comics-style', plugins_url( 'comics/rtl/comics-rtl.css', __FILE__ ) );
+ } else {
+ wp_enqueue_style( 'jetpack-comics-style', plugins_url( 'comics/comics.css', __FILE__ ) );
+ }
+
wp_enqueue_script( 'jetpack-comics', plugins_url( 'comics/comics.js', __FILE__ ), array( 'jquery', 'jquery.spin' ) );
$options = array(
@@ -189,7 +201,19 @@ class Jetpack_Comic {
wp_enqueue_style( 'jetpack-comics-admin', plugins_url( 'comics/admin.css', __FILE__ ) );
}
+ public function maybe_register_post_types() {
+ // Return early if theme does not support Jetpack Comic.
+ if ( ! ( $this->site_supports_comics() ) )
+ return;
+
+ $this->register_post_types();
+ }
+
function register_post_types() {
+ if ( post_type_exists( self::POST_TYPE ) ) {
+ return;
+ }
+
register_post_type( self::POST_TYPE, array(
'description' => __( 'Comics', 'jetpack' ),
'labels' => array(
@@ -291,23 +315,48 @@ class Jetpack_Comic {
return $messages;
}
+ /**
+ * Should this Custom Post Type be made available?
+ */
public function site_supports_comics() {
+ /**
+ * @todo: Extract this out into a wpcom only file.
+ */
if ( 'blog-rss.php' == substr( $_SERVER['PHP_SELF'], -12 ) && count( $_SERVER['argv'] ) > 1 ) {
// blog-rss.php isn't run in the context of the target blog when the init action fires,
// so check manually whether the target blog supports comics.
switch_to_blog( $_SERVER['argv'][1] );
// The add_theme_support( 'jetpack-comic' ) won't fire on switch_to_blog, so check for Panel manually.
- $supports_comics = $this->_site_supports_comics() || get_stylesheet() == 'pub/panel';
+ $supports_comics = ( ( function_exists( 'site_vertical' ) && 'comics' == site_vertical() )
+ || current_theme_supports( self::POST_TYPE )
+ || get_stylesheet() == 'pub/panel' );
restore_current_blog();
- return $supports_comics;
+ /** This action is documented in modules/custom-post-types/nova.php */
+ return (bool) apply_filters( 'jetpack_enable_cpt', $supports_comics, self::POST_TYPE );
}
- else {
- return $this->_site_supports_comics();
+
+ $supports_comics = false;
+
+ /**
+ * If we're on WordPress.com, and it has the menu site vertical.
+ * @todo: Extract this out into a wpcom only file.
+ */
+ if ( function_exists( 'site_vertical' ) && 'comics' == site_vertical() ) {
+ $supports_comics = true;
}
- }
- private function _site_supports_comics() {
- return ( ( function_exists( 'site_vertical' ) && 'comics' == site_vertical() ) || current_theme_supports( self::POST_TYPE ) );
+ /**
+ * Else, if the current theme requests it.
+ */
+ if ( current_theme_supports( self::POST_TYPE ) ) {
+ $supports_comics = true;
+ }
+
+ /**
+ * Filter it in case something else knows better.
+ */
+ /** This action is documented in modules/custom-post-types/nova.php */
+ return (bool) apply_filters( 'jetpack_enable_cpt', $supports_comics, self::POST_TYPE );
}
/**
@@ -448,6 +497,14 @@ class Jetpack_Comic {
return $query;
}
+ /**
+ * Add to REST API post type whitelist
+ */
+ public function allow_rest_api_type( $post_types ) {
+ $post_types[] = self::POST_TYPE;
+ return $post_types;
+ }
+
}
add_action( 'init', array( 'Jetpack_Comic', 'init' ) );
@@ -469,4 +526,3 @@ The WordPress.com Team", 'jetpack' );
}
add_filter( 'update_welcome_email_pre_replacement', 'comics_welcome_email', 10, 6 );
-
diff --git a/plugins/jetpack/modules/custom-post-types/comics/admin.css b/plugins/jetpack/modules/custom-post-types/comics/admin.css
index 4e1ac316..e347ac3c 100644
--- a/plugins/jetpack/modules/custom-post-types/comics/admin.css
+++ b/plugins/jetpack/modules/custom-post-types/comics/admin.css
@@ -1,4 +1,3 @@
-
#adminmenu #menu-posts-jetpack-comic .menu-icon-post div.wp-menu-image:before {
content: '\f125';
}
diff --git a/plugins/jetpack/modules/custom-post-types/comics/comics.js b/plugins/jetpack/modules/custom-post-types/comics/comics.js
index 2576c019..960fbfad 100644
--- a/plugins/jetpack/modules/custom-post-types/comics/comics.js
+++ b/plugins/jetpack/modules/custom-post-types/comics/comics.js
@@ -1,3 +1,6 @@
+/* jshint onevar: false, smarttabs: true, devel: true */
+/* global Jetpack_Comics_Options */
+
jQuery( function ( $ ) {
/**
* Enable front-end uploading of images for Comics users.
@@ -24,7 +27,7 @@ jQuery( function ( $ ) {
},
/**
- * Only upload image files.
+ * Only upload image files.
*/
filterImageFiles : function ( files ) {
var validFiles = [];
@@ -48,7 +51,7 @@ jQuery( function ( $ ) {
$( 'body' ).addClass( 'dragging' );
},
- onDragLeave: function ( event ) {
+ onDragLeave: function ( /*event*/ ) {
clearTimeout( Jetpack_Comics.dragTimeout );
// In Chrome, the screen flickers because we're moving the drop zone in front of 'body'
@@ -70,7 +73,7 @@ jQuery( function ( $ ) {
$( 'body' ).removeClass( 'dragging' );
- if ( files.length == 0 ) {
+ if ( files.length === 0 ) {
alert( Jetpack_Comics_Options.labels.invalidUpload );
return;
}
@@ -108,7 +111,7 @@ jQuery( function ( $ ) {
$( 'body' ).removeClass( 'uploading' );
}
} )
- .fail( function ( req ) {
+ .fail( function ( /*req*/ ) {
alert( Jetpack_Comics_Options.labels.error );
} );
}
diff --git a/plugins/jetpack/modules/custom-post-types/css/edit-items.css b/plugins/jetpack/modules/custom-post-types/css/edit-items.css
new file mode 100644
index 00000000..85fbbe96
--- /dev/null
+++ b/plugins/jetpack/modules/custom-post-types/css/edit-items.css
@@ -0,0 +1,24 @@
+.widefat .menu-label-row td {
+ border-bottom-width: 1px;
+}
+.widefat .menu-label-row td h3 {
+ padding-left: 30px;
+}
+.widefat .menu-order-value {
+ width: 2.5em;
+ text-align: center;
+}
+.widefat .menu-label-row, .widefat .menu-label-row td {
+ background-color: #d6d6d6;
+ color: #111;
+ border: 0 none;
+}
+.ui-sortable .type-nova_menu_item {
+ cursor: move;
+}
+.tablenav .button-reorder {
+ margin-top: 4px;
+}
+.tablenav .view-switch a, .tablenav div.tablenav-pages {
+ display: none;
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/custom-post-types/css/many-items.css b/plugins/jetpack/modules/custom-post-types/css/many-items.css
new file mode 100644
index 00000000..c9932430
--- /dev/null
+++ b/plugins/jetpack/modules/custom-post-types/css/many-items.css
@@ -0,0 +1,14 @@
+.many-items-table th, .many-items-table td {
+ width: 25%;
+}
+
+.many-items-table input, .many-items-table textarea {
+ width: 100%;
+}
+
+.many-items-table input[type=file] {
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ box-sizing: border-box;
+}
diff --git a/plugins/jetpack/modules/custom-post-types/css/nova-font.css b/plugins/jetpack/modules/custom-post-types/css/nova-font.css
new file mode 100644
index 00000000..5358f8f6
--- /dev/null
+++ b/plugins/jetpack/modules/custom-post-types/css/nova-font.css
@@ -0,0 +1,29 @@
+@font-face {
+ font-family: 'nova-font';
+ src: url('../fonts/nova.eot');
+}
+@font-face {
+ font-family: 'nova-font';
+ src: url(data:application/x-font-ttf;charset=utf-8;base64,AAEAAAALAIAAAwAwT1MvMg5lAuAAAAC8AAAAYGNtYXDL9xqaAAABHAAAADxnYXNwAAAAEAAAAVgAAAAIZ2x5Zrlfj0YAAAFgAAABrGhlYWQAW+atAAADDAAAADZoaGVhB2ED4AAAA0QAAAAkaG10eAXcAGQAAANoAAAADGxvY2EACgDWAAADdAAAAAhtYXhwAAgAkQAAA3wAAAAgbmFtZXvEneAAAAOcAAABHnBvc3QAAwAAAAAEvAAAACAAAwPoAZAABQAAAooCvAAAAIwCigK8AAAB4AAxAQIAAAAAAAAAAAAAAAAAAAABEAAAAAAAAAAAAAAAAAAAAABAACDmAwOp/8L/wgOpAD4AAAAAAAAAAAAAAAAAAAAgAAAAAAACAAAAAwAAABQAAwABAAAAFAAEACgAAAAGAAQAAQACACDmA///AAAAIOYD////4Rn/AAEAAAAAAAAAAQAB//8ADwABAAAAAAAAAAAAAgAANzkBAAAAAAQAZAAyA7YDhAAoAEUAfQCOAAABMhY6ATMyPgI/ASMHJz8BDwEnNycHDgMHFgYWBhcHMgYWIjMXNwUHDgMHHgMXHgMzMj4CPwEnKgMjFyc3Ni4CJy4DIyIOAgcOAxceAxceAz8BAR4DMzI+Ajc+Ayc2LgIvAQEmPgI3PgEeARceAxcnApQCBAQEAg4XFxQKtzGXH2oaM3UhlwHUCg0KBAEBAQIBAhQBAQEBAXIN/t3oCwwLAwEBAwsMCwgVFhkMDhgXEwuxcgICAwEC94wFBQMUIRkRLS0xFQsVFxULCQ8GAgQDDxMaDxUuNDIaDgEwBhAQFQkMExIQCAcMBgUBAQUGDAfm/i8CAwIHAhApLy0VCRMMCwLrAfUBBAoNCtWWIHYyGWsglDS5CRQWGQ0CBAQEAw8BAWkOKsIJFBYZDQ0YFxQJCg0KBAQKDQrWngp+DxczNTUXEx4VDAMHDAoKGh4iExMnJSMPFB4SBQQD/l8HCgYEBAcLCAcQEhQKCxMSEAjPAV8BBgcHBA4KCRgTCxgWFQlaAAAAAAEAAAABAAAD2anvXw889QALA+gAAAAAzsPRIgAAAADOw9EiAAAAAAO2A4QAAAAIAAIAAAAAAAAAAQAAA6n/wgAAA+gAAAAyA7YAAQAAAAAAAAAAAAAAAAAAAAMAAAAAAfQAAAPoAGQAAAAAAAoA1gABAAAAAwCPAAQAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAADgCuAAEAAAAAAAEACAAAAAEAAAAAAAIADgAyAAEAAAAAAAMACAAeAAEAAAAAAAQACABAAAEAAAAAAAUAFgAIAAEAAAAAAAYABAAmAAEAAAAAAAoAKABIAAMAAQQJAAEACAAAAAMAAQQJAAIADgAyAAMAAQQJAAMACAAeAAMAAQQJAAQACABAAAMAAQQJAAUAFgAIAAMAAQQJAAYACAAqAAMAAQQJAAoAKABIAG4AbwB2AGEAVgBlAHIAcwBpAG8AbgAgADAALgAwAG4AbwB2AGFub3ZhAG4AbwB2AGEAUgBlAGcAdQBsAGEAcgBuAG8AdgBhAEcAZQBuAGUAcgBhAHQAZQBkACAAYgB5ACAASQBjAG8ATQBvAG8AbgAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=) format('truetype'),
+ url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAAUoAAsAAAAABNwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPUy8yAAABCAAAAGAAAABgDmUC4GNtYXAAAAFoAAAAPAAAADzL9xqaZ2FzcAAAAaQAAAAIAAAACAAAABBnbHlmAAABrAAAAawAAAGsuV+PRmhlYWQAAANYAAAANgAAADYAW+ataGhlYQAAA5AAAAAkAAAAJAdhA+BobXR4AAADtAAAAAwAAAAMBdwAZGxvY2EAAAPAAAAACAAAAAgACgDWbWF4cAAAA8gAAAAgAAAAIAAIAJFuYW1lAAAD6AAAAR4AAAEee8Sd4HBvc3QAAAUIAAAAIAAAACAAAwAAAAMD6AGQAAUAAAKKArwAAACMAooCvAAAAeAAMQECAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg5gMDqf/C/8IDqQA+AAAAAAAAAAAAAAAAAAAAIAAAAAAAAgAAAAMAAAAUAAMAAQAAABQABAAoAAAABgAEAAEAAgAg5gP//wAAACDmA////+EZ/wABAAAAAAAAAAEAAf//AA8AAQAAAAAAAAAAAAIAADc5AQAAAAAEAGQAMgO2A4QAKABFAH0AjgAAATIWOgEzMj4CPwEjByc/AQ8BJzcnBw4DBxYGFgYXBzIGFiIzFzcFBw4DBx4DFx4DMzI+Aj8BJyoDIxcnNzYuAicuAyMiDgIHDgMXHgMXHgM/AQEeAzMyPgI3PgMnNi4CLwEBJj4CNz4BHgEXHgMXJwKUAgQEBAIOFxcUCrcxlx9qGjN1IZcB1AoNCgQBAQECAQIUAQEBAQFyDf7d6AsMCwMBAQMLDAsIFRYZDA4YFxMLsXICAgMBAveMBQUDFCEZES0tMRULFRcVCwkPBgIEAw8TGg8VLjQyGg4BMAYQEBUJDBMSEAgHDAYFAQEFBgwH5v4vAgMCBwIQKS8tFQkTDAsC6wH1AQQKDQrVliB2MhlrIJQ0uQkUFhkNAgQEBAMPAQFpDirCCRQWGQ0NGBcUCQoNCgQECg0K1p4Kfg8XMzU1FxMeFQwDBwwKChoeIhMTJyUjDxQeEgUEA/5fBwoGBAQHCwgHEBIUCgsTEhAIzwFfAQYHBwQOCgkYEwsYFhUJWgAAAAABAAAAAQAAA9mp718PPPUACwPoAAAAAM7D0SIAAAAAzsPRIgAAAAADtgOEAAAACAACAAAAAAAAAAEAAAOp/8IAAAPoAAAAMgO2AAEAAAAAAAAAAAAAAAAAAAADAAAAAAH0AAAD6ABkAAAAAAAKANYAAQAAAAMAjwAEAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAA4ArgABAAAAAAABAAgAAAABAAAAAAACAA4AMgABAAAAAAADAAgAHgABAAAAAAAEAAgAQAABAAAAAAAFABYACAABAAAAAAAGAAQAJgABAAAAAAAKACgASAADAAEECQABAAgAAAADAAEECQACAA4AMgADAAEECQADAAgAHgADAAEECQAEAAgAQAADAAEECQAFABYACAADAAEECQAGAAgAKgADAAEECQAKACgASABuAG8AdgBhAFYAZQByAHMAaQBvAG4AIAAwAC4AMABuAG8AdgBhbm92YQBuAG8AdgBhAFIAZQBnAHUAbABhAHIAbgBvAHYAYQBHAGUAbgBlAHIAYQB0AGUAZAAgAGIAeQAgAEkAYwBvAE0AbwBvAG4AAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) format('woff');
+ font-weight: normal;
+ font-style: normal;
+}
+
+#menu-posts-nova_menu_item:before,
+#dashboard_right_now .nova-menu-count a:before {
+ font-family: 'nova-font';
+ speak: none;
+ font-style: normal;
+ font-weight: normal;
+ font-variant: normal;
+ text-transform: none;
+ line-height: 1;
+
+ /* Better Font Rendering =========== */
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+#dashboard_right_now .nova-menu-count a:before {
+ content: '\e603';
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/custom-post-types/css/nova.css b/plugins/jetpack/modules/custom-post-types/css/nova.css
new file mode 100644
index 00000000..309b510f
--- /dev/null
+++ b/plugins/jetpack/modules/custom-post-types/css/nova.css
@@ -0,0 +1,110 @@
+/* edit-items.css
+-------------------------------------------------------------- */
+
+.widefat .menu-label-row td {
+ border-bottom-width: 1px;
+}
+.widefat .menu-label-row td h3 {
+ padding-left: 30px;
+}
+.widefat .menu-label-row td h3 .edit-nova-section {
+ font-size: .8em;
+ font-weight: normal;
+ margin-left: 5px;
+}
+.widefat .menu-order-value {
+ width: 2.5em;
+ text-align: center;
+}
+.widefat .menu-label-row, .widefat .menu-label-row td {
+ background-color: #eee;
+ color: #111;
+ border: 0 none;
+ -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.05);
+}
+.ui-sortable .type-nova_menu_item {
+ cursor: move;
+ background-color: #fff;
+}
+.ui-sortable .type-nova_menu_item:nth-child(even) {
+ background-color: #f9f9f9;
+}
+.ui-sortable .type-nova_menu_item.ui-sortable-helper {
+ -webkit-box-shadow: 0 0 1px rgba(0, 0, 0, 0.1);
+ box-shadow: 0 0 1px rgba(0, 0, 0, 0.1);
+}
+.tablenav .button-reorder {
+ margin-top: 4px;
+}
+.tablenav .view-switch a, .tablenav div.tablenav-pages {
+ display: none;
+}
+
+
+/* many-items.css
+-------------------------------------------------------------- */
+
+.many-items-table th, .many-items-table td {
+ width: 30%;
+}
+
+.many-items-table th.nova-price, .many-items-table td.nova-price {
+ width: 10%;
+}
+
+.many-items-table input, .many-items-table textarea {
+ width: 100%;
+}
+
+.many-items-table input[type=file] {
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+
+/* new
+-------------------------------------------------------------- */
+
+#the-list tr td:nth-of-type(2) {
+ padding-top: 15px;
+}
+
+.nova-move-menu-up:before,
+.nova-move-menu-down:before {
+ margin-right: 5px;
+ font: normal 10px/1 'dashicons' !important;
+ speak: none;
+}
+
+.nova-move-menu-up:before {
+ content: "\f342";
+}
+
+.nova-move-menu-down:before {
+ content: "\f346";
+}
+
+.dashicon:before {
+ font: normal 20px/1 'dashicons';
+ speak: none;
+ top: 5px;
+ display: inline-block;
+ position: relative;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ text-decoration: none !important;
+ vertical-align: top;
+}
+
+.dashicon-plus:before {
+ content: "\f132";
+}
+
+.dashicon-edit:before {
+ margin: 2px 5px 0 10px;
+ content: "\f327";
+ font-size: 10px;
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/custom-post-types/css/portfolio-shortcode.css b/plugins/jetpack/modules/custom-post-types/css/portfolio-shortcode.css
new file mode 100644
index 00000000..b3c2c1e3
--- /dev/null
+++ b/plugins/jetpack/modules/custom-post-types/css/portfolio-shortcode.css
@@ -0,0 +1,131 @@
+.jetpack-portfolio-shortcode {
+ clear: both;
+ margin: 0;
+ overflow: hidden;
+ padding: 0;
+}
+
+.portfolio-entry {
+ float: left;
+ margin: 0 0 3em;
+ padding: 0;
+ width: 100%;
+}
+
+/* Column setting */
+.portfolio-entry-column-1 {
+ width: 100%;
+}
+
+.portfolio-entry-column-2 {
+ margin-right: 4%;
+ width: 48%;
+}
+
+.portfolio-entry-column-3 {
+ margin-right: 3.5%;
+ width: 31%;
+}
+
+.portfolio-entry-column-4 {
+ margin-right: 3%;
+ width: 22%;
+}
+
+.portfolio-entry-column-5 {
+ margin-right: 2.5%;
+ width: 18%;
+}
+
+.portfolio-entry-column-6 {
+ margin-right: 2%;
+ width: 15%;
+}
+.portfolio-entry-first-item-row {
+ clear: both;
+}
+.portfolio-entry-last-item-row {
+ margin-right: 0;
+}
+
+@media screen and (max-width:768px) {
+ .portfolio-entry-mobile-first-item-row{
+ margin-right: 4%;
+ width: 48%;
+ clear:both;
+ }
+ .portfolio-entry-first-item-row {
+ clear:none;
+ }
+ .portfolio-entry-mobile-last-item-row{
+ width: 48%;
+ margin-right: 0;
+ }
+}
+/* Entry Header */
+.portfolio-entry-header {
+ border: 0;
+ margin: 0;
+ padding: 0;
+}
+
+.portfolio-featured-image {
+ margin: 0;
+ padding: 0;
+}
+
+.portfolio-featured-image img {
+ border: 0;
+ height: auto;
+ max-width: 100%;
+ vertical-align: middle;
+}
+
+.portfolio-entry-title {
+ font-weight: 700;
+ margin: 0;
+ padding: 0;
+}
+
+.portfolio-featured-image + .portfolio-entry-title {
+ margin-top: 1.0em;
+}
+
+.portfolio-entry-title a {
+ border: 0;
+ text-decoration: none;
+}
+
+/* Entry Meta */
+.portfolio-entry-meta {
+ margin: 0;
+ padding: 0;
+}
+
+.portfolio-entry-title + .portfolio-entry-meta {
+ margin-top: 0.75em;
+}
+
+.portfolio-entry-title + .portfolio-entry-meta:empty {
+ margin: 0;
+}
+
+.portfolio-entry-meta span,
+.portfolio-entry-meta a {
+ font-size: 0.9em;
+ padding: 0;
+}
+
+.portfolio-entry-meta a {
+ border: 0;
+ text-decoration: none;
+}
+/* Entry Content */
+.portfolio-entry-content {
+ margin: 0.75em 0 0;
+ padding: 0;
+}
+
+.portfolio-entry-content > :last-child {
+ margin: 0;
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/custom-post-types/css/testimonial-shortcode.css b/plugins/jetpack/modules/custom-post-types/css/testimonial-shortcode.css
new file mode 100644
index 00000000..1955e0ed
--- /dev/null
+++ b/plugins/jetpack/modules/custom-post-types/css/testimonial-shortcode.css
@@ -0,0 +1,101 @@
+.jetpack-testimonial-shortcode {
+ clear: both;
+ margin: 0;
+ overflow: hidden;
+ padding: 0;
+}
+
+.testimonial-entry {
+ float: left;
+ margin: 0 0 3em;
+ padding: 0;
+ width: 100%;
+}
+
+/* Column setting */
+.testimonial-entry-column-1 {
+ width: 100%;
+}
+
+.testimonial-entry-column-2 {
+ margin-right: 4%;
+ width: 48%;
+}
+
+.testimonial-entry-column-3 {
+ margin-right: 3.5%;
+ width: 31%;
+}
+
+.testimonial-entry-column-4 {
+ margin-right: 3%;
+ width: 22%;
+}
+
+.testimonial-entry-column-5 {
+ margin-right: 2.5%;
+ width: 18%;
+}
+
+.testimonial-entry-column-6 {
+ margin-right: 2%;
+ width: 15%;
+}
+.testimonial-entry-first-item-row {
+ clear: both;
+}
+.testimonial-entry-last-item-row {
+ margin-right: 0;
+}
+
+@media screen and (max-width:768px) {
+ .testimonial-entry-mobile-first-item-row{
+ margin-right: 4%;
+ width: 48%;
+ clear:both;
+ }
+ .testimonial-entry-first-item-row {
+ clear:none;
+ }
+ .testimonial-entry-mobile-last-item-row{
+ width: 48%;
+ margin-right: 0;
+ }
+}
+
+.testimonial-featured-image {
+ padding: 0;
+ margin: 0;
+}
+
+.testimonial-featured-image img {
+ border: 0;
+ height: auto;
+ max-width: 100%;
+ vertical-align: middle;
+}
+
+.testimonial-entry-title {
+ font-weight: 700;
+ margin: 0;
+ padding: 0;
+}
+
+.testimonial-featured-image + .testimonial-entry-title {
+ margin-top: 1.0em;
+}
+
+.testimonial-entry-title a {
+ border: 0;
+ text-decoration: none;
+}
+
+/* Entry Content */
+.testimonial-entry-content {
+ margin: 0.75em 0;
+ padding: 0;
+}
+
+.testimonial-entry-content > :last-child {
+ margin: 0;
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/custom-post-types/js/many-items.js b/plugins/jetpack/modules/custom-post-types/js/many-items.js
new file mode 100644
index 00000000..3da1bc33
--- /dev/null
+++ b/plugins/jetpack/modules/custom-post-types/js/many-items.js
@@ -0,0 +1,112 @@
+/* jshint onevar: false, smarttabs: true */
+
+(function( $ ){
+ var menuSelector, nonceInput, methods;
+
+ methods = {
+ init : function( /*options*/ ) {
+ var $this = this, tbody, row;
+
+ this
+ .on( 'keypress.manyItemsTable', function( event ) {
+ if ( 13 !== event.which ) {
+ return;
+ }
+
+ event.preventDefault();
+ if ( 'function' === typeof FormData ) {
+ methods.submitRow.apply( $this );
+ }
+ methods.addRow.apply( $this );
+ } )
+ .on( 'focus.manyItemsTable', ':input', function( /*event*/ ) {
+ $this.data( 'currentRow', $( this ).parents( 'tr:first' ) );
+ } );
+
+ tbody = this.find( 'tbody:last' );
+ row = tbody.find( 'tr:first' ).clone();
+
+ this.data( 'form', this.parents( 'form:first' ) );
+ this.data( 'tbody', tbody );
+ this.data( 'row', row );
+ this.data( 'currentRow', row );
+
+ menuSelector = $( '#nova-menu-tax' );
+ nonceInput = $( '#_wpnonce' );
+
+ return this;
+ },
+
+ destroy : function() {
+ this.off( '.manyItemsTable' );
+
+ return this;
+ },
+
+ submitRow : function() {
+ var submittedRow, currentInputs, allInputs, partialFormData;
+
+ submittedRow = this.data( 'currentRow' );
+ currentInputs = submittedRow.find( ':input' );
+ allInputs = this.data( 'form' ).find( ':input' ).not( currentInputs ).attr( 'disabled', true ).end();
+
+ partialFormData = new FormData( this.data( 'form' ).get( 0 ) );
+ partialFormData.append( 'ajax', '1' );
+ partialFormData.append( 'nova_menu_tax', menuSelector.val() );
+ partialFormData.append( '_wpnonce', nonceInput.val() );
+
+ allInputs.attr( 'disabled', false );
+
+ $.ajax( {
+ url: '',
+ type: 'POST',
+ data: partialFormData,
+ processData: false,
+ contentType: false
+ } ).complete( function( xhr ) {
+ submittedRow.html( xhr.responseText );
+ } );
+
+ currentInputs.attr( 'disabled', true );
+
+ return this;
+ },
+
+ addRow : function() {
+ var row = this.data( 'row' ).clone();
+ row.appendTo( this.data( 'tbody' ) );
+ row.find( ':input:first' ).focus();
+
+ return this;
+ }
+ };
+
+ $.fn.manyItemsTable = function( method ) {
+ // Method calling logic
+ if ( methods[method] ) {
+ return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ) );
+ } else if ( typeof method === 'object' || ! method ) {
+ return methods.init.apply( this, arguments );
+ } else {
+ $.error( 'Method ' + method + ' does not exist on jQuery.manyItemsTable' );
+ return this;
+ }
+ };
+
+ $.fn.clickAddRow = function() {
+ var tbody = this.find( 'tbody:last' ),
+ row = tbody.find( 'tr:first' ).clone();
+
+ $( row ).find( 'input' ).attr( 'value', '' );
+ $( row ).appendTo( tbody );
+ };
+
+})( jQuery );
+
+jQuery( '.many-items-table' ).one( 'focus', ':input', function( event ) {
+ jQuery( event.delegateTarget ).manyItemsTable();
+} );
+jQuery( '.many-items-table' ).on( 'click', 'a.nova-new-row', function( event ) {
+ jQuery( event.delegateTarget ).clickAddRow();
+} );
+
diff --git a/plugins/jetpack/modules/custom-post-types/js/menu-checkboxes.js b/plugins/jetpack/modules/custom-post-types/js/menu-checkboxes.js
new file mode 100644
index 00000000..b1cc6e35
--- /dev/null
+++ b/plugins/jetpack/modules/custom-post-types/js/menu-checkboxes.js
@@ -0,0 +1,49 @@
+/* jshint onevar: false, smarttabs: true, devel: true */
+
+(function($) {
+ var NovaCheckBoxes = {
+ inputs: null,
+ popInputs: null,
+
+ initialize: function() {
+ NovaCheckBoxes.popInputs = $( '#nova_menuchecklist-pop' ).find( ':checkbox' );
+
+ NovaCheckBoxes.inputs = $( '#nova_menuchecklist' )
+ .find( ':checkbox' )
+ .change( NovaCheckBoxes.checkOne )
+ .change( NovaCheckBoxes.syncPop );
+
+ if ( !NovaCheckBoxes.isChecked() ) {
+ NovaCheckBoxes.checkFirst();
+ }
+
+ NovaCheckBoxes.syncPop();
+ },
+
+ syncPop: function() {
+ NovaCheckBoxes.popInputs.each( function() {
+ var $this = $( this );
+ $this.prop( 'checked', $( '#in-nova_menu-' + $this.val() ).is( ':checked' ) );
+ } );
+ },
+
+ isChecked: function() {
+ return NovaCheckBoxes.inputs.is( ':checked' );
+ },
+
+ checkFirst: function() {
+ console.log( 'first!' );
+ NovaCheckBoxes.inputs.first().prop( 'checked', true );
+ },
+
+ checkOne: function( /*event*/ ) {
+ if ( $( this ).is( ':checked' ) ) {
+ return NovaCheckBoxes.inputs.not( this ).prop( 'checked', false );
+ } else {
+ return NovaCheckBoxes.checkFirst();
+ }
+ }
+ };
+
+ $( NovaCheckBoxes.initialize );
+})(jQuery);
diff --git a/plugins/jetpack/modules/custom-post-types/js/nova-drag-drop.js b/plugins/jetpack/modules/custom-post-types/js/nova-drag-drop.js
new file mode 100644
index 00000000..6feadd47
--- /dev/null
+++ b/plugins/jetpack/modules/custom-post-types/js/nova-drag-drop.js
@@ -0,0 +1,49 @@
+/* jshint onevar: false, smarttabs: true */
+/* global _novaDragDrop */
+
+(function($){
+ var list;
+
+ function init() {
+ list = $('#the-list');
+ dragMenus();
+ addNonce();
+ addSubmitButton();
+ }
+
+ function dragMenus() {
+ list.sortable({
+ cancel: '.no-items',
+ stop: function( event, ui ) {
+ if ( ui.item.is(':first-child') ) {
+ return list.sortable('cancel');
+ }
+ //
+ reOrder();
+ }
+ });
+ }
+
+ function reOrder() {
+ list.find('.menu-label-row').each(function() {
+ var term_id = $(this).data('term_id');
+ $(this).nextUntil('.menu-label-row').each(function(i) {
+ var row = $(this);
+ row.find('.menu-order-value').val(i);
+ row.find('.nova-menu-term').val(term_id);
+ });
+ });
+ }
+
+ function addSubmitButton() {
+ $('.tablenav').prepend('<input type="submit" class="button-primary button-reorder alignright" value="' + _novaDragDrop.reorder + '" name="' + _novaDragDrop.reorderName + '" />');
+ }
+
+ function addNonce() {
+ $('#posts-filter').append('<input type="hidden" name="' + _novaDragDrop.nonceName + '" value="' + _novaDragDrop.nonce + '" />');
+ }
+
+ // do it
+ $(document).ready(init);
+})(jQuery);
+
diff --git a/plugins/jetpack/modules/custom-post-types/nova.php b/plugins/jetpack/modules/custom-post-types/nova.php
new file mode 100644
index 00000000..58b931ae
--- /dev/null
+++ b/plugins/jetpack/modules/custom-post-types/nova.php
@@ -0,0 +1,1162 @@
+<?php
+
+/*
+ * Plugin Name: Nova - Restaurant Websites Shouldn't Suck
+ * Plugin URI: http://wordpress.org/extend/plugins/nova/
+ * Author: Automattic
+ * Version: 0.1
+ * License: GPL2+
+ * Text Domain: nova
+ * Domain Path: /languages/
+ */
+
+/*
+ * Put the following code in your theme's Food Menu Page Template to customize the markup of the menu.
+
+if ( class_exists( 'Nova_Restaurant' ) ) {
+ Nova_Restaurant::init( array(
+ 'menu_tag' => 'section',
+ 'menu_class' => 'menu-items',
+ 'menu_header_tag' => 'header',
+ 'menu_header_class' => 'menu-group-header',
+ 'menu_title_tag' => 'h1',
+ 'menu_title_class' => 'menu-group-title',
+ 'menu_description_tag' => 'div',
+ 'menu_description_class' => 'menu-group-description',
+ ) );
+}
+
+*/
+
+/* @todo
+
+Bulk/Quick edit response of Menu Item rows is broken.
+
+Drag and Drop reordering.
+*/
+
+class Nova_Restaurant {
+ const MENU_ITEM_POST_TYPE = 'nova_menu_item';
+ const MENU_ITEM_LABEL_TAX = 'nova_menu_item_label';
+ const MENU_TAX = 'nova_menu';
+
+ var $version = '0.1';
+
+ protected $default_menu_item_loop_markup = array(
+ 'menu_tag' => 'section',
+ 'menu_class' => 'menu-items',
+ 'menu_header_tag' => 'header',
+ 'menu_header_class' => 'menu-group-header',
+ 'menu_title_tag' => 'h1',
+ 'menu_title_class' => 'menu-group-title',
+ 'menu_description_tag' => 'div',
+ 'menu_description_class' => 'menu-group-description',
+ );
+
+ protected $menu_item_loop_markup = array();
+ protected $menu_item_loop_last_term_id = false;
+ protected $menu_item_loop_current_term = false;
+
+ static function init( $menu_item_loop_markup = array() ) {
+ static $instance = false;
+
+ if ( !$instance ) {
+ $instance = new Nova_Restaurant;
+ }
+
+ if ( $menu_item_loop_markup ) {
+ $instance->menu_item_loop_markup = wp_parse_args( $menu_item_loop_markup, $instance->default_menu_item_loop_markup );
+ }
+
+ return $instance;
+ }
+
+ function __construct() {
+ if ( ! $this->site_supports_nova() )
+ return;
+
+ $this->register_taxonomies();
+ $this->register_post_types();
+ add_action( 'admin_menu', array( $this, 'add_admin_menus' ) );
+ add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_nova_styles' ) );
+ add_action( 'admin_head', array( $this, 'set_custom_font_icon' ) );
+
+ // Enable Omnisearch for Menu Items.
+ if ( class_exists( 'Jetpack_Omnisearch_Posts' ) )
+ new Jetpack_Omnisearch_Posts( self::MENU_ITEM_POST_TYPE );
+
+ // Always sort menu items correctly
+ add_action( 'parse_query', array( $this, 'sort_menu_item_queries_by_menu_order' ) );
+ add_filter( 'posts_results', array( $this, 'sort_menu_item_queries_by_menu_taxonomy' ), 10, 2 );
+
+ add_action( 'wp_insert_post', array( $this, 'add_post_meta' ) );
+
+ $this->menu_item_loop_markup = $this->default_menu_item_loop_markup;
+
+ // Only output our Menu Item Loop Markup on a real blog view. Not feeds, XML-RPC, admin, etc.
+ add_filter( 'template_include', array( $this, 'setup_menu_item_loop_markup__in_filter' ) );
+
+ add_filter( 'enter_title_here', array( $this, 'change_default_title' ) );
+ add_filter( 'post_updated_messages', array( $this, 'updated_messages' ) );
+ add_filter( 'dashboard_glance_items', array( $this, 'add_to_dashboard' ) );
+ }
+
+ /**
+ * Should this Custom Post Type be made available?
+ */
+ function site_supports_nova() {
+ // If we're on WordPress.com, and it has the menu site vertical.
+ if ( function_exists( 'site_vertical' ) && 'nova_menu' == site_vertical() )
+ return true;
+
+ // Else, if the current theme requests it.
+ if ( current_theme_supports( self::MENU_ITEM_POST_TYPE ) )
+ return true;
+
+ // Otherwise, say no unless something wants to filter us to say yes.
+ /**
+ * Allow something else to hook in and enable this CPT.
+ *
+ * @since 2.6.0
+ *
+ * @param bool false Whether or not to enable this CPT.
+ * @param string $var The slug for this CPT.
+ */
+ return (bool) apply_filters( 'jetpack_enable_cpt', false, self::MENU_ITEM_POST_TYPE );
+ }
+
+/* Setup */
+
+ /**
+ * Register Taxonomies and Post Type
+ */
+ function register_taxonomies() {
+ register_taxonomy( self::MENU_ITEM_LABEL_TAX, self::MENU_ITEM_POST_TYPE, array(
+ 'labels' => array(
+ 'name' => __( 'Menu Item Labels', 'jetpack' ),
+ 'singular_name' => __( 'Menu Item Label', 'jetpack' ),
+ 'search_items' => __( 'Search Menu Item Labels', 'jetpack' ),
+ 'popular_items' => __( 'Popular Labels', 'jetpack' ),
+ 'all_items' => __( 'All Menu Item Labels', 'jetpack' ),
+ 'edit_item' => __( 'Edit Menu Item Label', 'jetpack' ),
+ 'view_item' => __( 'View Menu Item Label', 'jetpack' ),
+ 'update_item' => __( 'Update Menu Item Label', 'jetpack' ),
+ 'add_new_item' => __( 'Add New Menu Item Label', 'jetpack' ),
+ 'new_item_name' => __( 'New Menu Item Label Name', 'jetpack' ),
+ 'separate_items_with_commas' => __( 'For example, spicy, favorite, etc. <br /> Separate Labels with commas', 'jetpack' ),
+ 'add_or_remove_items' => __( 'Add or remove Labels', 'jetpack' ),
+ 'choose_from_most_used' => __( 'Choose from the most used Labels', 'jetpack' ),
+ ),
+ 'no_tagcloud' => __( 'No Labels found', 'jetpack' ),
+
+ 'hierarchical' => false,
+ ) );
+
+ register_taxonomy( self::MENU_TAX, self::MENU_ITEM_POST_TYPE, array(
+ 'labels' => array(
+ 'name' => __( 'Menu Sections', 'jetpack' ),
+ 'singular_name' => __( 'Menu Section', 'jetpack' ),
+ 'search_items' => __( 'Search Menu Sections', 'jetpack' ),
+ 'all_items' => __( 'All Menu Sections', 'jetpack' ),
+ 'parent_item' => __( 'Parent Menu Section', 'jetpack' ),
+ 'parent_item_colon' => __( 'Parent Menu Section:', 'jetpack' ),
+ 'edit_item' => __( 'Edit Menu Section', 'jetpack' ),
+ 'view_item' => __( 'View Menu Section', 'jetpack' ),
+ 'update_item' => __( 'Update Menu Section', 'jetpack' ),
+ 'add_new_item' => __( 'Add New Menu Section', 'jetpack' ),
+ 'new_item_name' => __( 'New Menu Sections Name', 'jetpack' ),
+ ),
+ 'rewrite' => array(
+ 'slug' => 'menu',
+ 'with_front' => false,
+ 'hierarchical' => true,
+ ),
+
+ 'hierarchical' => true,
+ 'show_tagcloud' => false,
+ 'query_var' => 'menu',
+ ) );
+ }
+
+ function register_post_types() {
+ register_post_type( self::MENU_ITEM_POST_TYPE, array(
+ 'description' => __( "Items on your restaurant's menu", 'jetpack' ),
+
+ 'labels' => array(
+ 'name' => __( 'Menu Items', 'jetpack' ),
+ 'singular_name' => __( 'Menu Item', 'jetpack' ),
+ 'menu_name' => __( 'Food Menus', 'jetpack' ),
+ 'all_items' => __( 'Menu Items', 'jetpack' ),
+ 'add_new' => __( 'Add One Item', 'jetpack' ),
+ 'add_new_item' => __( 'Add Menu Item', 'jetpack' ),
+ 'edit_item' => __( 'Edit Menu Item', 'jetpack' ),
+ 'new_item' => __( 'New Menu Item', 'jetpack' ),
+ 'view_item' => __( 'View Menu Item', 'jetpack' ),
+ 'search_items' => __( 'Search Menu Items', 'jetpack' ),
+ 'not_found' => __( 'No Menu Items found', 'jetpack' ),
+ 'not_found_in_trash' => __( 'No Menu Items found in Trash', 'jetpack' ),
+ ),
+ 'supports' => array(
+ 'title',
+ 'editor',
+ 'thumbnail',
+ 'excerpt',
+ ),
+ 'rewrite' => array(
+ 'slug' => 'item',
+ 'with_front' => false,
+ 'feeds' => false,
+ 'pages' => false,
+ ),
+ 'register_meta_box_cb' => array( $this, 'register_menu_item_meta_boxes' ),
+
+ 'public' => true,
+ 'show_ui' => true, // set to false to replace with custom UI
+ 'menu_position' => 20, // below Pages
+ 'capability_type' => 'page',
+ 'map_meta_cap' => true,
+ 'has_archive' => false,
+ 'query_var' => 'item',
+ ) );
+ }
+
+
+ /**
+ * Update messages for the Menu Item admin.
+ */
+ function updated_messages( $messages ) {
+ global $post;
+
+ $messages[self::MENU_ITEM_POST_TYPE] = array(
+ 0 => '', // Unused. Messages start at index 1.
+ 1 => sprintf( __( 'Menu item updated. <a href="%s">View item</a>', 'jetpack' ), esc_url( get_permalink( $post->ID ) ) ),
+ 2 => esc_html__( 'Custom field updated.', 'jetpack' ),
+ 3 => esc_html__( 'Custom field deleted.', 'jetpack' ),
+ 4 => esc_html__( 'Menu item updated.', 'jetpack' ),
+ /* translators: %s: date and time of the revision */
+ 5 => isset( $_GET['revision'] ) ? sprintf( esc_html__( 'Menu item restored to revision from %s', 'jetpack' ), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
+ 6 => sprintf( __( 'Menu item published. <a href="%s">View item</a>', 'jetpack' ), esc_url( get_permalink( $post->ID ) ) ),
+ 7 => esc_html__( 'Menu item saved.', 'jetpack' ),
+ 8 => sprintf( __( 'Menu item submitted. <a target="_blank" href="%s">Preview item</a>', 'jetpack' ), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) ) ),
+ 9 => sprintf( __( 'Menu item scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview item</a>', 'jetpack' ),
+ // translators: Publish box date format, see http://php.net/date
+ date_i18n( __( 'M j, Y @ G:i', 'jetpack' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post->ID) ) ),
+ 10 => sprintf( __( 'Menu item draft updated. <a target="_blank" href="%s">Preview item</a>', 'jetpack' ), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) ) ),
+ );
+
+ return $messages;
+ }
+
+
+ /**
+ * Nova Styles and Scripts
+ */
+ function enqueue_nova_styles( $hook ) {
+ global $post_type;
+ $pages = array( 'edit.php', 'post.php', 'post-new.php' );
+
+ if ( in_array( $hook, $pages ) && $post_type == self::MENU_ITEM_POST_TYPE ) {
+ wp_enqueue_style( 'nova-style', plugins_url( 'css/nova.css', __FILE__ ), array(), $this->version );
+ }
+
+ wp_enqueue_style( 'nova-font', plugins_url( 'css/nova-font.css', __FILE__ ), array(), $this->version );
+ }
+
+
+ /**
+ * Change ‘Enter Title Here’ text for the Menu Item.
+ */
+ function change_default_title( $title ) {
+ $screen = get_current_screen();
+
+ if ( self::MENU_ITEM_POST_TYPE == $screen->post_type )
+ $title = esc_html__( "Enter the menu item's name here", 'jetpack' );
+
+ return $title;
+ }
+
+
+ /**
+ * Add to Dashboard At A Glance
+ */
+ function add_to_dashboard() {
+ $number_menu_items = wp_count_posts( self::MENU_ITEM_POST_TYPE );
+ $number_menu_items_published = sprintf( '%1s %2s',
+ number_format_i18n( $number_menu_items->publish ),
+ _n( 'Food Menu Item', 'Food Menu Items', intval( $number_menu_items->publish ), 'jetpack' )
+ );
+
+ if ( current_user_can( 'administrator' ) ) {
+ $number_menu_items_published = sprintf( '<a href="%1s">%2s %3s</a>',
+ esc_url( get_admin_url( get_current_blog_id(), 'edit.php?post_type=' . self::MENU_ITEM_POST_TYPE ) ),
+ number_format_i18n( $number_menu_items->publish ),
+ _n( 'Food Menu Item', 'Food Menu Items', intval( $number_menu_items->publish ), 'jetpack' )
+ );
+ }
+
+ echo '<li class="nova-menu-count">' . $number_menu_items_published . '</li>';
+ }
+
+
+ /**
+ * Query
+ */
+ function is_menu_item_query( $query ) {
+ if (
+ ( isset( $query->query_vars['taxonomy'] ) && self::MENU_TAX == $query->query_vars['taxonomy'] )
+ ||
+ ( isset( $query->query_vars['post_type'] ) && self::MENU_ITEM_POST_TYPE == $query->query_vars['post_type'] )
+ ) {
+ return true;
+ }
+
+ return false;
+ }
+
+ function sort_menu_item_queries_by_menu_order( $query ) {
+ if ( ! $this->is_menu_item_query( $query ) ) {
+ return;
+ }
+
+ $query->query_vars['orderby'] = 'menu_order';
+ $query->query_vars['order'] = 'ASC';
+
+ // For now, just turn off paging so we can sort by taxonmy later
+ // If we want paging in the future, we'll need to add the taxonomy sort here (or at least before the DB query is made)
+ $query->query_vars['posts_per_page'] = -1;
+ }
+
+ function sort_menu_item_queries_by_menu_taxonomy( $posts, $query ) {
+ if ( !$posts ) {
+ return $posts;
+ }
+
+ if ( !$this->is_menu_item_query( $query ) ) {
+ return $posts;
+ }
+
+ $grouped_by_term = array();
+
+ foreach ( $posts as $post ) {
+ $term = $this->get_menu_item_menu_leaf( $post->ID );
+ if ( !$term || is_wp_error( $term ) ) {
+ $term_id = 0;
+ } else {
+ $term_id = $term->term_id;
+ }
+
+ if ( !isset( $grouped_by_term["$term_id"] ) ) {
+ $grouped_by_term["$term_id"] = array();
+ }
+
+ $grouped_by_term["$term_id"][] = $post;
+ }
+
+ $term_order = get_option( 'nova_menu_order', array() );
+
+ $return = array();
+ foreach ( $term_order as $term_id ) {
+ if ( isset( $grouped_by_term["$term_id"] ) ) {
+ $return = array_merge( $return, $grouped_by_term["$term_id"] );
+ unset( $grouped_by_term["$term_id"] );
+ }
+ }
+
+ foreach ( $grouped_by_term as $term_id => $posts ) {
+ $return = array_merge( $return, $posts );
+ }
+
+ return $return;
+ }
+
+
+ /**
+ * Add Many Items
+ */
+ function add_admin_menus() {
+ $hook = add_submenu_page(
+ 'edit.php?post_type=' . self::MENU_ITEM_POST_TYPE,
+ __( 'Add Many Items', 'jetpack' ),
+ __( 'Add Many Items', 'jetpack' ),
+ 'edit_pages',
+ 'add_many_nova_items',
+ array( $this, 'add_many_new_items_page' )
+ );
+
+ add_action( "load-$hook", array( $this, 'add_many_new_items_page_load' ) );
+
+ add_action( 'current_screen', array( $this, 'current_screen_load' ) );
+
+ //Adjust 'Add Many Items' submenu position
+ $submenu_item = array_pop( $GLOBALS['submenu']['edit.php?post_type=' . self::MENU_ITEM_POST_TYPE] );
+ $GLOBALS['submenu']['edit.php?post_type=' . self::MENU_ITEM_POST_TYPE][11] = $submenu_item;
+ ksort( $GLOBALS['submenu']['edit.php?post_type=' . self::MENU_ITEM_POST_TYPE] );
+
+ $this->setup_menu_item_columns();
+
+ wp_register_script( 'nova-menu-checkboxes', plugins_url( 'js/menu-checkboxes.js', __FILE__ ), array( 'jquery' ), $this->version, true );
+ }
+
+
+ /**
+ * Custom Nova Icon CSS
+ */
+ function set_custom_font_icon() {
+ ?>
+ <style type="text/css">
+ #menu-posts-nova_menu_item .wp-menu-image:before {
+ font-family: 'nova-font' !important;
+ content: '\e603' !important;
+ }
+ </style>
+ <?php
+ }
+
+ function current_screen_load() {
+ $screen = get_current_screen();
+ if ( 'edit-nova_menu_item' !== $screen->id ) {
+ return;
+ }
+
+ $this->edit_menu_items_page_load();
+ add_filter( 'admin_notices', array( $this, 'admin_notices' ) );
+ }
+
+/* Edit Items List */
+
+ function admin_notices() {
+ if ( isset( $_GET['nova_reordered'] ) )
+ printf( '<div class="updated"><p>%s</p></div>', __( 'Menu Items re-ordered.', 'jetpack' ) );
+ }
+
+ function no_title_sorting( $columns ) {
+ if ( isset( $columns['title'] ) )
+ unset( $columns['title'] );
+ return $columns;
+ }
+
+ function setup_menu_item_columns() {
+ add_filter( sprintf( 'manage_edit-%s_sortable_columns', self::MENU_ITEM_POST_TYPE ), array( $this, 'no_title_sorting' ) );
+ add_filter( sprintf( 'manage_%s_posts_columns', self::MENU_ITEM_POST_TYPE ), array( $this, 'menu_item_columns' ) );
+
+ add_action( sprintf( 'manage_%s_posts_custom_column', self::MENU_ITEM_POST_TYPE ), array( $this, 'menu_item_column_callback' ), 10, 2 );
+ }
+
+ function menu_item_columns( $columns ) {
+ unset( $columns['date'], $columns['likes'] );
+
+ $columns['thumbnail'] = __( 'Thumbnail', 'jetpack' );
+ $columns['labels'] = __( 'Labels', 'jetpack' );
+ $columns['price'] = __( 'Price', 'jetpack' );
+ $columns['order'] = __( 'Order', 'jetpack' );
+
+ return $columns;
+ }
+
+ function menu_item_column_callback( $column, $post_id ) {
+ $screen = get_current_screen();
+
+ switch ( $column ) {
+ case 'thumbnail':
+ echo get_the_post_thumbnail( $post_id, array( 50, 50 ) );
+ break;
+ case 'labels' :
+ $this->list_admin_labels( $post_id );
+ break;
+ case 'price' :
+ $this->display_price( $post_id );
+ break;
+ case 'order' :
+ $url = admin_url( $screen->parent_file );
+
+ $up_url = add_query_arg( array(
+ 'action' => 'move-item-up',
+ 'post_id' => (int) $post_id,
+ ), wp_nonce_url( $url, 'nova_move_item_up_' . $post_id ) );
+
+ $down_url = add_query_arg( array(
+ 'action' => 'move-item-down',
+ 'post_id' => (int) $post_id,
+ ), wp_nonce_url( $url, 'nova_move_item_down_' . $post_id ) );
+ $menu_item = get_post($post_id);
+ $this->get_menu_by_post_id( $post_id );
+ ?>
+ <input type="hidden" class="menu-order-value" name="nova_order[<?php echo (int) $post_id ?>]" value="<?php echo esc_attr( $menu_item->menu_order ) ?>" />
+ <input type="hidden" class='nova-menu-term' name="nova_menu_term[<?php echo (int) $post_id ?>]" value="<?php echo esc_attr( $this->get_menu_by_post_id( $post_id )->term_id ); ?>">
+
+ <span class="hide-if-js">
+ &nbsp; &nbsp; &mdash; <a class="nova-move-item-up" data-post-id="<?php echo (int) $post_id; ?>" href="<?php echo esc_url( $up_url ); ?>">up</a>
+ <br />
+ &nbsp; &nbsp; &mdash; <a class="nova-move-item-down" data-post-id="<?php echo (int) $post_id; ?>" href="<?php echo esc_url( $down_url ); ?>">down</a>
+ </span>
+ <?php
+ break;
+ }
+ }
+
+ function get_menu_by_post_id( $post_id = null ) {
+ if ( ! $post_id )
+ return false;
+
+ $terms = get_the_terms( $post_id, self::MENU_TAX );
+
+ if ( ! is_array( $terms ) )
+ return false;
+
+ return array_pop( $terms );
+ }
+
+ /**
+ * Fires on a menu edit page. We might have drag-n-drop reordered
+ */
+ function maybe_reorder_menu_items() {
+ // make sure we clicked our button
+ if ( ! ( isset( $_REQUEST['menu_reorder_submit'] ) && $_REQUEST['menu_reorder_submit'] === __( 'Save New Order', 'jetpack' ) ) )
+ return;
+ ;
+
+ // make sure we have the nonce
+ if ( ! ( isset( $_REQUEST['drag-drop-reorder'] ) && wp_verify_nonce( $_REQUEST['drag-drop-reorder'], 'drag-drop-reorder' ) ) )
+ return;
+
+ $term_pairs = array_map( 'absint', $_REQUEST['nova_menu_term'] );
+ $order_pairs = array_map( 'absint', $_REQUEST['nova_order'] );
+
+ foreach( $order_pairs as $ID => $menu_order ) {
+ $ID = absint( $ID );
+ unset( $order_pairs[$ID] );
+ if ( $ID < 0 )
+ continue;
+
+ $post = get_post( $ID );
+ if ( ! $post )
+ continue;
+
+ // save a write if the order hasn't changed
+ if ( $menu_order != $post->menu_order )
+ wp_update_post( compact( 'ID', 'menu_order' ) );
+
+ // save a write if the term hasn't changed
+ if ( $term_pairs[$ID] != $this->get_menu_by_post_id( $ID )->term_id )
+ wp_set_object_terms( $ID, $term_pairs[$ID], self::MENU_TAX );
+
+ }
+
+ $redirect = add_query_arg( array(
+ 'post_type' => self::MENU_ITEM_POST_TYPE,
+ 'nova_reordered' => '1'
+ ), admin_url( 'edit.php' ) );
+ wp_safe_redirect( $redirect );
+ exit;
+
+ }
+
+ function edit_menu_items_page_load() {
+ if ( isset( $_GET['action'] ) ) {
+ $this->handle_menu_item_actions();
+ }
+
+ $this->maybe_reorder_menu_items();
+
+ wp_enqueue_script( 'nova-drag-drop', plugins_url( 'js/nova-drag-drop.js', __FILE__ ), array( 'jquery-ui-sortable' ), $this->version, true );
+ wp_localize_script( 'nova-drag-drop', '_novaDragDrop', array(
+ 'nonce' => wp_create_nonce( 'drag-drop-reorder' ),
+ 'nonceName' => 'drag-drop-reorder',
+ 'reorder' => __( 'Save New Order', 'jetpack' ),
+ 'reorderName' => 'menu_reorder_submit'
+ ) );
+ add_action( 'the_post', array( $this, 'show_menu_titles_in_menu_item_list' ) );
+ }
+
+ function handle_menu_item_actions() {
+ $action = (string) $_GET['action'];
+
+ switch ( $action ) {
+ case 'move-item-up' :
+ case 'move-item-down' :
+ $reorder = false;
+
+ $post_id = (int) $_GET['post_id'];
+
+ $term = $this->get_menu_item_menu_leaf( $post_id );
+
+ // Get all posts in that term
+ $query = new WP_Query( array(
+ 'taxonomy' => self::MENU_TAX,
+ 'term' => $term->slug,
+ ) );
+
+ $order = array();
+ foreach ( $query->posts as $post ) {
+ $order[] = $post->ID;
+ }
+
+ if ( 'move-item-up' == $action ) {
+ check_admin_referer( 'nova_move_item_up_' . $post_id );
+
+ $first_post_id = $order[0];
+ if ( $post_id == $first_post_id ) {
+ break;
+ }
+
+ foreach ( $order as $menu_order => $order_post_id ) {
+ if ( $post_id != $order_post_id ) {
+ continue;
+ }
+
+ $swap_post_id = $order[$menu_order - 1];
+ $order[$menu_order - 1] = $post_id;
+ $order[$menu_order] = $swap_post_id;
+
+ $reorder = true;
+ break;
+ }
+ } else {
+ check_admin_referer( 'nova_move_item_down_' . $post_id );
+
+ $last_post_id = end( $order );
+ if ( $post_id == $last_post_id ) {
+ break;
+ }
+
+ foreach ( $order as $menu_order => $order_post_id ) {
+ if ( $post_id != $order_post_id ) {
+ continue;
+ }
+
+ $swap_post_id = $order[$menu_order + 1];
+ $order[$menu_order + 1] = $post_id;
+ $order[$menu_order] = $swap_post_id;
+
+ $reorder = true;
+ }
+ }
+
+ if ( $reorder ) {
+ foreach ( $order as $menu_order => $ID ) {
+ wp_update_post( compact( 'ID', 'menu_order' ) );
+ }
+ }
+
+ break;
+ case 'move-menu-up' :
+ case 'move-menu-down' :
+ $reorder = false;
+
+ $term_id = (int) $_GET['term_id'];
+
+ $terms = $this->get_menus();
+
+ $order = array();
+ foreach ( $terms as $term ) {
+ $order[] = $term->term_id;
+ }
+
+ if ( 'move-menu-up' == $action ) {
+ check_admin_referer( 'nova_move_menu_up_' . $term_id );
+
+ $first_term_id = $order[0];
+ if ( $term_id == $first_term_id ) {
+ break;
+ }
+
+ foreach ( $order as $menu_order => $order_term_id ) {
+ if ( $term_id != $order_term_id ) {
+ continue;
+ }
+
+ $swap_term_id = $order[$menu_order - 1];
+ $order[$menu_order - 1] = $term_id;
+ $order[$menu_order] = $swap_term_id;
+
+ $reorder = true;
+ break;
+ }
+ } else {
+ check_admin_referer( 'nova_move_menu_down_' . $term_id );
+
+ $last_term_id = end( $order );
+ if ( $term_id == $last_term_id ) {
+ break;
+ }
+
+ foreach ( $order as $menu_order => $order_term_id ) {
+ if ( $term_id != $order_term_id ) {
+ continue;
+ }
+
+ $swap_term_id = $order[$menu_order + 1];
+ $order[$menu_order + 1] = $term_id;
+ $order[$menu_order] = $swap_term_id;
+
+ $reorder = true;
+ }
+ }
+
+ if ( $reorder ) {
+ update_option( 'nova_menu_order', $order );
+ }
+
+ break;
+ default :
+ return;
+ }
+
+ $redirect = add_query_arg( array(
+ 'post_type' => self::MENU_ITEM_POST_TYPE,
+ 'nova_reordered' => '1'
+ ), admin_url( 'edit.php' ) );
+ wp_safe_redirect( $redirect );
+ exit;
+ }
+
+ /*
+ * Add menu title rows to the list table
+ */
+ function show_menu_titles_in_menu_item_list( $post ) {
+ global $wp_list_table;
+
+ static $last_term_id = false;
+
+ $term = $this->get_menu_item_menu_leaf( $post->ID );
+
+ if ( false !== $last_term_id && $last_term_id === $term->term_id )
+ return;
+
+ $last_term_id = $term->term_id;
+
+ $parent_count = 0;
+ $current_term = $term;
+ while ( $current_term->parent ) {
+ $parent_count++;
+ $current_term = get_term( $current_term->parent, self::MENU_TAX );
+ }
+
+ $non_order_column_count = $wp_list_table->get_column_count() - 1;
+
+ $screen = get_current_screen();
+
+ $url = admin_url( $screen->parent_file );
+
+ $up_url = add_query_arg( array(
+ 'action' => 'move-menu-up',
+ 'term_id' => (int) $term->term_id,
+ ), wp_nonce_url( $url, 'nova_move_menu_up_' . $term->term_id ) );
+
+ $down_url = add_query_arg( array(
+ 'action' => 'move-menu-down',
+ 'term_id' => (int) $term->term_id,
+ ), wp_nonce_url( $url, 'nova_move_menu_down_' . $term->term_id ) );
+
+?>
+ <tr class="no-items menu-label-row" data-term_id="<?php echo esc_attr( $term->term_id ) ?>">
+ <td class="colspanchange" colspan="<?php echo (int) $non_order_column_count; ?>">
+ <h3><?php
+ echo str_repeat( ' &mdash; ', (int) $parent_count );
+
+ if ( ! is_wp_error( $term ) ) {
+ echo esc_html( sanitize_term_field( 'name', $term->name, $term->term_id, self::MENU_TAX, 'display' ) );
+ edit_term_link( __( 'edit', 'jetpack' ), '<span class="edit-nova-section"><span class="dashicon dashicon-edit"></span>', '</span>', $term );
+
+ } else {
+ _e( 'Uncategorized' , 'jetpack' );
+ }
+ ?></h3>
+ </td>
+ <td>
+ <?php if ( ! is_wp_error( $term ) ) { ?>
+ <a class="nova-move-menu-up" title="<?php esc_attr_e( 'Move menu section up', 'jetpack' ); ?>" href="<?php echo esc_url( $up_url ); ?>"><?php esc_html_e( 'UP', 'jetpack' ); ?></a>
+ <br />
+ <a class="nova-move-menu-down" title="<?php esc_attr_e( 'Move menu section down', 'jetpack' ); ?>" href="<?php echo esc_url( $down_url ); ?>"><?php esc_html_e( 'DOWN', 'jetpack' ); ?></a>
+ <?php } ?>
+ </td>
+ </tr>
+<?php
+ }
+
+/* Edit Many Items */
+
+ function add_many_new_items_page_load() {
+ if ( 'POST' === strtoupper( $_SERVER['REQUEST_METHOD'] ) ) {
+ $this->process_form_request();
+ exit;
+ }
+
+ $this->enqueue_many_items_scripts();
+ }
+
+ function enqueue_many_items_scripts() {
+ wp_enqueue_script( 'nova-many-items', plugins_url( 'js/many-items.js', __FILE__ ), array( 'jquery' ), $this->version, true );
+ }
+
+ function process_form_request() {
+ if ( !isset( $_POST['nova_title'] ) || !is_array( $_POST['nova_title'] ) ) {
+ return;
+ }
+
+ $is_ajax = !empty( $_POST['ajax'] );
+
+ if ( $is_ajax ) {
+ check_ajax_referer( 'nova_many_items' );
+ } else {
+ check_admin_referer( 'nova_many_items' );
+ }
+
+ foreach ( array_keys( $_POST['nova_title'] ) as $key ) :
+ // $_POST is already slashed
+ $post_details = array(
+ 'post_status' => 'publish',
+ 'post_type' => self::MENU_ITEM_POST_TYPE,
+ 'post_content' => $_POST['nova_content'][$key],
+ 'post_title' => $_POST['nova_title'][$key],
+ 'tax_input' => array(
+ self::MENU_ITEM_LABEL_TAX => $_POST['nova_labels'][$key],
+ self::MENU_TAX => $_POST['nova_menu_tax'],
+ ),
+ );
+
+ $post_id = wp_insert_post( $post_details );
+ if ( !$post_id || is_wp_error( $post_id ) ) {
+ continue;
+ }
+
+ $this->set_price( $post_id, isset( $_POST['nova_price'][$key] ) ? stripslashes( $_POST['nova_price'][$key] ) : '' );
+
+ if ( $is_ajax ) :
+ $post = get_post( $post_id );
+ $GLOBALS['post'] = $post;
+ setup_postdata( $post );
+
+?>
+ <td><?php the_title(); ?></td>
+ <td class="nova-price"><?php $this->display_price(); ?></td>
+ <td><?php $this->list_labels( $post_id ); ?></td>
+ <td><?php the_content(); ?></td>
+<?php
+ endif;
+
+ endforeach;
+
+ if ( $is_ajax ) {
+ exit;
+ }
+
+ wp_safe_redirect( admin_url( 'edit.php?post_type=' . self::MENU_ITEM_POST_TYPE ) );
+ exit;
+ }
+
+ function add_many_new_items_page() {
+?>
+ <div class="wrap">
+ <h2><?php esc_html_e( 'Add Many Items', 'jetpack' ); ?></h2>
+
+ <p><?php _e( 'Use the <kbd>TAB</kbd> key on your keyboard to move between colums and the <kbd>ENTER</kbd> or <kbd>RETURN</kbd> key to save each row and move on to the next.', 'jetpack' ); ?></p>
+
+ <form method="post" action="" enctype="multipart/form-data">
+ <p><h3><?php esc_html_e( 'Add to section:', 'jetpack' ); ?> <?php wp_dropdown_categories( array(
+ 'id' => 'nova-menu-tax',
+ 'name' => 'nova_menu_tax',
+ 'taxonomy' => self::MENU_TAX,
+ 'hide_empty' => false,
+ 'hierarchical' => true,
+ ) ); ?></h3></p>
+
+ <table class="many-items-table wp-list-table widefat">
+ <thead>
+ <tr>
+ <th scope="col"><?php esc_html_e( 'Name', 'jetpack' ); ?></th>
+ <th scope="col" class="nova-price"><?php esc_html_e( 'Price', 'jetpack' ); ?></th>
+ <th scope="col"><?php _e( 'Labels: <small>spicy, favorite, etc. <em>Separate Labels with commas</em></small>', 'jetpack' ); ?></th>
+ <th scope="col"><?php esc_html_e( 'Description', 'jetpack' ); ?></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><input type="text" name="nova_title[]" aria-required="true" /></td>
+ <td class="nova-price"><input type="text" name="nova_price[]" /></td>
+ <td><input type="text" name="nova_labels[]" /></td>
+ <td><textarea name="nova_content[]" cols="20" rows="1"></textarea>
+ </tr>
+ </tbody>
+ <tbody>
+ <tr>
+ <td><input type="text" name="nova_title[]" aria-required="true" /></td>
+ <td class="nova-price"><input type="text" name="nova_price[]" /></td>
+ <td><input type="text" name="nova_labels[]" /></td>
+ <td><textarea name="nova_content[]" cols="20" rows="1"></textarea>
+ </tr>
+ </tbody>
+ <tfoot>
+ <tr>
+ <th><a class="button button-secondary nova-new-row"><span class="dashicon dashicon-plus"></span> <?php esc_html_e( 'New Row' , 'jetpack' ); ?></a></th>
+ <th class="nova-price"></th>
+ <th></th>
+ <th></th>
+ </tr>
+ </tfoot>
+ </table>
+
+ <p class="submit">
+ <input type="submit" class="button-primary" value="<?php esc_attr_e( 'Add These New Menu Items', 'jetpack' ); ?>" />
+ <?php wp_nonce_field( 'nova_many_items' ); ?>
+ </p>
+ </form>
+ </div>
+<?php
+ }
+
+/* Edit One Item */
+
+ function register_menu_item_meta_boxes() {
+ wp_enqueue_script( 'nova-menu-checkboxes' );
+
+ add_meta_box( 'menu_item_price', __( 'Price', 'jetpack' ), array( $this, 'menu_item_price_meta_box' ), null, 'side', 'high' );
+ }
+
+ function menu_item_price_meta_box( $post, $meta_box ) {
+ $price = $this->get_price( $post->ID );
+?>
+ <label for="nova-price-<?php echo (int) $post->ID; ?>" class="screen-reader-text"><?php esc_html_e( 'Price', 'jetpack' ); ?></label>
+ <input type="text" id="nova-price-<?php echo (int) $post->ID; ?>" class="widefat" name="nova_price[<?php echo (int) $post->ID; ?>]" value="<?php echo esc_attr( $price ); ?>" />
+<?php
+ }
+
+ function add_post_meta( $post_id ) {
+ if ( !isset( $_POST['nova_price'][$post_id] ) ) {
+ return;
+ }
+
+ $this->set_price( $post_id, stripslashes( $_POST['nova_price'][$post_id] ) );
+ }
+
+/* Data */
+
+ function get_menus( $args = array() ) {
+ $args = wp_parse_args( $args, array(
+ 'hide_empty' => false,
+ ) );
+
+ $terms = get_terms( self::MENU_TAX, $args );
+ if ( !$terms || is_wp_error( $terms ) ) {
+ return array();
+ }
+
+ $terms_by_id = array();
+ foreach ( $terms as $term ) {
+ $terms_by_id["{$term->term_id}"] = $term;
+ }
+
+ $term_order = get_option( 'nova_menu_order', array() );
+
+ $return = array();
+ foreach ( $term_order as $term_id ) {
+ if ( isset( $terms_by_id["$term_id"] ) ) {
+ $return[] = $terms_by_id["$term_id"];
+ unset( $terms_by_id["$term_id"] );
+ }
+ }
+
+ foreach ( $terms_by_id as $term_id => $term ) {
+ $return[] = $term;
+ }
+
+ return $return;
+ }
+
+ function get_menu_item_menu_leaf( $post_id ) {
+ // Get first menu taxonomy "leaf"
+ $term_ids = wp_get_object_terms( $post_id, self::MENU_TAX, array( 'fields' => 'ids' ) );
+
+ foreach ( $term_ids as $term_id ) {
+ $children = get_term_children( $term_id, self::MENU_TAX );
+ if ( ! $children ) {
+ break;
+ }
+ }
+
+ if ( ! isset( $term_id ) ) {
+ return false;
+ }
+
+ return get_term( $term_id, self::MENU_TAX );
+
+ }
+
+ function list_labels( $post_id = 0 ) {
+ $post = get_post( $post_id );
+ echo get_the_term_list( $post->ID, self::MENU_ITEM_LABEL_TAX, '', _x( ', ', 'Nova label separator', 'jetpack' ), '' );
+ }
+
+ function list_admin_labels( $post_id = 0 ) {
+ $post = get_post( $post_id );
+ $labels = get_the_terms( $post->ID, self::MENU_ITEM_LABEL_TAX );
+ if ( !empty( $labels ) ) {
+ $out = array();
+ foreach ( $labels as $label ) {
+ $out[] = sprintf( '<a href="%s">%s</a>',
+ esc_url( add_query_arg( array(
+ 'post_type' => self::MENU_ITEM_POST_TYPE,
+ 'taxonomy' => self::MENU_ITEM_LABEL_TAX,
+ 'term' => $label->slug
+ ), 'edit.php' ) ),
+ esc_html( sanitize_term_field( 'name', $label->name, $label->term_id, self::MENU_ITEM_LABEL_TAX, 'display' ) )
+ );
+ }
+
+ echo join( _x( ', ', 'Nova label separator', 'jetpack' ), $out );
+ } else {
+ esc_html_e( 'No Labels', 'jetpack' );
+ }
+ }
+
+ function set_price( $post_id = 0, $price = '' ) {
+ $post = get_post( $post_id );
+
+ return update_post_meta( $post->ID, 'nova_price', $price );
+ }
+
+ function get_price( $post_id = 0 ) {
+ $post = get_post( $post_id );
+
+ return get_post_meta( $post->ID, 'nova_price', true );
+ }
+
+ function display_price( $post_id = 0 ) {
+ echo esc_html( $this->get_price( $post_id ) );
+ }
+
+/* Menu Item Loop Markup */
+
+ /* Does not support nested loops */
+
+ function get_menu_item_loop_markup( $field = null ) {
+ return $this->menu_item_loop_markup;
+ }
+
+ /**
+ * Sets up the loop markup.
+ * Attached to the 'template_include' *filter*,
+ * which fires only during a real blog view (not in admin, feeds, etc.)
+ *
+ * @param string Template File
+ * @return string Template File. VERY Important.
+ */
+ function setup_menu_item_loop_markup__in_filter( $template ) {
+ add_action( 'loop_start', array( $this, 'start_menu_item_loop' ) );
+
+ return $template;
+ }
+
+ /**
+ * If the Query is a Menu Item Query, start outputing the Menu Item Loop Marku
+ * Attached to the 'loop_start' action.
+ *
+ * @param WP_Query
+ */
+ function start_menu_item_loop( $query ) {
+ if ( !$this->is_menu_item_query( $query ) ) {
+ return;
+ }
+
+ $this->menu_item_loop_last_term_id = false;
+ $this->menu_item_loop_current_term = false;
+
+ add_action( 'the_post', array( $this, 'menu_item_loop_each_post' ) );
+ add_action( 'loop_end', array( $this, 'stop_menu_item_loop' ) );
+ }
+
+ /**
+ * Outputs the Menu Item Loop Marku
+ * Attached to the 'the_post' action.
+ *
+ * @param WP_Post
+ */
+ function menu_item_loop_each_post( $post ) {
+ $this->menu_item_loop_current_term = $this->get_menu_item_menu_leaf( $post->ID );
+
+ if ( false === $this->menu_item_loop_last_term_id ) {
+ // We're at the very beginning of the loop
+
+ $this->menu_item_loop_open_element( 'menu' ); // Start a new menu section
+ $this->menu_item_loop_header(); // Output the menu's header
+ } elseif ( $this->menu_item_loop_last_term_id != $this->menu_item_loop_current_term->term_id ) {
+ // We're not at the very beginning but still need to start a new menu section. End the previous menu section first.
+
+ $this->menu_item_loop_close_element( 'menu' ); // End the previous menu section
+ $this->menu_item_loop_open_element( 'menu' ); // Start a new menu section
+ $this->menu_item_loop_header(); // Output the menu's header
+ }
+
+ $this->menu_item_loop_last_term_id = $this->menu_item_loop_current_term->term_id;
+ }
+
+ /**
+ * If the Query is a Menu Item Query, stop outputing the Menu Item Loop Marku
+ * Attached to the 'loop_end' action.
+ *
+ * @param WP_Query
+ */
+ function stop_menu_item_loop( $query ) {
+ if ( !$this->is_menu_item_query( $query ) ) {
+ return;
+ }
+
+ remove_action( 'the_post', array( $this, 'menu_item_loop_each_post' ) );
+ remove_action( 'loop_start', array( $this, 'start_menu_item_loop' ) );
+ remove_action( 'loop_end', array( $this, 'stop_menu_item_loop' ) );
+
+ $this->menu_item_loop_close_element( 'menu' ); // End the last menu section
+ }
+
+ /**
+ * Outputs the Menu Group Header
+ */
+ function menu_item_loop_header() {
+ $this->menu_item_loop_open_element( 'menu_header' );
+ $this->menu_item_loop_open_element( 'menu_title' );
+ echo esc_html( $this->menu_item_loop_current_term->name ); // @todo tax filter
+ $this->menu_item_loop_close_element( 'menu_title' );
+ if ( $this->menu_item_loop_current_term->description ) :
+ $this->menu_item_loop_open_element( 'menu_description' );
+ echo esc_html( $this->menu_item_loop_current_term->description ); // @todo kses, tax filter
+ $this->menu_item_loop_close_element( 'menu_description' );
+ endif;
+ $this->menu_item_loop_close_element( 'menu_header' );
+ }
+
+ /**
+ * Outputs a Menu Item Markup element opening tag
+ *
+ * @param string $field - Menu Item Markup settings field
+ */
+ function menu_item_loop_open_element( $field ) {
+ $markup = $this->get_menu_item_loop_markup();
+ echo '<' . tag_escape( $markup["{$field}_tag"] ) . $this->menu_item_loop_class( $markup["{$field}_class"] ) . ">\n";
+ }
+
+ /**
+ * Outputs a Menu Item Markup element closing tag
+ *
+ * @param string $field - Menu Item Markup settings field
+ */
+ function menu_item_loop_close_element( $field ) {
+ $markup = $this->get_menu_item_loop_markup();
+ echo '</' . tag_escape( $markup["{$field}_tag"] ) . ">\n";
+ }
+
+ /**
+ * Returns a Menu Item Markup element's class attribute
+ *
+ * @param string $class
+ * @return string HTML class attribute with leading whitespace
+ */
+ function menu_item_loop_class( $class ) {
+ if ( !$class ) {
+ return '';
+ }
+
+ return ' class="' . esc_attr( $class ) . '"';
+ }
+}
+
+add_action( 'init', array( 'Nova_Restaurant', 'init' ) );
diff --git a/plugins/jetpack/modules/custom-post-types/portfolios.php b/plugins/jetpack/modules/custom-post-types/portfolios.php
new file mode 100644
index 00000000..c38fd00b
--- /dev/null
+++ b/plugins/jetpack/modules/custom-post-types/portfolios.php
@@ -0,0 +1,730 @@
+<?php
+/**
+ * Plugin Name: Jetpack Portfolio
+ * Plugin URI:
+ * Author: Automattic
+ * Version: 0.1
+ * License: GPL v2 or later
+ * Text Domain: jetpack
+ * Domain Path: /languages/
+ */
+
+class Jetpack_Portfolio {
+ const CUSTOM_POST_TYPE = 'jetpack-portfolio';
+ const CUSTOM_TAXONOMY_TYPE = 'jetpack-portfolio-type';
+ const CUSTOM_TAXONOMY_TAG = 'jetpack-portfolio-tag';
+ const OPTION_NAME = 'jetpack_portfolio';
+ const OPTION_READING_SETTING = 'jetpack_portfolio_posts_per_page';
+
+ var $version = '0.1';
+
+ static function init() {
+ static $instance = false;
+
+ if ( ! $instance ) {
+ $instance = new Jetpack_Portfolio;
+ }
+
+ return $instance;
+ }
+
+ /**
+ * Conditionally hook into WordPress.
+ *
+ * Setup user option for enabling CPT
+ * If user has CPT enabled, show in admin
+ */
+ function __construct() {
+ // Add an option to enable the CPT
+ add_action( 'admin_init', array( $this, 'settings_api_init' ) );
+
+ // Check on theme switch if theme supports CPT and setting is disabled
+ add_action( 'after_switch_theme', array( $this, 'activation_post_type_support' ) );
+
+ // Make sure the post types are loaded for imports
+ add_action( 'import_start', array( $this, 'register_post_types' ) );
+
+ $setting = get_option( self::OPTION_NAME, '0' );
+
+ // Bail early if Portfolio option is not set and the theme doesn't declare support
+ if ( empty( $setting ) && ! $this->site_supports_custom_post_type() ) {
+ return;
+ }
+
+ // Enable Omnisearch for Portfolio Items.
+ if ( class_exists( 'Jetpack_Omnisearch_Posts' ) )
+ new Jetpack_Omnisearch_Posts( self::CUSTOM_POST_TYPE );
+
+ // CPT magic
+ $this->register_post_types();
+ add_action( sprintf( 'add_option_%s', self::OPTION_NAME ), array( $this, 'flush_rules_on_enable' ), 10 );
+ add_action( sprintf( 'update_option_%s', self::OPTION_NAME ), array( $this, 'flush_rules_on_enable' ), 10 );
+ add_action( sprintf( 'publish_%s', self::CUSTOM_POST_TYPE), array( $this, 'flush_rules_on_first_project' ) );
+ add_action( 'after_switch_theme', array( $this, 'flush_rules_on_switch' ) );
+
+ // Admin Customization
+ add_filter( 'post_updated_messages', array( $this, 'updated_messages' ) );
+ add_filter( sprintf( 'manage_%s_posts_columns', self::CUSTOM_POST_TYPE), array( $this, 'edit_admin_columns' ) );
+ add_filter( sprintf( 'manage_%s_posts_custom_column', self::CUSTOM_POST_TYPE), array( $this, 'image_column' ), 10, 2 );
+
+ add_image_size( 'jetpack-portfolio-admin-thumb', 50, 50, true );
+ add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_styles' ) );
+
+ // register jetpack_portfolio shortcode and portfolio shortcode (legacy)
+ add_shortcode( 'portfolio', array( $this, 'portfolio_shortcode' ) );
+ add_shortcode( 'jetpack_portfolio', array( $this, 'portfolio_shortcode' ) );
+
+ // Adjust CPT archive and custom taxonomies to obey CPT reading setting
+ add_filter( 'pre_get_posts', array( $this, 'query_reading_setting' ) );
+
+ // If CPT was enabled programatically and no CPT items exist when user switches away, disable
+ if ( $setting && $this->site_supports_custom_post_type() ) {
+ add_action( 'switch_theme', array( $this, 'deactivation_post_type_support' ) );
+ }
+ }
+
+ /**
+ * Add a checkbox field in 'Settings' > 'Writing'
+ * for enabling CPT functionality.
+ *
+ * @return null
+ */
+ function settings_api_init() {
+ add_settings_field(
+ self::OPTION_NAME,
+ '<span class="cpt-options">' . __( 'Portfolio Projects', 'jetpack' ) . '</span>',
+ array( $this, 'setting_html' ),
+ 'writing',
+ 'jetpack_cpt_section'
+ );
+ register_setting(
+ 'writing',
+ self::OPTION_NAME,
+ 'intval'
+ );
+
+ // Check if CPT is enabled first so that intval doesn't get set to NULL on re-registering
+ if ( get_option( self::OPTION_NAME, '0' ) || current_theme_supports( self::CUSTOM_POST_TYPE ) ) {
+ register_setting(
+ 'writing',
+ self::OPTION_READING_SETTING,
+ 'intval'
+ );
+ }
+ }
+
+ /**
+ * HTML code to display a checkbox true/false option
+ * for the Portfolio CPT setting.
+ *
+ * @return html
+ */
+ function setting_html() {
+ if ( current_theme_supports( self::CUSTOM_POST_TYPE ) ) : ?>
+ <p><?php printf( __( 'Your theme supports <strong>%s</strong>', 'jetpack' ), self::CUSTOM_POST_TYPE ); ?></p>
+ <?php else : ?>
+ <label for="<?php echo esc_attr( self::OPTION_NAME ); ?>">
+ <input name="<?php echo esc_attr( self::OPTION_NAME ); ?>" id="<?php echo esc_attr( self::OPTION_NAME ); ?>" <?php echo checked( get_option( self::OPTION_NAME, '0' ), true, false ); ?> type="checkbox" value="1" />
+ <?php esc_html_e( 'Enable Portfolio Projects for this site.', 'jetpack' ); ?>
+ <a target="_blank" href="http://en.support.wordpress.com/portfolios/"><?php esc_html_e( 'Learn More', 'jetpack' ); ?></a>
+ </label>
+ <?php endif;
+ if ( get_option( self::OPTION_NAME, '0' ) || current_theme_supports( self::CUSTOM_POST_TYPE ) ) :
+ printf( '<p><label for="%1$s">%2$s</label></p>',
+ esc_attr( self::OPTION_READING_SETTING ),
+ sprintf( __( 'Portfolio pages display at most %1$s projects', 'jetpack' ),
+ sprintf( '<input name="%1$s" id="%1$s" type="number" step="1" min="1" value="%2$s" class="small-text" />',
+ esc_attr( self::OPTION_READING_SETTING ),
+ esc_attr( get_option( self::OPTION_READING_SETTING, '10' ) )
+ )
+ )
+ );
+ endif;
+ }
+
+ /**
+ * Should this Custom Post Type be made available?
+ */
+ function site_supports_custom_post_type() {
+ // If the current theme requests it.
+ if ( current_theme_supports( self::CUSTOM_POST_TYPE ) || get_option( self::OPTION_NAME, '0' ) ) {
+ return true;
+ }
+
+ // Otherwise, say no unless something wants to filter us to say yes.
+ /** This action is documented in modules/custom-post-types/nova.php */
+ return (bool) apply_filters( 'jetpack_enable_cpt', false, self::CUSTOM_POST_TYPE );
+ }
+
+ /*
+ * Flush permalinks when CPT option is turned on/off
+ */
+ function flush_rules_on_enable() {
+ flush_rewrite_rules();
+ }
+
+ /*
+ * Count published projects and flush permalinks when first projects is published
+ */
+ function flush_rules_on_first_project() {
+ $projects = get_transient( 'jetpack-portfolio-count-cache' );
+
+ if ( false === $projects ) {
+ flush_rewrite_rules();
+ $projects = (int) wp_count_posts( self::CUSTOM_POST_TYPE )->publish;
+
+ if ( ! empty( $projects ) ) {
+ set_transient( 'jetpack-portfolio-count-cache', $projects, HOUR_IN_SECONDS * 12 );
+ }
+ }
+ }
+
+ /*
+ * Flush permalinks when CPT supported theme is activated
+ */
+ function flush_rules_on_switch() {
+ if ( current_theme_supports( self::CUSTOM_POST_TYPE ) ) {
+ flush_rewrite_rules();
+ }
+ }
+
+ /**
+ * On plugin/theme activation, check if current theme supports CPT
+ */
+ static function activation_post_type_support() {
+ if ( current_theme_supports( self::CUSTOM_POST_TYPE ) ) {
+ update_option( self::OPTION_NAME, '1' );
+ }
+ }
+
+ /**
+ * On theme switch, check if CPT item exists and disable if not
+ */
+ function deactivation_post_type_support() {
+ $portfolios = get_posts( array(
+ 'fields' => 'ids',
+ 'posts_per_page' => 1,
+ 'post_type' => self::CUSTOM_POST_TYPE,
+ 'suppress_filters' => false
+ ) );
+
+ if ( empty( $portfolios ) ) {
+ update_option( self::OPTION_NAME, '0' );
+ }
+ }
+
+ /**
+ * Register Post Type
+ */
+ function register_post_types() {
+ if ( post_type_exists( self::CUSTOM_POST_TYPE ) ) {
+ return;
+ }
+
+ register_post_type( self::CUSTOM_POST_TYPE, array(
+ 'description' => __( 'Portfolio Items', 'jetpack' ),
+ 'labels' => array(
+ 'name' => esc_html__( 'Projects', 'jetpack' ),
+ 'singular_name' => esc_html__( 'Project', 'jetpack' ),
+ 'menu_name' => esc_html__( 'Portfolio', 'jetpack' ),
+ 'all_items' => esc_html__( 'All Projects', 'jetpack' ),
+ 'add_new' => esc_html__( 'Add New', 'jetpack' ),
+ 'add_new_item' => esc_html__( 'Add New Project', 'jetpack' ),
+ 'edit_item' => esc_html__( 'Edit Project', 'jetpack' ),
+ 'new_item' => esc_html__( 'New Project', 'jetpack' ),
+ 'view_item' => esc_html__( 'View Project', 'jetpack' ),
+ 'search_items' => esc_html__( 'Search Projects', 'jetpack' ),
+ 'not_found' => esc_html__( 'No Projects found', 'jetpack' ),
+ 'not_found_in_trash' => esc_html__( 'No Projects found in Trash', 'jetpack' ),
+ ),
+ 'supports' => array(
+ 'title',
+ 'editor',
+ 'thumbnail',
+ 'comments',
+ 'publicize',
+ 'wpcom-markdown',
+ ),
+ 'rewrite' => array(
+ 'slug' => 'portfolio',
+ 'with_front' => false,
+ 'feeds' => true,
+ 'pages' => true,
+ ),
+ 'public' => true,
+ 'show_ui' => true,
+ 'menu_position' => 20, // below Pages
+ 'menu_icon' => 'dashicons-portfolio', // 3.8+ dashicon option
+ 'capability_type' => 'page',
+ 'map_meta_cap' => true,
+ 'taxonomies' => array( self::CUSTOM_TAXONOMY_TYPE, self::CUSTOM_TAXONOMY_TAG ),
+ 'has_archive' => true,
+ 'query_var' => 'portfolio',
+ ) );
+
+ register_taxonomy( self::CUSTOM_TAXONOMY_TYPE, self::CUSTOM_POST_TYPE, array(
+ 'hierarchical' => true,
+ 'labels' => array(
+ 'name' => esc_html__( 'Project Types', 'jetpack' ),
+ 'singular_name' => esc_html__( 'Project Type', 'jetpack' ),
+ 'menu_name' => esc_html__( 'Project Types', 'jetpack' ),
+ 'all_items' => esc_html__( 'All Project Types', 'jetpack' ),
+ 'edit_item' => esc_html__( 'Edit Project Type', 'jetpack' ),
+ 'view_item' => esc_html__( 'View Project Type', 'jetpack' ),
+ 'update_item' => esc_html__( 'Update Project Type', 'jetpack' ),
+ 'add_new_item' => esc_html__( 'Add New Project Type', 'jetpack' ),
+ 'new_item_name' => esc_html__( 'New Project Type Name', 'jetpack' ),
+ 'parent_item' => esc_html__( 'Parent Project Type', 'jetpack' ),
+ 'parent_item_colon' => esc_html__( 'Parent Project Type:', 'jetpack' ),
+ 'search_items' => esc_html__( 'Search Project Types', 'jetpack' ),
+ ),
+ 'public' => true,
+ 'show_ui' => true,
+ 'show_in_nav_menus' => true,
+ 'show_admin_column' => true,
+ 'query_var' => true,
+ 'rewrite' => array( 'slug' => 'project-type' ),
+ ) );
+
+ register_taxonomy( self::CUSTOM_TAXONOMY_TAG, self::CUSTOM_POST_TYPE, array(
+ 'hierarchical' => false,
+ 'labels' => array(
+ 'name' => esc_html__( 'Project Tags', 'jetpack' ),
+ 'singular_name' => esc_html__( 'Project Tag', 'jetpack' ),
+ 'menu_name' => esc_html__( 'Project Tags', 'jetpack' ),
+ 'all_items' => esc_html__( 'All Project Tags', 'jetpack' ),
+ 'edit_item' => esc_html__( 'Edit Project Tag', 'jetpack' ),
+ 'view_item' => esc_html__( 'View Project Tag', 'jetpack' ),
+ 'update_item' => esc_html__( 'Update Project Tag', 'jetpack' ),
+ 'add_new_item' => esc_html__( 'Add New Project Tag', 'jetpack' ),
+ 'new_item_name' => esc_html__( 'New Project Tag Name', 'jetpack' ),
+ 'search_items' => esc_html__( 'Search Project Tags', 'jetpack' ),
+ 'popular_items' => esc_html__( 'Popular Project Tags', 'jetpack' ),
+ 'separate_items_with_commas' => esc_html__( 'Separate tags with commas', 'jetpack' ),
+ 'add_or_remove_items' => esc_html__( 'Add or remove tags', 'jetpack' ),
+ 'choose_from_most_used' => esc_html__( 'Choose from the most used tags', 'jetpack' ),
+ 'not_found' => esc_html__( 'No tags found.', 'jetpack' ),
+ ),
+ 'public' => true,
+ 'show_ui' => true,
+ 'show_in_nav_menus' => true,
+ 'show_admin_column' => true,
+ 'query_var' => true,
+ 'rewrite' => array( 'slug' => 'project-tag' ),
+ ) );
+ }
+
+ /**
+ * Update messages for the Portfolio admin.
+ */
+ function updated_messages( $messages ) {
+ global $post;
+
+ $messages[self::CUSTOM_POST_TYPE] = array(
+ 0 => '', // Unused. Messages start at index 1.
+ 1 => sprintf( __( 'Project updated. <a href="%s">View item</a>', 'jetpack'), esc_url( get_permalink( $post->ID ) ) ),
+ 2 => esc_html__( 'Custom field updated.', 'jetpack' ),
+ 3 => esc_html__( 'Custom field deleted.', 'jetpack' ),
+ 4 => esc_html__( 'Project updated.', 'jetpack' ),
+ /* translators: %s: date and time of the revision */
+ 5 => isset( $_GET['revision'] ) ? sprintf( esc_html__( 'Project restored to revision from %s', 'jetpack'), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
+ 6 => sprintf( __( 'Project published. <a href="%s">View project</a>', 'jetpack' ), esc_url( get_permalink( $post->ID ) ) ),
+ 7 => esc_html__( 'Project saved.', 'jetpack' ),
+ 8 => sprintf( __( 'Project submitted. <a target="_blank" href="%s">Preview project</a>', 'jetpack'), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) ) ),
+ 9 => sprintf( __( 'Project scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview project</a>', 'jetpack' ),
+ // translators: Publish box date format, see http://php.net/date
+ date_i18n( __( 'M j, Y @ G:i', 'jetpack' ), strtotime( $post->post_date ) ), esc_url( get_permalink( $post->ID ) ) ),
+ 10 => sprintf( __( 'Project item draft updated. <a target="_blank" href="%s">Preview project</a>', 'jetpack' ), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) ) ),
+ );
+
+ return $messages;
+ }
+
+ /**
+ * Change ‘Title’ column label
+ * Add Featured Image column
+ */
+ function edit_admin_columns( $columns ) {
+ // change 'Title' to 'Project'
+ $columns['title'] = __( 'Project', 'jetpack' );
+ if ( current_theme_supports( 'post-thumbnails' ) ) {
+ // add featured image before 'Project'
+ $columns = array_slice( $columns, 0, 1, true ) + array( 'thumbnail' => '' ) + array_slice( $columns, 1, NULL, true );
+ }
+
+ return $columns;
+ }
+
+ /**
+ * Add featured image to column
+ */
+ function image_column( $column, $post_id ) {
+ global $post;
+ switch ( $column ) {
+ case 'thumbnail':
+ echo get_the_post_thumbnail( $post_id, 'jetpack-portfolio-admin-thumb' );
+ break;
+ }
+ }
+
+ /**
+ * Adjust image column width
+ */
+ function enqueue_admin_styles( $hook ) {
+ $screen = get_current_screen();
+
+ if ( 'edit.php' == $hook && self::CUSTOM_POST_TYPE == $screen->post_type && current_theme_supports( 'post-thumbnails' ) ) {
+ wp_add_inline_style( 'wp-admin', '.manage-column.column-thumbnail { width: 50px; } @media screen and (max-width: 360px) { .column-thumbnail{ display:none; } }' );
+ }
+ }
+
+ /**
+ * Follow CPT reading setting on CPT archive and taxonomy pages
+ */
+ function query_reading_setting( $query ) {
+ if ( ! is_admin() &&
+ $query->is_main_query() &&
+ ( $query->is_post_type_archive( self::CUSTOM_POST_TYPE ) || $query->is_tax( self::CUSTOM_TAXONOMY_TYPE ) || $query->is_tax( self::CUSTOM_TAXONOMY_TAG ) )
+ ) {
+ $query->set( 'posts_per_page', get_option( self::OPTION_READING_SETTING, '10' ) );
+ }
+ }
+
+ /**
+ * Our [portfolio] shortcode.
+ * Prints Portfolio data styled to look good on *any* theme.
+ *
+ * @return portfolio_shortcode_html
+ */
+ static function portfolio_shortcode( $atts ) {
+ // Default attributes
+ $atts = shortcode_atts( array(
+ 'display_types' => true,
+ 'display_tags' => true,
+ 'display_content' => true,
+ 'show_filter' => false,
+ 'include_type' => false,
+ 'include_tag' => false,
+ 'columns' => 2,
+ 'showposts' => -1,
+ 'order' => 'asc',
+ 'orderby' => 'date',
+ ), $atts, 'portfolio' );
+
+ // A little sanitization
+ if ( $atts['display_types'] && 'true' != $atts['display_types'] ) {
+ $atts['display_types'] = false;
+ }
+
+ if ( $atts['display_tags'] && 'true' != $atts['display_tags'] ) {
+ $atts['display_tags'] = false;
+ }
+
+ if ( $atts['display_content'] && 'true' != $atts['display_content'] ) {
+ $atts['display_content'] = false;
+ }
+
+ if ( $atts['include_type'] ) {
+ $atts['include_type'] = explode( ',', str_replace( ' ', '', $atts['include_type'] ) );
+ }
+
+ if ( $atts['include_tag'] ) {
+ $atts['include_tag'] = explode( ',', str_replace( ' ', '', $atts['include_tag'] ) );
+ }
+
+ $atts['columns'] = absint( $atts['columns'] );
+
+ $atts['showposts'] = intval( $atts['showposts'] );
+
+
+ if ( $atts['order'] ) {
+ $atts['order'] = urldecode( $atts['order'] );
+ $atts['order'] = strtoupper( $atts['order'] );
+ if ( 'DESC' != $atts['order'] ) {
+ $atts['order'] = 'ASC';
+ }
+ }
+
+ if ( $atts['orderby'] ) {
+ $atts['orderby'] = urldecode( $atts['orderby'] );
+ $atts['orderby'] = strtolower( $atts['orderby'] );
+ $allowed_keys = array( 'author', 'date', 'title', 'rand' );
+
+ $parsed = array();
+ foreach ( explode( ',', $atts['orderby'] ) as $portfolio_index_number => $orderby ) {
+ if ( ! in_array( $orderby, $allowed_keys ) ) {
+ continue;
+ }
+ $parsed[] = $orderby;
+ }
+
+ if ( empty( $parsed ) ) {
+ unset( $atts['orderby'] );
+ } else {
+ $atts['orderby'] = implode( ' ', $parsed );
+ }
+ }
+
+ // enqueue shortcode styles when shortcode is used
+ wp_enqueue_style( 'jetpack-portfolio-style', plugins_url( 'css/portfolio-shortcode.css', __FILE__ ), array(), '20140326' );
+
+ return self::portfolio_shortcode_html( $atts );
+ }
+
+ /**
+ * Query to retrieve entries from the Portfolio post_type.
+ *
+ * @return object
+ */
+ static function portfolio_query( $atts ) {
+ // Default query arguments
+ $default = array(
+ 'order' => $atts['order'],
+ 'orderby' => $atts['orderby'],
+ 'posts_per_page' => $atts['showposts'],
+ );
+
+ $args = wp_parse_args( $atts, $default );
+ $args['post_type'] = self::CUSTOM_POST_TYPE; // Force this post type
+
+ if ( false != $atts['include_type'] || false != $atts['include_tag'] ) {
+ $args['tax_query'] = array();
+ }
+
+ // If 'include_type' has been set use it on the main query
+ if ( false != $atts['include_type'] ) {
+ array_push( $args['tax_query'], array(
+ 'taxonomy' => self::CUSTOM_TAXONOMY_TYPE,
+ 'field' => 'slug',
+ 'terms' => $atts['include_type'],
+ ) );
+ }
+
+ // If 'include_tag' has been set use it on the main query
+ if ( false != $atts['include_tag'] ) {
+ array_push( $args['tax_query'], array(
+ 'taxonomy' => self::CUSTOM_TAXONOMY_TAG,
+ 'field' => 'slug',
+ 'terms' => $atts['include_tag'],
+ ) );
+ }
+
+ if ( false != $atts['include_type'] && false != $atts['include_tag'] ) {
+ $args['tax_query']['relation'] = 'AND';
+ }
+
+ // Run the query and return
+ $query = new WP_Query( $args );
+ return $query;
+ }
+
+ /**
+ * The Portfolio shortcode loop.
+ *
+ * @todo add theme color styles
+ * @return html
+ */
+ static function portfolio_shortcode_html( $atts ) {
+
+ $query = self::portfolio_query( $atts );
+ $portfolio_index_number = 0;
+
+ ob_start();
+
+ // If we have posts, create the html
+ // with hportfolio markup
+ if ( $query->have_posts() ) {
+
+ // Render styles
+ //self::themecolor_styles();
+
+ ?>
+ <div class="jetpack-portfolio-shortcode column-<?php echo esc_attr( $atts['columns'] ); ?>">
+ <?php // open .jetpack-portfolio
+
+ // Construct the loop...
+ while ( $query->have_posts() ) {
+ $query->the_post();
+ $post_id = get_the_ID();
+ ?>
+ <div class="portfolio-entry <?php echo esc_attr( self::get_project_class( $portfolio_index_number, $atts['columns'] ) ); ?>">
+ <header class="portfolio-entry-header">
+ <?php
+ // Featured image
+ echo self::get_portfolio_thumbnail_link( $post_id );
+ ?>
+
+ <h2 class="portfolio-entry-title"><a href="<?php echo esc_url( get_permalink() ); ?>" title="<?php echo esc_attr( the_title_attribute( ) ); ?>"><?php the_title(); ?></a></h2>
+
+ <div class="portfolio-entry-meta">
+ <?php
+ if ( false != $atts['display_types'] ) {
+ echo self::get_project_type( $post_id );
+ }
+
+ if ( false != $atts['display_tags'] ) {
+ echo self::get_project_tags( $post_id );
+ }
+ ?>
+ </div>
+
+ </header>
+
+ <?php
+ // The content
+ if ( false != $atts['display_content'] ): ?>
+ <div class="portfolio-entry-content"><?php the_excerpt(); ?></div>
+ <?php endif; ?>
+ </div><!-- close .portfolio-entry -->
+ <?php
+ $portfolio_index_number++;
+ } // end of while loop
+
+ wp_reset_postdata();
+ ?>
+ </div><!-- close .jetpack-portfolio -->
+ <?php
+ } else { ?>
+ <p><em><?php _e( 'Your Portfolio Archive currently has no entries. You can start creating them on your dashboard.', 'jetpack' ); ?></p></em>
+ <?php
+ }
+ $html = ob_get_clean();
+
+ // If there is a [portfolio] within a [portfolio], remove the shortcode
+ if ( has_shortcode( $html, 'portfolio' ) ){
+ remove_shortcode( 'portfolio' );
+ }
+
+ // Return the HTML block
+ return $html;
+ }
+
+ /**
+ * Individual project class
+ *
+ * @return string
+ */
+ static function get_project_class( $portfolio_index_number, $columns ) {
+ $project_types = wp_get_object_terms( get_the_ID(), self::CUSTOM_TAXONOMY_TYPE, array( 'fields' => 'slugs' ) );
+ $class = array();
+
+ $class[] = 'portfolio-entry-column-'.$columns;
+ // add a type- class for each project type
+ foreach ( $project_types as $project_type ) {
+ $class[] = 'type-' . esc_html( $project_type );
+ }
+ if( $columns > 1) {
+ if ( ( $portfolio_index_number % 2 ) == 0 ) {
+ $class[] = 'portfolio-entry-mobile-first-item-row';
+ } else {
+ $class[] = 'portfolio-entry-mobile-last-item-row';
+ }
+ }
+
+ // add first and last classes to first and last items in a row
+ if ( ( $portfolio_index_number % $columns ) == 0 ) {
+ $class[] = 'portfolio-entry-first-item-row';
+ } elseif ( ( $portfolio_index_number % $columns ) == ( $columns - 1 ) ) {
+ $class[] = 'portfolio-entry-last-item-row';
+ }
+
+
+ /**
+ * Filter the class applied to project div in the portfolio
+ *
+ * @since 3.1.0
+ *
+ * @param string $class class name of the div.
+ * @param int $portfolio_index_number iterator count the number of columns up starting from 0.
+ * @param int $columns number of columns to display the content in.
+ *
+ */
+ return apply_filters( 'portfolio-project-post-class', implode( " ", $class ) , $portfolio_index_number, $columns );
+ }
+
+ /**
+ * Displays the project type that a project belongs to.
+ *
+ * @return html
+ */
+ static function get_project_type( $post_id ) {
+ $project_types = get_the_terms( $post_id, self::CUSTOM_TAXONOMY_TYPE );
+
+ // If no types, return empty string
+ if ( empty( $project_types ) || is_wp_error( $project_types ) ) {
+ return;
+ }
+
+ $html = '<div class="project-types"><span>' . __( 'Types', 'jetpack' ) . ':</span>';
+ $types = array();
+ // Loop thorugh all the types
+ foreach ( $project_types as $project_type ) {
+ $project_type_link = get_term_link( $project_type, self::CUSTOM_TAXONOMY_TYPE );
+
+ if ( is_wp_error( $project_type_link ) ) {
+ return $project_type_link;
+ }
+
+ $types[] = '<a href="' . esc_url( $project_type_link ) . '" rel="tag">' . esc_html( $project_type->name ) . '</a>';
+ }
+ $html .= ' '.implode( ', ', $types );
+ $html .= '</div>';
+
+ return $html;
+ }
+
+ /**
+ * Displays the project tags that a project belongs to.
+ *
+ * @return html
+ */
+ static function get_project_tags( $post_id ) {
+ $project_tags = get_the_terms( $post_id, self::CUSTOM_TAXONOMY_TAG );
+
+ // If no tags, return empty string
+ if ( empty( $project_tags ) || is_wp_error( $project_tags ) ) {
+ return false;
+ }
+
+ $html = '<div class="project-tags"><span>' . __( 'Tags', 'jetpack' ) . ':</span>';
+ $tags = array();
+ // Loop thorugh all the tags
+ foreach ( $project_tags as $project_tag ) {
+ $project_tag_link = get_term_link( $project_tag, self::CUSTOM_TAXONOMY_TYPE );
+
+ if ( is_wp_error( $project_tag_link ) ) {
+ return $project_tag_link;
+ }
+
+ $tags[] = '<a href="' . esc_url( $project_tag_link ) . '" rel="tag">' . esc_html( $project_tag->name ) . '</a>';
+ }
+ $html .= ' '. implode( ', ', $tags );
+ $html .= '</div>';
+
+ return $html;
+ }
+
+ /**
+ * Display the featured image if it's available
+ *
+ * @return html
+ */
+ static function get_portfolio_thumbnail_link( $post_id ) {
+ if ( has_post_thumbnail( $post_id ) ) {
+ /**
+ * Change the Portfolio thumbnail size.
+ *
+ * @since 3.4.0
+ *
+ * @param string|array $var Either a registered size keyword or size array.
+ */
+ return '<a class="portfolio-featured-image" href="' . esc_url( get_permalink( $post_id ) ) . '">' . get_the_post_thumbnail( $post_id, apply_filters( 'jetpack_portfolio_thumbnail_size', 'large' ) ) . '</a>';
+ }
+ }
+}
+
+add_action( 'init', array( 'Jetpack_Portfolio', 'init' ) );
+
+// Check on plugin activation if theme supports CPT
+register_activation_hook( __FILE__, array( 'Jetpack_Portfolio', 'activation_post_type_support' ) );
+add_action( 'jetpack_activate_module_custom-content-types', array( 'Jetpack_Portfolio', 'activation_post_type_support' ) );
diff --git a/plugins/jetpack/modules/custom-post-types/testimonial.php b/plugins/jetpack/modules/custom-post-types/testimonial.php
index 6cd6b9d7..d90c3287 100644
--- a/plugins/jetpack/modules/custom-post-types/testimonial.php
+++ b/plugins/jetpack/modules/custom-post-types/testimonial.php
@@ -10,7 +10,9 @@
*/
class Jetpack_Testimonial {
- const TESTIMONIAL_POST_TYPE = 'jetpack-testimonial';
+ const CUSTOM_POST_TYPE = 'jetpack-testimonial';
+ const OPTION_NAME = 'jetpack_testimonial';
+ const OPTION_READING_SETTING = 'jetpack_testimonial_posts_per_page';
var $version = '0.1';
@@ -33,24 +35,205 @@ class Jetpack_Testimonial {
* WordPress. We'll just return early instead.
*/
function __construct() {
- // Return early if theme does not support Jetpack Testimonial.
- if ( ! current_theme_supports( self::TESTIMONIAL_POST_TYPE ) )
+ // Add an option to enable the CPT
+ add_action( 'admin_init', array( $this, 'settings_api_init' ) );
+
+ // Check on theme switch if theme supports CPT and setting is disabled
+ add_action( 'after_switch_theme', array( $this, 'activation_post_type_support' ) );
+
+ // Make sure the post types are loaded for imports
+ add_action( 'import_start', array( $this, 'register_post_types' ) );
+
+ $setting = get_option( self::OPTION_NAME, '0' );
+
+ // Bail early if Testimonial option is not set and the theme doesn't declare support
+ if ( empty( $setting ) && ! $this->site_supports_custom_post_type() ) {
return;
+ }
+ // Enable Omnisearch for Testimonials.
+ if ( class_exists( 'Jetpack_Omnisearch_Posts' ) )
+ new Jetpack_Omnisearch_Posts( self::CUSTOM_POST_TYPE );
+
+ // CPT magic
$this->register_post_types();
- add_filter( 'enter_title_here', array( $this, 'change_default_title' ) );
- add_filter( 'manage_jetpack-testimonial_posts_columns', array( $this, 'edit_title_column_label' ) );
- add_filter( 'post_updated_messages', array( $this, 'updated_messages' ) );
- add_action( 'customize_register', array( $this, 'customize_register' ) );
+ add_action( sprintf( 'add_option_%s', self::OPTION_NAME ), array( $this, 'flush_rules_on_enable' ), 10 );
+ add_action( sprintf( 'update_option_%s', self::OPTION_NAME ), array( $this, 'flush_rules_on_enable' ), 10 );
+ add_action( sprintf( 'publish_%s', self::CUSTOM_POST_TYPE ), array( $this, 'flush_rules_on_first_testimonial' ) );
+ add_action( 'after_switch_theme', array( $this, 'flush_rules_on_switch' ) );
+
+ // Admin Customization
+ add_filter( 'enter_title_here', array( $this, 'change_default_title' ) );
+ add_filter( sprintf( 'manage_%s_posts_columns', self::CUSTOM_POST_TYPE), array( $this, 'edit_title_column_label' ) );
+ add_filter( 'post_updated_messages', array( $this, 'updated_messages' ) );
+ add_action( 'customize_register', array( $this, 'customize_register' ) );
$num_testimonials = self::count_testimonials();
if ( ! empty( $num_testimonials ) )
- add_action( 'admin_menu', array( $this, 'add_customize_page' ) );
+ add_action( 'admin_menu', array( $this, 'add_customize_page' ) );
+
+ add_action( 'after_switch_theme', array( $this, 'flush_rules_on_switch' ) );
+
+ // Adjust CPT archive and custom taxonomies to obey CPT reading setting
+ add_filter( 'pre_get_posts', array( $this, 'query_reading_setting' ) );
+
+ // If called via REST API, we need to register later in lifecycle
+ add_action( 'restapi_theme_init', array( $this, 'maybe_register_cpt' ) );
+
+ // Register [jetpack_testimonials] always and
+ // register [testimonials] if [testimonials] isn't already set
+ add_shortcode( 'jetpack_testimonials', array( $this, 'jetpack_testimonial_shortcode' ) );
+
+ if ( ! shortcode_exists( 'testimonials' ) ) {
+ add_shortcode( 'testimonials', array( $this, 'jetpack_testimonial_shortcode' ) );
+ }
+
+ // If CPT was enabled programatically and no CPT items exist when user switches away, disable
+ if ( $setting && $this->site_supports_custom_post_type() ) {
+ add_action( 'switch_theme', array( $this, 'deactivation_post_type_support' ) );
+ }
+ }
+
+ /**
+ * Add a checkbox field in 'Settings' > 'Writing'
+ * for enabling CPT functionality.
+ *
+ * @return null
+ */
+ function settings_api_init() {
+ add_settings_field(
+ self::OPTION_NAME,
+ '<span class="cpt-options">' . __( 'Testimonials', 'jetpack' ) . '</span>',
+ array( $this, 'setting_html' ),
+ 'writing',
+ 'jetpack_cpt_section'
+ );
+ register_setting(
+ 'writing',
+ self::OPTION_NAME,
+ 'intval'
+ );
+
+ // Check if CPT is enabled first so that intval doesn't get set to NULL on re-registering
+ if ( get_option( self::OPTION_NAME, '0' ) || current_theme_supports( self::CUSTOM_POST_TYPE ) ) {
+ register_setting(
+ 'writing',
+ self::OPTION_READING_SETTING,
+ 'intval'
+ );
+ }
+ }
+
+
+
+ /**
+ * HTML code to display a checkbox true/false option
+ * for the Testimonial CPT setting.
+ *
+ * @return html
+ */
+ function setting_html() {
+ if ( current_theme_supports( self::CUSTOM_POST_TYPE ) ) : ?>
+ <p><?php printf( __( 'Your theme supports <strong>%s</strong>', 'jetpack' ), self::CUSTOM_POST_TYPE ); ?></p>
+ <?php else : ?>
+ <label for="<?php echo esc_attr( self::OPTION_NAME ); ?>">
+ <input name="<?php echo esc_attr( self::OPTION_NAME ); ?>" id="<?php echo esc_attr( self::OPTION_NAME ); ?>" <?php echo checked( get_option( self::OPTION_NAME, '0' ), true, false ); ?> type="checkbox" value="1" />
+ <?php esc_html_e( 'Enable Testimonials for this site.', 'jetpack' ); ?>
+ <a target="_blank" href="http://en.support.wordpress.com/testimonials/"><?php esc_html_e( 'Learn More', 'jetpack' ); ?></a>
+ </label>
+ <?php endif;
+
+ if ( get_option( self::OPTION_NAME, '0' ) || current_theme_supports( self::CUSTOM_POST_TYPE ) ) :
+ printf( '<p><label for="%1$s">%2$s</label></p>',
+ esc_attr( self::OPTION_READING_SETTING ),
+ sprintf( __( 'Testimonial pages display at most %1$s testimonials', 'jetpack' ),
+ sprintf( '<input name="%1$s" id="%1$s" type="number" step="1" min="1" value="%2$s" class="small-text" />',
+ esc_attr( self::OPTION_READING_SETTING ),
+ esc_attr( get_option( self::OPTION_READING_SETTING, '10' ) )
+ )
+ )
+ );
+ endif;
+ }
+
+ /**
+ * Should this Custom Post Type be made available?
+ */
+ function site_supports_custom_post_type() {
+ // If the current theme requests it.
+ if ( current_theme_supports( self::CUSTOM_POST_TYPE ) || get_option( self::OPTION_NAME, '0' ) ) {
+ return true;
+ }
+
+ // Otherwise, say no unless something wants to filter us to say yes.
+ /** This action is documented in modules/custom-post-types/nova.php */
+ return (bool) apply_filters( 'jetpack_enable_cpt', false, self::CUSTOM_POST_TYPE );
+ }
+
+ /*
+ * Flush permalinks when CPT option is turned on/off
+ */
+ function flush_rules_on_enable() {
+ flush_rewrite_rules();
+ }
+
+ /*
+ * Count published testimonials and flush permalinks when first testimonial is published
+ */
+ function flush_rules_on_first_testimonial() {
+ $testimonials = get_transient( 'jetpack-testimonial-count-cache' );
+
+ if ( false === $testimonials ) {
+ flush_rewrite_rules();
+ $testimonials = (int) wp_count_posts( self::CUSTOM_POST_TYPE )->publish;
+
+ if ( ! empty( $testimonials ) ) {
+ set_transient( 'jetpack-testimonial-count-cache', $testimonials, HOUR_IN_SECONDS * 12 );
+ }
+ }
+ }
+
+ /*
+ * Flush permalinks when CPT supported theme is activated
+ */
+ function flush_rules_on_switch() {
+ if ( current_theme_supports( self::CUSTOM_POST_TYPE ) ) {
+ flush_rewrite_rules();
+ }
+ }
+
+ /**
+ * On plugin/theme activation, check if current theme supports CPT
+ */
+ static function activation_post_type_support() {
+ if ( current_theme_supports( self::CUSTOM_POST_TYPE ) ) {
+ update_option( self::OPTION_NAME, '1' );
+ }
+ }
+
+ /**
+ * On theme switch, check if CPT item exists and disable if not
+ */
+ function deactivation_post_type_support() {
+ $portfolios = get_posts( array(
+ 'fields' => 'ids',
+ 'posts_per_page' => 1,
+ 'post_type' => self::CUSTOM_POST_TYPE,
+ 'suppress_filters' => false
+ ) );
+
+ if ( empty( $portfolios ) ) {
+ update_option( self::OPTION_NAME, '0' );
+ }
}
/* Setup */
function register_post_types() {
- register_post_type( self::TESTIMONIAL_POST_TYPE, array(
+ if ( post_type_exists( self::CUSTOM_POST_TYPE ) ) {
+ return;
+ }
+
+ register_post_type( self::CUSTOM_POST_TYPE, array(
'description' => __( 'Customer Testimonials', 'jetpack' ),
'labels' => array(
'name' => esc_html__( 'Testimonials', 'jetpack' ),
@@ -76,10 +259,10 @@ class Jetpack_Testimonial {
'slug' => 'testimonial',
'with_front' => false,
'feeds' => false,
- 'pages' => false,
+ 'pages' => true,
),
'public' => true,
- 'show_ui' => true, // set to false to replace with custom UI
+ 'show_ui' => true,
'menu_position' => 20, // below Pages
'capability_type' => 'page',
'map_meta_cap' => true,
@@ -135,6 +318,17 @@ class Jetpack_Testimonial {
return $messages;
}
+ /**
+ * Follow CPT reading setting on CPT archive page
+ */
+ function query_reading_setting( $query ) {
+ if ( ! is_admin() &&
+ $query->is_main_query() &&
+ ( $query->is_post_type_archive( self::CUSTOM_POST_TYPE ) )
+ ) {
+ $query->set( 'posts_per_page', get_option( self::OPTION_READING_SETTING, '10' ) );
+ }
+ }
function set_testimonial_option() {
$testimonials_option = get_option( 'jetpack_testimonial' );
@@ -181,6 +375,7 @@ class Jetpack_Testimonial {
$wp_customize->add_section( 'jetpack_testimonials', array(
'title' => esc_html__( 'Testimonials', 'jetpack' ),
'theme_supports' => 'jetpack-testimonial',
+ 'priority' => 130,
) );
$wp_customize->add_setting( 'jetpack_testimonials[page-title]', array(
@@ -205,23 +400,211 @@ class Jetpack_Testimonial {
'label' => esc_html__( 'Testimonial Page Content', 'jetpack' ),
) ) );
- if ( current_theme_supports( 'post-thumbnails' ) ) {
- $wp_customize->add_setting( 'jetpack_testimonials[featured-image]', array(
- 'default' => '',
- 'sanitize_callback' => array( 'Jetpack_Testimonial_Image_Control', 'attachment_guid_to_id' ),
- 'sanitize_js_callback' => array( 'Jetpack_Testimonial_Image_Control', 'attachment_guid_to_id' ),
- ) );
- $wp_customize->add_control( new Jetpack_Testimonial_Image_Control( $wp_customize, 'jetpack_testimonials[featured-image]', array(
- 'section' => 'jetpack_testimonials',
- 'label' => esc_html__( 'Testimonial Page Featured Image', 'jetpack' ),
- ) ) );
+ $wp_customize->add_setting( 'jetpack_testimonials[featured-image]', array(
+ 'default' => '',
+ 'sanitize_callback' => 'attachment_url_to_postid',
+ 'sanitize_js_callback' => 'attachment_url_to_postid',
+ 'theme_supports' => 'post-thumbnails',
+ ) );
+ $wp_customize->add_control( new WP_Customize_Image_Control( $wp_customize, 'jetpack_testimonials[featured-image]', array(
+ 'section' => 'jetpack_testimonials',
+ 'label' => esc_html__( 'Testimonial Page Featured Image', 'jetpack' ),
+ ) ) );
+ }
+
+
+ /**
+ * Our [testimonial] shortcode.
+ * Prints Testimonial data styled to look good on *any* theme.
+ *
+ * @return jetpack_testimonial_shortcode_html
+ */
+ static function jetpack_testimonial_shortcode( $atts ) {
+ // Default attributes
+ $atts = shortcode_atts( array(
+ 'display_content' => true,
+ 'image' => true,
+ 'columns' => 1,
+ 'showposts' => -1,
+ 'order' => 'asc',
+ 'orderby' => 'date',
+ ), $atts, 'testimonial' );
+
+ // A little sanitization
+ if ( $atts['display_content'] && 'true' != $atts['display_content'] ) {
+ $atts['display_content'] = false;
+ }
+
+ if ( $atts['image'] && 'true' != $atts['image'] ) {
+ $atts['image'] = false;
+ }
+
+ $atts['columns'] = absint( $atts['columns'] );
+
+ $atts['showposts'] = intval( $atts['showposts'] );
+
+
+ if ( $atts['order'] ) {
+ $atts['order'] = urldecode( $atts['order'] );
+ $atts['order'] = strtoupper( $atts['order'] );
+ if ( 'DESC' != $atts['order'] ) {
+ $atts['order'] = 'ASC';
+ }
+ }
+
+ if ( $atts['orderby'] ) {
+ $atts['orderby'] = urldecode( $atts['orderby'] );
+ $atts['orderby'] = strtolower( $atts['orderby'] );
+ $allowed_keys = array('author', 'date', 'title', 'rand');
+
+ $parsed = array();
+ foreach ( explode( ',', $atts['orderby'] ) as $testimonial_index_number => $orderby ) {
+ if ( ! in_array( $orderby, $allowed_keys ) ) {
+ continue;
+ }
+ $parsed[] = $orderby;
+ }
+
+ if ( empty( $parsed ) ) {
+ unset($atts['orderby']);
+ } else {
+ $atts['orderby'] = implode( ' ', $parsed );
+ }
+ }
+
+ // enqueue shortcode styles when shortcode is used
+ wp_enqueue_style( 'jetpack-testimonial-style', plugins_url( 'css/testimonial-shortcode.css', __FILE__ ), array(), '20140326' );
+
+ return self::jetpack_testimonial_shortcode_html( $atts );
+ }
+
+ /**
+ * The Testimonial shortcode loop.
+ *
+ * @return html
+ */
+ static function jetpack_testimonial_shortcode_html( $atts ) {
+ // Default query arguments
+ $defaults = array(
+ 'order' => $atts['order'],
+ 'orderby' => $atts['orderby'],
+ 'posts_per_page' => $atts['showposts'],
+ );
+
+ $args = wp_parse_args( $atts, $defaults );
+ $args['post_type'] = self::CUSTOM_POST_TYPE; // Force this post type
+ $query = new WP_Query( $args );
+
+ $testimonial_index_number = 0;
+
+ ob_start();
+
+ // If we have testimonials, create the html
+ if ( $query->have_posts() ) {
+
+ ?>
+ <div class="jetpack-testimonial-shortcode column-<?php echo esc_attr( $atts['columns'] ); ?>">
+ <?php // open .jetpack-testimonial-shortcode
+
+ // Construct the loop...
+ while ( $query->have_posts() ) {
+ $query->the_post();
+ $post_id = get_the_ID();
+ ?>
+ <div class="testimonial-entry <?php echo esc_attr( self::get_testimonial_class( $testimonial_index_number, $atts['columns'] ) ); ?>">
+ <?php
+ // The content
+ if ( false !== $atts['display_content'] ): ?>
+ <div class="testimonial-entry-content"><?php the_excerpt(); ?></div>
+ <?php endif; ?>
+
+ <span class="testimonial-entry-title">&#8213; <a href="<?php echo esc_url( get_permalink() ); ?>" title="<?php echo esc_attr( the_title_attribute( ) ); ?>"><?php the_title(); ?></a></span>
+ <?php
+ // Featured image
+ if ( false !== $atts['image'] ) :
+ echo self::get_testimonial_thumbnail_link( $post_id );
+ endif;
+ ?>
+ </div><!-- close .testimonial-entry -->
+ <?php
+ $testimonial_index_number++;
+ } // end of while loop
+
+ wp_reset_postdata();
+ ?>
+ </div><!-- close .jetpack-testimonial-shortcode -->
+ <?php
+ } else { ?>
+ <p><em><?php _e( 'Your Testimonial Archive currently has no entries. You can start creating them on your dashboard.', 'jetpack' ); ?></p></em>
+ <?php
+ }
+ $html = ob_get_clean();
+
+ // Return the HTML block
+ return $html;
+ }
+
+ /**
+ * Individual testimonial class
+ *
+ * @return string
+ */
+ static function get_testimonial_class( $testimonial_index_number, $columns ) {
+ $class = array();
+
+ $class[] = 'testimonial-entry-column-'.$columns;
+
+ if( $columns > 1) {
+ if ( ( $testimonial_index_number % 2 ) == 0 ) {
+ $class[] = 'testimonial-entry-mobile-first-item-row';
+ } else {
+ $class[] = 'testimonial-entry-mobile-last-item-row';
+ }
+ }
+
+ // add first and last classes to first and last items in a row
+ if ( ( $testimonial_index_number % $columns ) == 0 ) {
+ $class[] = 'testimonial-entry-first-item-row';
+ } elseif ( ( $testimonial_index_number % $columns ) == ( $columns - 1 ) ) {
+ $class[] = 'testimonial-entry-last-item-row';
+ }
+
+
+ /**
+ * Filter the class applied to testimonial div in the testimonial
+ *
+ * @since 3.4.0
+ *
+ * @param string $class class name of the div.
+ * @param int $testimonial_index_number iterator count the number of columns up starting from 0.
+ * @param int $columns number of columns to display the content in.
+ *
+ */
+ return apply_filters( 'testimonial-entry-post-class', implode( " ", $class ) , $testimonial_index_number, $columns );
+ }
+
+ /**
+ * Display the featured image if it's available
+ *
+ * @return html
+ */
+ static function get_testimonial_thumbnail_link( $post_id ) {
+ if ( has_post_thumbnail( $post_id ) ) {
+ /**
+ * Change the thumbnail size for the Testimonial CPT.
+ *
+ * @since 3.4.0
+ *
+ * @param string|array $var Either a registered size keyword or size array.
+ */
+ return '<a class="testimonial-featured-image" href="' . esc_url( get_permalink( $post_id ) ) . '">' . get_the_post_thumbnail( $post_id, apply_filters( 'jetpack_testimonial_thumbnail_size', 'thumbnail' ) ) . '</a>';
}
}
}
function jetpack_testimonial_custom_control_classes() {
class Jetpack_Testimonial_Title_Control extends WP_Customize_Control {
- public function sanitize_content( $value ) {
+ public static function sanitize_content( $value ) {
if ( '' != $value )
$value = trim( convert_chars( wptexturize( $value ) ) );
@@ -239,10 +622,11 @@ function jetpack_testimonial_custom_control_classes() {
<textarea rows="5" style="width:100%;" <?php $this->link(); ?>><?php echo esc_textarea( $this->value() ); ?></textarea>
</label>
<?php
- }
+ }
- public function sanitize_content( $value ) {
+ public static function sanitize_content( $value ) {
if ( ! empty( $value ) )
+ /** This filter is already documented in core. wp-includes/post-template.php */
$value = apply_filters( 'the_content', $value );
$value = preg_replace( '@<div id="jp-post-flair"([^>]+)?>(.+)?</div>@is', '', $value ); // Strip WPCOM and Jetpack post flair if included in content
@@ -250,37 +634,10 @@ function jetpack_testimonial_custom_control_classes() {
return $value;
}
}
-
- /**
- * Need to extend WP_Customize_Image_Control to return attachment ID instead of url
- */
- class Jetpack_Testimonial_Image_Control extends WP_Customize_Image_Control {
- public $context = 'custom_image';
-
- public function __construct( $manager, $id, $args ) {
- $this->get_url = array( $this, 'get_img_url' );
- parent::__construct( $manager, $id, $args );
- }
-
- public function get_img_url( $attachment_id = 0 ) {
- if ( is_numeric( $attachment_id ) && wp_attachment_is_image( $attachment_id ) )
- list( $image, $x, $y ) = wp_get_attachment_image_src( $attachment_id );
-
- return ! empty( $image ) ? $image : $attachment_id;
- }
-
- public function attachment_guid_to_id( $value ) {
- if ( is_numeric( $value ) )
- return $value;
-
- $matches = get_posts( array( 'post_type' => 'attachment', 'guid' => $value ) );
-
- if ( empty( $matches ) )
- return false;
-
- return $matches[0]->ID; // this is the match we want
- }
- }
}
add_action( 'init', array( 'Jetpack_Testimonial', 'init' ) );
+
+// Check on plugin activation if theme supports CPT
+register_activation_hook( __FILE__, array( 'Jetpack_Testimonial', 'activation_post_type_support' ) );
+add_action( 'jetpack_activate_module_custom-content-types', array( 'Jetpack_Testimonial', 'activation_post_type_support' ) );
diff --git a/plugins/jetpack/modules/enhanced-distribution.php b/plugins/jetpack/modules/enhanced-distribution.php
index 42495201..5a447890 100644
--- a/plugins/jetpack/modules/enhanced-distribution.php
+++ b/plugins/jetpack/modules/enhanced-distribution.php
@@ -1,11 +1,12 @@
<?php
/**
* Module Name: Enhanced Distribution
- * Module Description: Share your public posts and comments to search engines and other services in real-time.
- * Sort Order: 100
+ * Module Description: Share your public posts and comments to search engines and other services.
+ * Sort Order: 5
* First Introduced: 1.2
* Requires Connection: Yes
* Auto Activate: Public
+ * Module Tags: Writing
*/
Jetpack_Sync::sync_posts( __FILE__ );
@@ -30,3 +31,23 @@ function jetpack_enhanced_distribution_before_activate_default_modules() {
add_action( 'jetpack_activate_module_enhanced-distribution', 'jetpack_enhanced_distribution_activate' );
add_action( 'jetpack_before_activate_default_modules', 'jetpack_enhanced_distribution_before_activate_default_modules' );
+
+/**
+ * If a request has ?get_freshly_pressed_data=true appended
+ * to the end, then let's provide the necessary data back via JSON.
+ */
+if ( isset( $_GET['get_freshly_pressed_data'] ) ) {
+ add_action( 'template_redirect', 'jetpack_get_freshly_pressed_data' );
+ function jetpack_get_freshly_pressed_data() {
+ if ( is_single() ) {
+ wp_send_json_success( array(
+ 'blog_id' => Jetpack_Options::get_option( 'id' ),
+ 'post_id' => get_the_ID(),
+ ) );
+ } else {
+ wp_send_json_error( array(
+ 'message' => 'Not Singular',
+ ) );
+ }
+ }
+}
diff --git a/plugins/jetpack/modules/featured-content/featured-content.php b/plugins/jetpack/modules/featured-content/featured-content.php
deleted file mode 100644
index ac394903..00000000
--- a/plugins/jetpack/modules/featured-content/featured-content.php
+++ /dev/null
@@ -1,456 +0,0 @@
-<?php
-
-/**
- * Featured Content.
- *
- * This module will allow users to define a subset of posts
- * to be displayed in a theme-designated featured content area.
- *
- * This feature will only be activated for themes that declare
- * that they support it. This can be done by adding code similar
- * to the following during the "after_setup_theme" action:
- *
- * add_theme_support( 'featured-content', array(
- * 'featured_content_filter' => 'mytheme_get_featured_content',
- * 'description' => 'Describe the featured content area.',
- * 'max_posts' => 20,
- * ) );
- *
- * For maximum compatibility with different methods of posting
- * users will designate a featured post tag to associate posts
- * to. Since this tag now has special meaning beyond that of a
- * normal tags, users will have the ability to hide it from the
- * front-end of their site.
- */
-class Featured_Content {
-
- /**
- * The maximum number of posts that a featured content
- * area can contain. We define a default value here but
- * themes can override this by defining a "max_posts"
- * entry in the second parameter passed in the call to
- * add_theme_support( 'featured-content' ).
- *
- * @see Featured_Content::init()
- */
- public static $max_posts = 15;
-
- /**
- * Instantiate.
- *
- * All custom functionality will be hooked into the "init" action.
- */
- public static function setup() {
- add_action( 'init', array( __class__, 'init' ), 30 );
- }
-
- /**
- * Conditionally Hook into WordPress.
- *
- * Themes must declare that they support this module by adding
- * add_theme_support( 'featured-content' ); during after_setup_theme.
- *
- * If no theme support is found there is no need to hook into
- * WordPress. We'll just return early instead.
- *
- * @uses Featured_Content::$max_posts
- */
- public static function init() {
- $theme_support = get_theme_support( 'featured-content' );
-
- // Return early if theme does not support featured content.
- if ( ! $theme_support )
- return;
-
- // An array of named arguments must be passed as
- // the second parameter of add_theme_support().
- if ( ! isset( $theme_support[0] ) )
- return;
-
- // Return early if "featured_content_filter" has not been defined.
- if ( ! isset( $theme_support[0]['featured_content_filter'] ) )
- return;
-
- $filter = $theme_support[0]['featured_content_filter'];
-
- // Themes can override the number of max posts.
- if ( isset( $theme_support[0]['max_posts'] ) )
- self::$max_posts = absint( $theme_support[0]['max_posts'] );
-
- add_filter( $filter, array( __CLASS__, 'get_featured_posts' ) );
- add_action( 'admin_init', array( __CLASS__, 'register_setting' ) );
- add_action( 'save_post', array( __CLASS__, 'delete_transient' ) );
- add_action( 'delete_post_tag', array( __CLASS__, 'delete_post_tag' ) );
- add_action( 'pre_get_posts', array( __CLASS__, 'pre_get_posts' ) );
-
- // Hide "featured" tag from the front-end.
- if ( self::get_setting( 'hide-tag' ) ) {
- add_filter( 'get_terms', array( __CLASS__, 'hide_featured_term' ), 10, 2 );
- add_filter( 'get_the_terms', array( __CLASS__, 'hide_the_featured_term' ), 10, 3 );
- }
- }
-
- /**
- * Get Featured Posts.
- *
- * This method is not intended to be called directly.
- * Theme developers should place a filter directly in
- * their theme and then pass its name as a value of the
- * "featured_content_filter" key in the array passed as
- * the $args parameter during the call to:
- * add_theme_support( 'featured-content', $args ).
- *
- * @uses Featured_Content::get_featured_post_ids()
- *
- * @return array|bool
- */
- public static function get_featured_posts() {
- $post_ids = self::get_featured_post_ids();
-
- // User has disabled Featured Content.
- if ( false === $post_ids )
- return false;
-
- // No need to query if there is are no featured posts.
- if ( empty( $post_ids ) )
- return array();
-
- $featured_posts = get_posts( array(
- 'include' => $post_ids,
- 'posts_per_page' => count( $post_ids )
- ) );
-
- return $featured_posts;
- }
-
- /**
- * Get Featured Post IDs.
- *
- * This function will return the an array containing the
- * post IDs of all featured posts.
- *
- * Sets the "featured_content_ids" transient.
- *
- * @return array|false Array of post IDs. false if user has disabled this feature.
- */
- public static function get_featured_post_ids() {
- $settings = self::get_setting();
-
- // Return false if the user has disabled this feature.
- $tag = $settings['tag-id'];
- if ( empty( $tag ) )
- return false;
-
- // Return array of cached results if they exist.
- $featured_ids = get_transient( 'featured_content_ids' );
- if ( ! empty( $featured_ids ) )
- return array_map( 'absint', (array) $featured_ids );
-
- // Query for featured posts.
- $featured = get_posts( array(
- 'numberposts' => $settings['quantity'],
- 'tax_query' => array(
- array(
- 'field' => 'term_id',
- 'taxonomy' => 'post_tag',
- 'terms' => $tag,
- ),
- ),
- ) );
-
- // Return empty array if no featured content exists.
- if ( ! $featured )
- return array();
-
- // Ensure correct format before save/return.
- $featured_ids = wp_list_pluck( (array) $featured, 'ID' );
- $featured_ids = array_map( 'absint', $featured_ids );
-
- set_transient( 'featured_content_ids', $featured_ids );
-
- return $featured_ids;
- }
-
- /**
- * Delete Transient.
- *
- * Hooks in the "save_post" action.
- * @see Featured_Content::validate_settings().
- */
- public static function delete_transient() {
- delete_transient( 'featured_content_ids' );
- }
-
- /**
- * Exclude featured posts from the blog query when the blog is the front-page.
- *
- * Filter the home page posts, and remove any featured post ID's from it. Hooked
- * onto the 'pre_get_posts' action, this changes the parameters of the query
- * before it gets any posts.
- *
- * @uses Featured_Content::get_featured_post_ids();
- * @param WP_Query $query
- * @return WP_Query Possibly modified WP_query
- */
- public static function pre_get_posts( $query = false ) {
-
- // Bail if not home, not a query, not main query.
- if ( ! is_home() || ! is_a( $query, 'WP_Query' ) || ! $query->is_main_query() )
- return;
-
- $page_on_front = get_option( 'page_on_front' );
-
- // Bail if the blog page is not the front page.
- if ( ! empty( $page_on_front ) )
- return;
-
- $featured = self::get_featured_post_ids();
-
- // Bail if no featured posts.
- if ( ! $featured )
- return;
-
- // We need to respect post ids already in the blacklist.
- $post__not_in = $query->get( 'post__not_in' );
-
- if ( ! empty( $post__not_in ) ) {
- $featured = array_merge( (array) $post__not_in, $featured );
- $featured = array_unique( $featured );
- }
-
- $query->set( 'post__not_in', $featured );
- }
-
- /**
- * Reset tag option when the saved tag is deleted.
- *
- * It's important to mention that the transient needs
- * to be deleted too. While it may not be obvious by
- * looking at the function alone, the transient is
- * deleted by Featured_Content::validate_settings().
- *
- * @param int $tag_id the term_id of the tag that has been deleted.
- *
- * Hooks in the "delete_post_tag" action.
- * @see Featured_Content::validate_settings().
- */
- public static function delete_post_tag( $tag_id ) {
- $settings = self::get_setting();
-
- if ( empty( $settings['tag-id'] ) )
- return;
-
- if ( $tag_id != $settings['tag-id'] )
- return;
-
- $settings['tag-id'] = 0;
- $settings = self::validate_settings( $settings );
- update_option( 'featured-content', $settings );
- }
-
- /**
- * Hide featured tag from displaying when global terms are queried from the front-end.
- *
- * Hooks into the "get_terms" filter.
- *
- * @param array $terms A list of term objects. This is the return value of get_terms().
- * @param array $taxonomies An array of taxonomy slugs.
- *
- * @uses Featured_Content::get_setting()
- */
- public static function hide_featured_term( $terms, $taxonomies ) {
-
- // This filter is only appropriate on the front-end.
- if ( is_admin() )
- return $terms;
-
- // We only want to hide the featured tag.
- if ( ! in_array( 'post_tag', $taxonomies ) )
- return $terms;
-
- // Bail if no terms were returned.
- if ( empty( $terms ) )
- return $terms;
-
- foreach( $terms as $order => $term ) {
- if ( self::get_setting( 'tag-id' ) == $term->term_id && 'post_tag' == $term->taxonomy )
- unset( $terms[$order] );
- }
-
- return $terms;
- }
-
- /**
- * Hide featured tag from displaying when terms associated with
- * a post object are queried from the front-end.
- *
- * Hooks into the "get_the_terms" filter.
- *
- * @param array $terms A list of term objects. This is the return value of get_the_terms().
- * @param int $id The ID field for the post object that terms are associated with.
- * @param array $taxonomy An array of taxonomy slugs.
- *
- * @uses Featured_Content::get_setting()
- */
- public static function hide_the_featured_term( $terms, $id, $taxonomy ) {
-
- // This filter is only appropriate on the front-end.
- if ( is_admin() )
- return $terms;
-
- // Make sure we are in the correct taxonomy.
- if ( ! 'post_tag' == $taxonomy )
- return $terms;
-
- // No terms? Return early!
- if ( empty( $terms ) )
- return $terms;
-
- foreach( $terms as $order => $term ) {
- if ( self::get_setting( 'tag-id' ) == $term->term_id )
- unset( $terms[$term->term_id] );
- }
-
- return $terms;
- }
-
- /**
- * Register custom setting on the Settings -> Reading screen.
- *
- * @uses Featured_Content::render_form()
- * @uses Featured_Content::validate_settings()
- */
- public static function register_setting() {
- add_settings_field( 'featured-content', __( 'Featured content', 'jetpack' ), array( __class__, 'render_form' ), 'reading' );
- register_setting( 'reading', 'featured-content', array( __class__, 'validate_settings' ) );
- }
-
- /**
- * Renders all form fields on the Settings -> Reading screen.
- */
- public static function render_form() {
- $settings = self::get_setting();
-
- $tag_name = '';
- if ( ! empty( $settings['tag-id'] ) ) {
- $tag = get_term( $settings['tag-id'], 'post_tag' );
- if ( ! is_wp_error( $tag ) && isset( $tag->name ) )
- $tag_name = $tag->name;
- }
- ?>
- <div id="featured-content-ui">
- <p>
- <label for="featured-content-tag-name"><?php echo _e( 'Tag name:', 'jetpack' ); ?></label>
- <input type="text" id="featured-content-tag-name" name="featured-content[tag-name]" value="<?php echo esc_attr( $tag_name ); ?>">
- <input type="hidden" id="featured-content-tag-id" name="featured-content[tag-id]" value="<?php echo esc_attr( $settings['tag-id'] ); ?>">
- </p>
- <p>
- <label for="featured-content-quantity"><?php _e( 'Number of posts:', 'jetpack' ); ?></label>
- <input class="small-text" type="number" step="1" min="1" max="<?php echo esc_attr( self::$max_posts ); ?>" id="featured-content-quantity" name="featured-content[quantity]" value="<?php echo esc_attr( $settings['quantity'] ); ?>">
- </p>
- <p>
- <input type="checkbox" id="featured-content-hide-tag" name="featured-content[hide-tag]" <?php checked( $settings['hide-tag'], 1 ); ?>">
- <label for="featured-content-hide-tag"><?php _e( 'Hide tag from displaying in post meta and tag clouds.', 'jetpack' ); ?></label>
- </p>
- </div>
- <?php
- }
-
- /**
- * Get Settings.
- *
- * Get all settings recognized by this module. This
- * function will return all settings whether or not
- * they have been stored in the database yet. This
- * ensures that all keys are available at all times.
- *
- * In the event that you only require one setting, you
- * may pass its name as the first parameter to the function
- * and only that value will be returned.
- *
- * @uses Featured_Content::self::sanitize_quantity()
- *
- * @param string $key The key of a recognized setting.
- * @return mixed Array of all settings by default. A single value if passed as first parameter.
- */
- public static function get_setting( $key = 'all' ) {
- $saved = (array) get_option( 'featured-content' );
-
- $defaults = array(
- 'hide-tag' => 1,
- 'quantity' => 5,
- 'tag-id' => 0,
- );
-
- $options = wp_parse_args( $saved, $defaults );
- $options = array_intersect_key( $options, $defaults );
- $options['quantity'] = self::sanitize_quantity( $options['quantity'] );
-
- if ( 'all' != $key ) {
- if ( isset( $options[$key] ) )
- return $options[$key];
- else
- return false;
- }
-
- return $options;
- }
-
- /**
- * Validate Settings.
- *
- * Make sure that all user supplied content is in an
- * expected format before saving to the database. This
- * function will also delete the transient set in
- * Featured_Content::get_featured_content().
- *
- * @uses Featured_Content::self::sanitize_quantity()
- * @uses Featured_Content::self::delete_transient()
- */
- function validate_settings( $input ) {
- $output = array();
-
- if ( isset( $input['tag-id'] ) )
- $output['tag-id'] = absint( $input['tag-id'] );
-
- if ( isset( $input['tag-name'] ) && ! empty( $input['tag-name'] ) ) {
- $new_tag = wp_create_tag( $input['tag-name'] );
- if ( ! is_wp_error( $new_tag ) && isset( $new_tag['term_id'] ) )
- $tag = get_term( $new_tag['term_id'], 'post_tag' );
- if ( isset( $tag->term_id ) )
- $output['tag-id'] = $tag->term_id;
- } else {
- unset( $output['tag-id'] );
- }
-
- if ( isset( $input['quantity'] ) )
- $output['quantity'] = self::sanitize_quantity( $input['quantity'] );
-
- $output['hide-tag'] = ( isset( $input['hide-tag'] ) ) ? 1 : 0;
-
- self::delete_transient();
-
- return $output;
- }
-
- /**
- * Sanitize Quantity
- *
- * @param int $input The value to sanitize.
- * @output int A number between 1 and FeaturedContent::$max_posts.
- *
- * @uses Featured_Content::$max_posts
- */
- public static function sanitize_quantity( $input ) {
- $quantity = absint( $input );
-
- if ( $quantity > self::$max_posts )
- $quantity = self::$max_posts;
- else if ( 1 > $quantity )
- $quantity = 1;
-
- return $quantity;
- }
-}
-
-Featured_Content::setup();
diff --git a/plugins/jetpack/modules/gplus-authorship.php b/plugins/jetpack/modules/gplus-authorship.php
index aae851b7..88c13090 100644
--- a/plugins/jetpack/modules/gplus-authorship.php
+++ b/plugins/jetpack/modules/gplus-authorship.php
@@ -1,206 +1,6 @@
<?php
/**
-* Module Name: Google+ Profile
-* Module Description: Show a link to your Google+ in the sharing area of your posts and add your blog URL to your Google+ profile.
-* Sort Order: 10
-* First Introduced: 2.5
-* Requires Connection: Yes
-* Auto Activate: Yes
-*/
-function jetpack_init_gplus_authorship() {
- new GPlus_Authorship;
-}
-add_action( 'init', 'jetpack_init_gplus_authorship' );
-
-class GPlus_Authorship {
-
- function __construct() {
- $this->in_jetpack = ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ? false : true;
- if ( $this->in_jetpack ) {
- require "gplus-authorship/admin/ui.php";
- $gplus_admin = new GPlus_Authorship_Admin;
- add_action( 'save_post', array( 'GPlus_Authorship_Admin', 'save_post_meta' ) );
- add_action( 'wp_ajax_save_gplus_profile_data', array( $this, 'save_profile_data' ) );
- add_filter( 'the_content', array( $this, 'post_output_wrapper' ), 22, 1 );
- } else {
- add_filter( 'post_flair', array( $this, 'post_output_wrapper' ), 22 );
- }
- add_action( 'wp_head', array( $this, 'link_tag_styles_and_scripts' ) );
- add_filter( 'the_author', array( $this, 'overwrite_the_author' ) );
- add_filter( 'the_content', array( $this, 'overwrite_rel_attrs' ) );
- }
-
- function show_on_this_post() {
- global $post;
- $show = apply_filters( 'gplus_authorship_show', true, $post );
- $author = $this->information( $post->post_author );
- if ( empty( $author ) )
- $show = false;
- $meta = get_post_meta( $post->ID, 'gplus_authorship_disabled', true );
- if ( isset( $meta ) && true == $meta )
- $show = false;
- return $show;
- }
-
- function information( $author ) {
- $authors = get_option( 'gplus_authors', array() );
- return ( empty( $authors[ $author ] ) ? array() : $authors[ $author ] );
- }
-
- /**
- * Both overwrite_rel_attrs and rel_callback remove 'author' from the rel attribute of a link if it is found
- * and if the post is being viewed on a single page, with G+ authorship enabled.
- * based on prior art from privatize_link in wp-content/mu-plugins/private-blog.php
- */
- function overwrite_rel_attrs( $content ) {
- if ( !is_single() ) // don't bother unless we are on a page where the G+ authorship link is actually being displayed
- return $content;
- if ( !$this->show_on_this_post() ) // G+ isn't enabled
- return $content;
- return preg_replace_callback( '#<a\s+[^>]+>#i', array( $this, 'rel_callback' ), $content );
- }
-
- function rel_callback( $link ) {
- $link = $link[0]; // preg replace returns as array
-
- $dom = new DOMDocument;
- $link = mb_convert_encoding( $link, 'HTML-ENTITIES', 'UTF-8' );
- @$dom->loadHTML( "<html><body>$link</a></body></html>" );
- $link_node = false;
- foreach ( $dom->childNodes as $child ) {
- if ( XML_ELEMENT_NODE === $child->nodeType && 'html' === strtolower( $child->tagName ) ) {
- $link_node = $child->firstChild->firstChild;
- break;
- }
- }
-
- // Don't bother if it's not actually a link (pointing to another document) or if there is no rel attribute.
- if ( !$link_node )
- return $link;
- if ( !$link_node->hasAttribute( 'href' ) )
- return $link;
- if ( !$link_node->hasAttribute( 'rel' ) )
- return $link;
-
- $rels = explode( ' ', $link_node->getAttribute( 'rel' ) );
-
- // delete 'author' from the list
- if ( ( $key = array_search( 'author', $rels ) ) !== false ) {
- unset( $rels[$key] );
- }
-
- // if there was more then one part of the attribute, set the new value, otherwise just get rid of the attribute all together
- if ( count( $rels ) > 0 )
- $link_node->setAttribute( 'rel', join( ' ', $rels ) );
- else
- $link_node->removeAttribute( 'rel' );
-
- $link = $dom->saveXML( $link_node );
- $link = rtrim( $link, '/>' ) . '>';
- return $link;
- }
-
- /**
- * Jetpack Only
- */
- function save_profile_data() {
- global $current_user;
- check_ajax_referer( 'gplus-connect', 'state' );
- if ( !is_numeric( $_POST['id'] ) )
- return;
- $connections = get_option( 'gplus_authors', array() );
- $connections[ $current_user->ID ]['name'] = $_POST['name'];
- $connections[ $current_user->ID ]['id'] = $_POST['id'];
- $connections[ $current_user->ID ]['url'] = esc_url_raw( $_POST['url'] );
- $connections[ $current_user->ID ]['profile_image'] = esc_url_raw( $_POST['profile_image'] );
- update_option( 'gplus_authors', $connections );
- }
-
- /**
- * Google+ insits we don't have two different bylines..
- * so we will display their G+ username in the byline here too
- */
- function overwrite_the_author( $author_name ) {
- global $post;
-
- if ( !$this->show_on_this_post() )
- return $author_name;
-
- $author = $this->information( $post->post_author );
- return esc_html( $author['name'] );
- }
-
- function byline( $post ) {
- $author = $this->information( $post->post_author );
- $image = '<img src="' . esc_url( $author['profile_image'] ) . '?sz=40" alt="" width="20" height="20" align="absmiddle" /> ';
- $byline = sprintf( '<a href="%1$s">%2$s</a><a rel="author" href="%1$s" class="gplus-profile">%3$s</a>', esc_url( $author['url'] ), $image, esc_html( $author['name'] ) );
- return apply_filters( 'gplus_authorship_byline', $byline, $post );
- }
-
- function link_tag_styles_and_scripts() {
- if ( !is_single() )
- return;
- if ( get_post_type() != 'post' )
- return;
- if ( !$this->show_on_this_post() )
- return;
-
- global $post;
- $author = $this->information( $post->post_author );
- echo '<link rel="author" href="'. esc_url( $author['url'] ) .'" title="' . esc_attr( $author['name'] ) . ' ' . __( 'on Google+', 'jetpack' ) .'" /> ' . "\n";
- if ( $this->in_jetpack )
- $css = plugins_url( 'gplus-authorship/style.css', __FILE__ );
- else
- $css = plugins_url( 'gplus/style.css', __FILE__ );
- wp_enqueue_style( 'gplus', $css );
- wp_enqueue_script( 'plusone', '//apis.google.com/js/plusone.js' );
- }
-
- function follow_button( $post ) {
- $author = $this->information( $post->post_author );
- return '<span class="g-follow-wrapper"><span class="g-follow" data-href="' . esc_url( $author['url'] ) . '" data-rel="author" data-height="15"></span></span>';
- }
-
- function post_output_wrapper( $text = '', $echo = false ) {
- global $post, $wp_current_filter;
-
- if ( !is_single() )
- return $text;
- if ( get_post_type() != 'post' )
- return $text;
- $author = $this->information( $post->post_author );
- if ( empty( $author ) )
- return $text;
-
- // Don't allow G+ to be added to the_content more than once (prevent infinite loops)
- $done = false;
- foreach ( $wp_current_filter as $filter ) {
- if ( 'the_content' == $filter ) {
- if ( $done )
- return $text;
- else
- $done = true;
- }
- }
-
- if ( !$this->show_on_this_post())
- return $text;
-
- $output = '';
- $output .= '<div class="sharedaddy sd-block sd-social sd-gplus">';
- $output .= '<h3 class="sd-title">' . __( 'Google+', 'jetpack' ) . '</h3>';
- $output .= '<div class="sd-content">';
- $output .= $this->byline( $post );
- $output .= $this->follow_button( $post );
- $output .= '</div>';
- $output .= '</div>';
-
- if ( $echo )
- echo $text . $output;
- else
- return $text . $output;
- }
-
-}
-
-?>
+ * Deprecated. No longer needed.
+ *
+ * @package Jetpack
+ */
diff --git a/plugins/jetpack/modules/gplus-authorship/admin/connect.js b/plugins/jetpack/modules/gplus-authorship/admin/connect.js
deleted file mode 100644
index 72798ba2..00000000
--- a/plugins/jetpack/modules/gplus-authorship/admin/connect.js
+++ /dev/null
@@ -1,42 +0,0 @@
-function googlePlusSignInCallback( authResult ) {
- var blogID = jQuery( '#current-blog-id' ).attr( 'data-value' );
- if ( authResult['code'] ) {
- jQuery.ajax( {
- type: 'POST',
- url: 'index.php?page=gplus-authorship&blog_id=' + blogID + '&store_token=' + authResult['code'] + '&state=' + state,
- contentType: 'application/json; charset=utf-8',
- processData: false,
-
- success: function(result) {
- if ( 'undefined' == typeof result.error ) {
- googlePlusSendToParent( { success: true } );
- } else {
- googlePlusSendToParent( { error: result.error } );
- }
- },
-
- error: function( result ) {
- if ( 'undefined' != typeof result.error ) {
- googlePlusSendToParent( { error: result.error } );
- } else {
- googlePlusSendToParent( { error: 'unknown' } );
- }
- }
- } );
- } else if ( authResult['error'] ) {
- googlePlusSendToParent( { error: authResult['error'] } );
- } else {
- googlePlusSendToParent( { error: 'unknown' } );
- }
-}
-
- function googlePlusSendToParent( data ) {
- if ( 'immediate_failed' == data.error )
- return;
- pm( {
- target: window.parent,
- type: 'googlePlusSignInMessage',
- data: data,
- origin: '*'
- } );
-} \ No newline at end of file
diff --git a/plugins/jetpack/modules/gplus-authorship/admin/listener.js b/plugins/jetpack/modules/gplus-authorship/admin/listener.js
deleted file mode 100644
index 01005a2b..00000000
--- a/plugins/jetpack/modules/gplus-authorship/admin/listener.js
+++ /dev/null
@@ -1,57 +0,0 @@
-jQuery( function( $ ) {
-
- pm.bind( 'googlePlusSignInMessage', function( message ) {
- if ( 'undefined' != typeof message.error)
- GooglePlusMessageHandler.error( message.error );
- else if ( 'undefined' != typeof message.success && 'undefined' != typeof message.result )
- GooglePlusMessageHandler.success( message.result );
- else
- GooglePlusMessageHandler.unknownMessage( message );
- } );
-
- var GooglePlusMessageHandler = {
-
- outputContainer: '#result',
-
- success: function( result ) {
- $.post( './admin-ajax.php',
- {
- action: 'save_gplus_profile_data',
- name: result.name,
- url: result.url,
- profile_image: result.profile_image,
- id: result.id,
- state: result.state
- }, function() {
- $( GooglePlusMessageHandler.outputContainer ).text( GPlusL10n.connected );
- window.location.href = 'options-general.php?page=sharing&r=' + Math.round( Math.random()*100000 ) + '#gplus';
- }
- );
- },
-
- error: function( error ) {
- if ( 'unknown' == error ) {
- $( GooglePlusMessageHandler.outputContainer ).text( GPlusL10n.unknownError );
- } else if ( 'access_denied' == error ) {
- $( GooglePlusMessageHandler.outputContainer ).text( GPlusL10n.accessDenied );
- } else {
- $( GooglePlusMessageHandler.outputContainer ).text( error );
- }
- },
-
- unknownMessage: function( message ) {
- console.log( 'DEBUG: An unknown message was passed via postMessage:' );
- console.log( message );
- GooglePlusMessageHandler.error( 'unknown' );
- },
-
- };
-
- $( '#disconnect-gplus' ).click( function() {
- var ays = confirm( 'Are you sure you want to disconnect your Google+ profile? If you have any Publicize accounts connected to this profile they will also be disconnected.' );
- if ( ! ays ) {
- return false;
- }
- } );
-
-} );
diff --git a/plugins/jetpack/modules/gplus-authorship/admin/style.css b/plugins/jetpack/modules/gplus-authorship/admin/style.css
deleted file mode 100644
index 04a16a37..00000000
--- a/plugins/jetpack/modules/gplus-authorship/admin/style.css
+++ /dev/null
@@ -1,51 +0,0 @@
-#gplus-connection-details {
- margin-top: 10px;
- padding: 15px;
- background: #fff;
- border: none !important;
- -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.13);
- box-shadow: 0 1px 3px rgba(0,0,0,0.13);
- width: 400px;
-}
-
-#gplus-connection-details p {
- padding: 0;
-}
-
-#gplus-connection-details img {
- float: left;
- margin-right: .5em;
-}
-
-.gplus-clear {
- clear: both;
-}
-
-.gplus-connected {
- float: right;
- font-weight: bold;
- color: #78AB46;
-}
-
-.gplus-disconnect {
- float:right;
- position: relative;
- top: 13px;
- right: -5px;
-}
-
-.gplus-disconnect a {
- color: #c21c19;
- font-size: 110%;
-}
-
-.gplus-post-meta-box img {
- vertical-align: middle;
- margin-bottom: 5px;
- height: 20px;
- width: 20px;
-}
-
-.gplus-sharing-screen {
- margin: 10px 0 45px 0;
-} \ No newline at end of file
diff --git a/plugins/jetpack/modules/gplus-authorship/admin/ui.php b/plugins/jetpack/modules/gplus-authorship/admin/ui.php
deleted file mode 100644
index ad05eb62..00000000
--- a/plugins/jetpack/modules/gplus-authorship/admin/ui.php
+++ /dev/null
@@ -1,270 +0,0 @@
-<?php
-function jetpack_init_gplus_authorship_admin() {
- $gplus_admin = new GPlus_Authorship_Admin;
- add_action( 'save_post', array( 'GPlus_Authorship_Admin', 'save_post_meta' ) );
-}
-add_action( 'init', 'jetpack_init_gplus_authorship_admin' );
-
-class GPlus_Authorship_Admin {
-
- public function __construct() {
- $this->in_jetpack = ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ? false : true;
-
- if ( $this->in_jetpack ) {
- $active = Jetpack::get_active_modules();
- if ( ! in_array( 'sharedaddy', $active ) && ! in_array( 'publicize', $active ) && ! in_array( 'likes', $active ) ) {
- add_action( 'admin_menu', array( $this, 'sharing_menu' ) ); // we don't have a sharing page yet
- }
-
- add_action( 'jetpack_activate_module_likes', array( $this, 'module_toggle' ) );
- add_action( 'jetpack_deactivate_module_likes', array( $this, 'module_toggle' ) );
-
- Jetpack::enable_module_configurable( __FILE__ );
- Jetpack::module_configuration_load( __FILE__, array( $this, 'configuration_redirect' ) );
- }
-
- // The visible UI elements for the user
- add_action( 'load-settings_page_sharing', array( $this, 'load_management_script_assets' ) );
- add_action( 'pre_admin_screen_sharing', array( $this, 'connection_screen' ), 15 );
- add_action( 'admin_init', array( $this, 'add_meta_box' ) );
- add_action( 'do_meta_boxes', array( $this, 'should_we_show_the_meta_box' ) );
-
- if ( $this->in_jetpack )
- add_action( 'pre_admin_screen_sharing', array( $this, 'jetpack_disconnect' ), 10 );
- }
-
- function module_toggle() {
- $jetpack = Jetpack::init();
- $jetpack->sync->register( 'noop' );
- }
-
- /**
- * Redirects to the likes section of the sharing page.
- */
- function configuration_redirect() {
- wp_safe_redirect( admin_url( 'options-general.php?page=sharing#gplus' ) );
- die();
- }
-
- /**
- * Adds the 'sharing' menu to the settings menu.
- * Only ran if sharedaddy, publicize, and likes are not already active.
- */
- function sharing_menu() {
- add_submenu_page( 'options-general.php', esc_html__( 'Sharing Settings', 'jetpack' ), esc_html__( 'Sharing', 'jetpack' ), 'manage_options', 'sharing', array( $this, 'sharing_page' ) );
- }
-
- /**
- * Provides a sharing page with the sharing_global_options hook
- * so we can display the setting.
- * Only ran if sharedaddy and publicize are not already active.
- */
- function sharing_page() { ?>
- <div class="wrap">
- <div class="icon32" id="icon-options-general"><br /></div>
- <h2><?php esc_html_e( 'Sharing Settings', 'jetpack' ); ?></h2>
- <?php do_action( 'pre_admin_screen_sharing' ) ?>
- </div><?php
- }
-
-
- public function load_management_script_assets() {
- if ( $this->in_jetpack )
- $pm = plugins_url( '_inc/postmessage.js', dirname( dirname ( dirname(__FILE__) ) ) );
- else
- $pm = '/wp-content/js/postmessage.js';
- wp_enqueue_script( 'postmessage', $pm, array( 'jquery' ) );
- wp_enqueue_script( 'gplus-listener', plugins_url( 'listener.js', __FILE__ ), array( 'jquery', 'postmessage' ) );
- wp_localize_script( 'gplus-listener', 'GPlusL10n', array(
- 'connected' => __( 'Your Google+ account has been connected.', 'jetpack' ),
- 'unknownError' => __( 'There was a problem connecting your Google+ account. Please try again.', 'jetpack' ),
- 'accessDenied' => __( "You must click 'Accept' in the Google+ dialog to connect your account.", 'jetpack' ),
- ) );
- wp_enqueue_style( 'gplus', plugins_url( 'style.css', __FILE__ ) );
- }
-
- public function jetpack_disconnect() {
- if ( empty( $_GET['disconnect'] ) || 'gplus' != $_GET['disconnect'] )
- return;
-
- global $current_user;
- // security check - did we actually want to disconnect?
- $nonce = $_GET['_wpnonce'];
- if ( !wp_verify_nonce( $nonce, 'disconnect-gplus' ) )
- return;
-
- $connections = get_option( 'gplus_authors', array() );
-
- Jetpack::load_xml_rpc_client();
- $xml = new Jetpack_IXR_Client();
- $xml->query( 'jetpack.disconnectGooglePlus', $connections[ $current_user->ID ]['id'] );
-
- if ( !$xml->isError() ) {
- unset( $connections[ $current_user->ID ] );
- update_option( 'gplus_authors', $connections );
- } else {
- // @todo error
- }
- }
-
- public function connection_screen() { ?>
- <div id="gplus"></div>
- <div class="gplus-sharing-screen">
- <h3><?php _e( 'Google+ Profile', 'jetpack' ) ?></h3><?php
- $this->disconnected_message();
- if ( GPlus_Authorship_Utils::is_current_user_connected() ) {
- $this->connected_message();
- } else {
- $this->connect_button();
- ?><div id="result"></div><?php // where output from Javascript (success/error messages) are placed
- } ?>
- </div><?php
- }
-
- private function disconnect_button() { ?>
- <a href="<?php echo wp_nonce_url( 'options-general.php?page=sharing&disconnect=gplus', 'disconnect-gplus' ); ?>" id="disconnect-gplus" class="pub-disconnect-button" title="<?php _e( 'Disconnect', 'jetpack'); ?>">&times;</a><?php
- }
-
- private function connect_button() { ?>
- <?php _e( 'Connect your WordPress account to Google+ to add this blog to your Google+ profile and improve the visibility of your blog posts on Google.', 'jetpack' ) ?></p>
- <iframe src="//dashboard.wordpress.com/wp-admin/options-general.php?page=gplus-authorship&amp;gplus=frame&amp;blog_id=<?php echo intval( GPlus_Authorship_Utils::get_blog_id() ); ?>&amp;jpstate=<?php echo wp_create_nonce( 'gplus-connect' ); ?>" width="400" height="45" style="overflow:none;" scrolling="no"></iframe>
- <p><small><a href="http://support.wordpress.com/google-plus-profile/" target="_blank"><?php esc_html_e( 'Need help?', 'jetpack' ); ?></a></small></p><?php
- }
-
- private function disconnected_message() {
- global $publicize;
- if ( !empty( $_GET['disconnect'] ) && 'gplus' == $_GET['disconnect'] ) {
- if ( isset( $publicize->disconnected_from_authorship ) && $publicize->disconnected_from_authorship ) { ?>
- <div class="updated"><p><?php echo sprintf( __( "Your Google+ profile and WordPress.com accounts have been disconnected, including your Publicize connections. If you no longer wish to be associated with this blog on Google we recommend that you also remove the blog URL from your <a href='%s' target='_blank'>Google+ profile</a>.", 'jetpack' ), 'http://plus.google.com/me/about/edit/co' ); ?></p></div><?php
- } else { ?>
- <div class="updated"><p><?php echo sprintf( __( "Your Google+ profile and WordPress.com accounts have been disconnected. If you no longer wish to be associated with this blog on Google we recommend that you also remove the blog URL from your <a href='%s' target='_blank'>Google+ profile</a>.", 'jetpack' ), 'http://plus.google.com/me/about/edit/co' ); ?></p></div><?php
- }
- }
- }
-
- private function connected_message() {
- $users_gplus_info = GPlus_Authorship_Utils::get_current_users_gplus_info(); ?>
- <p><?php _e( 'Your Google+ profile name and URL will be displayed in the sharing area of your posts.', 'jetpack' ); ?></p>
- <div id="gplus-connection-details">
- <div class="gplus-disconnect">
- <?php $this->disconnect_button(); ?>
- </div>
- <img src="<?php echo esc_url( $users_gplus_info['profile_image'] ); ?>?sz=50" alt="" />
- <p>
- <span class="gplus-user"><a href="<?php echo esc_url( $users_gplus_info['url'] ); ?>"><?php echo esc_html( $users_gplus_info['name'] ); ?></a></span>
- <span class="gplus-connected"><?php esc_html_e( 'Connected', 'jetpack' ); ?></span>
- </p>
- <div class="gplus-clear"></div>
- </div><?php
- }
-
- function add_meta_box() {
- $gplus_connections = GPlus_Authorship_Utils::get_all_gplus_authors();
- if ( empty( $gplus_connections ) || count( $gplus_connections ) < 1 )
- return;
- add_meta_box( 'gplus_authorship', __( 'Google+', 'jetpack' ), array( $this, 'post_screen_meta_box' ), 'post', 'advanced', 'high' );
- }
-
- function should_we_show_the_meta_box( $page ) {
- if ( 'post' != $page )
- return;
-
- global $post;
- $gplus_connections = GPlus_Authorship_Utils::get_all_gplus_authors();
- if ( empty( $gplus_connections ) || count( $gplus_connections ) < 1 )
- remove_meta_box( 'gplus_authorship', 'post', 'advanced' );
- $users_gplus_info = GPlus_Authorship_Utils::get_post_authors_gplus_info( $post );
- if ( empty( $users_gplus_info ) )
- remove_meta_box( 'gplus_authorship', 'post', 'advanced' );
- }
-
- function post_screen_meta_box( $post = '' ) {
- wp_enqueue_style( 'gplus', plugins_url( 'style.css', __FILE__ ) );
- $enabled_on_post = true;
- $meta = get_post_meta( $post->ID, 'gplus_authorship_disabled', true );
- if ( isset( $meta ) && true == $meta )
- $enabled_on_post = false;
- $users_gplus_info = GPlus_Authorship_Utils::get_post_authors_gplus_info( $post );?>
- <p>
- <label for="gplus_authorship_enable">
- <input type="checkbox" name="gplus_authorship" id="gplus_authorship_enable" value="1" <?php checked( $enabled_on_post ); ?>>
- <?php esc_html_e( 'Show Google+ infomation with this post', 'jetpack' ); ?> <br />
- <?php if ( !empty( $users_gplus_info ) ) { ?>
- <div class="gplus-post-meta-box">
- <img src="<?php echo esc_url( $users_gplus_info['profile_image'] ); ?>?sz=25" alt="" />
- <em><?php echo __( sprintf( 'Profile: <a href="%s" target="_blank">%s</a>', esc_url( $users_gplus_info['url'] ), esc_html( $users_gplus_info['name'] ) ), 'jetpack' ); ?></em>
- </div>
- <?php } ?>
- </label>
- </p><?php
- }
-
- static function save_post_meta( $post_id ) {
- if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE )
- return $post_id;
- global $post;
- $authors = get_option( 'gplus_authors', array() );
- if ( empty( $authors ) || empty( $post ) )
- return $post_id;
- if ( empty( $authors[ $post->post_author ] ) )
- return $post_id;
- if ( isset( $_POST['post_type'] ) && ( 'post' == $_POST['post_type'] ) ) {
- if ( empty( $_POST['gplus_authorship'] ) ) {
- update_post_meta( $post_id, 'gplus_authorship_disabled', 1 );
- } else {
- delete_post_meta( $post_id, 'gplus_authorship_disabled' );
- }
- }
-
- return $post_id;
- }
-
-}
-
-class GPlus_Authorship_Utils {
-
- static function get_blog_id() {
- if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
- $blog_id = get_current_blog_id();
- } else {
- $jetpack = Jetpack::init();
- $blog_id = $jetpack->get_option( 'id' );
- }
- return $blog_id;
- }
-
- static function can_current_user_connect( $_blog_id = false ) {
- global $current_user;
- if ( !$_blog_id )
- $_blog_id = GPlus_Authorship_Utils::get_blog_id();
- if ( is_user_member_of_blog( $current_user->ID, $_blog_id ) || is_super_admin( $current_user->ID ) )
- return true;
- return false;
- }
-
- static function is_current_user_connected( $_blog_id = false ) {
- if ( $_blog_id )
- switch_to_blog( $_blog_id );
- $gplus = self::get_current_users_gplus_info();
- if ( $_blog_id )
- restore_current_blog();
- return (bool) !empty( $gplus );
- }
-
- static function get_all_gplus_authors() {
- return get_option( 'gplus_authors', array() );
- }
-
- static function get_current_users_gplus_info() {
- global $current_user;
- $all = self::get_all_gplus_authors();
- return ( empty( $all[ $current_user->ID ] ) ? array() : $all[ $current_user->ID ] );
- }
-
- static function get_post_authors_gplus_info( $post ) {
- $id = $post->post_author;
- $all = self::get_all_gplus_authors();
- return ( empty( $all[ $id ] ) ? array() : $all[ $id ] );
- }
-
-}
diff --git a/plugins/jetpack/modules/gplus-authorship/style.css b/plugins/jetpack/modules/gplus-authorship/style.css
deleted file mode 100644
index 3fada404..00000000
--- a/plugins/jetpack/modules/gplus-authorship/style.css
+++ /dev/null
@@ -1,17 +0,0 @@
-.g-follow-wrapper {
- display: inline-block;
- position: relative;
- top: 3px;
-}
-
-.sd-gplus img {
- vertical-align: middle;
- margin-bottom: 5px;
- height: 20px;
- width: 20px;
- display: inline;
-}
-
-.gplus-profile {
- margin-right: 10px;
-} \ No newline at end of file
diff --git a/plugins/jetpack/modules/gravatar-hovercards.php b/plugins/jetpack/modules/gravatar-hovercards.php
index 1c111fc7..b3df9839 100644
--- a/plugins/jetpack/modules/gravatar-hovercards.php
+++ b/plugins/jetpack/modules/gravatar-hovercards.php
@@ -1,11 +1,15 @@
<?php
/**
* Module Name: Gravatar Hovercards
- * Module Description: Show a pop-up business card of your users' gravatar profiles in comments.
- * Sort Order: 8
+ * Module Description: Enable pop-up business cards over commenters’ Gravatars.
+ * Jumpstart Description: let commenters link their profiles to their Gravatar accounts, making it easy for your visitors to learn more about your community.
+ * Sort Order: 11
+ * Recommendation Order: 13
* First Introduced: 1.1
* Requires Connection: No
* Auto Activate: Yes
+ * Module Tags: Social, Appearance
+ * Feature: Jumpstart
*/
define( 'GROFILES__CACHE_BUSTER', gmdate( 'YM' ) . 'aa' ); // Break CDN cache, increment when gravatar.com/js/gprofiles.js changes
@@ -26,7 +30,7 @@ function grofiles_hovercards_init() {
}
function gravatar_hovercards_configuration_load() {
- wp_safe_redirect( admin_url( 'options-discussion.php#gravatar-hovercard-options' ) );
+ wp_safe_redirect( admin_url( 'options-discussion.php#show_avatars' ) );
exit;
}
@@ -170,8 +174,15 @@ function grofiles_get_avatar( $avatar, $author ) {
function grofiles_attach_cards() {
global $blog_id;
- if ( 'disabled' == get_option( 'gravatar_disable_hovercards' ) )
+ // Is the display of Avatars disabled?
+ if ( ! get_option( 'show_avatars' ) ) {
return;
+ }
+
+ // Is the display of Gravatar Hovercards disabled?
+ if ( 'disabled' == get_option( 'gravatar_disable_hovercards' ) ) {
+ return;
+ }
wp_enqueue_script( 'grofiles-cards', ( is_ssl() ? 'https://secure' : 'http://s' ) . '.gravatar.com/js/gprofiles.js', array( 'jquery' ), GROFILES__CACHE_BUSTER, true );
wp_enqueue_script( 'wpgroho', plugins_url( 'wpgroho.js', __FILE__ ), array( 'grofiles-cards' ), false, true );
diff --git a/plugins/jetpack/modules/infinite-scroll.php b/plugins/jetpack/modules/infinite-scroll.php
index 51a98988..b4f09260 100644
--- a/plugins/jetpack/modules/infinite-scroll.php
+++ b/plugins/jetpack/modules/infinite-scroll.php
@@ -1,11 +1,12 @@
<?php
/**
* Module Name: Infinite Scroll
- * Module Description: Automatically pull the next set of posts into view when the reader approaches the bottom of the page.
- * Sort Order: 14
+ * Module Description: Add support for infinite scroll to your theme.
+ * Sort Order: 26
* First Introduced: 2.0
* Requires Connection: No
* Auto Activate: No
+ * Module Tags: Appearance
*/
/**
@@ -147,7 +148,7 @@ class Jetpack_Infinite_Scroll_Extras {
// Abort if Stats module isn't active
if ( in_array( 'stats', Jetpack::get_active_modules() ) ) {
// Abort if user is logged in but logged-in users shouldn't be tracked.
- if ( is_user_logged_in() ) {
+ if ( is_user_logged_in() && function_exists( 'stats_get_options' ) ) {
$stats_options = stats_get_options();
$track_loggedin_users = isset( $stats_options['reg_users'] ) ? (bool) $stats_options['reg_users'] : false;
@@ -173,16 +174,53 @@ class Jetpack_Infinite_Scroll_Extras {
}
/**
- * Load VideoPress scripts if plugin is active.
+ * Always load certain scripts when IS is enabled, as they can't be loaded after `document.ready` fires, meaning they can't leverage IS's script loader.
*
* @global $videopress
+ * @uses do_action()
+ * @uses apply_filters()
+ * @uses wp_enqueue_style()
+ * @uses wp_enqueue_script()
* @action wp_enqueue_scripts
* @return null
*/
public function action_wp_enqueue_scripts() {
+ // Do not load scripts and styles on singular pages and static pages
+ $load_scripts_and_styles = ! ( is_singular() || is_page() );
+ if ( ! apply_filters( 'jetpack_infinite_scroll_load_scripts_and_styles', $load_scripts_and_styles ) )
+ return;
+
+ // VideoPress stand-alone plugin
global $videopress;
- if ( ! empty( $videopress ) && The_Neverending_Home_Page::archive_supports_infinity() && is_a( $videopress, 'VideoPress' ) && method_exists( $videopress, 'enqueue_scripts' ) )
+ if ( ! empty( $videopress ) && The_Neverending_Home_Page::archive_supports_infinity() && is_a( $videopress, 'VideoPress' ) && method_exists( $videopress, 'enqueue_scripts' ) ) {
$videopress->enqueue_scripts();
+ }
+
+ // VideoPress Jetpack module
+ if ( Jetpack::is_module_active( 'videopress' ) ) {
+ Jetpack_VideoPress_Shortcode::enqueue_scripts();
+ }
+
+ // Fire the post_gallery action early so Carousel scripts are present.
+ if ( Jetpack::is_module_active( 'carousel' ) ) {
+ do_action( 'post_gallery', '', '' );
+ }
+
+ // Always enqueue Tiled Gallery scripts when both IS and Tiled Galleries are enabled
+ if ( Jetpack::is_module_active( 'tiled-gallery' ) ) {
+ Jetpack_Tiled_Gallery::default_scripts_and_styles();
+ }
+
+ // Core's Audio and Video Shortcodes
+ if ( 'mediaelement' === apply_filters( 'wp_audio_shortcode_library', 'mediaelement' ) ) {
+ wp_enqueue_style( 'wp-mediaelement' );
+ wp_enqueue_script( 'wp-mediaelement' );
+ }
+
+ if ( 'mediaelement' === apply_filters( 'wp_video_shortcode_library', 'mediaelement' ) ) {
+ wp_enqueue_style( 'wp-mediaelement' );
+ wp_enqueue_script( 'wp-mediaelement' );
+ }
}
}
Jetpack_Infinite_Scroll_Extras::instance();
@@ -195,4 +233,4 @@ require_once( dirname( __FILE__ ) . "/infinite-scroll/infinity.php" );
/**
* Remove the IS annotation loading function bundled with the IS plugin in favor of the Jetpack-specific version in Jetpack_Infinite_Scroll_Extras::action_after_setup_theme();
*/
-remove_action( 'after_setup_theme', 'the_neverending_home_page_theme_support', 5 ); \ No newline at end of file
+remove_action( 'after_setup_theme', 'the_neverending_home_page_theme_support', 5 );
diff --git a/plugins/jetpack/modules/infinite-scroll/infinity.css b/plugins/jetpack/modules/infinite-scroll/infinity.css
index 0a09f245..4c84e294 100644
--- a/plugins/jetpack/modules/infinite-scroll/infinity.css
+++ b/plugins/jetpack/modules/infinite-scroll/infinity.css
@@ -19,6 +19,36 @@
}
/**
+ * Using a highly-specific rule to make sure that all button styles
+ * will be reset
+ */
+#infinite-handle span button,
+#infinite-handle span button:hover,
+#infinite-handle span button:focus {
+ display: inline;
+ position: static;
+ padding: 0;
+ margin: 0;
+ border: none;
+ line-height: inherit;
+ background: transparent;
+ color: inherit;
+ cursor: inherit;
+ font-size: inherit;
+ font-weight: inherit;
+ font-family: inherit;
+}
+
+/**
+ * This is used to avoid unnecessary inner button spacing in Firefox
+ */
+#infinite-handle span button::-moz-focus-inner {
+ margin: 0;
+ padding: 0;
+ border: none;
+}
+
+/**
* For smaller viewports, remove the down-arrow icon and turn
* the button into a block element, spanning the content's full width.
*/
@@ -59,7 +89,7 @@
margin: 0 auto;
overflow: hidden;
padding: 1px 20px;
- width: 640px;
+ width: 780px;
}
#infinite-footer .blog-info,
#infinite-footer .blog-credits {
diff --git a/plugins/jetpack/modules/infinite-scroll/infinity.js b/plugins/jetpack/modules/infinite-scroll/infinity.js
index 51099153..55b69ad2 100644
--- a/plugins/jetpack/modules/infinite-scroll/infinity.js
+++ b/plugins/jetpack/modules/infinite-scroll/infinity.js
@@ -1,7 +1,6 @@
(function($){ // Open closure
-
// Local vars
-var Scroller, ajaxurl, stats, type, text, totop, timer;
+var Scroller, ajaxurl, stats, type, text, totop;
// IE requires special handling
var isIE = ( -1 != navigator.userAgent.search( 'MSIE' ) );
@@ -10,6 +9,11 @@ if ( isIE ) {
var IEVersion = parseInt( IEVersion[1] );
}
+// HTTP ajaxurl when site is HTTPS causes Access-Control-Allow-Origin failure in Desktop and iOS Safari
+if ( "https:" == document.location.protocol ) {
+ infiniteScroll.settings.ajaxurl = infiniteScroll.settings.ajaxurl.replace( "http://", "https://" );
+}
+
/**
* Loads new posts when users scroll near the bottom of the page.
*/
@@ -26,17 +30,23 @@ Scroller = function( settings ) {
this.disabled = false;
this.page = 1;
this.offset = settings.offset;
+ this.currentday = settings.currentday;
this.order = settings.order;
this.throttle = false;
- this.handle = '<div id="infinite-handle"><span>' + text.replace( '\\', '' ) + '</span></div>';
+ this.handle = '<div id="infinite-handle"><span><button>' + text.replace( '\\', '' ) + '</button></span></div>';
+ this.click_handle = settings.click_handle;
this.google_analytics = settings.google_analytics;
this.history = settings.history;
this.origURL = window.location.href;
+ this.pageCache = {};
// Footer settings
this.footer = $( '#infinite-footer' );
this.footer.wrap = settings.footer;
+ // Core's native MediaElement.js implementation needs special handling
+ this.wpMediaelement = null;
+
// We have two type of infinite scroll
// cases 'scroll' and 'click'
@@ -60,31 +70,46 @@ Scroller = function( settings ) {
self.thefooter();
// Fire the refresh
self.refresh();
+ self.determineURL(); // determine the url
}
- }, 300 );
+ }, 250 );
// Ensure that enough posts are loaded to fill the initial viewport, to compensate for short posts and large displays.
self.ensureFilledViewport();
this.body.bind( 'post-load', { self: self }, self.checkViewportOnLoad );
} else if ( type == 'click' ) {
- this.element.append( self.handle );
- this.element.delegate( '#infinite-handle', 'click.infinity', function() {
+ if ( this.click_handle ) {
+ this.element.append( this.handle );
+ }
+
+ this.body.delegate( '#infinite-handle', 'click.infinity', function() {
// Handle the handle
- $( '#infinite-handle' ).remove();
+ if ( self.click_handle ) {
+ $( '#infinite-handle' ).remove();
+ }
+
// Fire the refresh
self.refresh();
});
}
+
+ // Initialize any Core audio or video players loaded via IS
+ this.body.bind( 'post-load', { self: self }, self.initializeMejs );
};
/**
* Check whether we should fetch any additional posts.
*/
Scroller.prototype.check = function() {
- var bottom = this.window.scrollTop() + this.window.height(),
- threshold = this.element.offset().top + this.element.outerHeight(false) - this.window.height();
+ var container = this.element.offset();
- threshold = Math.round( threshold * 0.75 );
+ // If the container can't be found, stop otherwise errors result
+ if ( 'object' !== typeof container ) {
+ return false;
+ }
+
+ var bottom = this.window.scrollTop() + this.window.height(),
+ threshold = container.top + this.element.outerHeight(false) - (this.window.height() * 2);
return bottom > threshold;
};
@@ -97,8 +122,7 @@ Scroller.prototype.render = function( response ) {
// Check if we can wrap the html
this.element.append( response.html );
-
- this.body.trigger( 'post-load' );
+ this.body.trigger( 'post-load', response );
this.ready = true;
};
@@ -107,10 +131,13 @@ Scroller.prototype.render = function( response ) {
*/
Scroller.prototype.query = function() {
return {
- page: this.page,
- order: this.order,
- scripts: window.infiniteScroll.settings.scripts,
- styles: window.infiniteScroll.settings.styles
+ page : this.page,
+ currentday : this.currentday,
+ order : this.order,
+ scripts : window.infiniteScroll.settings.scripts,
+ styles : window.infiniteScroll.settings.styles,
+ query_args : window.infiniteScroll.settings.query_args,
+ last_post_date : window.infiniteScroll.settings.last_post_date,
};
};
@@ -170,15 +197,17 @@ Scroller.prototype.refresh = function() {
this.ready = false;
// Create a loader element to show it's working.
- loader = '<span class="infinite-loader"></span>';
- this.element.append( loader );
+ if ( this.click_handle ) {
+ loader = '<span class="infinite-loader"></span>';
+ this.element.append( loader );
- loader = this.element.find( '.infinite-loader' );
- color = loader.css( 'color' );
+ loader = this.element.find( '.infinite-loader' );
+ color = loader.css( 'color' );
- try {
- loader.spin( 'medium-left', color );
- } catch ( error ) { }
+ try {
+ loader.spin( 'medium-left', color );
+ } catch ( error ) { }
+ }
// Generate our query vars.
query = $.extend({
@@ -186,19 +215,23 @@ Scroller.prototype.refresh = function() {
}, this.query() );
// Fire the ajax request.
- jqxhr = $.get( infiniteScroll.settings.ajaxurl, query );
+ jqxhr = $.post( infiniteScroll.settings.ajaxurl, query );
// Allow refreshes to occur again if an error is triggered.
jqxhr.fail( function() {
- loader.hide();
+ if ( self.click_handle ) {
+ loader.hide();
+ }
+
self.ready = true;
});
// Success handler
jqxhr.done( function( response ) {
-
// On success, let's hide the loader circle.
- loader.hide();
+ if ( self.click_handle ) {
+ loader.hide();
+ }
// Check for and parse our response.
if ( ! response )
@@ -221,6 +254,8 @@ Scroller.prototype.refresh = function() {
// If additional scripts are required by the incoming set of posts, parse them
if ( response.scripts ) {
$( response.scripts ).each( function() {
+ var elementToAppendTo = this.footer ? 'body' : 'head';
+
// Add script handle to list of those already parsed
window.infiniteScroll.settings.scripts.push( this.handle );
@@ -232,7 +267,7 @@ Scroller.prototype.refresh = function() {
data.type = 'text/javascript';
data.appendChild( dataContent );
- document.getElementsByTagName( this.footer ? 'body' : 'head' )[0].appendChild(data);
+ document.getElementsByTagName( elementToAppendTo )[0].appendChild(data);
}
// Build script tag and append to DOM in requested location
@@ -240,7 +275,20 @@ Scroller.prototype.refresh = function() {
script.type = 'text/javascript';
script.src = this.src;
script.id = this.handle;
- document.getElementsByTagName( this.footer ? 'body' : 'head' )[0].appendChild(script);
+
+ // If MediaElement.js is loaded in by this set of posts, don't initialize the players a second time as it breaks them all
+ if ( 'wp-mediaelement' === this.handle ) {
+ self.body.unbind( 'post-load', self.initializeMejs );
+ }
+
+ if ( 'wp-mediaelement' === this.handle && 'undefined' === typeof mejs ) {
+ self.wpMediaelement = {};
+ self.wpMediaelement.tag = script;
+ self.wpMediaelement.element = elementToAppendTo;
+ setTimeout( self.maybeLoadMejs.bind( self ), 250 );
+ } else {
+ document.getElementsByTagName( elementToAppendTo )[0].appendChild(script);
+ }
} );
}
@@ -266,12 +314,15 @@ Scroller.prototype.refresh = function() {
} );
}
+ // stash the response in the page cache
+ self.pageCache[self.page] = response;
+
// Increment the page number
self.page++;
// Record pageview in WP Stats, if available.
if ( stats )
- new Image().src = document.location.protocol + '//stats.wordpress.com/g.gif?' + stats + '&post=0&baba=' + Math.random();
+ new Image().src = document.location.protocol + '//pixel.wp.com/g.gif?' + stats + '&post=0&baba=' + Math.random();
// Add new posts to the postflair object
if ( 'object' == typeof response.postflair && 'object' == typeof WPCOM_sharing_counts )
@@ -280,13 +331,38 @@ Scroller.prototype.refresh = function() {
// Render the results
self.render.apply( self, arguments );
- // If 'click' type, add back the handle
- if ( type == 'click' )
- self.element.append( self.handle );
+ // If 'click' type and there are still posts to fetch, add back the handle
+ if ( type == 'click' ) {
+ if ( response.lastbatch ) {
+ if ( self.click_handle ) {
+ $( '#infinite-handle' ).remove();
+ } else {
+ self.body.trigger( 'infinite-scroll-posts-end' );
+ }
+ } else {
+ if ( self.click_handle ) {
+ self.element.append( self.handle );
+ } else {
+ self.body.trigger( 'infinite-scroll-posts-more' );
+ }
+ }
+ }
+
+ // Update currentday to the latest value returned from the server
+ if ( response.currentday ) {
+ self.currentday = response.currentday;
+ }
// Fire Google Analytics pageview
- if ( self.google_analytics && 'object' == typeof _gaq )
- _gaq.push(['_trackPageview', self.history.path.replace( /%d/, self.page ) ]);
+ if ( self.google_analytics ) {
+ var ga_url = self.history.path.replace( /%d/, self.page );
+ if ( 'object' === typeof _gaq ) {
+ _gaq.push( [ '_trackPageview', ga_url ] );
+ }
+ if ( 'function' === typeof ga ) {
+ ga( 'send', 'pageview', ga_url );
+ }
+ }
}
});
@@ -294,13 +370,69 @@ Scroller.prototype.refresh = function() {
};
/**
+ * Core's native media player uses MediaElement.js
+ * The library's size is sufficient that it may not be loaded in time for Core's helper to invoke it, so we need to delay until `mejs` exists.
+ */
+Scroller.prototype.maybeLoadMejs = function() {
+ if ( null === this.wpMediaelement ) {
+ return;
+ }
+
+ if ( 'undefined' === typeof mejs ) {
+ setTimeout( this.maybeLoadMejs, 250 );
+ } else {
+ document.getElementsByTagName( this.wpMediaelement.element )[0].appendChild( this.wpMediaelement.tag );
+ this.wpMediaelement = null;
+
+ // Ensure any subsequent IS loads initialize the players
+ this.body.bind( 'post-load', { self: this }, this.initializeMejs );
+ }
+}
+
+/**
+ * Initialize the MediaElement.js player for any posts not previously initialized
+ */
+Scroller.prototype.initializeMejs = function( ev, response ) {
+ // Are there media players in the incoming set of posts?
+ if ( ! response.html || -1 === response.html.indexOf( 'wp-audio-shortcode' ) && -1 === response.html.indexOf( 'wp-video-shortcode' ) ) {
+ return;
+ }
+
+ // Don't bother if mejs isn't loaded for some reason
+ if ( 'undefined' === typeof mejs ) {
+ return;
+ }
+
+ // Adapted from wp-includes/js/mediaelement/wp-mediaelement.js
+ // Modified to not initialize already-initialized players, as Mejs doesn't handle that well
+ $(function () {
+ var settings = {};
+
+ if ( typeof _wpmejsSettings !== 'undefined' ) {
+ settings.pluginPath = _wpmejsSettings.pluginPath;
+ }
+
+ settings.success = function (mejs) {
+ var autoplay = mejs.attributes.autoplay && 'false' !== mejs.attributes.autoplay;
+ if ( 'flash' === mejs.pluginType && autoplay ) {
+ mejs.addEventListener( 'canplay', function () {
+ mejs.play();
+ }, false );
+ }
+ };
+
+ $('.wp-audio-shortcode, .wp-video-shortcode').not( '.mejs-container' ).mediaelementplayer( settings );
+ });
+}
+
+/**
* Trigger IS to load additional posts if the initial posts don't fill the window.
* On large displays, or when posts are very short, the viewport may not be filled with posts, so we overcome this by loading additional posts when IS initializes.
*/
Scroller.prototype.ensureFilledViewport = function() {
var self = this,
windowHeight = self.window.height(),
- postsHeight = self.element.height()
+ postsHeight = self.element.height(),
aveSetHeight = 0,
wrapperQty = 0;
@@ -349,11 +481,12 @@ Scroller.prototype.checkViewportOnLoad = function( ev ) {
* Identify archive page that corresponds to majority of posts shown in the current browser window.
*/
Scroller.prototype.determineURL = function () {
- var self = window.infiniteScroll.scroller,
+ var self = this,
windowTop = $( window ).scrollTop(),
windowBottom = windowTop + $( window ).height(),
windowSize = windowBottom - windowTop,
setsInView = [],
+ setsHidden = [],
pageNum = false;
// Find out which sets are in view
@@ -365,7 +498,7 @@ Scroller.prototype.determineURL = function () {
setPageNum = $( this ).data( 'page-num' );
// Account for containers that have no height because their children are floated elements.
- if ( 0 == setHeight ) {
+ if ( 0 === setHeight ) {
$( '> *', this ).each( function() {
setHeight += $( this ).outerHeight( false );
} );
@@ -383,9 +516,37 @@ Scroller.prototype.determineURL = function () {
}
else if( setBottom > windowTop && setBottom < windowBottom ) { // bottom of set is between top (gt) and bottom (lt)
setsInView.push({'id': id, 'top': setTop, 'bottom': setBottom, 'pageNum': setPageNum });
+ } else {
+ setsHidden.push({'id': id, 'top': setTop, 'bottom': setBottom, 'pageNum': setPageNum });
}
} );
+ $.each(setsHidden, function() {
+ var $set = $('#' + this.id);
+ if( $set.hasClass( 'is--replaced' ) ) {
+ return;
+ }
+
+ self.pageCache[ this.pageNum].html = $set.html();
+
+ $set.css('min-height', ( this.bottom - this.top ) + 'px' )
+ .addClass('is--replaced')
+ .empty();
+ });
+
+ $.each(setsInView, function() {
+ var $set = $('#' + this.id);
+
+ if( $set.hasClass('is--replaced') ) {
+ $set.css('min-height', '').removeClass('is--replaced');
+ if( this.pageNum in self.pageCache ) {
+ $set.html( self.pageCache[this.pageNum].html );
+ self.body.trigger( 'post-load', self.pageCache[this.pageNum] );
+ }
+ }
+
+ });
+
// Parse number of sets found in view in an attempt to update the URL to match the set that comprises the majority of the window.
if ( 0 == setsInView.length ) {
pageNum = -1;
@@ -433,7 +594,7 @@ Scroller.prototype.determineURL = function () {
// -1 indicates that the original requested URL should be used.
if ( 'number' == typeof pageNum ) {
if ( pageNum != -1 )
- pageNum += ( 0 == self.offset ) ? 1 : self.offset;
+ pageNum++;
self.updateURL( pageNum );
}
@@ -441,14 +602,20 @@ Scroller.prototype.determineURL = function () {
/**
* Update address bar to reflect archive page URL for a given page number.
- * Checks if URL is different to prevent polution of browser history.
+ * Checks if URL is different to prevent pollution of browser history.
*/
Scroller.prototype.updateURL = function( page ) {
+ // IE only supports pushState() in v10 and above, so don't bother if those conditions aren't met.
+ if ( ! window.history.pushState ) {
+ return;
+ }
var self = this,
- pageSlug = -1 == page ? self.origURL : window.location.protocol + '//' + self.history.host + self.history.path.replace( /%d/, page );
+ offset = self.offset > 0 ? self.offset - 1 : 0,
+ pageSlug = -1 == page ? self.origURL : window.location.protocol + '//' + self.history.host + self.history.path.replace( /%d/, page + offset ) + self.history.parameters;
- if ( window.location.href != pageSlug )
+ if ( window.location.href != pageSlug ) {
history.pushState( null, null, pageSlug );
+ }
}
/**
@@ -456,7 +623,7 @@ Scroller.prototype.updateURL = function( page ) {
*/
$( document ).ready( function() {
// Check for our variables
- if ( 'object' != typeof infiniteScroll )
+ if ( 'object' != typeof infiniteScroll )
return;
// Set ajaxurl (for brevity)
@@ -475,14 +642,18 @@ $( document ).ready( function() {
/**
* Monitor user scroll activity to update URL to correspond to archive page for current set of IS posts
- * IE only supports pushState() in v10 and above, so don't bother if those conditions aren't met.
*/
- if ( ! isIE || ( isIE && IEVersion >= 10 ) ) {
- $( window ).bind( 'scroll', function() {
- clearTimeout( timer );
- timer = setTimeout( infiniteScroll.scroller.determineURL , 100 );
- });
- }
+ if( type == 'click' ) {
+ var timer = null;
+ $( window ).bind( 'scroll', function() {
+ // run the real scroll handler once every 250 ms.
+ if ( timer ) { return; }
+ timer = setTimeout( function() {
+ infiniteScroll.scroller.determineURL();
+ timer = null;
+ } , 250 );
+ });
+ }
});
diff --git a/plugins/jetpack/modules/infinite-scroll/infinity.php b/plugins/jetpack/modules/infinite-scroll/infinity.php
index 20ff5eff..ee8aef0d 100644
--- a/plugins/jetpack/modules/infinite-scroll/infinity.php
+++ b/plugins/jetpack/modules/infinite-scroll/infinity.php
@@ -29,6 +29,8 @@ class The_Neverending_Home_Page {
add_action( 'template_redirect', array( $this, 'action_template_redirect' ) );
add_action( 'template_redirect', array( $this, 'ajax_response' ) );
add_action( 'custom_ajax_infinite_scroll', array( $this, 'query' ) );
+ add_filter( 'infinite_scroll_query_args', array( $this, 'inject_query_args' ) );
+ add_filter( 'infinite_scroll_allowed_vars', array( $this, 'allowed_query_vars' ) );
add_action( 'the_post', array( $this, 'preserve_more_tag' ) );
add_action( 'wp_footer', array( $this, 'footer' ) );
@@ -66,7 +68,8 @@ class The_Neverending_Home_Page {
'render' => false, // optional function, otherwise the `content` template part will be used
'footer' => true, // boolean to enable or disable the infinite footer | string to provide an html id to derive footer width from
'footer_callback' => false, // function to be called to render the IS footer, in place of the default
- 'posts_per_page' => false // int | false to set based on IS type
+ 'posts_per_page' => false, // int | false to set based on IS type
+ 'click_handle' => true, // boolean to enable or disable rendering the click handler div. If type is click and this is false, page must include its own trigger with the HTML ID `infinite-handle`.
);
// Validate settings passed through add_theme_support()
@@ -141,6 +144,13 @@ class The_Neverending_Home_Page {
break;
+ case 'click_handle' :
+ if ( is_bool( $value ) ) {
+ $settings[ $key ] = $value;
+ }
+
+ break;
+
default:
continue;
@@ -201,9 +211,18 @@ class The_Neverending_Home_Page {
$settings['type'] = 'click';
}
+ // Ignore posts_per_page theme setting for [click] type
+ if ( 'click' == $settings['type'] )
+ $settings['posts_per_page'] = (int) get_option( 'posts_per_page' );
+
// Backwards compatibility for posts_per_page setting
- if ( false === $settings['posts_per_page'] )
- $settings['posts_per_page'] = 'click' == $settings['type'] ? (int) get_option( 'posts_per_page' ) : 7;
+ elseif ( false === $settings['posts_per_page'] )
+ $settings['posts_per_page'] = 7;
+
+ // Force display of the click handler and attendant bits when the type isn't `click`
+ if ( 'click' !== $settings['type'] ) {
+ $settings['click_handle'] = true;
+ }
// Store final settings in a class static to avoid reparsing
self::$settings = apply_filters( 'infinite_scroll_settings', $settings );
@@ -232,6 +251,13 @@ class The_Neverending_Home_Page {
}
/**
+ * Is this guaranteed to be the last batch of posts?
+ */
+ static function is_last_batch() {
+ return (bool) ( count( self::wp_query()->posts ) < self::get_settings()->posts_per_page );
+ }
+
+ /**
* The more tag will be ignored by default if the blog page isn't our homepage.
* Let's force the $more global to false.
*/
@@ -268,7 +294,7 @@ class The_Neverending_Home_Page {
* for the infinite_scroll setting.
*/
function infinite_setting_html() {
- $notice = '<em>' . __( "We've disabled this option for you since you have footer widgets in Appearance &rarr; Widgets, or because your theme does not support infinite scroll.", 'jetpack' ) . '</em>';
+ $notice = '<em>' . __( 'We&rsquo;ve changed this option to a click-to-scroll version for you since you have footer widgets in Appearance &rarr; Widgets, or your theme uses click-to-scroll as the default behavior.', 'jetpack' ) . '</em>';
// If the blog has footer widgets, show a notice instead of the checkbox
if ( self::get_settings()->footer_widgets || 'click' == self::get_settings()->requested_type ) {
@@ -281,7 +307,7 @@ class The_Neverending_Home_Page {
/**
* Does the legwork to determine whether the feature is enabled.
*
- * @uses current_theme_supports, self::archive_supports_infinity, self::get_settings, self::set_last_post_time, add_filter, wp_enqueue_script, plugins_url, wp_enqueue_style, add_action
+ * @uses current_theme_supports, self::archive_supports_infinity, self::get_settings, add_filter, wp_enqueue_script, plugins_url, wp_enqueue_style, add_action
* @action template_redirect
* @return null
*/
@@ -296,24 +322,24 @@ class The_Neverending_Home_Page {
if ( empty( $id ) )
return;
- // Bail if there are not enough posts for infinity.
- if ( ! self::set_last_post_time() )
+ // Make sure there are enough posts for IS
+ if ( 'click' == self::get_settings()->type && self::is_last_batch() )
return;
// Add a class to the body.
add_filter( 'body_class', array( $this, 'body_class' ) );
// Add our scripts.
- wp_enqueue_script( 'the-neverending-homepage', plugins_url( 'infinity.js', __FILE__ ), array( 'jquery' ), '20130523' );
+ wp_enqueue_script( 'the-neverending-homepage', plugins_url( 'infinity.js', __FILE__ ), array( 'jquery' ), 20141016, true );
// Add our default styles.
- wp_enqueue_style( 'the-neverending-homepage', plugins_url( 'infinity.css', __FILE__ ), array(), '20120612' );
+ wp_enqueue_style( 'the-neverending-homepage', plugins_url( 'infinity.css', __FILE__ ), array(), '20140422' );
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_spinner_scripts' ) );
- add_action( 'wp_head', array( $this, 'action_wp_head' ), 2 );
+ add_action( 'wp_footer', array( $this, 'action_wp_footer_settings' ), 2 );
- add_action( 'wp_footer', array( $this, 'action_wp_footer' ), 99999999 );
+ add_action( 'wp_footer', array( $this, 'action_wp_footer' ), 21 ); // Core prints footer scripts at priority 20, so we just need to be one later than that
add_filter( 'infinite_scroll_results', array( $this, 'filter_infinite_scroll_results' ), 10, 3 );
}
@@ -329,42 +355,168 @@ class The_Neverending_Home_Page {
* Adds an 'infinite-scroll' class to the body.
*/
function body_class( $classes ) {
- $classes[] = 'infinite-scroll';
-
- if ( 'scroll' == self::get_settings()->type )
- $classes[] = 'neverending';
+ // Do not add infinity-scroll class if disabled through the Reading page
+ $disabled = '' === get_option( self::$option_name_enabled ) ? true : false;
+ if ( ! $disabled || 'click' == self::get_settings()->type ) {
+ $classes[] = 'infinite-scroll';
+
+ if ( 'scroll' == self::get_settings()->type )
+ $classes[] = 'neverending';
+ }
return $classes;
}
/**
- * Grab the timestamp for the last post.
- * @return string 'Y-m-d H:i:s' or null
+ * In case IS is activated on search page, we have to exclude initially loaded posts which match the keyword by title, not the content as they are displayed before content-matching ones
+ *
+ * @uses self::wp_query
+ * @uses self::get_last_post_date
+ * @uses self::has_only_title_matching_posts
+ * @return array
*/
- function set_last_post_time( $date = false ) {
- $posts = self::wp_query()->posts;
- $count = count( $posts );
+ function get_excluded_posts() {
+
+ $excluded_posts = array();
+ //loop through posts returned by wp_query call
+ foreach( self::wp_query()->get_posts() as $post ) {
+
+ $orderby = isset( self::wp_query()->query_vars['orderby'] ) ? self::wp_query()->query_vars['orderby'] : '';
+ $post_date = ( ! empty( $post->post_date ) ? $post->post_date : false );
+ if ( 'modified' === $orderby || false === $post_date ) {
+ $post_date = $post->post_modified;
+ }
- if ( ! empty( $date ) && preg_match( '|\d{4}\-\d{2}\-\d{2}|', $_GET['date'] ) ) {
- self::$the_time = "$date 00:00:00";
- return self::$the_time;
+ //in case all posts initially displayed match the keyword by title we add em all to excluded posts array
+ //else, we add only posts which are older than last_post_date param as newer are natually excluded by last_post_date condition in the SQL query
+ if ( self::has_only_title_matching_posts() || $post_date <= self::get_last_post_date() ) {
+ array_push( $excluded_posts, $post->ID );
+ }
}
+ return $excluded_posts;
+ }
+
+ /**
+ * In case IS is active on search, we have to exclude posts matched by title rather than by post_content in order to prevent dupes on next pages
+ *
+ * @uses self::wp_query
+ * @uses self::get_excluded_posts
+ * @return array
+ */
+ function get_query_vars() {
+
+ $query_vars = self::wp_query()->query_vars;
+ //applies to search page only
+ if ( true === self::wp_query()->is_search() ) {
+ //set post__not_in array in query_vars in case it does not exists
+ if ( false === isset( $query_vars['post__not_in'] ) ) {
+ $query_vars['post__not_in'] = array();
+ }
+ //get excluded posts
+ $excluded = self::get_excluded_posts();
+ //merge them with other post__not_in posts (eg.: sticky posts)
+ $query_vars['post__not_in'] = array_merge( $query_vars['post__not_in'], $excluded );
+ }
+ return $query_vars;
+ }
+
+ /**
+ * This function checks whether all posts returned by initial wp_query match the keyword by title
+ * The code used in this function is borrowed from WP_Query class where it is used to construct like conditions for keywords
+ *
+ * @uses self::wp_query
+ * @return bool
+ */
+ function has_only_title_matching_posts() {
+
+ //apply following logic for search page results only
+ if ( false === self::wp_query()->is_search() ) {
+ return false;
+ }
+
+ //grab the last posts in the stack as if the last one is title-matching the rest is title-matching as well
+ $post = end( self::wp_query()->posts );
+
+ //code inspired by WP_Query class
+ if ( preg_match_all( '/".*?("|$)|((?<=[\t ",+])|^)[^\t ",+]+/', self::wp_query()->get( 's' ), $matches ) ) {
+ $search_terms = self::wp_query()->parse_search_terms( $matches[0] );
+ // if the search string has only short terms or stopwords, or is 10+ terms long, match it as sentence
+ if ( empty( $search_terms ) || count( $search_terms ) > 9 ) {
+ $search_terms = array( self::wp_query()->get( 's' ) );
+ }
+ } else {
+ $search_terms = array( self::wp_query()->get( 's' ) );
+ }
+
+ //actual testing. As search query combines multiple keywords with AND, it's enough to check if any of the keywords is present in the title
+ if ( false !== strpos( $post->post_title, current( $search_terms ) ) ) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Grab the timestamp for the initial query's last post.
+ *
+ * This takes into account the query's 'orderby' parameter and returns
+ * false if the posts are not ordered by date.
+ *
+ * @uses self::got_infinity
+ * @uses self::has_only_title_matching_posts
+ * @uses self::wp_query
+ * @return string 'Y-m-d H:i:s' or false
+ */
+ function get_last_post_date() {
+ if ( self::got_infinity() )
+ return;
- // If we don't have enough posts for infinity, return early
- if ( ! $count || $count < self::get_settings()->posts_per_page )
- return self::$the_time;
+ if ( ! self::wp_query()->have_posts() ) {
+ return null;
+ }
- $last_post = end( $posts );
+ //In case there are only title-matching posts in the initial WP_Query result, we don't want to use the last_post_date param yet
+ if ( true === self::has_only_title_matching_posts() ) {
+ return false;
+ }
- // If the function is called again but we already have a value, return it
- if ( null != self::$the_time ) {
- return self::$the_time;
- } elseif ( isset( $last_post->post_date_gmt ) ) {
- // Grab the latest post time in Y-m-d H:i:s gmt format
- self::$the_time = $last_post->post_date_gmt;
+ $post = end( self::wp_query()->posts );
+ $orderby = isset( self::wp_query()->query_vars['orderby'] ) ?
+ self::wp_query()->query_vars['orderby'] : '';
+ $post_date = ( ! empty( $post->post_date ) ? $post->post_date : false );
+ switch ( $orderby ) {
+ case 'modified':
+ return $post->post_modified;
+ case 'date':
+ case '':
+ return $post_date;
+ default:
+ return false;
}
+ }
- return self::$the_time;
+ /**
+ * Returns the appropriate `wp_posts` table field for a given query's
+ * 'orderby' parameter, if applicable.
+ *
+ * @param optional object $query
+ * @uses self::wp_query
+ * @return string or false
+ */
+ function get_query_sort_field( $query = null ) {
+ if ( empty( $query ) )
+ $query = self::wp_query();
+
+ $orderby = isset( $query->query_vars['orderby'] ) ? $query->query_vars['orderby'] : '';
+
+ switch ( $orderby ) {
+ case 'modified':
+ return 'post_modified';
+ case 'date':
+ case '':
+ return 'post_date';
+ default:
+ return false;
+ }
}
/**
@@ -376,19 +528,29 @@ class The_Neverending_Home_Page {
* @param string $where
* @param object $query
* @uses apply_filters
- * @uses self::set_last_post_time
* @filter posts_where
* @return string
*/
function query_time_filter( $where, $query ) {
- global $wpdb;
+ if ( self::got_infinity() ) {
+ global $wpdb;
+
+ $sort_field = self::get_query_sort_field( $query );
+ if ( false == $sort_field )
+ return $where;
- $operator = 'ASC' == $query->get( 'order' ) ? '>' : '<';
+ $last_post_date = $_REQUEST['last_post_date'];
+ // Sanitize timestamp
+ if ( empty( $last_post_date ) || !preg_match( '|\d{4}\-\d{2}\-\d{2}|', $last_post_date ) )
+ return $where;
- // Construct the date query using our timestamp
- $clause = $wpdb->prepare( " AND {$wpdb->posts}.post_date_gmt {$operator} %s", self::set_last_post_time() );
+ $operator = 'ASC' == $_REQUEST['query_args']['order'] ? '>' : '<';
- $where .= apply_filters( 'infinite_scroll_posts_where', $clause, $query, $operator, self::set_last_post_time() );
+ // Construct the date query using our timestamp
+ $clause = $wpdb->prepare( " AND {$wpdb->posts}.{$sort_field} {$operator} %s", $last_post_date );
+
+ $where .= apply_filters( 'infinite_scroll_posts_where', $clause, $query, $operator, $last_post_date );
+ }
return $where;
}
@@ -420,19 +582,11 @@ class The_Neverending_Home_Page {
* Returns the Ajax url
*
* @global $wp
- * @uses home_url, is_ssl, add_query_arg, trailingslashit, apply_filters
+ * @uses home_url, add_query_arg, apply_filters
* @return string
*/
function ajax_url() {
- global $wp;
-
- // When using default permalinks, $wp->request will be null, so we reconstruct the request from the query arguments WP parsed.
- if ( is_null( $wp->request ) ) {
- $base_url = home_url( '/', is_ssl() ? 'https' : 'http' );
- $base_url = add_query_arg( $wp->query_vars, $base_url );
- } else {
- $base_url = home_url( trailingslashit( $wp->request ), is_ssl() ? 'https' : 'http' );
- }
+ $base_url = set_url_scheme( home_url( '/' ) );
$ajaxurl = add_query_arg( array( 'infinity' => 'scrolling' ), $base_url );
@@ -447,7 +601,10 @@ class The_Neverending_Home_Page {
if ( ! self::got_infinity() )
return false;
- define( 'DOING_AJAX', true );
+ // This should already be defined below, but make sure.
+ if ( ! defined( 'DOING_AJAX' ) ) {
+ define( 'DOING_AJAX', true );
+ }
@header( 'Content-Type: text/html; charset=' . get_option( 'blog_charset' ) );
send_nosniff_header();
@@ -457,15 +614,51 @@ class The_Neverending_Home_Page {
}
/**
+ * Alias for renamed class method.
+ *
+ * Previously, JS settings object was unnecessarily output in the document head.
+ * When the hook was changed, the method name no longer made sense.
+ */
+ function action_wp_head() {
+ $this->action_wp_footer_settings();
+ }
+
+ /**
* Prints the relevant infinite scroll settings in JS.
*
* @global $wp_rewrite
- * @uses self::get_settings, esc_js, esc_url_raw, self::has_wrapper, __, apply_filters, do_action
- * @action wp_head
+ * @uses self::get_settings, esc_js, esc_url_raw, self::has_wrapper, __, apply_filters, do_action, self::get_query_vars
+ * @action wp_footer
* @return string
*/
- function action_wp_head() {
+ function action_wp_footer_settings() {
global $wp_rewrite;
+ global $currentday;
+
+ // Default click handle text
+ $click_handle_text = __( 'Older posts', 'jetpack' );
+
+ // If a single CPT is displayed, use its plural name instead of "posts"
+ // Could be empty (posts) or an array of multiple post types.
+ // In the latter two cases cases, the default text is used, leaving the `infinite_scroll_js_settings` filter for further customization.
+ $post_type = self::wp_query()->get( 'post_type' );
+ if ( is_string( $post_type ) && ! empty( $post_type ) ) {
+ $post_type = get_post_type_object( $post_type );
+
+ if ( is_object( $post_type ) && ! is_wp_error( $post_type ) ) {
+ if ( isset( $post_type->labels->name ) ) {
+ $cpt_text = $post_type->labels->name;
+ } elseif ( isset( $post_type->label ) ) {
+ $cpt_text = $post_type->label;
+ }
+
+ if ( isset( $cpt_text ) ) {
+ $click_handle_text = sprintf( __( 'Older %s', 'jetpack' ), $cpt_text );
+ unset( $cpt_text );
+ }
+ }
+ }
+ unset( $post_type );
// Base JS settings
$js_settings = array(
@@ -475,8 +668,10 @@ class The_Neverending_Home_Page {
'wrapper' => self::has_wrapper(),
'wrapper_class' => is_string( self::get_settings()->wrapper ) ? esc_js( self::get_settings()->wrapper ) : 'infinite-wrap',
'footer' => is_string( self::get_settings()->footer ) ? esc_js( self::get_settings()->footer ) : self::get_settings()->footer,
- 'text' => esc_js( __( 'Older posts', 'jetpack' ) ),
+ 'click_handle' => esc_js( self::get_settings()->click_handle ),
+ 'text' => esc_js( $click_handle_text ),
'totop' => esc_js( __( 'Scroll back to top', 'jetpack' ) ),
+ 'currentday' => $currentday,
'order' => 'DESC',
'scripts' => array(),
'styles' => array(),
@@ -485,13 +680,16 @@ class The_Neverending_Home_Page {
'history' => array(
'host' => preg_replace( '#^http(s)?://#i', '', untrailingslashit( get_option( 'home' ) ) ),
'path' => self::get_request_path(),
- 'use_trailing_slashes' => $wp_rewrite->use_trailing_slashes
- )
+ 'use_trailing_slashes' => $wp_rewrite->use_trailing_slashes,
+ 'parameters' => self::get_request_parameters(),
+ ),
+ 'query_args' => self::get_query_vars(),
+ 'last_post_date' => self::get_last_post_date(),
);
// Optional order param
- if ( isset( $_GET['order'] ) ) {
- $order = strtoupper( $_GET['order'] );
+ if ( isset( $_REQUEST['order'] ) ) {
+ $order = strtoupper( $_REQUEST['order'] );
if ( in_array( $order, array( 'ASC', 'DESC' ) ) )
$js_settings['order'] = $order;
@@ -541,8 +739,8 @@ class The_Neverending_Home_Page {
$path = user_trailingslashit( $path );
} else {
- // Clean up raw $_GET input
- $path = array_map( 'sanitize_text_field', $_GET );
+ // Clean up raw $_REQUEST input
+ $path = array_map( 'sanitize_text_field', $_REQUEST );
$path = array_filter( $path );
$path['paged'] = '%d';
@@ -554,6 +752,19 @@ class The_Neverending_Home_Page {
}
/**
+ * Return query string for current request, prefixed with '?'.
+ *
+ * @return string
+ */
+ private function get_request_parameters() {
+ $uri = $_SERVER[ 'REQUEST_URI' ];
+ $uri = preg_replace( '/^[^?]*(\?.*$)/', '$1', $uri, 1, $count );
+ if ( $count != 1 )
+ return '';
+ return $uri;
+ }
+
+ /**
* Provide IS with a list of the scripts and stylesheets already present on the page.
* Since posts may contain require additional assets that haven't been loaded, this data will be used to track the additional assets.
*
@@ -590,7 +801,7 @@ class The_Neverending_Home_Page {
return $results;
// Parse and sanitize the script handles already output
- $initial_scripts = isset( $_GET['scripts'] ) && is_array( $_GET['scripts'] ) ? array_map( 'sanitize_text_field', $_GET['scripts'] ) : false;
+ $initial_scripts = isset( $_REQUEST['scripts'] ) && is_array( $_REQUEST['scripts'] ) ? array_map( 'sanitize_text_field', $_REQUEST['scripts'] ) : false;
if ( is_array( $initial_scripts ) ) {
global $wp_scripts;
@@ -649,7 +860,7 @@ class The_Neverending_Home_Page {
unset( $results['scripts' ] );
// Parse and sanitize the style handles already output
- $initial_styles = isset( $_GET['styles'] ) && is_array( $_GET['styles'] ) ? array_map( 'sanitize_text_field', $_GET['styles'] ) : false;
+ $initial_styles = isset( $_REQUEST['styles'] ) && is_array( $_REQUEST['styles'] ) ? array_map( 'sanitize_text_field', $_REQUEST['styles'] ) : false;
if ( is_array( $initial_styles ) ) {
global $wp_styles;
@@ -742,28 +953,37 @@ class The_Neverending_Home_Page {
*
* @global $wp_query
* @global $wp_the_query
- * @uses current_theme_supports, get_option, self::wp_query, self::set_last_post_time, current_user_can, apply_filters, self::get_settings, add_filter, WP_Query, remove_filter, have_posts, wp_head, do_action, add_action, this::render, this::has_wrapper, esc_attr, wp_footer, sharing_register_post_for_share_counts, get_the_id
+ * @uses current_theme_supports, get_option, self::wp_query, current_user_can, apply_filters, self::get_settings, add_filter, WP_Query, remove_filter, have_posts, wp_head, do_action, add_action, this::render, this::has_wrapper, esc_attr, wp_footer, sharing_register_post_for_share_counts, get_the_id
* @return string or null
*/
function query() {
- if ( ! isset( $_GET['page'] ) || ! current_theme_supports( 'infinite-scroll' ) )
+ if ( ! isset( $_REQUEST['page'] ) || ! current_theme_supports( 'infinite-scroll' ) )
die;
- $page = (int) $_GET['page'];
+ $page = (int) $_REQUEST['page'];
+
+ // Sanitize and set $previousday. Expected format: dd.mm.yy
+ if ( preg_match( '/^\d{2}\.\d{2}\.\d{2}$/', $_REQUEST['currentday'] ) ) {
+ global $previousday;
+ $previousday = $_REQUEST['currentday'];
+ }
$sticky = get_option( 'sticky_posts' );
$post__not_in = self::wp_query()->get( 'post__not_in' );
+
+ //we have to take post__not_in args into consideration here not only sticky posts
+ if ( true === isset( $_REQUEST['query_args']['post__not_in'] ) ) {
+ $post__not_in = array_merge( $post__not_in, array_map( 'intval', (array) $_REQUEST['query_args']['post__not_in'] ) );
+ }
+
if ( ! empty( $post__not_in ) )
$sticky = array_unique( array_merge( $sticky, $post__not_in ) );
- if ( ! empty( $_GET['date'] ) )
- self::set_last_post_time( $_GET['date'] );
-
$post_status = array( 'publish' );
if ( current_user_can( 'read_private_posts' ) )
array_push( $post_status, 'private' );
- $order = in_array( $_GET['order'], array( 'ASC', 'DESC' ) ) ? $_GET['order'] : 'DESC';
+ $order = in_array( $_REQUEST['order'], array( 'ASC', 'DESC' ) ) ? $_REQUEST['order'] : 'DESC';
$query_args = array_merge( self::wp_query()->query_vars, array(
'paged' => $page,
@@ -773,6 +993,11 @@ class The_Neverending_Home_Page {
'order' => $order
) );
+ // 4.0 ?s= compatibility, see https://core.trac.wordpress.org/ticket/11330#comment:50
+ if ( empty( $query_args['s'] ) && ! isset( self::wp_query()->query['s'] ) ) {
+ unset( $query_args['s'] );
+ }
+
// By default, don't query for a specific page of a paged post object.
// This argument can come from merging self::wp_query() into $query_args above.
// Since IS is only used on archives, we should always display the first page of any paged content.
@@ -830,6 +1055,12 @@ class The_Neverending_Home_Page {
wp_footer();
ob_end_clean();
+ if ( 'success' == $results['type'] ) {
+ global $currentday;
+ $results['lastbatch'] = self::is_last_batch();
+ $results['currentday'] = $currentday;
+ }
+
// Loop through posts to capture sharing data for new posts loaded via Infinite Scroll
if ( 'success' == $results['type'] && function_exists( 'sharing_register_post_for_share_counts' ) ) {
global $jetpack_sharing_counts;
@@ -847,11 +1078,79 @@ class The_Neverending_Home_Page {
$results['type'] = 'empty';
}
- echo json_encode( apply_filters( 'infinite_scroll_results', $results, $query_args, self::wp_query() ) );
+ echo wp_json_encode( apply_filters( 'infinite_scroll_results', $results, $query_args, self::wp_query() ) );
die;
}
/**
+ * Update the $allowed_vars array with the standard WP public and private
+ * query vars, as well as taxonomy vars
+ *
+ * @global $wp
+ * @param array $allowed_vars
+ * @filter infinite_scroll_allowed_vars
+ * @return array
+ */
+ function allowed_query_vars( $allowed_vars ) {
+ global $wp;
+
+ $allowed_vars += $wp->public_query_vars;
+ $allowed_vars += $wp->private_query_vars;
+ $allowed_vars += $this->get_taxonomy_vars();
+
+ foreach ( array_keys( $allowed_vars, 'paged' ) as $key ) {
+ unset( $allowed_vars[ $key ] );
+ }
+
+ return array_unique( $allowed_vars );
+ }
+
+ /**
+ * Returns an array of stock and custom taxonomy query vars
+ *
+ * @global $wp_taxonomies
+ * @return array
+ */
+ function get_taxonomy_vars() {
+ global $wp_taxonomies;
+
+ $taxonomy_vars = array();
+ foreach ( $wp_taxonomies as $taxonomy => $t ) {
+ if ( $t->query_var )
+ $taxonomy_vars[] = $t->query_var;
+ }
+
+ // still needed?
+ $taxonomy_vars[] = 'tag_id';
+
+ return $taxonomy_vars;
+ }
+
+ /**
+ * Update the $query_args array with the parameters provided via AJAX/GET.
+ *
+ * @param array $query_args
+ * @filter infinite_scroll_query_args
+ * @return array
+ */
+ function inject_query_args( $query_args ) {
+ $allowed_vars = apply_filters( 'infinite_scroll_allowed_vars', array(), $query_args );
+
+ $query_args = array_merge( $query_args, array(
+ 'suppress_filters' => false,
+ ) );
+
+ if ( is_array( $_REQUEST[ 'query_args' ] ) ) {
+ foreach ( $_REQUEST[ 'query_args' ] as $var => $value ) {
+ if ( in_array( $var, $allowed_vars ) && ! empty( $value ) )
+ $query_args[ $var ] = $value;
+ }
+ }
+
+ return $query_args;
+ }
+
+ /**
* Rendering fallback used when themes don't specify their own handler.
*
* @uses have_posts, the_post, get_template_part, get_post_format
@@ -873,7 +1172,11 @@ class The_Neverending_Home_Page {
* @return bool
*/
public static function archive_supports_infinity() {
- $supported = current_theme_supports( 'infinite-scroll' ) && ( is_home() || is_archive() );
+ $supported = current_theme_supports( 'infinite-scroll' ) && ( is_home() || is_archive() || is_search() );
+ // Disable infinite scroll in customizer previews
+ if ( isset( $_REQUEST[ 'wp_customize' ] ) && 'on' === $_REQUEST[ 'wp_customize' ] ) {
+ return false;
+ }
return (bool) apply_filters( 'infinite_scroll_archive_supported', $supported, self::get_settings() );
}
@@ -881,7 +1184,7 @@ class The_Neverending_Home_Page {
/**
* The Infinite Blog Footer
*
- * @uses self::get_settings, self::set_last_post_time, self::archive_supports_infinity, self::default_footer
+ * @uses self::get_settings, self::archive_supports_infinity, self::default_footer
* @return string or null
*/
function footer() {
@@ -889,10 +1192,6 @@ class The_Neverending_Home_Page {
if ( false == self::get_settings()->footer )
return;
- // Bail if there are not enough posts for infinity.
- if ( ! self::set_last_post_time() )
- return;
-
// We only need the new footer for the 'scroll' type
if ( 'scroll' != self::get_settings()->type || ! self::archive_supports_infinity() )
return;
@@ -919,7 +1218,7 @@ class The_Neverending_Home_Page {
<div id="infinite-footer">
<div class="container">
<div class="blog-info">
- <a id="infinity-blog-title" href="<?php echo home_url( '/' ); ?>" title="<?php echo esc_attr( get_bloginfo( 'name', 'display' ) ); ?>" rel="home">
+ <a id="infinity-blog-title" href="<?php echo home_url( '/' ); ?>" rel="home">
<?php bloginfo( 'name' ); ?>
</a>
</div>
@@ -981,3 +1280,168 @@ function the_neverending_home_page_theme_support() {
require_once( $customization_file );
}
add_action( 'after_setup_theme', 'the_neverending_home_page_theme_support', 5 );
+
+/**
+ * Early accommodation of the Infinite Scroll AJAX request
+ */
+if ( The_Neverending_Home_Page::got_infinity() ) {
+ /**
+ * If we're sure this is an AJAX request (i.e. the HTTP_X_REQUESTED_WITH header says so),
+ * indicate it as early as possible for actions like init
+ */
+ if ( ! defined( 'DOING_AJAX' ) &&
+ isset( $_SERVER['HTTP_X_REQUESTED_WITH'] ) &&
+ strtoupper( $_SERVER['HTTP_X_REQUESTED_WITH'] ) == 'XMLHTTPREQUEST'
+ ) {
+ define( 'DOING_AJAX', true );
+ }
+
+ // Don't load the admin bar when doing the AJAX response.
+ show_admin_bar( false );
+}
+
+/**
+ * Include the wp_json_encode functions for pre-wordpress-4.1
+ */
+
+if ( ! function_exists( 'wp_json_encode' ) ) :
+ /**
+ * Encode a variable into JSON, with some sanity checks.
+ *
+ * @since 4.1.0
+ *
+ * @param mixed $data Variable (usually an array or object) to encode as JSON.
+ * @param int $options Optional. Options to be passed to json_encode(). Default 0.
+ * @param int $depth Optional. Maximum depth to walk through $data. Must be
+ * greater than 0. Default 512.
+ * @return bool|string The JSON encoded string, or false if it cannot be encoded.
+ */
+ function wp_json_encode( $data, $options = 0, $depth = 512 ) {
+ /*
+ * json_encode() has had extra params added over the years.
+ * $options was added in 5.3, and $depth in 5.5.
+ * We need to make sure we call it with the correct arguments.
+ */
+ if ( version_compare( PHP_VERSION, '5.5', '>=' ) ) {
+ $args = array( $data, $options, $depth );
+ } elseif ( version_compare( PHP_VERSION, '5.3', '>=' ) ) {
+ $args = array( $data, $options );
+ } else {
+ $args = array( $data );
+ }
+
+ $json = call_user_func_array( 'json_encode', $args );
+
+ // If json_encode() was successful, no need to do more sanity checking.
+ // ... unless we're in an old version of PHP, and json_encode() returned
+ // a string containing 'null'. Then we need to do more sanity checking.
+ if ( false !== $json && ( version_compare( PHP_VERSION, '5.5', '>=' ) || false === strpos( $json, 'null' ) ) ) {
+ return $json;
+ }
+
+ try {
+ $args[0] = _wp_json_sanity_check( $data, $depth );
+ } catch ( Exception $e ) {
+ return false;
+ }
+
+ return call_user_func_array( 'json_encode', $args );
+ }
+endif;
+
+if ( ! function_exists( '_wp_json_sanity_check' ) ) :
+ /**
+ * Perform sanity checks on data that shall be encoded to JSON.
+ *
+ * @see wp_json_encode()
+ *
+ * @since 4.1.0
+ * @access private
+ * @internal
+ *
+ * @param mixed $data Variable (usually an array or object) to encode as JSON.
+ * @param int $depth Maximum depth to walk through $data. Must be greater than 0.
+ * @return mixed The sanitized data that shall be encoded to JSON.
+ */
+ function _wp_json_sanity_check( $data, $depth ) {
+ if ( $depth < 0 ) {
+ throw new Exception( 'Reached depth limit' );
+ }
+
+ if ( is_array( $data ) ) {
+ $output = array();
+ foreach ( $data as $id => $el ) {
+ // Don't forget to sanitize the ID!
+ if ( is_string( $id ) ) {
+ $clean_id = _wp_json_convert_string( $id );
+ } else {
+ $clean_id = $id;
+ }
+
+ // Check the element type, so that we're only recursing if we really have to.
+ if ( is_array( $el ) || is_object( $el ) ) {
+ $output[ $clean_id ] = _wp_json_sanity_check( $el, $depth - 1 );
+ } elseif ( is_string( $el ) ) {
+ $output[ $clean_id ] = _wp_json_convert_string( $el );
+ } else {
+ $output[ $clean_id ] = $el;
+ }
+ }
+ } elseif ( is_object( $data ) ) {
+ $output = new stdClass;
+ foreach ( $data as $id => $el ) {
+ if ( is_string( $id ) ) {
+ $clean_id = _wp_json_convert_string( $id );
+ } else {
+ $clean_id = $id;
+ }
+
+ if ( is_array( $el ) || is_object( $el ) ) {
+ $output->$clean_id = _wp_json_sanity_check( $el, $depth - 1 );
+ } elseif ( is_string( $el ) ) {
+ $output->$clean_id = _wp_json_convert_string( $el );
+ } else {
+ $output->$clean_id = $el;
+ }
+ }
+ } elseif ( is_string( $data ) ) {
+ return _wp_json_convert_string( $data );
+ } else {
+ return $data;
+ }
+
+ return $output;
+ }
+endif;
+
+if ( ! function_exists( '_wp_json_convert_string' ) ) :
+ /**
+ * Convert a string to UTF-8, so that it can be safely encoded to JSON.
+ *
+ * @see _wp_json_sanity_check()
+ *
+ * @since 4.1.0
+ * @access private
+ * @internal
+ *
+ * @param string $string The string which is to be converted.
+ * @return string The checked string.
+ */
+ function _wp_json_convert_string( $string ) {
+ static $use_mb = null;
+ if ( is_null( $use_mb ) ) {
+ $use_mb = function_exists( 'mb_convert_encoding' );
+ }
+
+ if ( $use_mb ) {
+ $encoding = mb_detect_encoding( $string, mb_detect_order(), true );
+ if ( $encoding ) {
+ return mb_convert_encoding( $string, 'UTF-8', $encoding );
+ } else {
+ return mb_convert_encoding( $string, 'UTF-8', 'UTF-8' );
+ }
+ } else {
+ return wp_check_invalid_utf8( $string, true );
+ }
+ }
+endif;
diff --git a/plugins/jetpack/modules/infinite-scroll/themes/twentyeleven.php b/plugins/jetpack/modules/infinite-scroll/themes/twentyeleven.php
index a80ee810..ff6f7878 100644
--- a/plugins/jetpack/modules/infinite-scroll/themes/twentyeleven.php
+++ b/plugins/jetpack/modules/infinite-scroll/themes/twentyeleven.php
@@ -10,9 +10,8 @@
*/
function twenty_eleven_infinite_scroll_init() {
add_theme_support( 'infinite-scroll', array(
- 'container' => 'content',
- 'footer_widgets' => array( 'sidebar-3', 'sidebar-4', 'sidebar-5' ),
- 'footer' => 'page',
+ 'container' => 'content',
+ 'footer' => 'page',
) );
}
add_action( 'init', 'twenty_eleven_infinite_scroll_init' );
@@ -24,4 +23,26 @@ function twenty_eleven_infinite_scroll_enqueue_styles() {
// Add theme specific styles.
wp_enqueue_style( 'infinity-twentyeleven', plugins_url( 'twentyeleven.css', __FILE__ ), array( 'the-neverending-homepage' ), '20121002' );
}
-add_action( 'wp_enqueue_scripts', 'twenty_eleven_infinite_scroll_enqueue_styles', 25 ); \ No newline at end of file
+add_action( 'wp_enqueue_scripts', 'twenty_eleven_infinite_scroll_enqueue_styles', 25 );
+
+/**
+ * Have we any footer widgets?
+ *
+ * @param bool $has_widgets
+ * @uses is_active_sidebar
+ * @uses jetpack_is_mobile
+ * @filter infinite_scroll_has_footer_widgets
+ * @return bool
+ */
+function twenty_eleven_has_footer_widgets( $has_widgets ) {
+ // Are any of the "Footer Area" sidebars active?
+ if ( is_active_sidebar( 'sidebar-3' ) || is_active_sidebar( 'sidebar-4' ) || is_active_sidebar( 'sidebar-5' ) )
+ return true;
+
+ // If we're on mobile and the Main Sidebar has widgets, it falls below the content, so we have footer widgets.
+ if ( function_exists( 'jetpack_is_mobile' ) && jetpack_is_mobile() && is_active_sidebar( 'sidebar-1' ) )
+ return true;
+
+ return $has_widgets;
+}
+add_filter( 'infinite_scroll_has_footer_widgets', 'twenty_eleven_has_footer_widgets' );
diff --git a/plugins/jetpack/modules/infinite-scroll/themes/twentyfifteen-rtl.css b/plugins/jetpack/modules/infinite-scroll/themes/twentyfifteen-rtl.css
new file mode 100644
index 00000000..c7bb9595
--- /dev/null
+++ b/plugins/jetpack/modules/infinite-scroll/themes/twentyfifteen-rtl.css
@@ -0,0 +1,216 @@
+/**
+ * Infinite Scroll
+ */
+
+.infinite-scroll .pagination,
+.infinite-scroll.neverending .site-footer {
+ display: none;
+}
+
+.infinity-end.neverending .site-footer {
+ display: block;
+}
+
+/* Spinner */
+.infinite-loader {
+ clear: both;
+ height: 24px;
+ margin: 24px 0;
+}
+
+.infinite-loader .spinner {
+ top: 50% !important;
+ right: 50% !important;
+}
+
+/* Click-to-load */
+#infinite-handle {
+ clear: both;
+ margin: 7.6923%;
+ text-align: center;
+}
+
+#infinite-handle span {
+ background-color: #333;
+ font-family: "Noto Sans", sans-serif;
+ font-size: 12px;
+ font-size: 1.2rem;
+ font-weight: 700;
+ letter-spacing: 0.04em;
+ line-height: normal;
+ padding: 0.7917em;
+ text-transform: uppercase;
+}
+
+#infinite-handle span:hover,
+#infinite-handle span:focus {
+ background-color: #707070;
+ background-color: rgba(51, 51, 51, 0.7);
+ color: #fff;
+}
+
+/* Footer */
+#infinite-footer {
+ display: none;
+ z-index: 999;
+}
+
+#infinite-footer .container {
+ background-color: #fff;
+ background-color: rgba(255, 255, 255, 0.5);
+ border-color: #eaeaea;
+ border-color: rgba(51, 51, 51, 0.1);
+ padding: 0 0.8em;
+ width: 100% !important;
+}
+
+#infinite-footer .blog-info {
+ font-family: "Noto Sans", sans-serif;
+}
+
+#infinite-footer .blog-info,
+#infinite-footer .blog-credits {
+ height: 24px;
+ line-height: 24px;
+}
+
+#infinite-footer .blog-info a,
+#infinite-footer .blog-credits {
+ font-size: 12px;
+ font-size: 1.2rem;
+}
+
+#infinite-footer .blog-info a,
+#infinite-footer .blog-credits a:hover,
+#infinite-footer .blog-credits a:focus {
+ color: #333;
+}
+
+#infinite-footer .blog-info a:hover,
+#infinite-footer .blog-info a:focus,
+#infinite-footer .blog-credits,
+#infinite-footer .blog-credits a {
+ color: #707070;
+ color: rgba(51, 51, 51, 0.7);
+}
+
+#infinite-footer .blog-info a:hover,
+#infinite-footer .blog-info a:focus,
+#infinite-footer .blog-credits a:hover,
+#infinite-footer .blog-credits a:focus {
+ text-decoration: none;
+}
+
+@media screen and (min-width: 38.75em) {
+ .infinite-loader {
+ margin: 7.6923% 0;
+ }
+
+ .infinite-wrap {
+ margin-top: 7.6923%;
+ }
+
+ #infinite-handle {
+ margin-bottom: 0;
+ }
+}
+
+@media screen and (min-width: 46.25em) {
+ #infinite-handle span {
+ display: block;
+ font-size: 14px;
+ font-size: 1.4rem;
+ padding: 0.8214em
+ }
+}
+
+@media screen and (min-width: 55em) {
+ #infinite-handle span {
+ font-size: 16px;
+ font-size: 1.6rem;
+ padding: 0.8125em;
+ }
+}
+
+@media screen and (min-width: 59.6875em) {
+ .infinite-loader {
+ margin: 8.3333% 0;
+ }
+
+ .infinite-wrap {
+ margin-top: 8.3333%;
+ }
+
+ #infinite-handle {
+ margin: 8.3333% 8.3333% 0;
+ }
+
+ #infinite-handle span {
+ display: inline-block;
+ font-size: 12px;
+ font-size: 1.2rem;
+ padding: 0.7917em 1.5833em;
+ }
+
+ #infinite-footer {
+ display: block;
+ position: fixed;
+ }
+}
+
+@media screen and (min-width: 68.75em) {
+ #infinite-handle span {
+ display: inline-block;
+ font-size: 14px;
+ font-size: 1.4rem;
+ padding: 0.8214em 1.5714em;
+ }
+
+ #infinite-footer .container {
+ padding: 0 0.8235em;
+ }
+
+ #infinite-footer .blog-info,
+ #infinite-footer .blog-credits {
+ height: 27px;
+ line-height: 27px;
+ }
+
+ #infinite-footer .blog-info a {
+ font-size: 14px;
+ font-size: 1.4rem;
+ }
+
+ #infinite-footer .blog-credits {
+ font-size: 12px;
+ font-size: 1.2rem;
+ }
+}
+
+@media screen and (min-width: 77.5em) {
+ #infinite-handle span {
+ font-size: 16px;
+ font-size: 1.6rem;
+ padding: 0.8125em 1.625em;
+ }
+
+ #infinite-footer .container {
+ padding: 0 0.8421em;
+ }
+
+ #infinite-footer .blog-info,
+ #infinite-footer .blog-credits {
+ height: 32px;
+ line-height: 32px;
+ }
+
+ #infinite-footer .blog-info a {
+ font-size: 16px;
+ font-size: 1.6rem;
+ }
+
+ #infinite-footer .blog-credits {
+ font-size: 13px;
+ font-size: 1.3rem;
+ }
+}
diff --git a/plugins/jetpack/modules/infinite-scroll/themes/twentyfifteen.css b/plugins/jetpack/modules/infinite-scroll/themes/twentyfifteen.css
new file mode 100644
index 00000000..17ff0983
--- /dev/null
+++ b/plugins/jetpack/modules/infinite-scroll/themes/twentyfifteen.css
@@ -0,0 +1,216 @@
+/**
+ * Infinite Scroll
+ */
+
+.infinite-scroll .pagination,
+.infinite-scroll.neverending .site-footer {
+ display: none;
+}
+
+.infinity-end.neverending .site-footer {
+ display: block;
+}
+
+/* Spinner */
+.infinite-loader {
+ clear: both;
+ height: 24px;
+ margin: 24px 0;
+}
+
+.infinite-loader .spinner {
+ top: 50% !important;
+ left: 50% !important;
+}
+
+/* Click-to-load */
+#infinite-handle {
+ clear: both;
+ margin: 7.6923%;
+ text-align: center;
+}
+
+#infinite-handle span {
+ background-color: #333;
+ font-family: "Noto Sans", sans-serif;
+ font-size: 12px;
+ font-size: 1.2rem;
+ font-weight: 700;
+ letter-spacing: 0.04em;
+ line-height: normal;
+ padding: 0.7917em;
+ text-transform: uppercase;
+}
+
+#infinite-handle span:hover,
+#infinite-handle span:focus {
+ background-color: #707070;
+ background-color: rgba(51, 51, 51, 0.7);
+ color: #fff;
+}
+
+/* Footer */
+#infinite-footer {
+ display: none;
+ z-index: 999;
+}
+
+#infinite-footer .container {
+ background-color: #fff;
+ background-color: rgba(255, 255, 255, 0.5);
+ border-color: #eaeaea;
+ border-color: rgba(51, 51, 51, 0.1);
+ padding: 0 0.8em;
+ width: 100% !important;
+}
+
+#infinite-footer .blog-info {
+ font-family: "Noto Sans", sans-serif;
+}
+
+#infinite-footer .blog-info,
+#infinite-footer .blog-credits {
+ height: 24px;
+ line-height: 24px;
+}
+
+#infinite-footer .blog-info a,
+#infinite-footer .blog-credits {
+ font-size: 12px;
+ font-size: 1.2rem;
+}
+
+#infinite-footer .blog-info a,
+#infinite-footer .blog-credits a:hover,
+#infinite-footer .blog-credits a:focus {
+ color: #333;
+}
+
+#infinite-footer .blog-info a:hover,
+#infinite-footer .blog-info a:focus,
+#infinite-footer .blog-credits,
+#infinite-footer .blog-credits a {
+ color: #707070;
+ color: rgba(51, 51, 51, 0.7);
+}
+
+#infinite-footer .blog-info a:hover,
+#infinite-footer .blog-info a:focus,
+#infinite-footer .blog-credits a:hover,
+#infinite-footer .blog-credits a:focus {
+ text-decoration: none;
+}
+
+@media screen and (min-width: 38.75em) {
+ .infinite-loader {
+ margin: 7.6923% 0;
+ }
+
+ .infinite-wrap {
+ margin-top: 7.6923%;
+ }
+
+ #infinite-handle {
+ margin-bottom: 0;
+ }
+}
+
+@media screen and (min-width: 46.25em) {
+ #infinite-handle span {
+ display: block;
+ font-size: 14px;
+ font-size: 1.4rem;
+ padding: 0.8214em
+ }
+}
+
+@media screen and (min-width: 55em) {
+ #infinite-handle span {
+ font-size: 16px;
+ font-size: 1.6rem;
+ padding: 0.8125em;
+ }
+}
+
+@media screen and (min-width: 59.6875em) {
+ .infinite-loader {
+ margin: 8.3333% 0;
+ }
+
+ .infinite-wrap {
+ margin-top: 8.3333%;
+ }
+
+ #infinite-handle {
+ margin: 8.3333% 8.3333% 0;
+ }
+
+ #infinite-handle span {
+ display: inline-block;
+ font-size: 12px;
+ font-size: 1.2rem;
+ padding: 0.7917em 1.5833em;
+ }
+
+ #infinite-footer {
+ display: block;
+ position: fixed;
+ }
+}
+
+@media screen and (min-width: 68.75em) {
+ #infinite-handle span {
+ display: inline-block;
+ font-size: 14px;
+ font-size: 1.4rem;
+ padding: 0.8214em 1.5714em;
+ }
+
+ #infinite-footer .container {
+ padding: 0 0.8235em;
+ }
+
+ #infinite-footer .blog-info,
+ #infinite-footer .blog-credits {
+ height: 27px;
+ line-height: 27px;
+ }
+
+ #infinite-footer .blog-info a {
+ font-size: 14px;
+ font-size: 1.4rem;
+ }
+
+ #infinite-footer .blog-credits {
+ font-size: 12px;
+ font-size: 1.2rem;
+ }
+}
+
+@media screen and (min-width: 77.5em) {
+ #infinite-handle span {
+ font-size: 16px;
+ font-size: 1.6rem;
+ padding: 0.8125em 1.625em;
+ }
+
+ #infinite-footer .container {
+ padding: 0 0.8421em;
+ }
+
+ #infinite-footer .blog-info,
+ #infinite-footer .blog-credits {
+ height: 32px;
+ line-height: 32px;
+ }
+
+ #infinite-footer .blog-info a {
+ font-size: 16px;
+ font-size: 1.6rem;
+ }
+
+ #infinite-footer .blog-credits {
+ font-size: 13px;
+ font-size: 1.3rem;
+ }
+}
diff --git a/plugins/jetpack/modules/infinite-scroll/themes/twentyfifteen.php b/plugins/jetpack/modules/infinite-scroll/themes/twentyfifteen.php
new file mode 100644
index 00000000..e47a7c2c
--- /dev/null
+++ b/plugins/jetpack/modules/infinite-scroll/themes/twentyfifteen.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * Infinite Scroll Theme Assets
+ *
+ * Register support for Twenty Fifteen.
+ */
+
+/**
+ * Add theme support for infinite scroll
+ */
+function twentyfifteen_infinite_scroll_init() {
+ add_theme_support( 'infinite-scroll', array(
+ 'container' => 'main',
+ 'footer' => 'page',
+ ) );
+}
+add_action( 'after_setup_theme', 'twentyfifteen_infinite_scroll_init' );
+
+/**
+ * Enqueue CSS stylesheet with theme styles for Infinite Scroll.
+ */
+function twentyfifteen_infinite_scroll_enqueue_styles() {
+ wp_enqueue_style( 'infinity-twentyfifteen', plugins_url( 'twentyfifteen.css', __FILE__ ), array( 'the-neverending-homepage' ), '20141022' );
+ wp_style_add_data( 'infinity-twentyfifteen', 'rtl', 'replace' );
+}
+add_action( 'wp_enqueue_scripts', 'twentyfifteen_infinite_scroll_enqueue_styles', 25 );
diff --git a/plugins/jetpack/modules/infinite-scroll/themes/twentyfourteen.css b/plugins/jetpack/modules/infinite-scroll/themes/twentyfourteen.css
new file mode 100644
index 00000000..8fb5647e
--- /dev/null
+++ b/plugins/jetpack/modules/infinite-scroll/themes/twentyfourteen.css
@@ -0,0 +1,111 @@
+/* Spinner */
+
+.infinite-loader {
+ height: 36px;
+ padding: 24px 0;
+}
+
+.infinite-loader .spinner {
+ margin: 0 auto;
+ top: 18px !important;
+ left: 0 !important;
+}
+
+.rtl .infinite-loader .spinner {
+ right: 0 !important;
+ left: auto !important;
+}
+
+/* Click-to-load */
+
+#infinite-handle {
+ padding: 24px 0;
+ text-align: center;
+}
+
+#infinite-handle span {
+ background: #24890d;
+ border-radius: 2px;
+ display: inline-block;
+ color: #fff;
+ font-size: 12px;
+ font-weight: 700;
+ line-height: 1;
+ padding: 12px 30px;
+ text-transform: uppercase;
+}
+
+#infinite-handle span:hover {
+ background-color: #41a62a;
+}
+
+#infinite-handle span:active {
+ background-color: #55d737;
+}
+
+/* Footer */
+
+#infinite-footer {
+ z-index: 2;
+}
+
+#infinite-footer .container {
+ margin: 0;
+ padding: 4px 20px;
+}
+
+#infinite-footer .blog-info a {
+ color: #2b2b2b;
+}
+
+#infinite-footer .blog-credits,
+#infinite-footer .blog-credits a {
+ color: #767676;
+}
+
+#infinite-footer .blog-info a:hover,
+#infinite-footer .blog-credits a:hover {
+ color: #41a62a;
+ text-decoration: none;
+}
+
+/* Elements to hide: post navigation, normal footer. */
+
+.infinite-scroll .paging-navigation,
+.infinite-scroll.neverending #colophon {
+ display: none;
+}
+
+@media (max-width: 640px) {
+ #infinite-footer {
+ display: none;
+ }
+}
+
+/* Hooks to infinity-end body class to restore footer. */
+
+.infinity-end.neverending #colophon {
+ display: block;
+}
+
+/* Reset top margin adjustment for subsequent posts added by Infinite Scroll */
+.full-width .site-content .infinite-wrap .hentry.has-post-thumbnail:first-child {
+ margin-top: 0;
+}
+
+@media screen and (min-width: 401px) {
+ .infinite-loader,
+ #infinite-handle {
+ padding: 0 0 48px;
+ }
+
+ .list-view .site-content .infinite-wrap .hentry:first-of-type {
+ border-top: 1px solid rgba(0, 0, 0, 0.1);
+ padding-top: 48px;
+ }
+
+ .list-view .site-content .infinite-wrap .hentry.has-post-thumbnail {
+ border-top: 0;
+ padding-top: 0;
+ }
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/infinite-scroll/themes/twentyfourteen.php b/plugins/jetpack/modules/infinite-scroll/themes/twentyfourteen.php
new file mode 100644
index 00000000..f6ddc700
--- /dev/null
+++ b/plugins/jetpack/modules/infinite-scroll/themes/twentyfourteen.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Infinite Scroll Theme Assets
+ *
+ * Register support for Twenty Fourteen.
+ */
+
+/**
+ * Add theme support for infinite scroll
+ */
+function twentyfourteen_infinite_scroll_init() {
+ add_theme_support( 'infinite-scroll', array(
+ 'container' => 'content',
+ 'footer' => 'page'
+ ) );
+}
+add_action( 'after_setup_theme', 'twentyfourteen_infinite_scroll_init' );
+
+/**
+ * Switch to the "click to load" type IS with the following cases
+ * 1. Viewed from iPad and the primary sidebar is active.
+ * 2. Viewed from mobile and either the primary or the content sudebar is active.
+ * 3. The footer widget is active.
+ *
+ * @return bool
+ */
+
+if ( function_exists( 'jetpack_is_mobile' ) ) {
+ function twentyfourteen_has_footer_widgets( $has_widgets ) {
+ if ( ( Jetpack_User_Agent_Info::is_ipad() && is_active_sidebar( 'sidebar-1' ) )
+ || ( jetpack_is_mobile( '', true ) && ( is_active_sidebar( 'sidebar-1' ) || is_active_sidebar( 'sidebar-2' ) ) )
+ || is_active_sidebar( 'sidebar-3' ) )
+
+ return true;
+
+ return $has_widgets;
+ }
+ add_filter( 'infinite_scroll_has_footer_widgets', 'twentyfourteen_has_footer_widgets' );
+}
+
+/**
+ * Enqueue CSS stylesheet with theme styles for Infinite Scroll.
+ */
+function twentyfourteen_infinite_scroll_enqueue_styles() {
+ wp_enqueue_style( 'infinity-twentyfourteen', plugins_url( 'twentyfourteen.css', __FILE__ ), array( 'the-neverending-homepage' ), '20131118' );
+}
+add_action( 'wp_enqueue_scripts', 'twentyfourteen_infinite_scroll_enqueue_styles', 25 ); \ No newline at end of file
diff --git a/plugins/jetpack/modules/json-api.php b/plugins/jetpack/modules/json-api.php
index 233d56a9..87b4d702 100644
--- a/plugins/jetpack/modules/json-api.php
+++ b/plugins/jetpack/modules/json-api.php
@@ -2,20 +2,12 @@
/**
* Module Name: JSON API
* Module Description: Allow applications to securely access your content through the cloud.
- * Sort Order: 100
+ * Sort Order: 19
* First Introduced: 1.9
* Requires Connection: Yes
* Auto Activate: Public
+ * Module Tags: Writing, Developers
*/
-function jetpack_json_api_toggle() {
- $jetpack = Jetpack::init();
- $jetpack->sync->register( 'noop' );
-
- if ( false !== strpos( current_filter(), 'jetpack_activate_module_' ) ) {
- Jetpack::check_privacy( __FILE__ );
- }
-}
-
-add_action( 'jetpack_activate_module_json-api', 'jetpack_json_api_toggle' );
-add_action( 'jetpack_deactivate_module_json-api', 'jetpack_json_api_toggle' );
+add_action( 'jetpack_activate_module_json-api', array( Jetpack::init(), 'toggle_module_on_wpcom' ) );
+add_action( 'jetpack_deactivate_module_json-api', array( Jetpack::init(), 'toggle_module_on_wpcom' ) );
diff --git a/plugins/jetpack/modules/latex.php b/plugins/jetpack/modules/latex.php
index 2c90ba8b..5841257f 100644
--- a/plugins/jetpack/modules/latex.php
+++ b/plugins/jetpack/modules/latex.php
@@ -1,11 +1,12 @@
<?php
/**
* Module Name: Beautiful Math
- * Module Description: Mark up your posts with the <img src="//s0.wp.com/latex.php?latex=%5CLaTeX&amp;bg=transparent&amp;fg=000&amp;s=-2" alt="LaTeX logo" title="LaTeX" style="vertical-align: -25%" /> markup language, perfect for complex mathematical equations and other &#252;ber-geekery.
+ * Module Description: Use LaTeX markup language in posts and pages for complex equations and other geekery.
* Sort Order: 12
* First Introduced: 1.1
* Requires Connection: No
* Auto Activate: Yes
+ * Module Tags: Writing
*/
/**
@@ -84,7 +85,7 @@ function latex_shortcode( $atts, $content = '' ) {
's' => 0,
'bg' => latex_get_default_color( 'bg' ),
'fg' => latex_get_default_color( 'text', '000' )
- ), $atts ) );
+ ), $atts, 'latex' ) );
return latex_render( latex_entity_decode( $content ), $fg, $bg, $s );
}
diff --git a/plugins/jetpack/modules/likes.php b/plugins/jetpack/modules/likes.php
index 24e83ae2..e9bd71c5 100644
--- a/plugins/jetpack/modules/likes.php
+++ b/plugins/jetpack/modules/likes.php
@@ -1,14 +1,24 @@
<?php
/**
* Module Name: Likes
- * Module Description: Likes are a way for people to show their appreciation for content you have written. It’s also a way for you to show the world how popular your content has become.
+ * Module Description: Give visitors an easy way to show their appreciation for your content.
* First Introduced: 2.2
- * Sort Order: 4
+ * Sort Order: 23
* Requires Connection: Yes
* Auto Activate: No
+ * Module Tags: Social
*/
+
+Jetpack::dns_prefetch( array(
+ '//widgets.wp.com',
+ '//s0.wp.com',
+ '//0.gravatar.com',
+ '//1.gravatar.com',
+ '//2.gravatar.com',
+) );
+
class Jetpack_Likes {
- var $version = '20130620a';
+ var $version = '20141028';
public static function init() {
static $instance = NULL;
@@ -27,6 +37,7 @@ class Jetpack_Likes {
add_action( 'admin_init', array( $this, 'admin_init' ) );
if ( $this->in_jetpack ) {
+ add_action( 'jetpack_activate_module_likes', array( $this, 'maybe_sync_content' ) );
add_action( 'jetpack_activate_module_likes', array( $this, 'module_toggle' ) );
add_action( 'jetpack_deactivate_module_likes', array( $this, 'module_toggle' ) );
@@ -60,6 +71,7 @@ class Jetpack_Likes {
Jetpack_Sync::sync_options( __FILE__, 'social_notifications_like' );
} else { // wpcom
+ add_action( 'wpmu_new_blog', array( $this, 'enable_comment_likes' ), 10, 1 );
add_action( 'admin_init', array( $this, 'add_meta_box' ) );
add_action( 'end_likes_meta_box_content', array( $this, 'sharing_meta_box_content' ) );
add_filter( 'likes_meta_box_title', array( $this, 'add_likes_to_sharing_meta_box_title' ) );
@@ -69,11 +81,20 @@ class Jetpack_Likes {
add_action( 'admin_bar_menu', array( $this, 'admin_bar_likes' ), 60 );
+ add_action( 'wp_enqueue_scripts', array( $this, 'load_styles_register_scripts' ) );
+
add_action( 'save_post', array( $this, 'meta_box_save' ) );
+ add_action( 'edit_attachment', array( $this, 'meta_box_save' ) );
add_action( 'sharing_global_options', array( $this, 'admin_settings_init' ), 20 );
add_action( 'sharing_admin_update', array( $this, 'admin_settings_callback' ), 20 );
}
+ function maybe_sync_content() {
+ if ( Jetpack::init()->sync->reindex_needed() ) {
+ Jetpack::init()->sync->reindex_trigger();
+ }
+ }
+
function module_toggle() {
$jetpack = Jetpack::init();
$jetpack->sync->register( 'noop' );
@@ -91,7 +112,19 @@ class Jetpack_Likes {
* Loads Jetpack's CSS on the sharing page so we can use .jetpack-targetable
*/
function load_jp_css() {
- Jetpack::init()->admin_styles();
+ // Do we really need `admin_styles`? With the new admin UI, it's breaking some bits.
+ // Jetpack::init()->admin_styles();
+ }
+ /**
+ * Load style on the front end.
+ * @return null
+ */
+ function load_styles_register_scripts() {
+
+ wp_enqueue_style( 'jetpack_likes', plugins_url( 'likes/style.css', __FILE__ ), array(), JETPACK__VERSION );
+ if( $this->in_jetpack ) {
+ $this->register_scripts();
+ }
}
/**
@@ -130,10 +163,13 @@ class Jetpack_Likes {
if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE )
return $post_id;
+ if ( empty( $_POST['wpl_like_status_hidden'] ) )
+ return $post_id;
+
// Record sharing disable. Only needs to be done for WPCOM
if ( ! $this->in_jetpack ) {
- if ( isset( $_POST['post_type'] ) && ( 'post' == $_POST['post_type'] || 'page' == $_POST['post_type'] ) ) {
- if ( isset( $_POST['wpl_sharing_status_hidden'] ) && !isset( $_POST['wpl_enable_post_sharing'] ) ) {
+ if ( isset( $_POST['post_type'] ) && in_array( $_POST['post_type'], get_post_types( array( 'public' => true ) ) ) ) {
+ if ( ! isset( $_POST['wpl_enable_post_sharing'] ) ) {
update_post_meta( $post_id, 'sharing_disabled', 1 );
} else {
delete_post_meta( $post_id, 'sharing_disabled' );
@@ -141,9 +177,6 @@ class Jetpack_Likes {
}
}
- if ( empty( $_POST['wpl_like_status_hidden'] ) )
- return $post_id;
-
if ( 'post' == $_POST['post_type'] ) {
if ( !current_user_can( 'edit_post', $post_id ) ) {
return $post_id;
@@ -154,7 +187,7 @@ class Jetpack_Likes {
// site like setting.
if ( ( $this->is_enabled_sitewide() && empty( $_POST['wpl_enable_post_likes'] ) ) || ( ! $this->is_enabled_sitewide() && !empty( $_POST['wpl_enable_post_likes'] ) ) ) {
update_post_meta( $post_id, 'switch_like_status', 1 );
- //$g_gif = file_get_contents( 'http://stats.wordpress.com/g.gif?v=wpcom-no-pv&x_likes=switched_post_like_status' ); @todo stat
+ //$g_gif = file_get_contents( 'http://pixel.wp.com/g.gif?v=wpcom-no-pv&x_likes=switched_post_like_status' ); @todo stat
} else {
delete_post_meta( $post_id, 'switch_like_status' );
}
@@ -237,9 +270,9 @@ class Jetpack_Likes {
function admin_likes_get_option( $option ) {
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
- $option_setting = get_blog_option( get_current_blog_id(), $option );
+ $option_setting = get_blog_option( get_current_blog_id(), $option, 'on' );
} else {
- $option_setting = get_option( $option );
+ $option_setting = get_option( $option, 'on' );
}
return intval( 'on' == $option_setting );
@@ -283,20 +316,41 @@ class Jetpack_Likes {
</label>
<div>
</td>
- </tr> <?php /*
+ </tr>
+ <?php if ( ! $this->in_jetpack ) : ?>
+ <tr>
+ <th scope="row">
+ <label><?php esc_html_e( 'WordPress.com Reblog Button', 'jetpack' ); ?></label>
+ </th>
+ <td>
+ <div>
+ <label>
+ <input type="radio" class="code" name="jetpack_reblogs_enabled" value="on" <?php checked( $this->reblogs_enabled_sitewide(), true ); ?> />
+ <?php esc_html_e( 'Show the Reblog button on posts', 'jetpack' ); ?>
+ </label>
+ </div>
+ <div>
+ <label>
+ <input type="radio" class="code" name="jetpack_reblogs_enabled" value="off" <?php checked( $this->reblogs_enabled_sitewide(), false ); ?> />
+ <?php esc_html_e( 'Don\'t show the Reblog button on posts', 'jetpack' ); ?>
+ </label>
+ <div>
+ </td>
+ </tr>
<tr>
<th scope="row">
- <label><?php esc_html_e( 'Comment Likes', 'jetpack' ); ?></label>
+ <label><?php esc_html_e( 'Comment Likes are', 'jetpack' ); ?></label>
</th>
<td>
<div>
<label>
<input type="checkbox" class="code" name="jetpack_comment_likes_enabled" value="1" <?php checked( $this->is_comments_enabled(), true ); ?> />
- <?php esc_html_e( 'Allow people to like comments', 'jetpack' ); ?>
+ <?php esc_html_e( 'On for all comments', 'jetpack' ); ?>
</label>
</div>
</td>
- </tr> */ ?>
+ </tr>
+ <?php endif; ?>
</tbody> <?php // closes the tbody attached to sharing_show_buttons_on_row_start... ?>
<?php }
@@ -370,6 +424,7 @@ class Jetpack_Likes {
function process_update_requests_if_sharedaddy_not_loaded() {
if ( isset( $_GET['page'] ) && ( $_GET['page'] == 'sharing.php' || $_GET['page'] == 'sharing' ) ) {
if ( isset( $_POST['_wpnonce'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'sharing-options' ) ) {
+ /** This action is documented in modules/sharedaddy/sharing.php */
do_action( 'sharing_admin_update' );
wp_safe_redirect( admin_url( 'options-general.php?page=sharing&update=saved' ) );
die();
@@ -386,25 +441,42 @@ class Jetpack_Likes {
$new_state = !empty( $_POST['wpl_default'] ) ? $_POST['wpl_default'] : 'on';
$db_state = $this->is_enabled_sitewide();
+ $reblogs_new_state = !empty( $_POST['jetpack_reblogs_enabled'] ) ? $_POST['jetpack_reblogs_enabled'] : 'on';
+ $reblogs_db_state = $this->reblogs_enabled_sitewide();
/** Default State *********************************************************/
// Checked (enabled)
switch( $new_state ) {
case 'off' :
if ( true == $db_state && ! $this->in_jetpack ) {
- $g_gif = file_get_contents( 'http://stats.wordpress.com/g.gif?v=wpcom-no-pv&x_likes=disabled_likes' );
+ $g_gif = file_get_contents( 'http://pixel.wp.com/g.gif?v=wpcom-no-pv&x_likes=disabled_likes' );
}
update_option( 'disabled_likes', 1 );
break;
case 'on' :
default:
if ( false == $db_state && ! $this->in_jetpack ) {
- $g_gif = file_get_contents( 'http://stats.wordpress.com/g.gif?v=wpcom-no-pv&x_likes=reenabled_likes' );
+ $g_gif = file_get_contents( 'http://pixel.wp.com/g.gif?v=wpcom-no-pv&x_likes=reenabled_likes' );
}
delete_option( 'disabled_likes' );
break;
}
+ switch( $reblogs_new_state ) {
+ case 'off' :
+ if ( true == $reblogs_db_state && ! $this->in_jetpack ) {
+ $g_gif = file_get_contents( 'http://pixel.wp.com/g.gif?v=wpcom-no-pv&x_reblogs=disabled_reblogs' );
+ }
+ update_option( 'disabled_reblogs', 1 );
+ break;
+ case 'on' :
+ default:
+ if ( false == $reblogs_db_state && ! $this->in_jetpack ) {
+ $g_gif = file_get_contents( 'http://pixel.wp.com/g.gif?v=wpcom-no-pv&x_reblogs=reenabled_reblogs' );
+ }
+ delete_option( 'disabled_reblogs' );
+ break;
+ }
// comment setting
$new_comments_state = !empty( $_POST['jetpack_comment_likes_enabled'] ) ? $_POST['jetpack_comment_likes_enabled'] : false;
@@ -420,6 +492,16 @@ class Jetpack_Likes {
}
/**
+ * Force comment likes on for a blog
+ * Used when a new blog is created
+ */
+ function enable_comment_likes( $blog_id ) {
+ switch_to_blog( $blog_id );
+ update_option( 'jetpack_comment_likes_enabled', 1 );
+ restore_current_blog();
+ }
+
+ /**
* Adds the 'sharing' menu to the settings menu.
* Only ran if sharedaddy and publicize are not already active.
*/
@@ -458,7 +540,10 @@ class Jetpack_Likes {
<form method="post" action="">
<table class="form-table">
<tbody>
- <?php do_action( 'sharing_global_options' ); ?>
+ <?php
+ /** This action is documented in modules/sharedaddy/sharing.php */
+ do_action( 'sharing_global_options' );
+ ?>
</tbody>
</table>
@@ -477,28 +562,31 @@ class Jetpack_Likes {
add_action( 'manage_pages_custom_column', array( $this, 'likes_edit_column' ), 10, 2 );
add_action( 'admin_print_styles-edit.php', array( $this, 'load_admin_css' ) );
add_action( "admin_print_scripts-edit.php", array( $this, 'enqueue_admin_scripts' ) );
+
+ if ( $this->in_jetpack ) {
+ Jetpack_Sync::sync_posts( __FILE__ );
+ }
}
function action_init() {
- if ( is_admin() )
+ if ( is_admin() ) {
return;
+ }
if ( ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) ||
( defined( 'APP_REQUEST' ) && APP_REQUEST ) ||
( defined( 'REST_API_REQUEST' ) && REST_API_REQUEST ) ||
( defined( 'COOKIE_AUTH_REQUEST' ) && COOKIE_AUTH_REQUEST ) ||
- ( defined( 'JABBER_SERVER' ) && JABBER_SERVER ) )
+ ( defined( 'JABBER_SERVER' ) && JABBER_SERVER ) ) {
return;
+ }
// Comment Likes widget has been disabled, pending performance improvements.
// add_filter( 'comment_text', array( &$this, 'comment_likes' ), 10, 2 );
if ( $this->in_jetpack ) {
add_filter( 'the_content', array( &$this, 'post_likes' ), 30, 1 );
- wp_enqueue_script( 'postmessage', plugins_url( '_inc/postmessage.js', dirname(__FILE__) ), array( 'jquery' ), JETPACK__VERSION, false );
- wp_enqueue_script( 'jquery_inview', plugins_url( '_inc/jquery.inview.js', dirname(__FILE__) ), array( 'jquery' ), JETPACK__VERSION, false );
- wp_enqueue_script( 'jetpack_resize', plugins_url( '_inc/jquery.jetpack-resize.js' , dirname(__FILE__) ), array( 'jquery' ), JETPACK__VERSION, false );
- wp_enqueue_style( 'jetpack_likes', plugins_url( 'likes/style.css', __FILE__ ), array(), JETPACK__VERSION );
+ add_filter( 'the_excerpt', array( &$this, 'post_likes' ), 30, 1 );
} else {
add_filter( 'post_flair', array( &$this, 'post_likes' ), 30, 1 );
@@ -507,26 +595,55 @@ class Jetpack_Likes {
wp_enqueue_script( 'postmessage', '/wp-content/js/postmessage.js', array( 'jquery' ), JETPACK__VERSION, false );
wp_enqueue_script( 'jquery_inview', '/wp-content/js/jquery/jquery.inview.js', array( 'jquery' ), JETPACK__VERSION, false );
wp_enqueue_script( 'jetpack_resize', '/wp-content/js/jquery/jquery.jetpack-resize.js', array( 'jquery' ), JETPACK__VERSION, false );
- wp_enqueue_style( 'jetpack_likes', plugins_url( 'jetpack-likes.css', __FILE__ ), array(), JETPACK__VERSION );
+
+
+ // @todo: Remove this opt-out filter in the future
+ if ( apply_filters( 'wpl_sharing_2014_1', true ) ) {
+ wp_enqueue_style( 'jetpack_likes', plugins_url( 'jetpack-likes.css', __FILE__ ), array(), JETPACK__VERSION );
+ } else {
+ wp_enqueue_style( 'jetpack_likes', plugins_url( 'jetpack-likes-legacy.css', __FILE__ ), array(), JETPACK__VERSION );
+ }
}
}
/**
+ * Register scripts
+ */
+ function register_scripts() {
+ // Lets register all the sciprts
+ wp_register_script( 'postmessage', plugins_url( '_inc/postmessage.js', dirname(__FILE__) ), array( 'jquery' ), JETPACK__VERSION, false );
+ wp_register_script( 'jquery_inview', plugins_url( '_inc/jquery.inview.js', dirname(__FILE__) ), array( 'jquery' ), JETPACK__VERSION, false );
+ wp_register_script( 'jetpack_resize', plugins_url( '_inc/jquery.jetpack-resize.js' , dirname(__FILE__) ), array( 'jquery' ), JETPACK__VERSION, false );
+ wp_register_script( 'jetpack_likes_queuehandler', plugins_url( 'likes/queuehandler.js' , __FILE__ ), array( 'jquery', 'postmessage', 'jetpack_resize', 'jquery_inview' ), JETPACK__VERSION, true );
+ }
+
+ /**
* Load the CSS needed for the wp-admin area.
*/
- function load_admin_css() { ?>
+ function load_admin_css() {
+ ?>
<style type="text/css">
.fixed .column-likes { width: 5em; padding-top: 8px; text-align: center !important; }
.fixed .column-stats { width: 5em; }
.fixed .column-likes .post-com-count { background-image: none; }
- .fixed .column-likes .comment-count { background-color: #888; }
- .fixed .column-likes .comment-count:hover { background-color: #D54E21; }
- .mp6 .fixed .column-likes .post-com-count::after { border: none !important; }
- .mp6 .fixed .column-likes .comment-count { background-color: #bbb; }
- .mp6 .fixed .column-likes .comment-count:hover { background-color: #2ea2cc; }
- .mp6 .fixed .column-likes .vers img { display: none; }
- .mp6 .fixed .column-likes .vers:before {font:20px/1 dashicons;content: '\f155';-webkit-font-smoothing:antialiased;}
- </style> <?php
+ .fixed .column-likes .post-com-count::after { border: none !important; }
+ .fixed .column-likes .comment-count { background-color: #bbb; }
+ .fixed .column-likes .comment-count:hover { background-color: #2ea2cc; }
+ .fixed .column-likes .vers img { display: none; }
+ .fixed .column-likes .vers:before {
+ font: normal 20px/1 dashicons;
+ content: '\f155';
+ speak: none;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ }
+ @media screen and (max-width: 782px) {
+ .fixed .column-likes {
+ display: none;
+ }
+ }
+ </style>
+ <?php
}
/**
@@ -600,8 +717,8 @@ class Jetpack_Likes {
$url_parts = parse_url( $url );
$domain = $url_parts['host'];
}
-
- add_filter( 'wp_footer', array( $this, 'likes_master' ) );
+ // make sure to include the scripts before the iframe otherwise weird things happen
+ add_action( 'wp_footer', array( $this, 'likes_master' ), 21 );
/**
* if the same post appears more then once on a page the page goes crazy
@@ -614,10 +731,13 @@ class Jetpack_Likes {
$wrapper = sprintf( 'like-post-wrapper-%1$d-%2$d-%3$s', $blog_id, $post->ID, $uniqid );
$html = "<div class='sharedaddy sd-block sd-like jetpack-likes-widget-wrapper jetpack-likes-widget-unloaded' id='$wrapper' data-src='$src' data-name='$name'><h3 class='sd-title'>" . esc_html__( 'Like this:', 'jetpack' ) . '</h3>';
- $html .= "<div class='post-likes-widget-placeholder' style='height:55px'><span class='button'><span>" . esc_html__( 'Like', 'jetpack' ) . '</span></span> <span class="loading">' . esc_html__( 'Loading...', 'jetpack' ) . '</span></div>';
+ $html .= "<div class='likes-widget-placeholder post-likes-widget-placeholder' style='height:55px'><span class='button'><span>" . esc_html__( 'Like', 'jetpack' ) . '</span></span> <span class="loading">' . esc_html__( 'Loading...', 'jetpack' ) . '</span></div>';
$html .= "<span class='sd-text-color'></span><a class='sd-link-color'></a>";
$html .= '</div>';
+ // Lets make sure that the script is enqued
+ wp_enqueue_script( 'jetpack_likes_queuehandler' );
+
return $content . $html;
}
@@ -642,8 +762,8 @@ class Jetpack_Likes {
$url_parts = parse_url( $url );
$domain = $url_parts['host'];
}
-
- add_filter( 'wp_footer', array( $this, 'likes_master' ) );
+ // make sure to include the scripts before the iframe otherwise weird things happen
+ add_action( 'wp_footer', array( $this, 'likes_master' ), 21 );
$src = sprintf( '%1$s://widgets.wp.com/likes/#blog_id=%2$d&amp;comment_id=%3$d&amp;origin=%1$s://%4$s', $protocol, $blog_id, $comment->comment_ID, $domain );
$name = sprintf( 'like-comment-frame-%1$d-%2$d', $blog_id, $comment->comment_ID );
@@ -681,9 +801,9 @@ class Jetpack_Likes {
$url_parts = parse_url( $url );
$domain = $url_parts['host'];
}
+ // make sure to include the scripts before the iframe otherwise weird things happen
+ add_action( 'wp_footer', array( $this, 'likes_master' ), 21 );
- add_filter( 'wp_footer', array( $this, 'likes_master' ) );
-
$src = sprintf( '%1$s://widgets.wp.com/likes/#blog_id=%2$d&amp;post_id=%3$d&amp;origin=%1$s://%4$s', $protocol, $blog_id, $post->ID, $domain );
$html = "<iframe class='admin-bar-likes-widget jetpack-likes-widget' scrolling='no' frameBorder='0' name='admin-bar-likes-widget' src='$src'></iframe>";
@@ -698,233 +818,47 @@ class Jetpack_Likes {
$wp_admin_bar->add_node( $node );
}
+ /**
+ * This function needs to get loaded after the scripts get added to the page.
+ *
+ */
function likes_master() {
$protocol = 'http';
if ( is_ssl() )
$protocol = 'https';
- $locale = ( '' == get_locale() || 'en' == get_locale() ) ? '' : '&amp;lang=' . strtolower( substr( get_locale(), 0, 2 ) );
- $src = sprintf( '%1$s://widgets.wp.com/likes/master.html?ver=%2$s#ver=%2$s%3$s&amp;mp6=%4$d', $protocol, $this->version, $locale, apply_filters( 'mp6_enabled', 0 ) );
-
- $likersText = wp_kses( __( '<span>%d</span> bloggers like this:', 'jetpack' ), array( 'span' => array() ) );
-?>
- <iframe src='<?php echo $src; ?>' scrolling='no' id='likes-master' name='likes-master' style='display:none;'></iframe>
- <div id='likes-other-gravatars'><div class="likes-text"><?php echo $likersText; ?></div><ul class="wpl-avatars sd-like-gravatars"></ul></div>
- <script type="text/javascript">
- //<![CDATA[
- var jetpackLikesWidgetQueue = [];
- var jetpackLikesMasterReady = false;
-
- function JetpackLikespostMessage( message, target ) {
- if ( "string" === typeof message ){
- try{
- message = JSON.parse( message );
- }
- catch(e) {
- return;
- }
- }
-
- pm( {
- target: target,
- type: 'likesMessage',
- data: message,
- origin: '*'
- } );
- }
-
- function JetpackLikesMessageListener( event ) {
- if ( "undefined" == typeof event.event )
- return;
-
- if ( 'masterReady' == event.event ) {
- jQuery( document ).ready( function() {
- jetpackLikesMasterReady = true;
-
- var stylesData = {
- event: 'injectStyles'
- };
-
- if ( jQuery( 'iframe.admin-bar-likes-widget' ).length > 0 ) {
- JetpackLikespostMessage( { event: 'adminBarEnabled' }, window.frames[ 'likes-master' ] );
-
- stylesData.adminBarStyles = {
- background: jQuery( '#wpadminbar .quicklinks li#wp-admin-bar-wpl-like > a' ).css( 'background' )
- };
- }
-
- if ( !window.addEventListener )
- jQuery( '#wp-admin-bar-admin-bar-likes-widget' ).hide();
-
- stylesData.textStyles = {
- color: jQuery( '.sd-text-color').css( 'color' ),
- fontFamily: jQuery( '.sd-text-color' ).css( 'font-family' ),
- fontSize: jQuery( '.sd-text-color' ).css( 'font-size' ),
- direction: jQuery( '.sd-text-color' ).css( 'direction' ),
- fontWeight: jQuery( '.sd-text-color' ).css( 'font-weight' ),
- fontStyle: jQuery( '.sd-text-color' ).css( 'font-style' ),
- textDecoration: jQuery( '.sd-text-color' ).css('text-decoration')
- };
-
- stylesData.linkStyles = {
- color: jQuery( '.sd-link-color' ).css('color'),
- fontFamily: jQuery( '.sd-link-color' ).css('font-family'),
- fontSize: jQuery( '.sd-link-color' ).css('font-size'),
- textDecoration: jQuery( '.sd-link-color' ).css('text-decoration'),
- fontWeight: jQuery( '.sd-link-color' ).css( 'font-weight' ),
- fontStyle: jQuery( '.sd-link-color' ).css( 'font-style' )
- };
-
- JetpackLikespostMessage( stylesData, window.frames[ 'likes-master' ] );
-
- var requests = [];
- jQuery( '.jetpack-likes-widget-wrapper' ).each( function( i ) {
- var regex = /like-(post|comment)-wrapper-(\d+)-(\d+)-(\w+)/;
- var match = regex.exec( this.id );
- if ( ! match || match.length != 5 )
- return;
-
- var info = {
- blog_id: match[2],
- width: this.width
- };
-
- if ( 'post' == match[1] ) {
- info.post_id = match[3];
- } else if ( 'comment' == match[1] ) {
- info.comment_id = match[3];
- }
-
- info.obj_id = match[4];
-
- requests.push( info );
- });
-
- JetpackLikespostMessage( { event: 'initialBatch', requests: requests }, window.frames['likes-master'] );
-
- jQuery( document ).on( 'inview', 'div.jetpack-likes-widget-unloaded', function() {
- jetpackLikesWidgetQueue.push( this.id );
- });
- });
- }
-
- if ( 'showLikeWidget' == event.event ) {
- setTimeout( JetpackLikesWidgetQueueHandler, 10 );
- jQuery( '#' + event.id + ' .post-likes-widget-placeholder' ).fadeOut( 'fast', function() {
- jQuery( '#' + event.id + ' .post-likes-widget' ).fadeIn( 'fast', function() {
- JetpackLikespostMessage( { event: 'likeWidgetDisplayed', blog_id: event.blog_id, post_id: event.post_id, obj_id: event.obj_id }, window.frames['likes-master'] );
- });
- });
- }
-
- if ( 'showOtherGravatars' == event.event ) {
- var $container = jQuery( '#likes-other-gravatars' );
- var $list = $container.find( 'ul' );
-
- $container.hide();
- $list.html( '' );
-
- $container.find( '.likes-text span' ).text( event.total );
-
- jQuery.each( event.likers, function( i, liker ) {
- $list.append( '<li class="' + liker.css_class + '"><a href="' + liker.profile_URL + '" class="wpl-liker" rel="nofollow" target="_parent"><img src="' + liker.avatar_URL + '" alt="' + liker.name + '" width="30" height="30" style="padding-right: 3px;" /></a></li>');
- } );
-
- var offset = jQuery( "[name='" + event.parent + "']" ).offset();
-
- $container.css( 'left', offset.left + event.position.left - 10 + 'px' );
- $container.css( 'top', offset.top + event.position.top - 33 + 'px' );
-
- var rowLength = Math.floor( event.width / 37 );
- var height = ( Math.ceil( event.likers.length / rowLength ) * 37 ) + 13;
- if ( height > 204 ) {
- height = 204;
- }
-
- $container.css( 'height', height + 'px' );
- $container.css( 'width', rowLength * 37 - 7 + 'px' );
-
- $list.css( 'width', rowLength * 37 + 'px' );
+ if ( version_compare( $GLOBALS['wp_version'], '3.8-alpha', '>=' ) ) {
+ add_filter( 'mp6_enabled', '__return_true', 97 );
+ }
- $container.fadeIn( 'slow' );
+ $_locale = get_locale();
- var scrollbarWidth = $list[0].offsetWidth - $list[0].clientWidth;
- if ( scrollbarWidth > 0 ) {
- $container.width( $container.width() + scrollbarWidth );
- $list.width( $list.width() + scrollbarWidth );
- }
- }
+ // We have to account for WP.org vs WP.com locale divergence
+ if ( $this->in_jetpack ) {
+ if ( ! defined( 'JETPACK__GLOTPRESS_LOCALES_PATH' ) || ! file_exists( JETPACK__GLOTPRESS_LOCALES_PATH ) ) {
+ return false;
}
- pm.bind( 'likesMessage', function(e) { JetpackLikesMessageListener(e); } );
-
- jQuery( document ).click( function( e ) {
- var $container = jQuery( '#likes-other-gravatars' );
-
- if ( $container.has( e.target ).length === 0 ) {
- $container.fadeOut( 'slow' );
- }
- });
-
- function JetpackLikesWidgetQueueHandler() {
- var wrapperID;
- if ( ! jetpackLikesMasterReady ) {
- setTimeout( JetpackLikesWidgetQueueHandler, 500 );
- return;
- }
+ require_once JETPACK__GLOTPRESS_LOCALES_PATH;
- if ( jetpackLikesWidgetQueue.length > 0 ) {
- // We may have a widget that needs creating now
- var found = false;
- while( jetpackLikesWidgetQueue.length > 0 ) {
- // Grab the first member of the queue that isn't already loading.
- wrapperID = jetpackLikesWidgetQueue.splice( 0, 1 )[0];
- if ( jQuery( '#' + wrapperID ).hasClass( 'jetpack-likes-widget-unloaded' ) ) {
- found = true;
- break;
- }
- }
- if ( ! found ) {
- setTimeout( JetpackLikesWidgetQueueHandler, 500 );
- return;
- }
- } else if ( jQuery( 'div.jetpack-likes-widget-unloaded' ).length > 0 ) {
- // Get the next unloaded widget
- wrapperID = jQuery( 'div.jetpack-likes-widget-unloaded' ).first()[0].id;
- if ( ! wrapperID ) {
- // Everything is currently loaded
- setTimeout( JetpackLikesWidgetQueueHandler, 500 );
- return;
- }
- }
-
- var $wrapper = jQuery( '#' + wrapperID );
- $wrapper.find( 'iframe' ).remove();
-
- if ( $wrapper.hasClass( 'slim-likes-widget' ) ) {
- $wrapper.find( '.post-likes-widget-placeholder' ).after( "<iframe class='post-likes-widget jetpack-likes-widget' name='" + $wrapper.data( 'name' ) + "' height='22px' width='68px' frameBorder='0' scrolling='no' src='" + $wrapper.data( 'src' ) + "'></iframe>" );
- } else {
- $wrapper.find( '.post-likes-widget-placeholder' ).after( "<iframe class='post-likes-widget jetpack-likes-widget' name='" + $wrapper.data( 'name' ) + "' height='55px' width='100%' frameBorder='0' src='" + $wrapper.data( 'src' ) + "'></iframe>" );
- }
-
- $wrapper.removeClass( 'jetpack-likes-widget-unloaded' ).addClass( 'jetpack-likes-widget-loading' );
+ $gp_locale = GP_Locales::by_field( 'wp_locale', $_locale );
+ $_locale = isset( $gp_locale->slug ) ? $gp_locale->slug : '';
+ }
- $wrapper.find( 'iframe' ).load( function( e ) {
- var $iframe = jQuery( e.target );
- $wrapper.removeClass( 'jetpack-likes-widget-loading' ).addClass( 'jetpack-likes-widget-loaded' );
+ $likes_locale = ( '' == $_locale || 'en' == $_locale ) ? '' : '&amp;lang=' . strtolower( $_locale );
- JetpackLikespostMessage( { event: 'loadLikeWidget', name: $iframe.attr( 'name' ), width: $iframe.width() }, window.frames[ 'likes-master' ] );
+ // @todo: Remove this opt-out filter in the future
+ if ( apply_filters( 'wpl_sharing_2014_1', true ) ) {
+ $src = sprintf( '%1$s://widgets.wp.com/likes/master.html?ver=%2$s#ver=%2$s%3$s&amp;mp6=%4$d', $protocol, $this->version, $likes_locale, apply_filters( 'mp6_enabled', 0 ) );
+ } else {
+ $src = sprintf( '%1$s://widgets.wp.com/likes/master-legacy.html?ver=%2$s#ver=%2$s%3$s&amp;mp6=%4$d', $protocol, $this->version, $likes_locale, apply_filters( 'mp6_enabled', 0 ) );
+ }
- if ( $wrapper.hasClass( 'slim-likes-widget' ) ) {
- $wrapper.find( 'iframe' ).Jetpack( 'resizeable' );
- }
- });
- setTimeout( JetpackLikesWidgetQueueHandler, 250 );
- }
- JetpackLikesWidgetQueueHandler();
- //]]>
- </script>
-<?php
+ $likersText = wp_kses( __( '<span>%d</span> bloggers like this:', 'jetpack' ), array( 'span' => array() ) );
+ ?>
+ <iframe src='<?php echo $src; ?>' scrolling='no' id='likes-master' name='likes-master' style='display:none;'></iframe>
+ <div id='likes-other-gravatars'><div class="likes-text"><?php echo $likersText; ?></div><ul class="wpl-avatars sd-like-gravatars"></ul></div>
+ <?php
}
/**
@@ -972,7 +906,6 @@ class Jetpack_Likes {
*/
function is_likes_visible() {
- global $wp_current_filter; // Used to check 'get_the_excerpt' filter
global $post; // Used to apply 'sharing_show' filter
// Never show on feeds or previews
@@ -993,45 +926,46 @@ class Jetpack_Likes {
if ( post_password_required() )
$enabled = false;
- /** Other Checks ******************************************************/
-
- // Do not show on excerpts
- if ( in_array( 'get_the_excerpt', (array) $wp_current_filter ) ) {
- $enabled = false;
-
// Sharing Setting Overrides ****************************************
- } else {
- // Single post
- if ( is_singular( 'post' ) ) {
- if ( ! $this->is_single_post_enabled() ) {
- $enabled = false;
- }
- // Single page
- } elseif ( is_page() ) {
- if ( ! $this->is_single_page_enabled() ) {
- $enabled = false;
- }
+ // Single post including custom post types
+ if ( is_single() ) {
+ if ( ! $this->is_single_post_enabled( $post->post_type ) ) {
+ $enabled = false;
+ }
- // Attachment
- } elseif ( is_attachment() ) {
- if ( ! $this->is_attachment_enabled() ) {
- $enabled = false;
- }
+ // Single page
+ } elseif ( is_page() ) {
+ if ( ! $this->is_single_page_enabled() ) {
+ $enabled = false;
+ }
- // All other loops
- } elseif ( ! $this->is_index_enabled() ) {
+ // Attachment
+ } elseif ( is_attachment() ) {
+ if ( ! $this->is_attachment_enabled() ) {
$enabled = false;
}
+
+ // All other loops
+ } elseif ( ! $this->is_index_enabled() ) {
+ $enabled = false;
}
}
- // Check that the post is a public, published post.
- if ( 'publish' != $post->post_status ) {
- $enabled = false;
+ if( is_object( $post ) ) {
+ // Check that the post is a public, published post.
+ if ( 'attachment' == $post->post_type ) {
+ $post_status = get_post_status( $post->post_parent );
+ } else {
+ $post_status = $post->post_status;
+ }
+ if ( 'publish' != $post_status ) {
+ $enabled = false;
+ }
}
// Run through the sharing filters
+ /** This filter is documented in modules/sharedaddy/sharing-service.php */
$enabled = apply_filters( 'sharing_show', $enabled, $post );
return (bool) apply_filters( 'wpl_is_likes_visible', $enabled );
@@ -1046,12 +980,20 @@ class Jetpack_Likes {
}
/**
- * Returns if comment likes are enabled. Defaults to 'on'
+ * Returns the current state of the "WordPress.com Reblogs are" option.
+ * @return boolean true if enabled sitewide, false if not
+ */
+ function reblogs_enabled_sitewide() {
+ return (bool) apply_filters( 'wpl_reblogging_enabled_sitewide', ! get_option( 'disabled_reblogs' ) );
+ }
+
+ /**
+ * Returns if comment likes are enabled. Defaults to 'off'
* @todo decide what the default should be
* @return boolean true if we should show comment likes, false if not
*/
function is_comments_enabled() {
- return (bool) apply_filters( 'jetpack_comment_likes_enabled', get_option( 'jetpack_comment_likes_enabled', true ) );
+ return (bool) apply_filters( 'jetpack_comment_likes_enabled', get_option( 'jetpack_comment_likes_enabled', false ) );
}
function is_admin_bar_button_visible() {
@@ -1108,11 +1050,15 @@ class Jetpack_Likes {
/**
* Are Post Likes enabled on single posts?
*
+ * @param String $post_type custom post type identifier
* @return bool
*/
- function is_single_post_enabled() {
+ function is_single_post_enabled( $post_type = 'post' ) {
$options = $this->get_options();
- return (bool) apply_filters( 'wpl_is_single_post_disabled', (bool) in_array( 'post', $options['show'] ) );
+ return (bool) apply_filters(
+ "wpl_is_single_{$post_type}_disabled",
+ (bool) in_array( $post_type, $options['show'] )
+ );
}
/**
@@ -1134,7 +1080,6 @@ class Jetpack_Likes {
$options = $this->get_options();
return (bool) apply_filters( 'wpl_is_attachment_disabled', (bool) in_array( 'attachment', $options['show'] ) );
}
-
}
Jetpack_Likes::init();
diff --git a/plugins/jetpack/modules/likes/post-count-jetpack.js b/plugins/jetpack/modules/likes/post-count-jetpack.js
index 1c53362a..42e7a0eb 100644
--- a/plugins/jetpack/modules/likes/post-count-jetpack.js
+++ b/plugins/jetpack/modules/likes/post-count-jetpack.js
@@ -7,7 +7,7 @@ var wpPostLikeCount = wpPostLikeCount || {};
return $.ajax( {
type: 'GET',
url: wpPostLikeCount.jsonAPIbase + options.path,
- dataType : "jsonp",
+ dataType : 'jsonp',
data: options.data,
success: function( response ) { options.success( response ); },
error: function( response ) { options.error( response ); }
diff --git a/plugins/jetpack/modules/likes/post-count.js b/plugins/jetpack/modules/likes/post-count.js
index 935c0957..bf987f06 100644
--- a/plugins/jetpack/modules/likes/post-count.js
+++ b/plugins/jetpack/modules/likes/post-count.js
@@ -1,3 +1,5 @@
+/* jshint onevar: false, smarttabs: true */
+
var wpPostLikeCount = wpPostLikeCount || {};
(function($) {
@@ -28,21 +30,22 @@ var wpPostLikeCount = wpPostLikeCount || {};
data: '',
success: function( response ) {
for ( var path in response ) {
- if ( ! response[path]['error_data'] ) {
+ if ( ! response[path].error_data ) {
var urlPieces = path.split( '/' ); // pieces[4] = post id;
var post_id = urlPieces[4];
wpPostLikeCount.showCount( post_id, response[path].found );
}
}
},
- error: function( response ) {
+ error: function( /*response*/ ) {
}
};
var amp = '';
for( var i = 0; i < wpPostLikeCount.APIqueue.length; i++ ) {
- if ( i > 0 )
+ if ( i > 0 ) {
amp = '&';
+ }
batchRequest.data += amp + 'urls[]=' + wpPostLikeCount.APIqueue[i];
}
@@ -52,6 +55,6 @@ var wpPostLikeCount = wpPostLikeCount || {};
})(jQuery);
-jQuery(document).ready(function($) {
+jQuery(document).ready(function(/*$*/) {
wpPostLikeCount.wpPostLikeCount();
});
diff --git a/plugins/jetpack/modules/likes/queuehandler.js b/plugins/jetpack/modules/likes/queuehandler.js
new file mode 100644
index 00000000..cd619266
--- /dev/null
+++ b/plugins/jetpack/modules/likes/queuehandler.js
@@ -0,0 +1,242 @@
+/* global pm, wpcom_reblog */
+
+var jetpackLikesWidgetQueue = [];
+var jetpackLikesWidgetBatch = [];
+var jetpackLikesMasterReady = false;
+
+function JetpackLikespostMessage( message, target ) {
+ if ( 'string' === typeof message ){
+ try {
+ message = JSON.parse( message );
+ } catch(e) {
+ return;
+ }
+ }
+
+ pm( {
+ target: target,
+ type: 'likesMessage',
+ data: message,
+ origin: '*'
+ } );
+}
+
+function JetpackLikesBatchHandler() {
+ var requests = [];
+ jQuery( 'div.jetpack-likes-widget-unloaded' ).each( function() {
+ if ( jetpackLikesWidgetBatch.indexOf( this.id ) > -1 ) {
+ return;
+ }
+ jetpackLikesWidgetBatch.push( this.id );
+ var regex = /like-(post|comment)-wrapper-(\d+)-(\d+)-(\w+)/,
+ match = regex.exec( this.id ),
+ info;
+
+ if ( ! match || match.length !== 5 ) {
+ return;
+ }
+
+ info = {
+ blog_id: match[2],
+ width: this.width
+ };
+
+ if ( 'post' === match[1] ) {
+ info.post_id = match[3];
+ } else if ( 'comment' === match[1] ) {
+ info.comment_id = match[3];
+ }
+
+ info.obj_id = match[4];
+
+ requests.push( info );
+ });
+
+ if ( requests.length > 0 ) {
+ JetpackLikespostMessage( { event: 'initialBatch', requests: requests }, window.frames['likes-master'] );
+ }
+}
+
+function JetpackLikesMessageListener( event ) {
+ if ( 'undefined' === typeof event.event ) {
+ return;
+ }
+
+ if ( 'masterReady' === event.event ) {
+ jQuery( document ).ready( function() {
+ jetpackLikesMasterReady = true;
+
+ var stylesData = {
+ event: 'injectStyles'
+ },
+ $sdTextColor = jQuery( '.sd-text-color' ),
+ $sdLinkColor = jQuery( '.sd-link-color' );
+
+ if ( jQuery( 'iframe.admin-bar-likes-widget' ).length > 0 ) {
+ JetpackLikespostMessage( { event: 'adminBarEnabled' }, window.frames[ 'likes-master' ] );
+
+ stylesData.adminBarStyles = {
+ background: jQuery( '#wpadminbar .quicklinks li#wp-admin-bar-wpl-like > a' ).css( 'background' ),
+ isRtl: ( 'rtl' === jQuery( '#wpadminbar' ).css( 'direction' ) )
+ };
+ }
+
+ if ( ! window.addEventListener ) {
+ jQuery( '#wp-admin-bar-admin-bar-likes-widget' ).hide();
+ }
+
+ stylesData.textStyles = {
+ color: $sdTextColor.css( 'color' ),
+ fontFamily: $sdTextColor.css( 'font-family' ),
+ fontSize: $sdTextColor.css( 'font-size' ),
+ direction: $sdTextColor.css( 'direction' ),
+ fontWeight: $sdTextColor.css( 'font-weight' ),
+ fontStyle: $sdTextColor.css( 'font-style' ),
+ textDecoration: $sdTextColor.css('text-decoration')
+ };
+
+ stylesData.linkStyles = {
+ color: $sdLinkColor.css('color'),
+ fontFamily: $sdLinkColor.css('font-family'),
+ fontSize: $sdLinkColor.css('font-size'),
+ textDecoration: $sdLinkColor.css('text-decoration'),
+ fontWeight: $sdLinkColor.css( 'font-weight' ),
+ fontStyle: $sdLinkColor.css( 'font-style' )
+ };
+
+ JetpackLikespostMessage( stylesData, window.frames[ 'likes-master' ] );
+
+ JetpackLikesBatchHandler();
+
+ jQuery( document ).on( 'inview', 'div.jetpack-likes-widget-unloaded', function() {
+ jetpackLikesWidgetQueue.push( this.id );
+ });
+ });
+ }
+
+ if ( 'showLikeWidget' === event.event ) {
+ jQuery( '#' + event.id + ' .post-likes-widget-placeholder' ).fadeOut( 'fast', function() {
+ jQuery( '#' + event.id + ' .post-likes-widget' ).fadeIn( 'fast', function() {
+ JetpackLikespostMessage( { event: 'likeWidgetDisplayed', blog_id: event.blog_id, post_id: event.post_id, obj_id: event.obj_id }, window.frames['likes-master'] );
+ });
+ });
+ }
+
+ if ( 'clickReblogFlair' === event.event ) {
+ wpcom_reblog.toggle_reblog_box_flair( event.obj_id );
+ }
+
+ if ( 'showOtherGravatars' === event.event ) {
+ var $container = jQuery( '#likes-other-gravatars' ),
+ $list = $container.find( 'ul' ),
+ offset, rowLength, height, scrollbarWidth;
+
+ $container.hide();
+ $list.html( '' );
+
+ $container.find( '.likes-text span' ).text( event.total );
+
+ jQuery.each( event.likers, function( i, liker ) {
+ $list.append( '<li class="' + liker.css_class + '"><a href="' + liker.profile_URL + '" class="wpl-liker" rel="nofollow" target="_parent"><img src="' + liker.avatar_URL + '" alt="' + liker.name + '" width="30" height="30" style="padding-right: 3px;" /></a></li>');
+ } );
+
+ offset = jQuery( '[name=\'' + event.parent + '\']' ).offset();
+
+ $container.css( 'left', offset.left + event.position.left - 10 + 'px' );
+ $container.css( 'top', offset.top + event.position.top - 33 + 'px' );
+
+ rowLength = Math.floor( event.width / 37 );
+ height = ( Math.ceil( event.likers.length / rowLength ) * 37 ) + 13;
+ if ( height > 204 ) {
+ height = 204;
+ }
+
+ $container.css( 'height', height + 'px' );
+ $container.css( 'width', rowLength * 37 - 7 + 'px' );
+
+ $list.css( 'width', rowLength * 37 + 'px' );
+
+ $container.fadeIn( 'slow' );
+
+ scrollbarWidth = $list[0].offsetWidth - $list[0].clientWidth;
+ if ( scrollbarWidth > 0 ) {
+ $container.width( $container.width() + scrollbarWidth );
+ $list.width( $list.width() + scrollbarWidth );
+ }
+ }
+}
+
+pm.bind( 'likesMessage', function(e) { JetpackLikesMessageListener(e); } );
+
+jQuery( document ).click( function( e ) {
+ var $container = jQuery( '#likes-other-gravatars' );
+
+ if ( $container.has( e.target ).length === 0 ) {
+ $container.fadeOut( 'slow' );
+ }
+});
+
+function JetpackLikesWidgetQueueHandler() {
+ var $wrapper, wrapperID, found;
+ if ( ! jetpackLikesMasterReady ) {
+ setTimeout( JetpackLikesWidgetQueueHandler, 500 );
+ return;
+ }
+
+ if ( jetpackLikesWidgetQueue.length > 0 ) {
+ // We may have a widget that needs creating now
+ found = false;
+ while( jetpackLikesWidgetQueue.length > 0 ) {
+ // Grab the first member of the queue that isn't already loading.
+ wrapperID = jetpackLikesWidgetQueue.splice( 0, 1 )[0];
+ if ( jQuery( '#' + wrapperID ).hasClass( 'jetpack-likes-widget-unloaded' ) ) {
+ found = true;
+ break;
+ }
+ }
+ if ( ! found ) {
+ setTimeout( JetpackLikesWidgetQueueHandler, 500 );
+ return;
+ }
+ } else if ( jQuery( 'div.jetpack-likes-widget-unloaded' ).length > 0 ) {
+ // Grab any unloaded widgets for a batch request
+ JetpackLikesBatchHandler();
+
+ // Get the next unloaded widget
+ wrapperID = jQuery( 'div.jetpack-likes-widget-unloaded' ).first()[0].id;
+ if ( ! wrapperID ) {
+ // Everything is currently loaded
+ setTimeout( JetpackLikesWidgetQueueHandler, 500 );
+ return;
+ }
+ }
+
+ if ( 'undefined' === typeof wrapperID ) {
+ setTimeout( JetpackLikesWidgetQueueHandler, 500 );
+ return;
+ }
+
+ $wrapper = jQuery( '#' + wrapperID );
+ $wrapper.find( 'iframe' ).remove();
+
+ if ( $wrapper.hasClass( 'slim-likes-widget' ) ) {
+ $wrapper.find( '.post-likes-widget-placeholder' ).after( '<iframe class="post-likes-widget jetpack-likes-widget" name="' + $wrapper.data( 'name' ) + '" height="22px" width="68px" frameBorder="0" scrolling="no" src="' + $wrapper.data( 'src' ) + '"></iframe>' );
+ } else {
+ $wrapper.find( '.post-likes-widget-placeholder' ).after( '<iframe class="post-likes-widget jetpack-likes-widget" name="' + $wrapper.data( 'name' ) + '" height="55px" width="100%" frameBorder="0" src="' + $wrapper.data( 'src' ) + '"></iframe>' );
+ }
+
+ $wrapper.removeClass( 'jetpack-likes-widget-unloaded' ).addClass( 'jetpack-likes-widget-loading' );
+
+ $wrapper.find( 'iframe' ).load( function( e ) {
+ var $iframe = jQuery( e.target );
+ $wrapper.removeClass( 'jetpack-likes-widget-loading' ).addClass( 'jetpack-likes-widget-loaded' );
+
+ JetpackLikespostMessage( { event: 'loadLikeWidget', name: $iframe.attr( 'name' ), width: $iframe.width() }, window.frames[ 'likes-master' ] );
+
+ if ( $wrapper.hasClass( 'slim-likes-widget' ) ) {
+ $wrapper.find( 'iframe' ).Jetpack( 'resizeable' );
+ }
+ });
+ setTimeout( JetpackLikesWidgetQueueHandler, 250 );
+}
+JetpackLikesWidgetQueueHandler();
diff --git a/plugins/jetpack/modules/likes/style.css b/plugins/jetpack/modules/likes/style.css
index 525d3817..ab8938a0 100644
--- a/plugins/jetpack/modules/likes/style.css
+++ b/plugins/jetpack/modules/likes/style.css
@@ -1,7 +1,46 @@
+/**
+ * Like Button toolbar button, loading text & container styles
+ *
+ * @todo: doesn't look like "style.css" is used anymore.
+ */
+
+
+/* Master container */
+#jp-post-flair {
+ padding-top: .5em;
+}
+
+/* Overall Sharedaddy block title */
+div.sharedaddy,
+#content div.sharedaddy,
+#main div.sharedaddy {
+ clear: both;
+}
+
+div.sharedaddy h3.sd-title {
+ margin: 0 0 1em 0;
+ display: inline-block;
+ line-height: 1.2;
+ font-size: 9pt;
+ font-weight: bold;
+}
+
+div.sharedaddy h3.sd-title:before {
+ content: "";
+ display: block;
+ width: 100%;
+ min-width: 30px;
+ border-top: 1px solid #ddd;
+ margin-bottom: 1em;
+}
+
+
+/* Toolbar */
#wpadminbar li#wp-admin-bar-admin-bar-likes-widget {
width: 61px;
overflow: hidden;
}
+
#wpadminbar iframe.admin-bar-likes-widget {
width: 61px;
height: 28px;
@@ -13,6 +52,8 @@
div.jetpack-likes-widget-wrapper {
width: 100%;
+ min-height: 50px; /* Previous height, 60px */
+ position: relative; /* Need to abs position placeholder and iframe so there isn't a jarring jump */
}
div.jetpack-likes-widget-wrapper .sd-link-color {
@@ -21,17 +62,17 @@ div.jetpack-likes-widget-wrapper .sd-link-color {
div.jetpack-likes-widget-wrapper.slim-likes-widget {
width: 1px; /* initial default */
+ min-height: 0;
}
#likes-other-gravatars {
display: none;
position: absolute;
- padding: 10px;
- background-color: #000;
+ padding: 10px 10px 12px 10px;
+ background-color: #2e4453;
border-width: 0;
- opacity: 0.88;
- filter: alpha(opacity=88);
- box-shadow: 0 0 10px black;
+ box-shadow: 0 0 10px #2e4453;
+ box-shadow: 0 0 10px rgba(46,68,83,.6);
min-width: 130px;
z-index: 1000;
}
@@ -42,8 +83,8 @@ div.jetpack-likes-widget-wrapper.slim-likes-widget {
#likes-other-gravatars .likes-text {
color: white;
- font-size: 14px;
- padding-bottom: 5px;
+ font-size: 12px;
+ padding-bottom: 8px;
}
#likes-other-gravatars ul,
@@ -61,7 +102,6 @@ div.jetpack-likes-widget-wrapper.slim-likes-widget {
#likes-other-gravatars ul.wpl-avatars {
overflow: auto;
display: block;
- position: absolute;
max-height: 190px;
}
@@ -86,94 +126,36 @@ div.jetpack-likes-widget-wrapper.slim-likes-widget {
position: static;
}
-
div.sd-box {
border-top: 1px solid #ddd;
border-top: 1px solid rgba(0,0,0,.13);
}
-h3.sd-title {
- font-size: 12px;
- font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
- margin: 3px 0;
- padding: 0;
- text-transform: none;
- letter-spacing: 0;
- line-height: 1;
- font-weight: bold;
- width: 15.625%; /* 100px / 640px */ float: left;
- position: static;
- background: none;
- border: none;
-}
-
-.rtl .sd-title {
- float: right;
- text-align: right;
-}
-
.entry-content .post-likes-widget, .post-likes-widget,
.comment-likes-widget {
margin: 0;
border-width: 0;
+ display: block;
}
+
+/* Loading text */
.post-likes-widget-placeholder {
margin: 0;
border-width: 0;
+ position: relative;
}
.post-likes-widget-placeholder .button {
- margin: 0;
- padding: 0;
- display: inline-block;
- background: #efefef;
- background: -moz-linear-gradient(top, #f7f7f7 0%, #efefef 100%);
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f7f7f7), color-stop(100%,#efefef));
- background: -webkit-linear-gradient(top, #f7f7f7 0%,#efefef 100%);
- background: -o-linear-gradient(top, #f7f7f7 0%,#efefef 100%);
- background: -ms-linear-gradient(top, #f7f7f7 0%,#efefef 100%);
- background: linear-gradient(top, #f7f7f7 0%,#efefef 100%);
- border-radius: 3px;
- border: 1px solid #ddd !important;
- box-shadow: inset 0 1px 0 #fff;
- color: #999;
- text-decoration: none;
- line-height: 1;
- font-size: 12px;
- font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
- font-weight: normal;
+ display: none; /* Let's not show a dummy like button, let's just make a great button experience once it's loaded */
}
.post-likes-widget-placeholder .button span {
- padding: 1px 5px 1px 2px;
- display: block;
- opacity: .8;
- line-height: 1.5em;
- text-shadow: none;
-}
-
-.post-likes-widget-placeholder .button span:before {
- color: #97A8CC;
- font-family: "Noticons";
- content: '\f408';
- font-size: 16px;
- line-height: 0;
- text-shadow: 0 1px 0 #fff;
- position: relative;
- top: 3px;
}
.post-likes-widget-placeholder .loading {
color: #999;
font-size: 12px;
- font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
-}
-
-.post-likes-widget {
- width: 82.125%;
- display: none;
- float: right;
}
.slim-likes-widget .post-likes-widget {
@@ -181,8 +163,8 @@ h3.sd-title {
float: none;
}
-/* Like Special cases (display on it's own) */
+/* Like Special cases (display on it's own) */
div.sharedaddy.sd-like-enabled .sd-like h3 {
display: none;
}
@@ -190,17 +172,22 @@ div.sharedaddy.sd-like-enabled .sd-like h3 {
div.sharedaddy.sd-like-enabled .sd-like .post-likes-widget {
width: 100%;
float: none;
+ position: absolute; /* Need to abs position placeholder and iframe so there isn't a jarring jump */
+ top: 0;
}
-div.sharedaddy.sd-rating-enabled .sd-like .post-likes-widget, div.sharedaddy.sd-sharing-enabled .sd-like .post-likes-widget {
- width: 82.125%;
- float: right;
+.comment-likes-widget {
+ width: 100%;
}
-div.sharedaddy.sd-rating-enabled .sd-like h3, div.sharedaddy.sd-sharing-enabled .sd-like h3 {
- display: block;
+
+/* Make ratings block. @todo: make !important unnecessary by removing inline style */
+.pd-rating {
+ display: block !important;
}
-.comment-likes-widget {
- width: 100%;
+
+/* Hide G+ title */
+.sd-gplus .sd-title {
+ display: none;
}
diff --git a/plugins/jetpack/modules/manage.php b/plugins/jetpack/modules/manage.php
new file mode 100644
index 00000000..9baa4322
--- /dev/null
+++ b/plugins/jetpack/modules/manage.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Module Name: Manage
+ * Module Description: Manage all your sites from a centralized place, https://wordpress.com/sites.
+ * Jumpstart Description: helps you remotely manage plugins, turn on automated updates, and more from <a href="https://wordpress.com/plugins/" target="_blank">wordpress.com</a>.
+ * Sort Order: 1
+ * Recommendation Order: 3
+ * First Introduced: 3.4
+ * Requires Connection: Yes
+ * Auto Activate: No
+ * Module Tags: Centralized Management, Recommended
+ * Feature: Recommended, Jumpstart
+ */
+
+add_action( 'jetpack_activate_module_manage', array( Jetpack::init(), 'toggle_module_on_wpcom' ) );
+add_action( 'jetpack_deactivate_module_manage', array( Jetpack::init(), 'toggle_module_on_wpcom' ) );
diff --git a/plugins/jetpack/modules/markdown.php b/plugins/jetpack/modules/markdown.php
new file mode 100644
index 00000000..ce44b57d
--- /dev/null
+++ b/plugins/jetpack/modules/markdown.php
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * Module Name: Markdown
+ * Module Description: Write posts or pages in plain-text Markdown syntax.
+ * Sort Order: 31
+ * First Introduced: 2.8
+ * Requires Connection: No
+ * Auto Activate: No
+ * Module Tags: Writing
+ */
+
+include dirname( __FILE__ ) . '/markdown/easy-markdown.php';
+
+// If the module is active, let's make this active for posting, period.
+// Comments will still be optional.
+add_filter( 'pre_option_' . WPCom_Markdown::POST_OPTION, '__return_true' );
+function jetpack_markdown_posting_always_on() {
+ // why oh why isn't there a remove_settings_field?
+ global $wp_settings_fields;
+ if ( isset( $wp_settings_fields['writing']['default'][ WPCom_Markdown::POST_OPTION ] ) ) {
+ unset( $wp_settings_fields['writing']['default'][ WPCom_Markdown::POST_OPTION ] );
+ }
+}
+add_action( 'admin_init', 'jetpack_markdown_posting_always_on', 11 ); \ No newline at end of file
diff --git a/plugins/jetpack/modules/markdown/easy-markdown.php b/plugins/jetpack/modules/markdown/easy-markdown.php
new file mode 100644
index 00000000..d218a664
--- /dev/null
+++ b/plugins/jetpack/modules/markdown/easy-markdown.php
@@ -0,0 +1,714 @@
+<?php
+
+/*
+Plugin Name: Easy Markdown
+Plugin URI: http://automattic.com/
+Description: Write in Markdown, publish in WordPress
+Version: 0.1
+Author: Matt Wiebe
+Author URI: http://automattic.com/
+*/
+
+/**
+ * Copyright (c) Automattic. All rights reserved.
+ *
+ * Released under the GPL license
+ * http://www.opensource.org/licenses/gpl-license.php
+ *
+ * This is an add-on for WordPress
+ * http://wordpress.org/
+ *
+ * **********************************************************************
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * **********************************************************************
+ */
+
+class WPCom_Markdown {
+
+
+ const POST_OPTION = 'wpcom_publish_posts_with_markdown';
+ const COMMENT_OPTION = 'wpcom_publish_comments_with_markdown';
+ const POST_TYPE_SUPPORT = 'wpcom-markdown';
+ const IS_MD_META = '_wpcom_is_markdown';
+
+ private static $parser;
+ private static $instance;
+
+ // to ensure that our munged posts over xml-rpc are removed from the cache
+ public $posts_to_uncache = array();
+ private $monitoring = array( 'post' => array(), 'parent' => array() );
+
+
+ /**
+ * Yay singletons!
+ * @return object WPCom_Markdown instance
+ */
+ public static function get_instance() {
+ if ( ! self::$instance )
+ self::$instance = new self();
+ return self::$instance;
+ }
+
+ /**
+ * Kicks things off on `init` action
+ * @return null
+ */
+ public function load() {
+ $this->add_default_post_type_support();
+ $this->maybe_load_actions_and_filters();
+ if ( defined( 'REST_API_REQUEST' ) && REST_API_REQUEST ) {
+ add_action( 'switch_blog', array( $this, 'maybe_load_actions_and_filters' ), 10, 2 );
+ }
+ add_action( 'admin_init', array( $this, 'register_setting' ) );
+ add_action( 'admin_init', array( $this, 'maybe_unload_for_bulk_edit' ) );
+ if ( current_theme_supports( 'o2' ) || class_exists( 'P2' ) ) {
+ $this->add_o2_helpers();
+ }
+ }
+
+ /**
+ * If we're in a bulk edit session, unload so that we don't lose our markdown metadata
+ * @return null
+ */
+ public function maybe_unload_for_bulk_edit() {
+ if ( isset( $_REQUEST['bulk_edit'] ) && $this->is_posting_enabled() ) {
+ $this->unload_markdown_for_posts();
+ }
+ }
+
+ /**
+ * Called on init and fires on switch_blog to decide if our actions and filters
+ * should be running.
+ * @param int|null $new_blog_id New blog ID
+ * @param int|null $old_blog_id Old blog ID
+ * @return null
+ */
+ public function maybe_load_actions_and_filters( $new_blog_id = null, $old_blog_id = null ) {
+ // If this is a switch_to_blog call, and the blog isn't changing, we'll already be loaded
+ if ( $new_blog_id && $new_blog_id === $old_blog_id ) {
+ return;
+ }
+
+ if ( $this->is_posting_enabled() ) {
+ $this->load_markdown_for_posts();
+ } else {
+ $this->unload_markdown_for_posts();
+ }
+
+ if ( $this->is_commenting_enabled() ) {
+ $this->load_markdown_for_comments();
+ } else {
+ $this->unload_markdown_for_comments();
+ }
+ }
+
+ /**
+ * Set up hooks for enabling Markdown conversion on posts
+ * @return null
+ */
+ public function load_markdown_for_posts() {
+ add_action( 'wp_insert_post', array( $this, 'wp_insert_post' ) );
+ add_filter( 'wp_insert_post_data', array( $this, 'wp_insert_post_data' ), 10, 2 );
+ add_filter( 'edit_post_content', array( $this, 'edit_post_content' ), 10, 2 );
+ add_filter( 'edit_post_content_filtered', array( $this, 'edit_post_content_filtered' ), 10, 2 );
+ add_action( 'wp_restore_post_revision', array( $this, 'wp_restore_post_revision' ), 10, 2 );
+ add_filter( '_wp_post_revision_fields', array( $this, '_wp_post_revision_fields' ) );
+ add_action( 'xmlrpc_call', array( $this, 'xmlrpc_actions' ) );
+ add_filter( 'content_save_pre', array( $this, 'preserve_code_blocks' ), 1 );
+ if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
+ $this->check_for_early_methods();
+ }
+ }
+
+ /**
+ * Removes hooks to disable Markdown conversion on posts
+ * @return null
+ */
+ public function unload_markdown_for_posts() {
+ remove_action( 'wp_insert_post', array( $this, 'wp_insert_post' ) );
+ remove_filter( 'wp_insert_post_data', array( $this, 'wp_insert_post_data' ), 10, 2 );
+ remove_filter( 'edit_post_content', array( $this, 'edit_post_content' ), 10, 2 );
+ remove_filter( 'edit_post_content_filtered', array( $this, 'edit_post_content_filtered' ), 10, 2 );
+ remove_action( 'wp_restore_post_revision', array( $this, 'wp_restore_post_revision' ), 10, 2 );
+ remove_filter( '_wp_post_revision_fields', array( $this, '_wp_post_revision_fields' ) );
+ remove_action( 'xmlrpc_call', array( $this, 'xmlrpc_actions' ) );
+ remove_filter( 'content_save_pre', array( $this, 'preserve_code_blocks' ), 1 );
+ }
+
+ /**
+ * Set up hooks for enabling Markdown conversion on comments
+ * @return null
+ */
+ protected function load_markdown_for_comments() {
+ // Use priority 9 so that Markdown runs before KSES, which can clean up
+ // any munged HTML.
+ add_filter( 'pre_comment_content', array( $this, 'pre_comment_content' ), 9 );
+ }
+
+ /**
+ * Removes hooks to disable Markdown conversion
+ * @return null
+ */
+ protected function unload_markdown_for_comments() {
+ remove_filter( 'pre_comment_content', array( $this, 'pre_comment_content' ), 9 );
+ }
+
+ /**
+ * o2 does some of what we do. Let's take precedence.
+ * @return null
+ */
+ public function add_o2_helpers() {
+ if ( $this->is_posting_enabled() ) {
+ add_filter( 'content_save_pre', array( $this, 'o2_escape_lists' ), 1 );
+ }
+
+ add_filter( 'o2_preview_post', array( $this, 'o2_preview_post' ) );
+ add_filter( 'o2_preview_comment', array( $this, 'o2_preview_comment' ) );
+
+ add_filter( 'wpcom_markdown_transform_pre', array( $this, 'o2_unescape_lists' ) );
+ add_filter( 'wpcom_untransformed_content', array( $this, 'o2_unescape_lists' ) );
+ }
+
+ /**
+ * If Markdown is enabled for posts on this blog, filter the text for o2 previews
+ * @param string $text Post text
+ * @return string Post text transformed through the magic of Markdown
+ */
+ public function o2_preview_post( $text ) {
+ if ( $this->is_posting_enabled() ) {
+ $text = $this->transform( $text, array( 'unslash' => false ) );
+ }
+ return $text;
+ }
+
+ /**
+ * If Markdown is enabled for comments on this blog, filter the text for o2 previews
+ * @param string $text Comment text
+ * @return string Comment text transformed through the magic of Markdown
+ */
+ public function o2_preview_comment( $text ) {
+ if ( $this->is_commenting_enabled() ) {
+ $text = $this->transform( $text, array( 'unslash' => false ) );
+ }
+ return $text;
+ }
+
+ /**
+ * Escapes lists so that o2 doesn't trounce them
+ * @param string $text Post/comment text
+ * @return string Text escaped with HTML entity for asterisk
+ */
+ public function o2_escape_lists( $text ) {
+ return preg_replace( '/^\\* /um', '&#42; ', $text );
+ }
+
+ /**
+ * Unescapes the token we inserted on o2_escape_lists
+ * @param string $text Post/comment text with HTML entities for asterisks
+ * @return string Text with the HTML entity removed
+ */
+ public function o2_unescape_lists( $text ) {
+ return preg_replace( '/^[&]\#042; /um', '* ', $text );
+ }
+
+ /**
+ * Preserve code blocks from being munged by KSES before they have a chance
+ * @param string $text post content
+ * @return string post content with code blocks escaped
+ */
+ public function preserve_code_blocks( $text ) {
+ return $this->get_parser()->codeblock_preserve( $text );
+ }
+
+ /**
+ * Remove KSES if it's there. Store the result to manually invoke later if needed.
+ * @return null
+ */
+ public function maybe_remove_kses() {
+ // Filters return true if they existed before you removed them
+ if ( $this->is_posting_enabled() )
+ $this->kses = remove_filter( 'content_filtered_save_pre', 'wp_filter_post_kses' ) && remove_filter( 'content_save_pre', 'wp_filter_post_kses' );
+ }
+
+ /**
+ * Add our Writing and Discussion settings.
+ * @return null
+ */
+ public function register_setting() {
+ add_settings_field( self::POST_OPTION, __( 'Markdown', 'jetpack' ), array( $this, 'post_field' ), 'writing' );
+ register_setting( 'writing', self::POST_OPTION, array( $this, 'sanitize_setting') );
+ add_settings_field( self::COMMENT_OPTION, __( 'Markdown', 'jetpack' ), array( $this, 'comment_field' ), 'discussion' );
+ register_setting( 'discussion', self::COMMENT_OPTION, array( $this, 'sanitize_setting') );
+ }
+
+ /**
+ * Sanitize setting. Don't really want to store "on" value, so we'll store "1" instead!
+ * @param string $input Value received by settings API via $_POST
+ * @return bool Cast to boolean.
+ */
+ public function sanitize_setting( $input ) {
+ return (bool) $input;
+ }
+
+ /**
+ * Prints HTML for the Writing setting
+ * @return null
+ */
+ public function post_field() {
+ printf(
+ '<label><input name="%s" id="%s" type="checkbox"%s /> %s</label><p class="description">%s</p>',
+ self::POST_OPTION,
+ self::POST_OPTION,
+ checked( $this->is_posting_enabled(), true, false ),
+ esc_html__( 'Use Markdown for posts and pages.', 'jetpack' ),
+ sprintf( '<a href="%s">%s</a>', esc_url( $this->get_support_url() ), esc_html__( 'Learn more about Markdown.', 'jetpack' ) )
+ );
+ }
+
+ /**
+ * Prints HTML for the Discussion setting
+ * @return null
+ */
+ public function comment_field() {
+ printf(
+ '<label><input name="%s" id="%s" type="checkbox"%s /> %s</label><p class="description">%s</p>',
+ self::COMMENT_OPTION,
+ self::COMMENT_OPTION,
+ checked( $this->is_commenting_enabled(), true, false ),
+ esc_html__( 'Use Markdown for comments.', 'jetpack' ),
+ sprintf( '<a href="%s">%s</a>', esc_url( $this->get_support_url() ), esc_html__( 'Learn more about Markdown.', 'jetpack' ) )
+ );
+ }
+
+ /**
+ * Get the support url for Markdown
+ * @uses apply_filters
+ * @return string support url
+ */
+ protected function get_support_url() {
+ return apply_filters( 'easy_markdown_support_url', 'http://en.support.wordpress.com/markdown-quick-reference/' );
+ }
+
+ /**
+ * Is Mardown conversion for posts enabled?
+ * @return boolean
+ */
+ public function is_posting_enabled() {
+ return (bool) get_option( self::POST_OPTION, '' );
+ }
+
+ /**
+ * Is Markdown conversion for comments enabled?
+ * @return boolean
+ */
+ public function is_commenting_enabled() {
+ return (bool) get_option( self::COMMENT_OPTION, '' );
+ }
+
+ /**
+ * Check if a $post_id has Markdown enabled
+ * @param int $post_id A post ID.
+ * @return boolean
+ */
+ public function is_markdown( $post_id ) {
+ return get_metadata( 'post', $post_id, self::IS_MD_META, true );
+ }
+
+ /**
+ * Set Markdown as enabled on a post_id. We skip over update_postmeta so we
+ * can sneakily set metadata on post revisions, which we need.
+ * @param int $post_id A post ID.
+ * @return bool The metadata was successfully set.
+ */
+ protected function set_as_markdown( $post_id ) {
+ return update_metadata( 'post', $post_id, self::IS_MD_META, true );
+ }
+
+ /**
+ * Get our Markdown parser object, optionally requiring all of our needed classes and
+ * instantiating our parser.
+ * @return object WPCom_GHF_Markdown_Parser instance.
+ */
+ public function get_parser() {
+
+ if ( ! self::$parser ) {
+ jetpack_require_lib( 'markdown' );
+ self::$parser = new WPCom_GHF_Markdown_Parser;
+ }
+
+ return self::$parser;
+ }
+
+ /**
+ * We don't want Markdown conversion all over the place.
+ * @return null
+ */
+ public function add_default_post_type_support() {
+ add_post_type_support( 'post', self::POST_TYPE_SUPPORT );
+ add_post_type_support( 'page', self::POST_TYPE_SUPPORT );
+ add_post_type_support( 'revision', self::POST_TYPE_SUPPORT );
+ }
+
+ /**
+ * Figure out the post type of the post screen we're on
+ * @return string Current post_type
+ */
+ protected function get_post_screen_post_type() {
+ global $pagenow;
+ if ( 'post-new.php' === $pagenow )
+ return ( isset( $_GET['post_type'] ) ) ? $_GET['post_type'] : 'post';
+ if ( isset( $_GET['post'] ) ) {
+ $post = get_post( (int) $_GET['post'] );
+ if ( is_object( $post ) && isset( $post->post_type ) )
+ return $post->post_type;
+ }
+ return 'post';
+ }
+
+ /**
+ * Swap post_content and post_content_filtered for editing
+ * @param string $content Post content
+ * @param int $id post ID
+ * @return string Swapped content
+ */
+ public function edit_post_content( $content, $id ) {
+ if ( $this->is_markdown( $id ) ) {
+ $post = get_post( $id );
+ if ( $post && ! empty( $post->post_content_filtered ) ) {
+ $post = $this->swap_for_editing( $post );
+ return $post->post_content;
+ }
+ }
+ return $content;
+ }
+
+ /**
+ * Swap post_content_filtered and post_content for editing
+ * @param string $content Post content_filtered
+ * @param int $id post ID
+ * @return string Swapped content
+ */
+ public function edit_post_content_filtered( $content, $id ) {
+ // if markdown was disabled, let's turn this off
+ if ( ! $this->is_posting_enabled() && $this->is_markdown( $id ) ) {
+ $post = get_post( $id );
+ if ( $post && ! empty( $post->post_content_filtered ) )
+ $content = '';
+ }
+ return $content;
+ }
+
+ /**
+ * Magic happens here. Markdown is converted and stored on post_content. Original Markdown is stored
+ * in post_content_filtered so that we can continue editing as Markdown.
+ * @param array $post_data The post data that will be inserted into the DB. Slashed.
+ * @param array $postarr All the stuff that was in $_POST.
+ * @return array $post_data with post_content and post_content_filtered modified
+ */
+ public function wp_insert_post_data( $post_data, $postarr ) {
+ // $post_data array is slashed!
+ $post_id = isset( $postarr['ID'] ) ? $postarr['ID'] : false;
+ // bail early if markdown is disabled or this post type is unsupported.
+ if ( ! $this->is_posting_enabled() || ! post_type_supports( $post_data['post_type'], self::POST_TYPE_SUPPORT ) ) {
+ // it's disabled, but maybe this *was* a markdown post before.
+ if ( $this->is_markdown( $post_id ) && ! empty( $post_data['post_content_filtered'] ) ) {
+ $post_data['post_content_filtered'] = '';
+ }
+ // we have no context to determine supported post types in the `post_content_pre` hook,
+ // which already ran to sanitize code blocks. Undo that.
+ $post_data['post_content'] = $this->get_parser()->codeblock_restore( $post_data['post_content'] );
+ return $post_data;
+ }
+ // rejigger post_content and post_content_filtered
+ // revisions are already in the right place, except when we're restoring, but that's taken care of elsewhere
+ if ( 'revision' !== $post_data['post_type'] ) {
+ $post_data['post_content_filtered'] = apply_filters( 'wpcom_untransformed_content', $post_data['post_content'] );
+ $post_data['post_content'] = $this->transform( $post_data['post_content'], array( 'id' => $post_id ) );
+ $post_data['post_content'] = apply_filters( 'content_save_pre', $post_data['post_content'] );
+ } elseif ( 0 === strpos( $post_data['post_name'], $post_data['post_parent'] . '-autosave' ) ) {
+ // autosaves for previews are weird
+ $post_data['post_content'] = $this->transform( $post_data['post_content'], array( 'id' => $post_data['post_parent'] ) );
+ $post_data['post_content'] = apply_filters( 'content_save_pre', $post_data['post_content'] );
+ }
+
+ // set as markdown on the wp_insert_post hook later
+ if ( $post_id )
+ $this->monitoring['post'][ $post_id ] = true;
+ else
+ $this->monitoring['content'] = wp_unslash( $post_data['post_content'] );
+ if ( 'revision' === $postarr['post_type'] && $this->is_markdown( $postarr['post_parent'] ) )
+ $this->monitoring['parent'][ $postarr['post_parent'] ] = true;
+
+ return $post_data;
+ }
+
+ /**
+ * Calls on wp_insert_post action, after wp_insert_post_data. This way we can
+ * still set postmeta on our revisions after it's all been deleted.
+ * @param int $post_id The post ID that has just been added/updated
+ * @return null
+ */
+ public function wp_insert_post( $post_id ) {
+ $post_parent = get_post_field( 'post_parent', $post_id );
+ // this didn't have an ID yet. Compare the content that was just saved.
+ if ( isset( $this->monitoring['content'] ) && $this->monitoring['content'] === get_post_field( 'post_content', $post_id ) ) {
+ unset( $this->monitoring['content'] );
+ $this->set_as_markdown( $post_id );
+ }
+ if ( isset( $this->monitoring['post'][$post_id] ) ) {
+ unset( $this->monitoring['post'][$post_id] );
+ $this->set_as_markdown( $post_id );
+ } elseif ( isset( $this->monitoring['parent'][$post_parent] ) ) {
+ unset( $this->monitoring['parent'][$post_parent] );
+ $this->set_as_markdown( $post_id );
+ }
+ }
+
+ /**
+ * Run a comment through Markdown. Easy peasy.
+ * @param string $content
+ * @return string
+ */
+ public function pre_comment_content( $content ) {
+ return $this->transform( $content, array(
+ 'id' => $this->comment_hash( $content ),
+ ) );
+ }
+
+ protected function comment_hash( $content ) {
+ return 'c-' . substr( md5( $content ), 0, 8 );
+ }
+
+ /**
+ * Markdown conversion. Some DRYness for repetitive tasks.
+ * @param string $text Content to be run through Markdown
+ * @param array $args Arguments, with keys:
+ * id: provide a string to prefix footnotes with a unique identifier
+ * unslash: when true, expects and returns slashed data
+ * decode_code_blocks: when true, assume that text in fenced code blocks is already
+ * HTML encoded and should be decoded before being passed to Markdown, which does
+ * its own encoding.
+ * @return string Markdown-processed content
+ */
+ public function transform( $text, $args = array() ) {
+ $args = wp_parse_args( $args, array(
+ 'id' => false,
+ 'unslash' => true,
+ 'decode_code_blocks' => ! $this->get_parser()->use_code_shortcode
+ ) );
+ // probably need to unslash
+ if ( $args['unslash'] )
+ $text = wp_unslash( $text );
+
+ $text = apply_filters( 'wpcom_markdown_transform_pre', $text, $args );
+ // ensure our paragraphs are separated
+ $text = str_replace( array( '</p><p>', "</p>\n<p>" ), "</p>\n\n<p>", $text );
+ // visual editor likes to add <p>s. Buh-bye.
+ $text = $this->get_parser()->unp( $text );
+ // sometimes we get an encoded > at start of line, breaking blockquotes
+ $text = preg_replace( '/^&gt;/m', '>', $text );
+ // prefixes are because we need to namespace footnotes by post_id
+ $this->get_parser()->fn_id_prefix = $args['id'] ? $args['id'] . '-' : '';
+ // If we're not using the code shortcode, prevent over-encoding.
+ if ( $args['decode_code_blocks'] ) {
+ $text = $this->get_parser()->codeblock_restore( $text );
+ }
+ // Transform it!
+ $text = $this->get_parser()->transform( $text );
+ // Fix footnotes - kses doesn't like the : IDs it supplies
+ $text = preg_replace( '/((id|href)="#?fn(ref)?):/', "$1-", $text );
+ // Markdown inserts extra spaces to make itself work. Buh-bye.
+ $text = rtrim( $text );
+ $text = apply_filters( 'wpcom_markdown_transform_post', $text, $args );
+
+ // probably need to re-slash
+ if ( $args['unslash'] )
+ $text = wp_slash( $text );
+
+ return $text;
+ }
+
+ /**
+ * Shows Markdown in the Revisions screen, and ensures that post_content_filtered
+ * is maintained on revisions
+ * @param array $fields Post fields pertinent to revisions
+ * @return array Modified array to include post_content_filtered
+ */
+ public function _wp_post_revision_fields( $fields ) {
+ $fields['post_content_filtered'] = __( 'Markdown content', 'jetpack' );
+ return $fields;
+ }
+
+ /**
+ * Do some song and dance to keep all post_content and post_content_filtered content
+ * in the expected place when a post revision is restored.
+ * @param int $post_id The post ID have a restore done to it
+ * @param int $revision_id The revision ID being restored
+ * @return null
+ */
+ public function wp_restore_post_revision( $post_id, $revision_id ) {
+ if ( $this->is_markdown( $revision_id ) ) {
+ $revision = get_post( $revision_id, ARRAY_A );
+ $post = get_post( $post_id, ARRAY_A );
+ $post['post_content'] = $revision['post_content_filtered']; // Yes, we put it in post_content, because our wp_insert_post_data() expects that
+ // set this flag so we can restore the post_content_filtered on the last revision later
+ $this->monitoring['restore'] = true;
+ // let's not make a revision of our fixing update
+ add_filter( 'wp_revisions_to_keep', '__return_false', 99 );
+ wp_update_post( $post );
+ $this->fix_latest_revision_on_restore( $post_id );
+ remove_filter( 'wp_revisions_to_keep', '__return_false', 99 );
+ }
+ }
+
+ /**
+ * We need to ensure the last revision has Markdown, not HTML in its post_content_filtered
+ * column after a restore.
+ * @param int $post_id The post ID that was just restored.
+ * @return null
+ */
+ protected function fix_latest_revision_on_restore( $post_id ) {
+ global $wpdb;
+ $post = get_post( $post_id );
+ $last_revision = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_type = 'revision' AND post_parent = %d ORDER BY ID DESC", $post->ID ) );
+ $last_revision->post_content_filtered = $post->post_content_filtered;
+ wp_insert_post( (array) $last_revision );
+ }
+
+ /**
+ * Kicks off magic for an XML-RPC session. We want to keep editing Markdown
+ * and publishing HTML.
+ * @param string $xmlrpc_method The current XML-RPC method
+ * @return null
+ */
+ public function xmlrpc_actions( $xmlrpc_method ) {
+ switch ( $xmlrpc_method ) {
+ case 'metaWeblog.getRecentPosts':
+ case 'wp.getPosts':
+ case 'wp.getPages':
+ add_action( 'parse_query', array( $this, 'make_filterable' ), 10, 1 );
+ break;
+ case 'wp.getPost':
+ $this->prime_post_cache();
+ break;
+ }
+ }
+
+ /**
+ * metaWeblog.getPost and wp.getPage fire xmlrpc_call action *after* get_post() is called.
+ * So, we have to detect those methods and prime the post cache early.
+ * @return null
+ */
+ protected function check_for_early_methods() {
+ global $HTTP_RAW_POST_DATA;
+ if ( false === strpos( $HTTP_RAW_POST_DATA, 'metaWeblog.getPost' )
+ && false === strpos( $HTTP_RAW_POST_DATA, 'wp.getPage' ) ) {
+ return;
+ }
+ include_once( ABSPATH . WPINC . '/class-IXR.php' );
+ $message = new IXR_Message( $HTTP_RAW_POST_DATA );
+ $message->parse();
+ $post_id_position = 'metaWeblog.getPost' === $message->methodName ? 0 : 1;
+ $this->prime_post_cache( $message->params[ $post_id_position ] );
+ }
+
+ /**
+ * Prime the post cache with swapped post_content. This is a sneaky way of getting around
+ * the fact that there are no good hooks to call on the *.getPost xmlrpc methods.
+ *
+ * @return null
+ */
+ private function prime_post_cache( $post_id = false ) {
+ global $wp_xmlrpc_server;
+ if ( ! $post_id ) {
+ $post_id = $wp_xmlrpc_server->message->params[3];
+ }
+
+ // prime the post cache
+ if ( $this->is_markdown( $post_id ) ) {
+ $post = get_post( $post_id );
+ if ( ! empty( $post->post_content_filtered ) ) {
+ wp_cache_delete( $post->ID, 'posts' );
+ $post = $this->swap_for_editing( $post );
+ wp_cache_add( $post->ID, $post, 'posts' );
+ $this->posts_to_uncache[] = $post_id;
+ }
+ }
+ // uncache munged posts if using a persistent object cache
+ if ( wp_using_ext_object_cache() ) {
+ add_action( 'shutdown', array( $this, 'uncache_munged_posts' ) );
+ }
+ }
+
+ /**
+ * Swaps `post_content_filtered` back to `post_content` for editing purposes.
+ * @param object $post WP_Post object
+ * @return object WP_Post object with swapped `post_content_filtered` and `post_content`
+ */
+ protected function swap_for_editing( $post ) {
+ $markdown = $post->post_content_filtered;
+ // unencode encoded code blocks
+ $markdown = $this->get_parser()->codeblock_restore( $markdown );
+ // restore beginning of line blockquotes
+ $markdown = preg_replace( '/^&gt; /m', '> ', $markdown );
+ $post->post_content_filtered = $post->post_content;
+ $post->post_content = $markdown;
+ return $post;
+ }
+
+
+ /**
+ * We munge the post cache to serve proper markdown content to XML-RPC clients.
+ * Uncache these after the XML-RPC session ends.
+ * @return null
+ */
+ public function uncache_munged_posts() {
+ // $this context gets lost in testing sometimes. Weird.
+ foreach( WPCom_Markdown::get_instance()->posts_to_uncache as $post_id ) {
+ wp_cache_delete( $post_id, 'posts' );
+ }
+ }
+
+ /**
+ * Since *.(get)?[Rr]ecentPosts calls get_posts with suppress filters on, we need to
+ * turn them back on so that we can swap things for editing.
+ * @param object $wp_query WP_Query object
+ * @return null
+ */
+ public function make_filterable( $wp_query ) {
+ $wp_query->set( 'suppress_filters', false );
+ add_action( 'the_posts', array( $this, 'the_posts' ), 10, 2 );
+ }
+
+ /**
+ * Swaps post_content and post_content_filtered for editing.
+ * @param array $posts Posts returned by the just-completed query
+ * @param object $wp_query Current WP_Query object
+ * @return array Modified $posts
+ */
+ public function the_posts( $posts, $wp_query ) {
+ foreach ( $posts as $key => $post ) {
+ if ( $this->is_markdown( $post->ID ) && ! empty( $posts[ $key ]->post_content_filtered ) ) {
+ $markdown = $posts[ $key ]->post_content_filtered;
+ $posts[ $key ]->post_content_filtered = $posts[ $key ]->post_content;
+ $posts[ $key ]->post_content = $markdown;
+ }
+ }
+ return $posts;
+ }
+
+ /**
+ * Singleton silence is golden
+ */
+ private function __construct() {}
+}
+
+add_action( 'init', array( WPCom_Markdown::get_instance(), 'load' ) );
diff --git a/plugins/jetpack/modules/minileven.php b/plugins/jetpack/modules/minileven.php
index f3cb8f75..7e2486bb 100644
--- a/plugins/jetpack/modules/minileven.php
+++ b/plugins/jetpack/modules/minileven.php
@@ -2,11 +2,14 @@
/**
* Module Name: Mobile Theme
- * Module Description: Automatically optimize your site for mobile devices.
- * Sort Order: 11
+ * Module Description: Optimize your site with a mobile-friendly theme for smartphones.
+ * Sort Order: 21
+ * Recommendation Order: 11
* First Introduced: 1.8
* Requires Connection: No
* Auto Activate: No
+ * Module Tags: Appearance, Mobile, Recommended
+ * Feature: Recommended
*/
function jetpack_load_minileven() {
@@ -19,15 +22,20 @@ function jetpack_load_minileven() {
add_action( 'jetpack_modules_loaded', 'minileven_loaded' );
function minileven_loaded() {
- Jetpack::enable_module_configurable( __FILE__ );
- Jetpack::module_configuration_load( __FILE__, 'minileven_configuration_load' );
- Jetpack::module_configuration_screen( __FILE__, 'minileven_configuration_screen' );
+ Jetpack::enable_module_configurable( __FILE__ );
+ Jetpack::module_configuration_load( __FILE__, 'minileven_configuration_load' );
+ Jetpack::module_configuration_screen( __FILE__, 'minileven_configuration_screen' );
}
function minileven_configuration_load() {
if ( isset( $_POST['action'] ) && $_POST['action'] == 'save_options' && $_POST['_wpnonce'] == wp_create_nonce( 'minileven' ) ) {
- if ( isset( $_POST['wp_mobile_excerpt'] ) )
+ if ( isset( $_POST['wp_mobile_excerpt'] ) ) {
update_option( 'wp_mobile_excerpt', '1' == $_POST['wp_mobile_excerpt'] ? '1' : '0' );
+ }
+
+ if ( isset( $_POST['wp_mobile_featured_images'] ) ) {
+ update_option( 'wp_mobile_featured_images', '1' == $_POST['wp_mobile_featured_images'] ? '1' : '0' );
+ }
update_option( 'wp_mobile_app_promos', ( isset( $_POST['wp_mobile_app_promos'] ) ) ? '1' : '0' );
@@ -39,6 +47,7 @@ function minileven_configuration_load() {
function minileven_configuration_screen() {
$excerpts = ( 0 == get_option( 'wp_mobile_excerpt' ) ) ? 0 : 1;
+ $featured_images = ( 0 == get_option( 'wp_mobile_featured_images' ) ) ? 0 : 1;
$promos = ( '1' == get_option( 'wp_mobile_app_promos' ) ) ? 1 : 0;
?>
@@ -61,6 +70,20 @@ function minileven_configuration_screen() {
</td>
</tr>
<tr valign="top">
+ <th scope="row"><?php _e( 'Featured Images', 'jetpack' ); ?></th>
+ <td>
+ <label>
+ <input name="wp_mobile_featured_images" type="radio" value="0" class="code" <?php checked( 0, $featured_images, true ); ?> />
+ <?php _e( 'Hide all featured images', 'jetpack' ); ?>
+ </label>
+ <br />
+ <label>
+ <input name="wp_mobile_featured_images" type="radio" value="1" class="code" <?php checked( 1, $featured_images, true ); ?> />
+ <?php _e( 'Display featured images', 'jetpack' ); ?>
+ </label>
+ </td>
+ </tr>
+ <tr valign="top">
<th scope="row"><?php _e( 'Mobile App Promos', 'jetpack' ); ?></th>
<td>
<label>
@@ -71,13 +94,13 @@ function minileven_configuration_screen() {
</tr>
</table>
<p class="submit">
- <input type="submit" class="button-primary" value="<?php esc_attr_e( __( 'Save configuration', 'jetpack' ) ); ?>" />
+ <input type="submit" class="button-primary" value="<?php esc_attr_e( 'Save configuration', 'jetpack' ); ?>" />
</p>
</form>
<h3><?php _e( 'Mobile Apps', 'jetpack' ); ?></h3>
<p><?php _e( 'Take WordPress with you.', 'jetpack' ); ?></p>
<a href="http://wordpress.org/extend/mobile/"><img src="<?php echo plugin_dir_url( __FILE__ ); ?>/minileven/images/wp-app-devices.png" width="332" height="73" /></a>
- <p><?php printf( __( 'We have apps for <a href="%s">iOS (iPhone, iPad, iPod Touch)</a>, <a href="%s">Android</a>, <a href="%s">BlackBerry</a>, <a href="%s">Windows Phone</a>, and <a href="%s">more</a>!', 'jetpack' ), 'http://ios.wordpress.org/', 'http://android.wordpress.org/', 'http://blackberry.wordpress.org/', 'http://windowsphone.wordpress.org/', 'http://wordpress.org/extend/mobile/' ); ?></p>
+ <p><?php printf( __( 'We have apps for <a href="%s">iOS (iPhone, iPad, iPod Touch)</a>, <a href="%s">Android</a>, <a href="%s">BlackBerry</a>, and <a href="%s">more</a>!', 'jetpack' ), 'http://ios.wordpress.org/', 'http://android.wordpress.org/', 'http://blackberry.wordpress.org/', 'http://wordpress.org/mobile/' ); ?></p>
<?php
}
@@ -107,4 +130,4 @@ function minileven_enabled( $wp_mobile_disable_option ) {
add_filter( 'option_wp_mobile_disable', 'minileven_enabled' );
-jetpack_load_minileven(); \ No newline at end of file
+jetpack_load_minileven();
diff --git a/plugins/jetpack/modules/minileven/images/wp-app-devices.png b/plugins/jetpack/modules/minileven/images/wp-app-devices.png
index 4b5f4be9..2efefe20 100644
--- a/plugins/jetpack/modules/minileven/images/wp-app-devices.png
+++ b/plugins/jetpack/modules/minileven/images/wp-app-devices.png
Binary files differ
diff --git a/plugins/jetpack/modules/minileven/minileven.php b/plugins/jetpack/modules/minileven/minileven.php
index aa9551c2..15f3628b 100644
--- a/plugins/jetpack/modules/minileven/minileven.php
+++ b/plugins/jetpack/modules/minileven/minileven.php
@@ -167,14 +167,6 @@ function jetpack_mobile_theme_setup() {
header( 'Location: http://blackberry.wordpress.org/download/' );
exit;
break;
- case 'nokia':
- header( 'Location: http://nokia.wordpress.org/download/' );
- exit;
- break;
- case 'windowsphone':
- header( 'Location: http://social.zune.net/redirect?type=phoneApp&id=5f64ad85-f801-e011-9264-00237de2db9e' );
- exit;
- break;
}
}
@@ -198,34 +190,6 @@ if (isset($_COOKIE['akm_mobile']) && $_COOKIE['akm_mobile'] == 'false') {
add_action('wp_footer', 'jetpack_mobile_available');
}
-add_action( 'wp_footer', 'mobile_admin_bar', 20 );
-function mobile_admin_bar() {
- global $wp_version;
-
- if ( jetpack_is_mobile() && 1 != version_compare( $wp_version, '3.5-beta3-22631' ) ) :
- // This fix was made unnecessary in http://core.trac.wordpress.org/changeset/22636
- ?>
- <script type="text/javascript" id='mobile-admin-bar'>
- jQuery( function( $ ) {
- var menupop = $( '#wpadminbar .ab-top-menu > li.menupop' )
- .unbind( 'mouseover' )
- .unbind( 'mouseout' )
- .click( function ( e ) {
- $( this ).toggleClass( 'hover' );
- $( '#wpadminbar .menupop' ).not( this ).removeClass( 'hover' );
- } )
- .children( 'a' )
- .click( function( e ) {
- e.preventDefault();
- } );
- $( '#wpadminbar' ).css( 'position', 'absolute' );
- $( '#ab-reblog-box' ).css( 'position', 'absolute' );
- } );
- </script>
- <?php
- endif;
-}
-
function jetpack_mobile_app_promo() {
?>
<script type="text/javascript">
@@ -236,10 +200,6 @@ function jetpack_mobile_app_promo() {
document.write( '<span id="wpcom-mobile-app-promo" style="margin-top: 10px; font-size: 13px;"><strong>Now Available!</strong> <a href="/index.php?app-download=android">Download WordPress for Android</a></span><br /><br />' );
else if ( ( navigator.userAgent.match( /blackberry/i ) ) || ( navigator.userAgent.match( /playbook/i ) ) || ( navigator.userAgent.match( /bb10/i ) ) )
document.write( '<span id="wpcom-mobile-app-promo" style="margin-top: 10px; font-size: 13px;"><strong>Now Available!</strong> <a href="/index.php?app-download=blackberry">Download WordPress for BlackBerry</a></span><br /><br />' );
- else if ( ( navigator.userAgent.match( /windows phone os/i ) ) )
- document.write( '<span id="wpcom-mobile-app-promo" style="margin-top: 10px; font-size: 13px; line-height: 13px;"><strong>Now Available!</strong> <a href="/index.php?app-download=windowsphone">Download WordPress for <br />Windows Phone</a></span><br /><br />' );
- else if ( ( navigator.userAgent.match( /nokia/i ) ) )
- document.write( '<span id="wpcom-mobile-app-promo" style="margin-top: 10px; font-size: 13px;"><strong>Now Available!</strong> <a href="/index.php?app-download=nokia">Download WordPress for Nokia</a></span><br /><br />' );
}
</script>
<?php
diff --git a/plugins/jetpack/modules/minileven/theme/pub/minileven/content-gallery.php b/plugins/jetpack/modules/minileven/theme/pub/minileven/content-gallery.php
index 8db8861b..fd8697ea 100644
--- a/plugins/jetpack/modules/minileven/theme/pub/minileven/content-gallery.php
+++ b/plugins/jetpack/modules/minileven/theme/pub/minileven/content-gallery.php
@@ -11,18 +11,18 @@
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<header class="entry-header">
<div class="entry-heading">
- <h2 class="entry-title"><a href="<?php the_permalink(); ?>" title="<?php echo esc_attr( sprintf( __( 'Permalink to %s', 'jetpack' ), the_title_attribute( 'echo=0' ) ) ); ?>" rel="bookmark"><?php the_title(); ?></a></h2>
+ <h2 class="entry-title"><a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a></h2>
<h3 class="entry-format"><?php _e( 'Gallery', 'jetpack' ); ?></h3>
</div>
</header><!-- .entry-header -->
<div class="entry-content">
- <?php if ( is_single() ) : ?>
+ <?php if ( is_single() || post_password_required() ) : ?>
<?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'jetpack' ) ); ?>
<?php else : ?>
<?php
- $images = get_children( array( 'post_parent' => $post->ID, 'post_type' => 'attachment', 'post_mime_type' => 'image', 'orderby' => 'rand', 'order' => 'ASC', 'numberposts' => 999 ) );
+ $images = minileven_get_gallery_images();
if ( $images ) :
$total_images = count( $images );
$large_image = array_shift( $images );
@@ -68,7 +68,7 @@
<footer class="entry-meta">
<?php minileven_posted_on(); ?>
<?php if ( comments_open() ) : ?>
- <span class="comments-link"><?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a Reply', 'jetpack' ) . '</span>', __( '<b>1</b> Reply', 'minileven' , 'jetpack'), __( '<b>%</b> Replies', 'minileven' , 'jetpack') ); ?></span>
+ <span class="comments-link"><?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a Reply', 'jetpack' ) . '</span>', __( '<b>1</b> Reply', 'jetpack' ), __( '<b>%</b> Replies', 'jetpack' ) ); ?></span>
<?php endif; // End if comments_open() ?>
<?php edit_post_link( __( 'Edit', 'jetpack' ), '<span class="edit-link">', '</span>' ); ?>
diff --git a/plugins/jetpack/modules/minileven/theme/pub/minileven/content.php b/plugins/jetpack/modules/minileven/theme/pub/minileven/content.php
index 7d035c29..e434ea41 100644
--- a/plugins/jetpack/modules/minileven/theme/pub/minileven/content.php
+++ b/plugins/jetpack/modules/minileven/theme/pub/minileven/content.php
@@ -8,27 +8,25 @@
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<header class="entry-header">
- <?php if ( '1' == get_option( 'wp_mobile_featured_images' ) && is_home() || is_search() || is_archive() ) : ?>
+ <?php if ( '1' == get_option( 'wp_mobile_featured_images' ) && minileven_show_featured_images() ) : ?>
<div class="entry-thumbnail">
<a href="<?php the_permalink(); ?>" title="<?php echo esc_attr( sprintf( __( 'Permalink to %s', 'jetpack' ), the_title_attribute( 'echo=0' ) ) ); ?>" rel="<?php the_ID(); ?>" class="minileven-featured-thumbnail"><?php the_post_thumbnail(); ?></a>
</div><!-- .entry-thumbnail -->
<?php endif; ?>
<?php if ( is_sticky() ) : ?>
<div class="entry-heading">
- <h2 class="entry-title"><a href="<?php the_permalink(); ?>" title="<?php echo esc_attr( sprintf( __( 'Permalink to %s', 'jetpack' ), the_title_attribute( 'echo=0' ) ) ); ?>" rel="bookmark"><?php the_title(); ?></a></h2>
+ <h2 class="entry-title"><a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a></h2>
<h3 class="entry-format"><?php _e( 'Featured', 'jetpack' ); ?></h3>
<div>
<?php else : ?>
- <h1 class="entry-title"><a href="<?php the_permalink(); ?>" title="<?php echo esc_attr( sprintf( __( 'Permalink to %s', 'jetpack' ), the_title_attribute( 'echo=0' ) ) ); ?>" rel="bookmark"><?php the_title(); ?></a></h1>
+ <h1 class="entry-title"><a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a></h1>
<?php endif; ?>
<div class="entry-meta">
<?php if ( is_singular() && is_multi_author() ) : ?>
<span class="author-link">
<?php _e( 'Posted by ', 'jetpack' ); ?>
- <a href="<?php echo esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ); ?>" rel="author">
- <?php printf( __( '%s', 'jetpack' ), get_the_author() ); ?>
- </a>
+ <?php the_author_posts_link(); ?>
</span><!-- .author-link -->
<?php endif; ?>
</div><!-- .entry-meta -->
@@ -48,7 +46,7 @@
<?php minileven_posted_on(); ?>
<?php endif; ?>
<?php if ( comments_open() ) : ?>
- <span class="comments-link"><?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a reply', 'jetpack' ) . '</span>', __( '<b>1</b> Reply', 'minileven' , 'jetpack'), __( '<b>%</b> Replies', 'minileven' , 'jetpack') ); ?></span>
+ <span class="comments-link"><?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a reply', 'jetpack' ) . '</span>', __( '<b>1</b> Reply', 'jetpack' ), __( '<b>%</b> Replies', 'jetpack' ) ); ?></span>
<?php endif; // End if comments_open() ?>
<?php edit_post_link( __( 'Edit', 'jetpack' ), '<span class="edit-link">', '</span>' ); ?>
</footer><!-- #entry-meta -->
@@ -62,4 +60,4 @@
</nav><!-- #nav-single -->
<?php endif; ?>
- <?php comments_template( '', true ); ?> \ No newline at end of file
+ <?php comments_template( '', true ); ?>
diff --git a/plugins/jetpack/modules/minileven/theme/pub/minileven/footer.php b/plugins/jetpack/modules/minileven/theme/pub/minileven/footer.php
index d57b6177..b820b34f 100644
--- a/plugins/jetpack/modules/minileven/theme/pub/minileven/footer.php
+++ b/plugins/jetpack/modules/minileven/theme/pub/minileven/footer.php
@@ -21,14 +21,31 @@
global $wp;
$current_url = trailingslashit( home_url( add_query_arg( array(), $wp->request ) ) );
?>
- <a href="<?php echo $current_url . '?ak_action=reject_mobile'; ?>">View Full Site</a><br />
- <?php do_action( 'wp_mobile_theme_footer' ); ?>
- <?php do_action( 'minileven_credits' ); ?>
- <a href="<?php echo esc_url( __( 'http://wordpress.org/', 'jetpack' ) ); ?>" title="<?php esc_attr_e( 'Semantic Personal Publishing Platform', 'minileven' , 'jetpack'); ?>" rel="generator"><?php printf( __( 'Proudly powered by %s', 'minileven' , 'jetpack'), 'WordPress' ); ?></a>
+ <a href="<?php echo $current_url . '?ak_action=reject_mobile'; ?>"><?php _e( 'View Full Site', 'jetpack' ); ?></a><br />
+
+ <?php
+ /**
+ * Fires after the View Full Site link in the Mobile Theme's footer.
+ *
+ * By default, a promo to download the native apps is added to this action.
+ *
+ * @since 1.8.0
+ */
+ do_action( 'wp_mobile_theme_footer' );
+
+ /**
+ * Fires before the credit links in the Mobile Theme's footer.
+ *
+ * @since 1.8.0
+ */
+ do_action( 'minileven_credits' );
+ ?>
+
+ <a href="<?php echo esc_url( __( 'http://wordpress.org/', 'jetpack' ) ); ?>" title="<?php esc_attr_e( 'Semantic Personal Publishing Platform', 'jetpack' ); ?>" rel="generator"><?php printf( __( 'Proudly powered by %s', 'jetpack' ), 'WordPress' ); ?></a>
</div>
</footer><!-- #colophon -->
<?php wp_footer(); ?>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/plugins/jetpack/modules/minileven/theme/pub/minileven/functions.php b/plugins/jetpack/modules/minileven/theme/pub/minileven/functions.php
index b33de783..5904a0ae 100644
--- a/plugins/jetpack/modules/minileven/theme/pub/minileven/functions.php
+++ b/plugins/jetpack/modules/minileven/theme/pub/minileven/functions.php
@@ -50,7 +50,9 @@ function minileven_setup() {
* If you're building a theme based on Minileven, use a find and replace
* to change 'minileven' to the name of your theme in all the template files.
*/
- load_theme_textdomain( 'minileven', TEMPLATEPATH . '/languages' );
+/* Don't load a minileven textdomain, as it uses the Jetpack textdomain.
+ load_theme_textdomain( 'minileven', get_template_directory() . '/languages' );
+*/
// Add default posts and comments RSS feed links to <head>.
add_theme_support( 'automatic-feed-links' );
@@ -62,10 +64,7 @@ function minileven_setup() {
add_theme_support( 'post-formats', array( 'gallery' ) );
// Add support for custom backgrounds
- if ( version_compare( $wp_version, '3.4', '>=' ) )
- add_theme_support( 'custom-background' );
- else
- add_custom_background();
+ add_theme_support( 'custom-background' );
// Add support for post thumbnails
add_theme_support( 'post-thumbnails' );
@@ -93,13 +92,13 @@ function minileven_fonts() {
/* translators: If there are characters in your language that are not supported
by Open Sans, translate this to 'off'. Do not translate into your own language. */
- if ( 'off' !== _x( 'on', 'Open Sans font: on or off', 'minileven' ) ) {
+ if ( 'off' !== _x( 'on', 'Open Sans font: on or off', 'jetpack' ) ) {
$opensans_subsets = 'latin,latin-ext';
/* translators: To add an additional Open Sans character subset specific to your language, translate
this to 'greek', 'cyrillic' or 'vietnamese'. Do not translate into your own language. */
- $opensans_subset = _x( 'no-subset', 'Open Sans font: add new subset (greek, cyrillic, vietnamese)', 'minileven' );
+ $opensans_subset = _x( 'no-subset', 'Open Sans font: add new subset (greek, cyrillic, vietnamese)', 'jetpack' );
if ( 'cyrillic' == $opensans_subset )
$opensans_subsets .= ',cyrillic,cyrillic-ext';
@@ -108,13 +107,11 @@ function minileven_fonts() {
elseif ( 'vietnamese' == $opensans_subset )
$opensans_subsets .= ',vietnamese';
- $protocol = is_ssl() ? 'https' : 'http';
-
$opensans_query_args = array(
'family' => 'Open+Sans:200,200italic,300,300italic,400,400italic,600,600italic,700,700italic',
'subset' => $opensans_subsets,
);
- wp_register_style( 'minileven-open-sans', add_query_arg( $opensans_query_args, "$protocol://fonts.googleapis.com/css" ), array(), null );
+ wp_register_style( 'minileven-open-sans', add_query_arg( $opensans_query_args, "//fonts.googleapis.com/css" ), array(), null );
}
}
add_action( 'init', 'minileven_fonts' );
@@ -158,6 +155,10 @@ function minileven_get_menu_location() {
$theme_slug = minileven_actual_current_theme();
$mods = get_option( "theme_mods_{$theme_slug}" );
+ if ( has_filter( 'jetpack_mobile_theme_menu' ) ) {
+ return array( 'primary' => apply_filters( 'jetpack_mobile_theme_menu', $menu_id ) );
+ }
+
if ( isset( $mods['nav_menu_locations'] ) && ! empty( $mods['nav_menu_locations'] ) )
return $mods['nav_menu_locations'];
@@ -185,4 +186,56 @@ function minileven_get_background() {
* If the user has set a static front page, show all posts on the front page, instead of a static page.
*/
if ( '1' == get_option( 'wp_mobile_static_front_page' ) )
- add_filter( 'pre_option_page_on_front', '__return_zero' ); \ No newline at end of file
+ add_filter( 'pre_option_page_on_front', '__return_zero' );
+
+/**
+ * Retrieves the IDs for images in a gallery.
+ *
+ * @uses get_post_galleries() first, if available. Falls back to shortcode parsing,
+ * then as last option uses a get_posts() call.
+ *
+ * @return array List of image IDs from the post gallery.
+ */
+function minileven_get_gallery_images() {
+ $images = array();
+
+ if ( function_exists( 'get_post_galleries' ) ) {
+ $galleries = get_post_galleries( get_the_ID(), false );
+ if ( isset( $galleries[0]['ids'] ) )
+ $images = explode( ',', $galleries[0]['ids'] );
+ } else {
+ $pattern = get_shortcode_regex();
+ preg_match( "/$pattern/s", get_the_content(), $match );
+ $atts = shortcode_parse_atts( $match[3] );
+ if ( isset( $atts['ids'] ) )
+ $images = explode( ',', $atts['ids'] );
+ }
+
+ if ( ! $images ) {
+ $images = get_posts( array(
+ 'fields' => 'ids',
+ 'numberposts' => 999,
+ 'order' => 'ASC',
+ 'orderby' => 'menu_order',
+ 'post_mime_type' => 'image',
+ 'post_parent' => get_the_ID(),
+ 'post_type' => 'attachment',
+ ) );
+ }
+
+ return $images;
+}
+
+/**
+ * Allow plugins to filter where Featured Images are displayed.
+ * Default has Featured Images disabled on single view and pages.
+ *
+ * @uses is_search()
+ * @uses apply_filters()
+ * @return bool
+ */
+function minileven_show_featured_images() {
+ $enabled = ( is_home() || is_search() || is_archive() ) ? true : false;
+
+ return (bool) apply_filters( 'minileven_show_featured_images', $enabled );
+}
diff --git a/plugins/jetpack/modules/minileven/theme/pub/minileven/header.php b/plugins/jetpack/modules/minileven/theme/pub/minileven/header.php
index 1b7cad92..4273be0a 100644
--- a/plugins/jetpack/modules/minileven/theme/pub/minileven/header.php
+++ b/plugins/jetpack/modules/minileven/theme/pub/minileven/header.php
@@ -15,6 +15,7 @@
<link rel="profile" href="http://gmpg.org/xfn/11" />
<link rel="pingback" href="<?php bloginfo( 'pingback_url' ); ?>" />
<?php wp_head(); ?>
+</head>
<body <?php body_class(); ?>>
<div id="wrapper">
@@ -26,10 +27,11 @@
<h3 class="menu-toggle"><?php _e( 'Menu', 'jetpack' ); ?></h3>
<?php /* Allow screen readers / text browsers to skip the navigation menu and get right to the good stuff. */ ?>
- <div class="skip-link"><a class="assistive-text" href="#content" title="<?php esc_attr_e( 'Skip to primary content', 'jetpack' ); ?>"><?php _e( 'Skip to primary content', 'minileven' , 'jetpack'); ?></a></div>
+ <div class="skip-link"><a class="assistive-text" href="#content"><?php _e( 'Skip to primary content', 'jetpack' ); ?></a></div>
<?php /* Our navigation menu. If one isn't filled out, wp_nav_menu falls back to wp_page_menu. The menu assiged to the primary position is the one used. If none is assigned, the menu with the lowest ID is used. */
if ( false !== $location ) :
- $menu_id = array_shift( array_values( $location ) ); // acccess the ID of the menu assigned to that location. Using only the first menu ID returned in the array.
+ $location_values = array_values( $location );
+ $menu_id = array_shift( $location_values ); // acccess the ID of the menu assigned to that location. Using only the first menu ID returned in the array.
wp_nav_menu( array( 'theme_location' => 'primary', 'container_class' => '', 'menu_class' => 'nav-menu', 'menu' => $menu_id ) );
else: // if the $location variable is false, wp_page_menu() is shown instead.
wp_nav_menu( array( 'theme_location' => 'primary', 'container_class' => '', 'menu_class' => 'nav-menu' ) );
@@ -41,7 +43,24 @@
</div><!-- .search-form-->
</div><!-- .menu-search-->
- <?php minileven_header(); ?>
+ <?php
+ /**
+ * Fires before Minileven header.
+ *
+ * @since 3.4.0
+ */
+ do_action( 'jetpack_mobile_header_before' );
+
+ if ( function_exists( 'minileven_header' ) )
+ minileven_header();
+
+ /**
+ * Fires after Minileven header.
+ *
+ * @since 3.4.0
+ */
+ do_action( 'jetpack_mobile_header_after' );
+ ?>
<div id="page" class="hfeed">
- <div id="main"> \ No newline at end of file
+ <div id="main">
diff --git a/plugins/jetpack/modules/minileven/theme/pub/minileven/image.php b/plugins/jetpack/modules/minileven/theme/pub/minileven/image.php
index 30f57195..15c5f1d5 100644
--- a/plugins/jetpack/modules/minileven/theme/pub/minileven/image.php
+++ b/plugins/jetpack/modules/minileven/theme/pub/minileven/image.php
@@ -77,14 +77,14 @@ get_header(); ?>
?>
</div><!-- .attachment-meta-->
<?php if ( comments_open() ) : ?>
- <span class="comments-link"><?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a reply', 'jetpack' ) . '</span>', __( '<b>1</b> Reply', 'minileven' , 'jetpack'), __( '<b>%</b> Replies', 'minileven' , 'jetpack') ); ?></span>
+ <span class="comments-link"><?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a reply', 'jetpack' ) . '</span>', __( '<b>1</b> Reply', 'jetpack' ), __( '<b>%</b> Replies', 'jetpack' ) ); ?></span>
<?php endif; // End if comments_open() ?>
<?php edit_post_link( __( 'Edit', 'jetpack' ), '<span class="edit-link">', '</span>' ); ?>
</footer><!-- #entry-meta -->
</article><!-- #post-<?php the_ID(); ?> -->
<nav id="nav-single">
- <h3 class="assistive-text"><?php _e( 'Image navigation', 'next-saturday' , 'jetpack' ); ?></h3>
+ <h3 class="assistive-text"><?php _ex( 'Image navigation', 'next-saturday' , 'jetpack' ); ?></h3>
<span class="nav-previous"><?php previous_image_link( false, __( '&laquo; Previous' , 'jetpack' ) ); ?></span>
<span class="nav-next"><?php next_image_link( false, __( 'Next &raquo; ' , 'jetpack' ) ); ?></span>
</nav><!-- #nav-single -->
@@ -95,4 +95,4 @@ get_header(); ?>
</div><!-- #content -->
</div><!-- #primary -->
-<?php get_footer(); ?> \ No newline at end of file
+<?php get_footer(); ?>
diff --git a/plugins/jetpack/modules/minileven/theme/pub/minileven/inc/tweaks.php b/plugins/jetpack/modules/minileven/theme/pub/minileven/inc/tweaks.php
index 8bbaf4da..a0c664f5 100644
--- a/plugins/jetpack/modules/minileven/theme/pub/minileven/inc/tweaks.php
+++ b/plugins/jetpack/modules/minileven/theme/pub/minileven/inc/tweaks.php
@@ -96,3 +96,8 @@ function minileven_wp_title( $title, $sep ) {
return $title;
}
add_filter( 'wp_title', 'minileven_wp_title', 10, 2 );
+
+/**
+ * Add theme support for Responsive Videos.
+ */
+add_theme_support( 'jetpack-responsive-videos' ); \ No newline at end of file
diff --git a/plugins/jetpack/modules/minileven/theme/pub/minileven/index.php b/plugins/jetpack/modules/minileven/theme/pub/minileven/index.php
index 9821b6d6..63a51a19 100644
--- a/plugins/jetpack/modules/minileven/theme/pub/minileven/index.php
+++ b/plugins/jetpack/modules/minileven/theme/pub/minileven/index.php
@@ -30,7 +30,7 @@ get_header(); ?>
<?php elseif ( is_tag() ) : ?>
<?php printf( __( 'Tagged with %s', 'jetpack' ), '<span>' . single_tag_title( '', false ) . '</span>' ); ?>
<?php elseif( is_author() ) : ?>
- <?php printf( __( 'Posted by', 'jetpack' ), '<span>' . get_the_author() . '</span>' ); ?>
+ <?php printf( __( 'Posted by %s', 'jetpack' ), '<span>' . get_the_author() . '</span>' ); ?>
<?php else : ?>
<?php _e( 'Blog Archives', 'jetpack' ); ?>
<?php endif; ?>
@@ -72,4 +72,4 @@ get_header(); ?>
</div><!-- #primary -->
<?php get_sidebar(); ?>
-<?php get_footer(); ?> \ No newline at end of file
+<?php get_footer(); ?>
diff --git a/plugins/jetpack/modules/minileven/theme/pub/minileven/js/small-menu.js b/plugins/jetpack/modules/minileven/theme/pub/minileven/js/small-menu.js
index 7eaf1e33..1f336a2f 100644
--- a/plugins/jetpack/modules/minileven/theme/pub/minileven/js/small-menu.js
+++ b/plugins/jetpack/modules/minileven/theme/pub/minileven/js/small-menu.js
@@ -5,12 +5,14 @@
*/
( function() {
var nav = document.getElementById( 'access' ), button, menu;
- if ( ! nav )
+ if ( ! nav ) {
return;
+ }
button = nav.getElementsByTagName( 'h3' )[0];
menu = nav.getElementsByTagName( 'ul' )[0];
- if ( ! button )
+ if ( ! button ) {
return;
+ }
// Hide button if menu is missing or empty.
if ( ! menu || ! menu.childNodes.length ) {
@@ -19,10 +21,11 @@
}
button.onclick = function() {
- if ( -1 == menu.className.indexOf( 'nav-menu' ) )
+ if ( -1 === menu.className.indexOf( 'nav-menu' ) ) {
menu.className = 'nav-menu';
+ }
- if ( -1 != button.className.indexOf( 'toggled-on' ) ) {
+ if ( -1 !== button.className.indexOf( 'toggled-on' ) ) {
button.className = button.className.replace( ' toggled-on', '' );
menu.className = menu.className.replace( ' toggled-on', '' );
} else {
@@ -30,4 +33,4 @@
menu.className += ' toggled-on';
}
};
-} )(); \ No newline at end of file
+} )();
diff --git a/plugins/jetpack/modules/minileven/theme/pub/minileven/screenshot.png b/plugins/jetpack/modules/minileven/theme/pub/minileven/screenshot.png
index 348e94c0..d735057f 100644
--- a/plugins/jetpack/modules/minileven/theme/pub/minileven/screenshot.png
+++ b/plugins/jetpack/modules/minileven/theme/pub/minileven/screenshot.png
Binary files differ
diff --git a/plugins/jetpack/modules/minileven/theme/pub/minileven/style.css b/plugins/jetpack/modules/minileven/theme/pub/minileven/style.css
index 0def5169..28a3273e 100644
--- a/plugins/jetpack/modules/minileven/theme/pub/minileven/style.css
+++ b/plugins/jetpack/modules/minileven/theme/pub/minileven/style.css
@@ -7,7 +7,7 @@ Description: The Minileven theme is a clean, lightweight mobile experience for y
Version: 2.0-wpcom
License: GNU General Public License
License URI: license.txt
-Tags: dark, light, white, black, gray, one-column, flexible-width, responsive-width, custom-background, custom-header, custom-menu, full-width-template, infinite-scroll, microformats, post-formats, rtl-language-support, sticky-post, theme-options, translation-ready, blog, bright, clean, contemporary, elegant, minimal, modern, photography, simple, tumblelog
+Tags: dark, light, white, black, gray, one-column, fluid-layout, responsive-layout, custom-background, custom-header, custom-menu, full-width-template, infinite-scroll, microformats, post-formats, rtl-language-support, sticky-post, theme-options, translation-ready, blog, bright, clean, contemporary, elegant, minimal, modern, photography, simple, tumblelog
*/
.image-attachment .entry-caption p {
@@ -59,7 +59,6 @@ table, caption, tbody, tfoot, thead, tr, th, td {
body {
background: #fff;
line-height: 1;
- -webkit-overflow-scrolling: touch;
}
ol, ul {
list-style: none;
@@ -290,6 +289,19 @@ iframe,
object {
width: auto;
}
+.jetpack-video-wrapper {
+ margin-bottom: 1.0em;
+}
+
+/* Make sure the WordPress Video Shortcode scales on smaller screens */
+video {
+ height: 100% !important;
+ max-width: 100% !important;
+ width: 100% !important;
+}
+.wp-video {
+ width: 100% !important;
+}
/* =Header
@@ -363,10 +375,6 @@ header img {
#access h3.toggled-on {
opacity: 0.8;
}
-#access {
- position: relative;
- z-index: 99999;
- }
#access ul.nav-menu {
background: #fff;
-webkit-box-shadow: 0 0 2px rgba(0, 0, 0, 0.15), 0 3px 8px rgba(0, 0, 0, 0.1);
@@ -379,6 +387,9 @@ header img {
width: 100%;
z-index: 99999;
}
+.admin-bar #access ul.nav-menu {
+ top: 6.6em;
+}
.main-small-navigation .menu {
background: #f9f9f9;
border: 1px solid #e9e9e9;
@@ -655,9 +666,7 @@ dl.gallery-item {
.entry-content img,
.comment-content img,
.widget img {
- display: block;
height: auto;
- margin: 0 auto;
max-width: 100% !important; /* Fluid images for posts, comments, and widgets */
}
#content .gallery-columns-3 .gallery-item img,
@@ -677,6 +686,12 @@ img.size-large {
width: auto; /* Prevent stretching of full-size and large-size images with height and width attributes in IE8 */
height: auto; /* Make sure images with WordPress-added height and width attributes are scaled correctly */
}
+img.size-full,
+img.size-large,
+img.size-medium {
+ display: block;
+ margin: 0 auto;
+}
.entry-content img.wp-smiley {
border: none;
margin-bottom: 0;
@@ -1396,7 +1411,6 @@ a.comment-reply-link > span {
}
#reply-title {
font-size: 1.5em;
- line-height: 0.733;
}
.comment #reply-title {
margin-top: 1em;
diff --git a/plugins/jetpack/modules/mobile-push.php b/plugins/jetpack/modules/mobile-push.php
index 2d28653e..a421f47d 100644
--- a/plugins/jetpack/modules/mobile-push.php
+++ b/plugins/jetpack/modules/mobile-push.php
@@ -1,13 +1,6 @@
<?php
/**
- * Module Name: Mobile Push Notifications
- * Module Description: Receive notifications on your mobile device.
- * Sort Order: 100
- * First Introduced: 1.9
- * Requires Connection: Yes
- * Auto Activate: Yes
- */
-
-Jetpack_Sync::sync_comments( __FILE__, array(
- 'comment_stati' => array( 'approved', 'unapproved' ),
-) );
+ * Deprecated. See notes.php for the new module
+ *
+ * @package Jetpack
+ **/
diff --git a/plugins/jetpack/modules/module-extras.php b/plugins/jetpack/modules/module-extras.php
index 86bcbc5d..1402ea09 100644
--- a/plugins/jetpack/modules/module-extras.php
+++ b/plugins/jetpack/modules/module-extras.php
@@ -4,11 +4,22 @@
* For example, if a module shouldn't be activatable unless certain conditions are met, the code belongs in this file.
*/
-// Happy Holidays!
-require_once( dirname( __FILE__ ) . '/holiday-snow.php' );
-
// Include extra tools that aren't modules, in a filterable way
-$jetpack_tools_to_include = apply_filters( 'jetpack-tools-to-include', array( 'theme-tools.php' ) );
+$tools = array(
+ 'theme-tools/social-links.php',
+ 'holiday-snow.php', // Happy Holidays!!!
+ 'theme-tools/random-redirect.php',
+ 'theme-tools/featured-content.php',
+ 'theme-tools/infinite-scroll.php',
+ 'theme-tools/responsive-videos.php',
+ 'theme-tools/site-logo.php',
+ 'theme-tools/site-breadcrumbs.php',
+ 'custom-post-types/comics.php',
+ 'custom-post-types/testimonial.php',
+ 'custom-post-types/nova.php',
+ 'theme-tools.php',
+);
+$jetpack_tools_to_include = apply_filters( 'jetpack-tools-to-include', $tools );
if ( ! empty( $jetpack_tools_to_include ) ) {
foreach ( $jetpack_tools_to_include as $tool ) {
@@ -16,4 +27,4 @@ if ( ! empty( $jetpack_tools_to_include ) ) {
require_once( JETPACK__PLUGIN_DIR . '/modules/' . $tool );
}
}
-} \ No newline at end of file
+}
diff --git a/plugins/jetpack/modules/module-headings.php b/plugins/jetpack/modules/module-headings.php
new file mode 100644
index 00000000..836e9ca4
--- /dev/null
+++ b/plugins/jetpack/modules/module-headings.php
@@ -0,0 +1,240 @@
+<?php return;
+
+/**
+ * This file exists soley to store the module
+ * header translation strings, that exist ordinarily
+ * in comments on files in this directory.
+ *
+ * It is never included anywhere, and is used for parsing.
+ */
+
+// modules/after-the-deadline.php
+_x( 'Spelling and Grammar', 'Module Name', 'jetpack' );
+_x( 'Check your spelling, style, and grammar with the After the Deadline proofreading service.', 'Module Description', 'jetpack' );
+
+// modules/carousel.php
+_x( 'Carousel', 'Module Name', 'jetpack' );
+_x( 'Transform standard image galleries into full-screen slideshows.', 'Module Description', 'jetpack' );
+_x( 'brings your photos and images to life as full-size, easily navigable galleries.', 'Jumpstart Description', 'jetpack' );
+
+// modules/comments.php
+_x( 'Jetpack Comments', 'Module Name', 'jetpack' );
+_x( 'Let readers comment with WordPress.com, Twitter, Facebook, or Google+ accounts.', 'Module Description', 'jetpack' );
+
+// modules/contact-form.php
+_x( 'Contact Form', 'Module Name', 'jetpack' );
+_x( 'Insert a contact form anywhere on your site.', 'Module Description', 'jetpack' );
+_x( 'adds a button to your post and page editors, allowing you to build simple forms to help visitors stay in touch.', 'Jumpstart Description', 'jetpack' );
+
+// modules/custom-content-types.php
+_x( 'Custom Content Types', 'Module Name', 'jetpack' );
+_x( 'Organize and display different types of content on your site, separate from posts and pages.', 'Module Description', 'jetpack' );
+
+// modules/custom-css.php
+_x( 'Custom CSS', 'Module Name', 'jetpack' );
+_x( 'Customize your site’s CSS without modifying your theme.', 'Module Description', 'jetpack' );
+
+// modules/enhanced-distribution.php
+_x( 'Enhanced Distribution', 'Module Name', 'jetpack' );
+_x( 'Share your public posts and comments to search engines and other services.', 'Module Description', 'jetpack' );
+
+// modules/gravatar-hovercards.php
+_x( 'Gravatar Hovercards', 'Module Name', 'jetpack' );
+_x( 'Enable pop-up business cards over commenters’ Gravatars.', 'Module Description', 'jetpack' );
+_x( 'let commenters link their profiles to their Gravatar accounts, making it easy for your visitors to learn more about your community.', 'Jumpstart Description', 'jetpack' );
+
+// modules/infinite-scroll.php
+_x( 'Infinite Scroll', 'Module Name', 'jetpack' );
+_x( 'Add support for infinite scroll to your theme.', 'Module Description', 'jetpack' );
+
+// modules/json-api.php
+_x( 'JSON API', 'Module Name', 'jetpack' );
+_x( 'Allow applications to securely access your content through the cloud.', 'Module Description', 'jetpack' );
+
+// modules/latex.php
+_x( 'Beautiful Math', 'Module Name', 'jetpack' );
+_x( 'Use LaTeX markup language in posts and pages for complex equations and other geekery.', 'Module Description', 'jetpack' );
+
+// modules/likes.php
+_x( 'Likes', 'Module Name', 'jetpack' );
+_x( 'Give visitors an easy way to show their appreciation for your content.', 'Module Description', 'jetpack' );
+
+// modules/manage.php
+_x( 'Manage', 'Module Name', 'jetpack' );
+_x( 'Manage all your sites from a centralized place, https://wordpress.com/sites.', 'Module Description', 'jetpack' );
+_x( 'helps you remotely manage plugins, turn on automated updates, and more from <a href="https://wordpress.com/plugins/" target="_blank">wordpress.com</a>.', 'Jumpstart Description', 'jetpack' );
+
+// modules/markdown.php
+_x( 'Markdown', 'Module Name', 'jetpack' );
+_x( 'Write posts or pages in plain-text Markdown syntax.', 'Module Description', 'jetpack' );
+
+// modules/minileven.php
+_x( 'Mobile Theme', 'Module Name', 'jetpack' );
+_x( 'Optimize your site with a mobile-friendly theme for smartphones.', 'Module Description', 'jetpack' );
+
+// modules/monitor.php
+_x( 'Monitor', 'Module Name', 'jetpack' );
+_x( 'Receive notifications from Jetpack if your site goes offline — and when it it returns.', 'Module Description', 'jetpack' );
+
+// modules/notes.php
+_x( 'Notifications', 'Module Name', 'jetpack' );
+_x( 'Receive notification of site activity via the admin toolbar and your Mobile devices.', 'Module Description', 'jetpack' );
+
+// modules/omnisearch.php
+_x( 'Omnisearch', 'Module Name', 'jetpack' );
+_x( 'Search your entire database from a single field in your Dashboard.', 'Module Description', 'jetpack' );
+
+// modules/photon.php
+_x( 'Photon', 'Module Name', 'jetpack' );
+_x( 'Accelerate your site by loading images from the WordPress.com CDN.', 'Module Description', 'jetpack' );
+_x( 'mirrors and serves your images from our free and fast image CDN, improving your site’s performance with no additional load on your servers.', 'Jumpstart Description', 'jetpack' );
+
+// modules/post-by-email.php
+_x( 'Post by Email', 'Module Name', 'jetpack' );
+_x( 'Publish posts by email, using any device and email client.', 'Module Description', 'jetpack' );
+
+// modules/protect.php
+_x( 'Protect', 'Module Name', 'jetpack' );
+_x( 'Adds brute force protection to your login page. Formerly BruteProtect.', 'Module Description', 'jetpack' );
+
+// modules/publicize.php
+_x( 'Publicize', 'Module Name', 'jetpack' );
+_x( 'Share new posts on social media networks automatically.', 'Module Description', 'jetpack' );
+
+// modules/related-posts.php
+_x( 'Related Posts', 'Module Name', 'jetpack' );
+_x( 'Display links to your related content under posts and pages.', 'Module Description', 'jetpack' );
+_x( 'keep visitors engaged on your blog by highlighting relevant and new content at the bottom of each published post.', 'Jumpstart Description', 'jetpack' );
+
+// modules/sharedaddy.php
+_x( 'Sharing', 'Module Name', 'jetpack' );
+_x( 'Allow visitors to share your content on Facebook, Twitter, and more with a click.', 'Module Description', 'jetpack' );
+_x( 'Twitter, Facebook and Google+ buttons at the bottom of each post, making it easy for visitors to share your content.', 'Jumpstart Description', 'jetpack' );
+
+// modules/shortcodes.php
+_x( 'Shortcode Embeds', 'Module Name', 'jetpack' );
+_x( 'Embed content from YouTube, Vimeo, SlideShare, and more, no coding necessary.', 'Module Description', 'jetpack' );
+
+// modules/shortlinks.php
+_x( 'WP.me Shortlinks', 'Module Name', 'jetpack' );
+_x( 'Enable WP.me-powered shortlinks for all posts and pages.', 'Module Description', 'jetpack' );
+
+// modules/site-icon.php
+_x( 'Site Icon', 'Module Name', 'jetpack' );
+_x( 'Add a site icon to your site.', 'Module Description', 'jetpack' );
+
+// modules/sso.php
+_x( 'Jetpack Single Sign On', 'Module Name', 'jetpack' );
+_x( 'Allow your users to log in using their WordPress.com accounts.', 'Module Description', 'jetpack' );
+_x( 'lets you login to all your Jetpack-enabled sites with one click using your WordPress.com account.', 'Jumpstart Description', 'jetpack' );
+
+// modules/stats.php
+_x( 'WordPress.com Stats', 'Module Name', 'jetpack' );
+_x( 'Monitor your stats with clear, concise reports and no additional load on your server.', 'Module Description', 'jetpack' );
+
+// modules/subscriptions.php
+_x( 'Subscriptions', 'Module Name', 'jetpack' );
+_x( 'Allow users to subscribe to your posts and comments and receive notifications via email.', 'Module Description', 'jetpack' );
+_x( 'give visitors two easy subscription options — while commenting, or via a separate email subscription widget you can display.', 'Jumpstart Description', 'jetpack' );
+
+// modules/tiled-gallery.php
+_x( 'Tiled Galleries', 'Module Name', 'jetpack' );
+_x( 'Display your image galleries in a variety of sleek, graphic arrangements.', 'Module Description', 'jetpack' );
+
+// modules/vaultpress.php
+_x( 'VaultPress', 'Module Name', 'jetpack' );
+_x( 'Protect your site with automatic backups and security scans. (Subscription required.)', 'Module Description', 'jetpack' );
+
+// modules/verification-tools.php
+_x( 'Site Verification', 'Module Name', 'jetpack' );
+_x( 'Verify your site or domain with Google Webmaster Tools, Pinterest, and others.', 'Module Description', 'jetpack' );
+
+// modules/videopress.php
+_x( 'VideoPress', 'Module Name', 'jetpack' );
+_x( 'Upload and embed videos right on your site. (Subscription required.)', 'Module Description', 'jetpack' );
+
+// modules/widget-visibility.php
+_x( 'Widget Visibility', 'Module Name', 'jetpack' );
+_x( 'Specify which widgets appear on which pages of your site.', 'Module Description', 'jetpack' );
+
+// modules/widgets.php
+_x( 'Extra Sidebar Widgets', 'Module Name', 'jetpack' );
+_x( 'Add images, Twitter streams, your site’s RSS links, and more to your sidebar.', 'Module Description', 'jetpack' );
+
+// Modules with `Other` tag:
+// - modules/contact-form.php
+// - modules/notes.php
+// - modules/site-icon.php
+_x( 'Other', 'Module Tag', 'jetpack' );
+
+// Modules with `Writing` tag:
+// - modules/after-the-deadline.php
+// - modules/custom-content-types.php
+// - modules/enhanced-distribution.php
+// - modules/json-api.php
+// - modules/latex.php
+// - modules/markdown.php
+// - modules/post-by-email.php
+// - modules/shortcodes.php
+_x( 'Writing', 'Module Tag', 'jetpack' );
+
+// Modules with `Photos and Videos` tag:
+// - modules/carousel.php
+// - modules/photon.php
+// - modules/shortcodes.php
+// - modules/tiled-gallery.php
+// - modules/videopress.php
+_x( 'Photos and Videos', 'Module Tag', 'jetpack' );
+
+// Modules with `Social` tag:
+// - modules/comments.php
+// - modules/gravatar-hovercards.php
+// - modules/likes.php
+// - modules/publicize.php
+// - modules/sharedaddy.php
+// - modules/shortcodes.php
+// - modules/shortlinks.php
+// - modules/subscriptions.php
+// - modules/widgets.php
+_x( 'Social', 'Module Tag', 'jetpack' );
+
+// Modules with `Appearance` tag:
+// - modules/custom-css.php
+// - modules/gravatar-hovercards.php
+// - modules/infinite-scroll.php
+// - modules/minileven.php
+// - modules/photon.php
+// - modules/shortcodes.php
+// - modules/widget-visibility.php
+// - modules/widgets.php
+_x( 'Appearance', 'Module Tag', 'jetpack' );
+
+// Modules with `Developers` tag:
+// - modules/json-api.php
+// - modules/omnisearch.php
+// - modules/sso.php
+_x( 'Developers', 'Module Tag', 'jetpack' );
+
+// Modules with `Centralized Management` tag:
+// - modules/manage.php
+_x( 'Centralized Management', 'Module Tag', 'jetpack' );
+
+// Modules with `Recommended` tag:
+// - modules/manage.php
+// - modules/minileven.php
+// - modules/monitor.php
+// - modules/photon.php
+// - modules/protect.php
+// - modules/publicize.php
+// - modules/related-posts.php
+// - modules/sharedaddy.php
+// - modules/stats.php
+_x( 'Recommended', 'Module Tag', 'jetpack' );
+
+// Modules with `Mobile` tag:
+// - modules/minileven.php
+_x( 'Mobile', 'Module Tag', 'jetpack' );
+
+// Modules with `WordPress.com Stats` tag:
+// - modules/stats.php
+_x( 'WordPress.com Stats', 'Module Tag', 'jetpack' );
diff --git a/plugins/jetpack/modules/module-info.php b/plugins/jetpack/modules/module-info.php
index f4b8ac8c..d78f3cf5 100644
--- a/plugins/jetpack/modules/module-info.php
+++ b/plugins/jetpack/modules/module-info.php
@@ -5,6 +5,8 @@
* jetpack_module_more_info_<module-slug> hooks are for pre-connection information
* jetpack_module_more_info_connected_<module-slug> hooks are used once the user
* is connected to show them links to admin panels, usage info etc.
+ * jetpack_search_terms_<module-slug> filters are searchable from the settings page.
+ * Separate your search terms by comma, and please send translation context with _x()
*/
// VaultPress (stub)
@@ -19,11 +21,10 @@ function vaultpress_jetpack_more_info() {
<div class="jp-info-img">
<a href="<?php echo $vaultpress_url?>">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/vaultpress.png' ) ?>" alt="<?php esc_attr_e( 'VaultPress', 'jetpack' ) ?>" width="300" height="150" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/vaultpress.png' ) ?>" alt="<?php esc_attr_e( 'VaultPress', 'jetpack' ) ?>" width="300" height="150" />
</a>
</div>
- <h4><?php esc_html_e( 'VaultPress', 'jetpack' ) ?></h4>
<?php if ( class_exists( 'VaultPress' ) || function_exists( 'vaultpress_contact_service' ) ) : ?>
<p><?php esc_html_e( 'Your WordPress installation is currently being protected with the world&#8217;s best security, backup, and support.', 'jetpack' ); ?></p>
<p><?php printf( _x( 'To check your backups, see any security alerts, or check your VaultPress Vitality, visit your %s.', 'Visit your _VaultPress_dashboard_.', 'jetpack' ), '<a href="https://dashboard.vaultpress.com/">' . esc_html__( 'VaultPress dashboard', 'jetpack' ) . '</a>' ); ?></a></p>
@@ -50,11 +51,10 @@ add_filter( 'jetpack_learn_more_button_vaultpress', 'vaultpress_jetpack_load_mor
function grofiles_more_info() { ?>
<div class="jp-info-img">
<a href="http://blog.gravatar.com/2010/10/06/gravatar-hovercards-on-wordpress-com/">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/hovercards.png' ) ?>" alt="<?php esc_attr_e( 'Gravatar Hovercard', 'jetpack' ) ?>" width="300" height="150" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/hovercards.png' ) ?>" alt="<?php esc_attr_e( 'Gravatar Hovercard', 'jetpack' ) ?>" width="300" height="150" />
</a>
</div>
- <h4><?php esc_html_e( 'Gravatar Hovercards', 'jetpack' ) ?></h4>
<h5><?php esc_html_e( "What&#8217;s a Hovercard?", 'jetpack' ) ?></h5>
<p><?php esc_html_e( 'Hovercards enhance plain Gravatar images with information about a person: name, bio, pictures, their contact info, and other services they use on the web like Twitter, Facebook, or LinkedIn.', 'jetpack' ); ?></p>
<p><?php esc_html_e( 'Hovercards offer a great way to show your internet presence and help people find your own blog.', 'jetpack' ); ?></p>
@@ -65,11 +65,10 @@ add_action( 'jetpack_module_more_info_gravatar-hovercards', 'grofiles_more_info'
function grofiles_more_info_connected() { ?>
<div class="jp-info-img">
<a href="http://blog.gravatar.com/2010/10/06/gravatar-hovercards-on-wordpress-com/">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/hovercards.png' ) ?>" alt="<?php esc_attr_e( 'Gravatar Hovercard', 'jetpack' ) ?>" width="300" height="150" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/hovercards.png' ) ?>" alt="<?php esc_attr_e( 'Gravatar Hovercard', 'jetpack' ) ?>" width="300" height="150" />
</a>
</div>
- <h4><?php esc_html_e( 'Gravatar Hovercards', 'jetpack' ) ?></h4>
<h5><?php esc_html_e( "What&#8217;s a Hovercard?", 'jetpack' ) ?></h5>
<p><?php esc_html_e( 'Hovercards enhance plain Gravatar images with information about a person: name, bio, pictures, their contact info, and other services.', 'jetpack' ); ?></p>
<p><?php esc_html_e( 'To see hovercards, look at any blog post on your blog that has comments. If the commenter has a hovercard associated with their gravatar, mouse over their image and the hovercard will appear. To turn hovercards off, click the Deactivate button above.', 'jetpack' ); ?></p>
@@ -87,11 +86,10 @@ add_filter( 'jetpack_learn_more_button_gravatar-hovercards', 'grofiles_load_more
function jetpack_shortcodes_more_info() { ?>
<div class="jp-info-img">
<a href="http://en.support.wordpress.com/shortcodes/">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/shortcodes.png' ) ?>" alt="<?php esc_attr_e( 'Shortcode Embeds', 'jetpack' ) ?>" width="300" height="150" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/shortcodes.png' ) ?>" alt="<?php esc_attr_e( 'Shortcode Embeds', 'jetpack' ) ?>" width="300" height="150" />
</a>
</div>
- <h4><?php esc_html_e( 'Shortcode Embeds', 'jetpack' ) ?></h4>
<p><?php esc_html_e( 'Shortcodes allow you to easily and safely embed media from other places in your site. With just one simple code, you can tell WordPress to embed YouTube, Flickr, and other media.', 'jetpack' ) ?></p>
<?php
}
@@ -100,25 +98,35 @@ add_action( 'jetpack_module_more_info_shortcodes', 'jetpack_shortcodes_more_info
function jetpack_shortcodes_more_info_connected() { ?>
<div class="jp-info-img">
<a href="http://en.support.wordpress.com/shortcodes/">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/shortcodes.png' ) ?>" alt="<?php esc_attr_e( 'Shortcode Embeds', 'jetpack' ) ?>" width="300" height="150" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/shortcodes.png' ) ?>" alt="<?php esc_attr_e( 'Shortcode Embeds', 'jetpack' ) ?>" width="300" height="150" />
</a>
</div>
- <h4><?php esc_html_e( 'Shortcode Embeds', 'jetpack' ) ?></h4>
<p><?php esc_html_e( 'Shortcodes allow you to easily and safely embed media from other places in your site. With just one simple code, you can tell WordPress to embed YouTube, Flickr, and other media.', 'jetpack' ) ?></p>
<p><?php esc_html_e( 'Enter a shortcode directly into the Post/Page editor to embed media. For specific instructions follow the links below.', 'jetpack' ) ?></p>
<?php
$codes = array( 'archives' => 'http://support.wordpress.com/archives-shortcode/',
- 'audio' => 'http://support.wordpress.com/audio/',
+ 'bandcamp' => 'http://en.support.wordpress.com/audio/bandcamp/',
'blip.tv' => 'http://support.wordpress.com/videos/bliptv/',
'dailymotion' => 'http://support.wordpress.com/videos/dailymotion/',
+ 'facebook' => 'http://en.support.wordpress.com/facebook-integration/facebook-embeds/',
'flickr' => 'http://support.wordpress.com/videos/flickr-video/',
+ 'gist' => 'http://en.support.wordpress.com/gist/',
+ 'googlemaps' => 'http://support.wordpress.com/google-maps/',
+ 'jetpack_subscription_form' => 'http://jetpack.me/support/subscriptions/#display',
+ 'polldaddy' => 'http://support.polldaddy.com/wordpress-shortcodes/',
+ 'presentation' => 'http://en.support.wordpress.com/presentations/',
+ 'recipes' => 'http://en.support.wordpress.com/recipes/',
'scribd' => 'http://support.wordpress.com/scribd/',
'slideshare' => 'http://support.wordpress.com/slideshows/slideshare/',
+ 'slideshow' => 'http://en.support.wordpress.com/slideshows/',
'soundcloud' => 'http://support.wordpress.com/audio/soundcloud-audio-player/',
+ 'ted' => 'http://en.support.wordpress.com/videos/ted-talks/',
+ 'twitter-timeline' => 'http://en.support.wordpress.com/widgets/twitter-timeline-widget/#embedding-with-a-shortcode',
+ // 'upcomingevents' => 'http://en.support.wordpress.com/widgets/upcoming-events/#events-list-shortcode',
'vimeo' => 'http://support.wordpress.com/videos/vimeo/',
+ 'vine' => 'http://en.support.wordpress.com/videos/vine/',
'youtube' => 'http://support.wordpress.com/videos/youtube/',
- 'polldaddy' => 'http://support.polldaddy.com/wordpress-shortcodes/',
);
$codes['wpvideo (VideoPress)'] = 'http://en.support.wordpress.com/videopress/';
@@ -144,11 +152,10 @@ add_filter( 'jetpack_learn_more_button_shortcodes', 'jetpack_shortcodes_load_mor
function wpme_more_info() { ?>
<div class="jp-info-img">
<a href="http://wp.me/sf2B5-shorten">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/shortlinks.png' ) ?>" alt="<?php esc_attr_e( 'WP.me Shortlinks', 'jetpack' ) ?>" width="300" height="150" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/shortlinks.png' ) ?>" alt="<?php esc_attr_e( 'WP.me Shortlinks', 'jetpack' ) ?>" width="300" height="150" />
</a>
</div>
- <h4><?php esc_html_e( 'WP.me Shortlinks' , 'jetpack' ); ?></h4>
<p><?php esc_html_e( "Instead of typing or copy-pasting long URLs, you can now get a short and simple link to your posts and pages. This uses the super compact wp.me domain name, and gives you a unique URL you can use that will be safe and reliable.", 'jetpack' ) ?></p>
<p><?php esc_html_e( "It&#8217;s perfect for use on Twitter, Facebook, and cell phone text messages where every character counts.", 'jetpack' ) ?></p>
<?php
@@ -158,11 +165,10 @@ add_action( 'jetpack_module_more_info_shortlinks', 'wpme_more_info' );
function wpme_more_info_connected() { ?>
<div class="jp-info-img">
<a href="http://wp.me/sf2B5-shorten">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/shortlinks.png' ) ?>" alt="<?php esc_attr_e( 'WP.me Shortlinks', 'jetpack' ) ?>" width="300" height="150" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/shortlinks.png' ) ?>" alt="<?php esc_attr_e( 'WP.me Shortlinks', 'jetpack' ) ?>" width="300" height="150" />
</a>
</div>
- <h4><?php esc_html_e( 'WP.me Shortlinks' , 'jetpack' ); ?></h4>
<p><?php esc_html_e( "Instead of typing or copy-pasting long URLs, you can now get a short and simple link to your posts and pages. This uses the super compact wp.me domain name, and gives you a unique URL you can use that will be safe and reliable.", 'jetpack' ) ?></p>
<p><?php esc_html_e( "To use shortlinks, go to any already published post (or publish something new!). A &#8220;Get Shortlink&#8221; button will be visible under the Post title. When you click it, a dialog box will appear with the shortlink and you can copy and paste to Twitter, Facebook or wherever your heart desires.", 'jetpack' ) ?></p>
<?php
@@ -179,11 +185,10 @@ add_filter( 'jetpack_learn_more_button_shortlinks', 'wpme_load_more_link' );
function stats_more_info() { ?>
<div class="jp-info-img">
<a href="http://en.support.wordpress.com/stats/">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/stats.png' ) ?>" alt="<?php esc_attr_e( 'WordPress.com Stats', 'jetpack' ) ?>" width="300" height="150" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/stats.png' ) ?>" alt="<?php esc_attr_e( 'WordPress.com Stats', 'jetpack' ) ?>" width="300" height="150" />
</a>
</div>
- <h4><?php esc_html_e( 'WordPress.com Stats' , 'jetpack' ); ?></h4>
<p><?php esc_html_e( 'There are many plugins and services that provide statistics, but data can be overwhelming. WordPress.com Stats makes the most popular metrics easy to understand through a clear and attractive interface.', 'jetpack' ) ?></p>
<?php
}
@@ -192,11 +197,10 @@ add_action( 'jetpack_module_more_info_stats', 'stats_more_info' );
function stats_more_info_connected() { ?>
<div class="jp-info-img">
<a href="http://en.support.wordpress.com/stats/">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/stats.png' ) ?>" alt="<?php esc_attr_e( 'WordPress.com Stats', 'jetpack' ) ?>" width="300" height="150" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/stats.png' ) ?>" alt="<?php esc_attr_e( 'WordPress.com Stats', 'jetpack' ) ?>" width="300" height="150" />
</a>
</div>
- <h4><?php esc_html_e( 'WordPress.com Stats' , 'jetpack' ); ?></h4>
<p><?php esc_html_e( 'There are many plugins and services that provide statistics, but data can be overwhelming. WordPress.com Stats makes the most popular metrics easy to understand through a clear and attractive interface.', 'jetpack' ) ?></p>
<p><?php printf( __( 'You can <a href="%s">view your stats dashboard here</a>.', 'jetpack' ), admin_url( 'admin.php?page=stats' ) ); ?></p>
<?php
@@ -208,15 +212,20 @@ function stats_load_more_link( $description ) {
}
add_filter( 'jetpack_learn_more_button_stats', 'stats_load_more_link' );
+function jetpack_stats_search_terms( $terms ) {
+ $terms = _x( 'statistics, tracking, analytics, views, traffic', 'search terms', 'jetpack' );
+ return $terms;
+}
+add_filter( 'jetpack_search_terms_stats', 'jetpack_stats_search_terms' );
+
// Publicize
function publicize_more_info() { ?>
<div class="jp-info-img">
<a href="http://en.support.wordpress.com/publicize/">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/publicize.png' ) ?>" alt="<?php esc_attr_e( 'Publicize', 'jetpack' ) ?>" width="328" height="123" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/publicize.png' ) ?>" alt="<?php esc_attr_e( 'Publicize', 'jetpack' ) ?>" width="328" height="123" />
</a>
</div>
- <h4><?php esc_html_e( 'Publicize' , 'jetpack' ); ?></h4>
<p><?php esc_html_e( 'Publicize allows you to connect your blog to popular social networking sites and automatically share new posts with your friends. You can make a connection for just yourself or for all users on your blog.', 'jetpack' ) ?></p>
<p><?php esc_html_e( 'Publicize allows you to share your posts on Facebook, Twitter, Tumblr, Yahoo!, and Linkedin.', 'jetpack' ); ?></p>
@@ -242,11 +251,10 @@ add_filter( 'jetpack_learn_more_button_publicize', 'publicize_load_more_link' );
function notes_more_info() { ?>
<div class="jp-info-img">
<a href="http://support.wordpress.com/notifications/">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/notes.png' ) ?>" alt="<?php esc_attr_e( 'Notifications', 'jetpack' ) ?>" width="300" height="150" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/notes.png' ) ?>" alt="<?php esc_attr_e( 'Notifications', 'jetpack' ) ?>" width="300" height="150" />
</a>
</div>
- <h4><?php esc_html_e( 'Notifications' , 'jetpack' ); ?></h4>
<p><?php esc_html_e( 'Keep up with the latest happenings on all your WordPress sites and interact with other WordPress.com users.', 'jetpack' ) ?></p>
<?php
}
@@ -255,11 +263,10 @@ add_action( 'jetpack_module_more_info_notes', 'notes_more_info' );
function notes_more_info_connected() { ?>
<div class="jp-info-img">
<a href="http://support.wordpress.com/notifications/">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/notes.png' ) ?>" alt="<?php esc_attr_e( 'Notifications', 'jetpack' ) ?>" width="300" height="150" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/notes.png' ) ?>" alt="<?php esc_attr_e( 'Notifications', 'jetpack' ) ?>" width="300" height="150" />
</a>
</div>
- <h4><?php esc_html_e( 'Notifications' , 'jetpack' ); ?></h4>
<p><?php esc_html_e( 'Keep up with the latest happenings on all your WordPress sites and interact with other WordPress.com users.', 'jetpack' ) ?></p>
<p><?php printf( __( 'You can view your notifications in the Toolbar and <a href="%s">on WordPress.com</a>.', 'jetpack' ), 'http://wordpress.com/#!/notifications/' ); ?></p>
<?php
@@ -276,11 +283,10 @@ add_filter( 'jetpack_learn_more_button_notes', 'notes_load_more_link' );
function latex_more_info() { ?>
<div class="jp-info-img">
<a href="http://support.wordpress.com/latex/">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/beautifulmath.png' ) ?>" alt="<?php esc_attr_e( 'LaTeX', 'jetpack' ) ?>" width="300" height="150" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/beautifulmath.png' ) ?>" alt="<?php esc_attr_e( 'LaTeX', 'jetpack' ) ?>" width="300" height="150" />
</a>
</div>
- <h4><img src="//s0.wp.com/latex.php?latex=%5CLaTeX&amp;bg=transparent&amp;fg=000&amp;s=1" alt="LaTeX logo" title="LaTeX" style="vertical-align: -27%" /> Makes Beautiful Math</h4>
<p><?php printf( esc_html__( '%s is a powerful markup language for writing complex mathematical equations, formulas, etc.', 'jetpack' ), '<a href="http://www.latex-project.org/" target="_blank"><img src="//s0.wp.com/latex.php?latex=%5CLaTeX&amp;bg=transparent&amp;fg=000&amp;s=-1" alt="LaTeX logo" title="LaTeX" style="vertical-align: -25%" /></a>' ); ?></p>
<p><?php printf( esc_html__( 'Jetpack combines the power of %s and the simplicity of WordPress to give you the ultimate in math blogging platforms.', 'jetpack' ), '<img src="//s0.wp.com/latex.php?latex=%5CLaTeX&amp;bg=transparent&amp;fg=000&amp;s=-1" alt="LaTeX logo" title="LaTeX" style="vertical-align: -25%" />' ); ?></p>
<p><?php esc_html_e( 'Wow, that sounds nerdy.', 'jetpack' ) ?></p>
@@ -291,11 +297,10 @@ add_action( 'jetpack_module_more_info_latex', 'latex_more_info' );
function latex_more_info_connected() { ?>
<div class="jp-info-img">
<a href="http://support.wordpress.com/latex/">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/beautifulmath.png' ) ?>" alt="<?php esc_attr_e( 'LaTeX', 'jetpack' ) ?>" width="300" height="150" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/beautifulmath.png' ) ?>" alt="<?php esc_attr_e( 'LaTeX', 'jetpack' ) ?>" width="300" height="150" />
</a>
</div>
- <h4><img src="//s0.wp.com/latex.php?latex=%5CLaTeX&amp;bg=transparent&amp;fg=000&amp;s=1" alt="LaTeX logo" title="LaTeX" style="vertical-align: -27%;" /> Makes Beautiful Math</h4>
<p><?php printf( esc_html__( '%s is a powerful markup language for writing complex mathematical equations, formulas, etc.', 'jetpack' ), '<a href="http://www.latex-project.org/" target="_blank"><img src="//s0.wp.com/latex.php?latex=%5CLaTeX&amp;bg=transparent&amp;fg=000&amp;s=-1" alt="LaTeX logo" title="LaTeX" style="vertical-align: -25%" /></a>' ); ?></p>
<p><?php printf( __( 'Use <code>$latex your latex code here$</code> or <code>[latex]your latex code here[/latex]</code> to include %s in your posts and comments. There are <a href="%s" target="_blank">all sorts of options</a> available.', 'jetpack' ), '<img src="//s0.wp.com/latex.php?latex=%5CLaTeX&amp;bg=transparent&amp;fg=000&amp;s=-1" alt="LaTeX logo" title="LaTeX" style="vertical-align: -25%" />', 'http://support.wordpress.com/latex/' ); ?></p>
<?php
@@ -312,10 +317,9 @@ add_filter( 'jetpack_learn_more_button_latex', 'latex_load_more_link' );
function sharedaddy_more_info() { ?>
<div class="jp-info-img">
<a href="http://en.support.wordpress.com/sharing/">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/sharing.png' ) ?>" alt="<?php esc_attr_e( 'Sharing', 'jetpack' ) ?>" width="300" height="150" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/sharing.png' ) ?>" alt="<?php esc_attr_e( 'Sharing', 'jetpack' ) ?>" width="300" height="150" />
</a>
</div>
- <h4><?php esc_html_e( 'Sharing' , 'jetpack' ); ?></h4>
<p><?php esc_html_e( 'Share your posts with Twitter, Facebook, and a host of other services. You can configure services to appear as icons, text, or both. Some services have additional options to display smart buttons, such as Twitter, which will update the number of times the post has been shared.', 'jetpack' ); ?></p>
<p><?php
@@ -336,7 +340,6 @@ function sharedaddy_more_info_connected() { ?>
<embed type="application/x-shockwave-flash" src="http://s0.videopress.com/player.swf?v=1.02" height="190" wmode="transparent" seamlesstabbing="true" allowfullscreen="true" allowscriptaccess="always" overstretch="true" flashvars="guid=WV0JOwY2"></embed>
</div>
- <h4><?php esc_html_e( 'Sharing' , 'jetpack' ); ?></h4>
<?php
if ( class_exists( 'Sharing_Admin' ) ) {
?>
@@ -363,12 +366,10 @@ add_filter( 'jetpack_learn_more_button_sharedaddy', 'sharedaddy_load_more_link'
function jpatd_more_info() { ?>
<div class="jp-info-img">
<a href="http://en.support.wordpress.com/proofreading/">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/spelling.png' ) ?>" alt="<?php esc_attr_e( 'Spelling and Grammar', 'jetpack' ) ?>" width="300" height="150" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/spelling.png' ) ?>" alt="<?php esc_attr_e( 'Spelling and Grammar', 'jetpack' ) ?>" width="300" height="150" />
</a>
</div>
- <h4><?php esc_html_e( 'Spelling and Grammar' , 'jetpack' ); ?></h4>
-
<p><?php printf( __( "The <a href='%s'>After&nbsp;the&nbsp;Deadline</a> Proofreading service improves your writing by using artificial intelligence to find your errors and offer smart suggestions.", 'jetpack' ), 'http://www.afterthedeadline.com/' ); ?></p>
<p><?php printf( __( 'After the Deadline provides a number of <a href="%s">customization options</a>, which you can edit in your profile.', 'jetpack' ), esc_url( get_edit_profile_url( get_current_user_id() ) ) . '#atd' ); ?></p>
<?php
@@ -384,11 +385,9 @@ add_filter( 'jetpack_learn_more_button_after-the-deadline', 'jpatd_load_more_lin
// RSS Links Widget, Image Widget, Twitter Widget
function jetpack_widgets_more_info() { ?>
<div class="jp-info-img">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/widgets.png' ) ?>" alt="<?php esc_attr_e( 'Widgets Screenshot', 'jetpack' ) ?>" width="300" height="150" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/widgets.png' ) ?>" alt="<?php esc_attr_e( 'Widgets Screenshot', 'jetpack' ) ?>" width="300" height="150" />
</div>
- <h4><?php esc_html_e( 'Extra Sidebar Widgets' , 'jetpack' ); ?></h4>
-
<p><strong><?php esc_html_e( 'The RSS Links Widget ', 'jetpack' ); ?></strong> <?php esc_html_e( "allows you to add links to your blog&#8217;s post and comment RSS feeds in your sidebar. This makes it easy for your readers to stay updated when you post new content or receive new comments.", 'jetpack' ) ?></p>
<p><strong><?php esc_html_e( 'The Twitter Widget ', 'jetpack' ); ?></strong> <?php esc_html_e( "shows your latest tweets within a sidebar on your theme. It&#8217;s an easy way to add more activity to your site. There are also a number of customization options.", 'jetpack' ) ?> <strong><?php esc_html_e( 'The Facebook Like Box Widget ', 'jetpack' ); ?></strong> <?php esc_html_e( "shows your Facebook Like Box within a sidebar on your theme. It&#8217;s a great way to let your readers show their support.", 'jetpack' ) ?> <strong><?php esc_html_e( 'The Image Widget ', 'jetpack' ); ?></strong><?php esc_html_e( "allows you to easily add images to widget areas in your theme. It&#8217;s an easy way to add more visual interest to your site.", 'jetpack' ) ?></p>
@@ -398,15 +397,16 @@ add_action( 'jetpack_module_more_info_widgets', 'jetpack_widgets_more_info' );
function jetpack_widgets_more_info_connected() { ?>
<div class="jp-info-img">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/widgets.png' ) ?>" alt="<?php esc_attr_e( 'Widgets Screenshot', 'jetpack' ) ?>" width="300" height="150" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/widgets.png' ) ?>" alt="<?php esc_attr_e( 'Widgets Screenshot', 'jetpack' ) ?>" width="300" height="150" />
</div>
- <h4><?php esc_html_e( 'Extra Sidebar Widgets' , 'jetpack' ); ?></h4>
-
- <p><strong><?php esc_html_e( 'The RSS Links Widget', 'jetpack' ); ?></strong> <?php esc_html_e( 'lets you easily add post and comment RSS feeds to a sidebar on your theme.', 'jetpack' ) ?></p>
- <p><strong><?php esc_html_e( 'The Twitter Widget', 'jetpack' ); ?></strong> <?php esc_html_e( 'shows your latest tweets within a sidebar on your theme.', 'jetpack' ) ?></p>
- <p><strong><?php esc_html_e( 'The Facebook Like Box Widget', 'jetpack' ); ?></strong> <?php esc_html_e( 'shows your Facebook Like Box within a sidebar on your theme.', 'jetpack' ) ?></p>
- <p><strong><?php esc_html_e( 'The Image Widget', 'jetpack' ); ?></strong> <?php esc_html_e( 'lets you easily add images to a sidebar on your theme.', 'jetpack' ) ?></p>
+ <p><?php printf( __( '<strong>The Twitter Widget</strong> shows your latest tweets within a sidebar on your theme.', 'jetpack' ) ); ?></p>
+ <p><?php printf( __( '<strong>The Facebook Like Box Widget</strong> shows your Facebook Like Box within a sidebar on your theme.', 'jetpack' ) ); ?></p>
+ <p><?php printf( __( '<strong>The Image Widget</strong> lets you easily add images to a sidebar on your theme.', 'jetpack' ) ); ?></strong> <?php esc_html_e( '', 'jetpack' ) ?></p>
+ <p><?php printf( __( '<strong>The Gravatar Widget</strong> allows you to pull in your Gravatar image along with some of your Gravatar profile data.', 'jetpack' ) ); ?></p>
+ <p><?php printf( __( '<strong>The Gallery Widget</strong> provides you with a simple way to display a photo gallery or slideshow in your blog’s sidebar. Requires the Tiled Gallery module.', 'jetpack' ) ); ?></p>
+ <p><?php printf( __( '<strong>The Display WordPress Posts Widget</strong> lets you display up to ten recent posts from another WordPress.com blog, or a self-hosted WordPress site with Jetpack enabled.', 'jetpack' ) ); ?></p>
+ <p><?php printf( __( '<strong>The Upcoming Events Widget</strong> allows you to use an iCalendar link to display a list of events on your site.', 'jetpack' ) ); ?></p>
<p><?php esc_html_e( 'Each of these widgets has a number of customization options.', 'jetpack' ); ?> <?php printf( __( 'To use the widgets, go to Appearance &#8594; <a href="%s">Widgets</a>. Drag them into one of your sidebars and configure away.', 'jetpack' ), admin_url( 'widgets.php' ) ); ?></p>
<?php
@@ -421,11 +421,9 @@ add_filter( 'jetpack_learn_more_button_widgets', 'jetpack_widgets_load_more_link
// Subscriptions
function jetpack_subscriptions_more_info() { ?>
<div class="jp-info-img">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/subscriptions.png' ) ?>" alt="<?php esc_attr_e( 'Subsriptions Screenshot', 'jetpack' ) ?>" width="300" height="150" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/subscriptions.png' ) ?>" alt="<?php esc_attr_e( 'Subsriptions Screenshot', 'jetpack' ) ?>" width="300" height="150" />
</div>
- <h4><?php esc_html_e( 'Subscriptions' , 'jetpack' ); ?></h4>
-
<p><?php esc_html_e( 'Easily allow any visitor to subscribe to all of your posts via email through a widget in your blog&#8217;s sidebar. Every time you publish a post, WordPress.com will send a notification to all your subscribers.', 'jetpack' ); ?></p>
<p><?php esc_html_e( 'When leaving comments, your visitors can also subscribe to a post&#8217;s comments to keep up with the conversation.', 'jetpack' ); ?></p>
@@ -434,6 +432,7 @@ function jetpack_subscriptions_more_info() { ?>
if ( 'jetpack_module_more_info_connected_subscriptions' == current_filter() )
printf( '<p>' . __( 'To use the Subscriptions widget, go to Appearance &#8594; <a href="%s">Widgets</a>. Drag the widget labeled &#8220;Blog Subscriptions (Jetpack)&#8221; into one of your sidebars and configure away.', 'jetpack' ) . '</p>', admin_url( 'widgets.php' ) );
printf( '<p>' . __( 'You can also make changes to your Subscription settings at the bottom of the <a href="%s">Discussion Settings</a> page.', 'jetpack' ) . '</p>', admin_url( 'options-discussion.php#jetpack-subscriptions-settings' ) );
+ printf( '<p>' . __( 'To customize the emails sent from your blog to your followers, check the settings at the bottom of the <a href="%s">Reading Settings</a> page.', 'jetpack' ) . '</p>', admin_url( 'options-reading.php#follower-settings' ) );
}
add_action( 'jetpack_module_more_info_subscriptions', 'jetpack_subscriptions_more_info' );
add_action( 'jetpack_module_more_info_connected_subscriptions', 'jetpack_subscriptions_more_info' );
@@ -446,8 +445,6 @@ add_action( 'jetpack_learn_more_button_subscriptions', 'jetpack_subscriptions_lo
// Enhanced Distribution
function jetpack_enhanced_distribution_more_info() { ?>
- <h4><?php esc_html_e( 'Enhanced Distribution' , 'jetpack' ); ?></h4>
-
<p><?php esc_html_e( 'Jetpack will automatically take the great published content from your blog or website and share it instantly with third party services like search engines, increasing your reach and traffic.', 'jetpack' ); ?></p>
<?php
@@ -461,10 +458,31 @@ function jetpack_enhanced_distribution_more_link() {
}
add_action( 'jetpack_learn_more_button_enhanced-distribution', 'jetpack_enhanced_distribution_more_link' );
+// Protect
+function jetpack_protect_more_info() { ?>
+ <p><?php esc_html_e( 'Jetpack Protect is a cloud-powered brute force attack prevention tool. We leverage the millions of WordPress sites to identify and block malicious IPs.
+
+Jetpack Protect tracks failed login attempts across all installed users of the plugin. If any single IP has too many failed attempts in a short period of time, they are blocked from logging in to any site with this plugin installed.
+
+Jetpack Protect is derived from BruteProtect, and will disable BruteProtect on your site if it is currently enabled.', 'jetpack' ); ?></p><?php
+}
+
+add_action( 'jetpack_module_more_info_protect', 'jetpack_protect_more_info' );
+add_action( 'jetpack_module_more_info_connected_protect', 'jetpack_protect_more_info' );
+
+function jetpack_protect_more_link() {
+ echo '<a class="button-secondary more-info-link" href="http://jetpack.me/support/protect/">' . esc_html__( 'Learn More', 'jetpack' ) . '</a>';
+}
+add_action( 'jetpack_learn_more_button_protect', 'jetpack_protect_more_link' );
+
+function jetpack_protect_search_terms( $terms ) {
+ $terms = _x( 'security, secure, protection, botnet, brute force', 'search terms', 'jetpack' );
+ return $terms;
+}
+add_filter( 'jetpack_search_terms_protect', 'jetpack_protect_search_terms' );
+
// JSON API
function jetpack_json_api_more_info() { ?>
- <h4><?php esc_html_e( 'JSON API' , 'jetpack' ); ?></h4>
-
<p><?php esc_html_e( 'Jetpack will allow you to authorize applications and services to securely connect to your blog and allow them to use your content in new ways and offer you new functionality.', 'jetpack' ); ?>
<p><?php _e( "Developers can use WordPress.com's <a href='http://developer.wordpress.com/docs/oauth2/'>OAuth2</a> authentication system and <a href='http://developer.wordpress.com/docs/api/'>WordPress.com REST API</a> to manage and access your site's content.", 'jetpack' ); ?></p>
@@ -486,20 +504,19 @@ function jetpack_contact_form_learn_more_button() {
}
function jetpack_contact_form_more_info() {
- echo '<div class="jp-info-img">';
- echo '<a href="http://support.wordpress.com/contact-form/">';
- echo '<img class="jp-info-img" src="' . plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/contactform.png' ) . '" alt="' . esc_attr__( 'Contact Form', 'jetpack' ) . '" width="300" height="150" />';
- echo '</a>';
- echo '</div>';
-
- echo '<h4>' . esc_html__( 'Contact Form', 'jetpack' ) . '</h4>';
+ echo '<div class="jp-info-img">';
+ echo '<a href="http://support.wordpress.com/contact-form/">';
+ echo '<img class="jp-info-img" src="' . plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/contactform.png' ) . '" alt="' . esc_attr__( 'Contact Form', 'jetpack' ) . '" width="300" height="150" />';
+ echo '</a>';
+ echo '</div>';
- echo '<p>';
- _e( 'A contact form is a great way to offer your readers the ability to get in touch, without giving out your personal email address.', 'jetpack' );
- echo '</p>';
+ echo '<p>';
+ _e( 'A contact form is a great way to offer your readers the ability to get in touch, without giving out your personal email address.', 'jetpack' );
+ echo '</p>';
- echo '<p>'; _e( 'Each contact form can easily be customized to fit your needs. When a user submits your contact form, the feedback will be filtered through <a href="http://akismet.com/">Akismet</a> (if it is active on your site) to make sure it’s not spam. Any legitimate feedback will then be emailed to you, and added to your feedback management area.', 'jetpack' );
- echo '</p>';
+ echo '<p>';
+ _e( 'Each contact form can easily be customized to fit your needs. When a user submits your contact form, the feedback will be filtered through <a href="http://akismet.com/">Akismet</a> (if it is active on your site) to make sure it’s not spam. Any legitimate feedback will then be emailed to you, and added to your feedback management area.', 'jetpack' );
+ echo '</p>';
}
add_action( 'jetpack_learn_more_button_contact-form', 'jetpack_contact_form_learn_more_button' );
@@ -515,11 +532,9 @@ function jetpack_comments_learn_more_button() {
function jetpack_comments_more_info() {
?>
<div class="jp-info-img">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/comments.png' ) ?>" alt="<?php esc_attr_e( 'Jetpack Comments Screenshot', 'jetpack' ) ?>" width="300" height="150" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/comments.png' ) ?>" alt="<?php esc_attr_e( 'Jetpack Comments Screenshot', 'jetpack' ) ?>" width="300" height="150" />
</div>
- <h4><?php esc_html_e( 'Jetpack Comments', 'jetpack' ); ?></h4>
-
<p><?php esc_html_e( 'Jetpack Comments enables your visitors to use their WordPress.com, Twitter, or Facebook accounts when commenting on your site.', 'jetpack' ); ?></p>
<?php if ( 'jetpack_module_more_info_connected_comments' == current_filter() ) : ?>
@@ -540,18 +555,16 @@ add_action( 'jetpack_module_more_info_connected_comments', 'jetpack_comments_mor
// Gallery Carousel: START
function jetpack_carousel_learn_more_button() {
- echo '<a class="button-secondary more-info-link" href="#">' . __( 'Learn More', 'jetpack' ) . '</a>';
+ echo '<a class="button-secondary more-info-link" href="#">' . __( 'Learn More', 'jetpack' ) . '</a>';
}
function jetpack_carousel_more_info() {
?>
<div class="jp-info-img">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/carousel.png' ) ?>" alt="<?php esc_attr_e( 'Gallery Carousel Screenshot', 'jetpack' ) ?>" width="300" height="188" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/carousel.png' ) ?>" alt="<?php esc_attr_e( 'Gallery Carousel Screenshot', 'jetpack' ) ?>" width="300" height="188" />
</div>
- <h4><?php esc_html_e( 'Carousel', 'jetpack' ); ?></h4>
-
- <p><?php esc_html_e( 'With Carousel active, any standard WordPress galleries you have embedded in posts or pages will launch a gorgeous full-screen photo browsing experience with comments and EXIF metadata.', 'jetpack' ); ?></p>
+ <p><?php esc_html_e( 'With Carousel active, any standard WordPress galleries you have embedded in posts or pages will launch a gorgeous full-screen photo browsing experience with comments and EXIF metadata.', 'jetpack' ); ?></p>
<?php
}
@@ -564,10 +577,9 @@ add_action( 'jetpack_module_more_info_connected_carousel', 'jetpack_carousel_mor
function jetpack_custom_css_more_info() {
?>
<div class="jp-info-img">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/custom-css.png' ) ?>" alt="<?php esc_attr_e( 'Custom CSS', 'jetpack' ) ?>" width="300" height="150" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/custom-css.png' ) ?>" alt="<?php esc_attr_e( 'Custom CSS', 'jetpack' ) ?>" width="300" height="150" />
</div>
- <h4><?php esc_html_e( 'Custom CSS', 'jetpack' ); ?></h4>
<p><?php esc_html_e( "The Custom CSS editor gives you the ability to add to or replace your theme's CSS, all while supplying syntax coloring, auto-indentation, and immediate feedback on the validity of the CSS you're writing.", 'jetpack' ); ?></p>
<p><?php printf( __( 'To use the CSS editor, go to Appearance &#8594; <a href="%s">Edit CSS</a>.', 'jetpack' ), admin_url( 'themes.php?page=editcss' ) ); ?></p>
@@ -586,10 +598,9 @@ add_action( 'jetpack_module_more_info_custom-css', 'jetpack_custom_css_more_info
function jetpack_minileven_more_info() {
?>
<div class="jp-info-img">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/mobile-theme.png' ) ?>" alt="<?php esc_attr_e( 'Mobile Theme', 'jetpack' ) ?>" width="300" height="150" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/mobile-theme.png' ) ?>" alt="<?php esc_attr_e( 'Mobile Theme', 'jetpack' ) ?>" width="300" height="150" />
</div>
- <h4><?php esc_html_e( 'Mobile Theme', 'jetpack' ); ?></h4>
<p><?php esc_html_e( "There's a good chance that visitors to your site will be using a smartphone, and it's important to provide them with a great reading experience while on the small screen.", 'jetpack' ); ?></p>
<p><?php esc_html_e( "Jetpack's mobile theme is optimized for small screens. It uses the header image, background, and widgets from your current theme for a great custom look. Post format support is included, so your photos and galleries will look fantastic on a smartphone.", 'jetpack' ); ?></p>
<p><?php esc_html_e( 'Visitors on iPhone, Android, Windows Phone, and other mobile devices will automatically see the mobile theme, with the option to view the full site. You can enable or disable the mobile theme by clicking the "Activate" or "Deactive" button above.', 'jetpack' ); ?></p>
@@ -604,28 +615,6 @@ add_action( 'jetpack_learn_more_button_minileven', 'jetpack_minileven_more_butto
add_action( 'jetpack_module_more_info_minileven', 'jetpack_minileven_more_info' );
// Minileven: STOP
-
-// Mobile Push Notifications: START
-function jetpack_mobile_push_notifications_more_info() { ?>
- <div class="jp-info-img">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/mobile-push-notifications.jpg' ) ?>" alt="<?php esc_attr_e( 'Mobile Push Notifications', 'jetpack' ) ?>" width="300" height="150" />
- </div>
-
- <h4><?php esc_html_e( 'Mobile Push Notifications' , 'jetpack' ); ?></h4>
-
- <p><?php echo sprintf( __( 'If you use <a href="%1$s">WordPress for iOS</a> or <a href="%2$s">WordPress for Android</a>, you’ll now be able to opt in to receive push notifications of new comments, which makes it easier than ever to keep up with your readers and moderate comments on the go.', 'jetpack' ), 'http://ios.wordpress.org/', 'http://android.wordpress.org/' ); ?></p>
-
-<?php
-}
-
-function jetpack_mobile_push_notifications_more_link() {
- echo '<a class="button-secondary more-info-link" href="#">' . __( 'Learn More', 'jetpack' ) . '</a>';
-}
-
-add_action( 'jetpack_learn_more_button_mobile-push', 'jetpack_mobile_push_notifications_more_link' );
-add_action( 'jetpack_module_more_info_mobile-push', 'jetpack_mobile_push_notifications_more_info' );
-// Mobile Push Notifications: STOP
-
// Infinite Scroll: START
/**
*
@@ -634,7 +623,6 @@ function jetpack_infinite_scroll_more_info() {
$support_text = sprintf( __( 'If you are a theme author, you can learn about adding support for Infinite Scroll at <a href="%1$s">%1$s</a>.', 'jetpack' ), 'http://jetpack.me/support/infinite-scroll/' );
?>
- <h4><?php esc_html_e( 'Infinite Scroll', 'jetpack' ); ?></h4>
<?php if ( ! Jetpack::is_active() || ( Jetpack::is_active() && current_theme_supports( 'infinite-scroll' ) ) ) : ?>
<p><?php esc_html_e( 'When you write great content, all you really want is people to find it, right?', 'jetpack' ); ?></p>
@@ -678,11 +666,9 @@ add_action( 'jetpack_learn_more_button_infinite-scroll', 'jetpack_infinite_scrol
// Post by Email: START
function jetpack_post_by_email_more_info() { ?>
<div class="jp-info-img">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/post-by-email.png' ) ?>" alt="<?php esc_attr_e( 'Post by Email', 'jetpack' ) ?>" width="300" height="115" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/post-by-email.png' ) ?>" alt="<?php esc_attr_e( 'Post by Email', 'jetpack' ) ?>" width="300" height="115" />
</div>
- <h4><?php esc_html_e( 'Post by Email' , 'jetpack' ); ?></h4>
-
<p><?php esc_html_e( 'Post by Email is a way of publishing posts on your blog by email. Any email client can be used to send the email, allowing you to publish quickly and easily from devices such as cell phones.', 'jetpack' ); ?></p>
<?php if ( 'jetpack_module_more_info_connected_post-by-email' == current_filter() ) : ?>
@@ -711,8 +697,6 @@ add_action( 'jetpack_learn_more_button_post-by-email', 'jetpack_post_by_email_mo
*
*/
function jetpack_photon_more_info() { ?>
- <h4><?php esc_html_e( 'Photon' , 'jetpack' ); ?></h4>
-
<p><?php esc_html_e( "Give your site a boost by loading images in posts from the WordPress.com content delivery network. We cache your images and serve them from our super-fast network, reducing the burden on your Web host with the click of a button.", 'jetpack' ); ?></p>
<?php
}
@@ -732,10 +716,8 @@ add_action( 'jetpack_learn_more_button_photon', 'jetpack_photon_more_link' );
// Tiled Galleries: START
function jetpack_tiled_gallery_more_info() { ?>
- <h4><?php esc_html_e( 'Tiled Galleries' , 'jetpack' ); ?></h4>
-
<div class="jp-info-img">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/tiled-gallery.png' ) ?>" alt="<?php esc_attr_e( 'Tiled Galleries', 'jetpack' ) ?>" width="300" height="150" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/tiled-gallery.png' ) ?>" alt="<?php esc_attr_e( 'Tiled Galleries', 'jetpack' ) ?>" width="300" height="150" />
</div>
<p><?php esc_html_e( 'Create elegant magazine-style mosaic layouts for your photos without having to use an external graphic editor.', 'jetpack' ); ?></p>
@@ -756,12 +738,10 @@ function jetpack_likes_more_info() { ?>
<div class="jp-info-img">
<a href="http://jetpack.me/support/likes/">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/likes.png' ) ?>" alt="<?php esc_attr_e( 'Likes', 'jetpack' ) ?>" width="323" height="69" />
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/likes.png' ) ?>" alt="<?php esc_attr_e( 'Likes', 'jetpack' ) ?>" width="323" height="69" />
</a>
</div>
- <h4><?php esc_html_e( 'Likes' , 'jetpack' ); ?></h4>
-
<p><?php esc_html_e( 'Likes allow your readers to show their appreciation for your posts and other published content using their WordPress.com accounts. Your readers will then be able to review their liked posts from WordPress.com.', 'jetpack' ) ?></p>
<p><?php esc_html_e( 'Displayed below your posts will be how many people have liked your posts and the Gravatars of those who have liked them.', 'jetpack' ); ?></p>
@@ -777,39 +757,11 @@ function jetpack_likes_more_link() {
add_action( 'jetpack_learn_more_button_likes', 'jetpack_likes_more_link' );
// Likes: STOP
-// Google+ Profile: START
-function jetpack_gplus_authorship_more_info() { ?>
-
- <div class="jp-info-img">
- <a href="http://jetpack.me/support/google-plus/">
- <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/_inc/images/screenshots/google-plus.png' ) ?>" alt="<?php esc_attr_e( 'Google+ Profile', 'jetpack' ) ?>" width="350" height="33" />
- </a>
- </div>
-
- <h4><?php esc_html_e( 'Google+ Profile' , 'jetpack' ); ?></h4>
-
- <p><?php esc_html_e( 'The Google+ profile module allows you to connect your blog and Google+ accounts.', 'jetpack' ) ?></p>
- <p><?php esc_html_e( 'Displayed below your posts will be a link back to your Google+ profile and a Google+ follow button. A link will also be added to your Google+ profile.', 'jetpack' ); ?></p>
-
- <p>&rarr; <a href="http://jetpack.me/support/google-plus/"><?php esc_html_e( 'More information on using Google+ Profile.', 'jetpack' ); ?></a></p>
-
-<?php
-}
-add_action( 'jetpack_module_more_info_gplus-authorship', 'jetpack_gplus_authorship_more_info' );
-
-function jetpack_gplus_authorship_more_link() {
- echo '<a class="button-secondary more-info-link" href="#">' . __( 'Learn More', 'jetpack' ) . '</a>';
-}
-add_action( 'jetpack_learn_more_button_gplus-authorship', 'jetpack_gplus_authorship_more_link' );
-// Google+ Profile: STOP
-
// Omnisearch: START
function jetpack_omnisearch_more_info() {
?>
- <h4><?php esc_html_e( 'Omnisearch' , 'jetpack' ); ?></h4>
-
- <p><?php esc_html_e( 'Search once, get results from everything! Currently supports searching posts, pages, comments, and plugins.', 'jetpack' ); ?></p>
+ <p><?php esc_html_e( 'Search once, get results from everything! Currently supports searching posts, pages, comments, media, and plugins.', 'jetpack' ); ?></p>
<p><?php esc_html_e( 'Omnisearch plays nice with other plugins by letting other providers offer results as well.', 'jetpack' ); ?></p>
@@ -830,8 +782,6 @@ add_action( 'jetpack_learn_more_button_omnisearch', 'jetpack_omnisearch_more_lin
// Widget Visibility: START
function jetpack_widget_visibility_more_info() { ?>
- <h4><?php esc_html_e( 'Widget Visibility', 'jetpack' ); ?></h4>
-
<p><?php esc_html_e( 'Control which pages your widgets appear on with Widget Visibility.', 'jetpack' ); ?></p>
<p><?php esc_html_e( 'To control visibility, expand the widget and click the Visibility button next to the Save button, and then, choose a set of visibility options.', 'jetpack' ); ?></p>
<p><?php esc_html_e( 'For example, if you wanted the Archives widget to only appear on category archives and error pages, choose "Show" from the first dropdown and then add two rules: "Page is 404 Error Page" and "Category is All Category Pages."', 'jetpack' ); ?></p>
@@ -847,30 +797,14 @@ add_action( 'jetpack_module_more_info_widget-visibility', 'jetpack_widget_visib
add_action( 'jetpack_learn_more_button_widget-visibility', 'jetpack_widget_visibility_more_link' );
// Widget Visibility: STOP
-
-// WordPress.com Connect: START
-function jetpack_wpcc_more_info() { ?>
- <h4><?php esc_html_e( 'WordPress.com Connect' , 'jetpack' ); ?></h4>
-
- <p><?php esc_html_e( 'With WordPress.com Connect, your users will be able to log into your WordPress admin with the same credentials they use to log into WordPress.com. It\'s safe and secure.' , 'jetpack' ); ?></p>
- <p><?php esc_html_e( 'Once enabled, a "Connect with WordPress.com" option will be added to your existing log-in form.' , 'jetpack' ); ?></p>
-
-<?php
-}
-
-function jetpack_wpcc_more_link() {
- echo '<a class="button-secondary more-info-link" href="http://jetpack.me/support/wpcc/">' . __( 'Learn More', 'jetpack' ) . '</a>';
-}
-
-add_action( 'jetpack_module_more_info_wpcc', 'jetpack_wpcc_more_info' );
-add_action( 'jetpack_learn_more_button_wpcc', 'jetpack_wpcc_more_link' );
-// WordPress.com Connect: STOP
-
// VideoPress: START
function jetpack_videopress_more_info() {
?>
- <h4><?php esc_html_e( 'VideoPress', 'jetpack' ); ?></h4>
- <p><?php _e( 'With the VideoPress module you can easily upload videos to your WordPress site and embed them in your posts and pages. This module requires a WordPress.com account with an active <a href="http://store.wordpress.com/premium-upgrades/videopress/" target="_blank">VideoPress subscription</a>.', 'jetpack' ); ?></p>
+ <p><?php printf(
+ __( 'With the VideoPress module you can easily upload videos to your WordPress site and embed them in your posts and pages. This module requires a WordPress.com account with an active <a href="%1$s" target="_blank">VideoPress subscription</a>. Once you have purchased a VideoPress subscription, <a href="%2$s">click here to configure VideoPress</a>.', 'jetpack' ),
+ 'http://store.wordpress.com/premium-upgrades/videopress/',
+ Jetpack::admin_url( 'page=jetpack&configure=videopress' )
+ ); ?></p>
<?php
}
add_action( 'jetpack_module_more_info_videopress', 'jetpack_videopress_more_info' );
@@ -880,3 +814,184 @@ function jetpack_videopress_more_link() {
}
add_action( 'jetpack_learn_more_button_videopress', 'jetpack_videopress_more_link' );
// VideoPress: STOP
+
+// SSO: START
+function jetpack_sso_more_info() { ?>
+
+ <p><?php esc_html_e( 'With WordPress.com Single Sign On, your users will be able to log in to or register for your WordPress site with the same credentials they use on WordPress.com. It\'s safe and secure.' , 'jetpack' ); ?></p>
+ <p><?php esc_html_e( 'Once enabled, a "Log in with WordPress.com" option will be added to your existing log in form.' , 'jetpack' ); ?></p>
+
+<?php
+}
+
+function jetpack_sso_more_link() {
+ echo '<a class="button-secondary more-info-link" href="http://jetpack.me/support/sso/">' . __( 'Learn More', 'jetpack' ) . '</a>';
+}
+
+add_action( 'jetpack_module_more_info_sso', 'jetpack_sso_more_info' );
+add_action( 'jetpack_learn_more_button_sso', 'jetpack_sso_more_link' );
+// SSO: STOP
+
+// Monitor: START
+function jetpack_monitor_more_info() { ?>
+
+ <p><?php esc_html_e( 'Nobody likes downtime, and that\'s why Jetpack Monitor is on the job, keeping tabs on your site by checking it every five minutes. As soon as any downtime is detected, you will receive an email notification alerting you to the issue. That way you can act quickly, to get your site back online again!', 'jetpack' ); ?>
+
+ <p><?php esc_html_e( 'We’ll also let you know as soon as your site is up and running, so you can keep an eye on total downtime.', 'jetpack'); ?></p>
+
+<?php
+}
+add_action( 'jetpack_module_more_info_monitor', 'jetpack_monitor_more_info' );
+
+function jetpack_monitor_more_link() {
+ echo '<a class="button-secondary more-info-link" href="http://jetpack.me/support/monitor/">' . esc_html__( 'Learn More', 'jetpack' ) . '</a>';
+}
+add_action( 'jetpack_learn_more_button_monitor', 'jetpack_monitor_more_link' );
+// Monitor: STOP
+
+// Related Posts: START
+function jetpack_related_posts_more_info() {
+ $template = <<<EOT
+ <div class="jp-info-img">
+ <a href="http://jetpack.me/support/related-posts/">
+ <img class="jp-info-img" src="%s" alt="%s" width="300" height="98" />
+ </a>
+ </div>
+
+ <p>%s</p>
+ <p>&rarr; <a href="http://jetpack.me/support/related-posts/">%s</a></p>
+EOT;
+ printf(
+ $template,
+ plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/related-posts.png' ),
+ esc_attr__( 'Related Posts', 'jetpack' ),
+ esc_html__( '"Related Posts" shows additional relevant links from your site under your posts. If the feature is enabled, links appear underneath your Sharing Buttons and WordPress.com Likes (if you’ve turned these on).', 'jetpack' ),
+ esc_html__( 'More information on using Related Posts.', 'jetpack' )
+ );
+}
+add_action( 'jetpack_module_more_info_related-posts', 'jetpack_related_posts_more_info' );
+
+function jetpack_related_posts_more_info_connected() {
+ $template = <<<EOT
+ <div class="jp-info-img">
+ <a href="http://jetpack.me/support/related-posts/">
+ <img class="jp-info-img" src="%s" alt="%s" width="300" height="98" />
+ </a>
+ </div>
+
+ <p>%s</p>
+ <p>&rarr; <a href="http://jetpack.me/support/related-posts/">%s</a></p>
+ <hr />
+ <p><a href="%s#sync-related-posts">%s</a></p>
+EOT;
+ printf(
+ $template,
+ plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/related-posts.png' ),
+ esc_attr__( 'Related Posts', 'jetpack' ),
+ esc_html__( '"Related Posts" shows additional relevant links from your site under your posts. If the feature is enabled, links appear underneath your Sharing Buttons and WordPress.com Likes (if you’ve turned these on).', 'jetpack' ),
+ esc_html__( 'More information on using Related Posts.', 'jetpack' ),
+ esc_url( Jetpack::admin_url( array( 'page' => 'jetpack-debugger' ) ) ),
+ esc_html__( 'This feature uses the WordPress.com infrastructure and requires that your public content be mirrored there. If you see intermittent issues only affecting certain posts, request a reindex of your posts.', 'jetpack' )
+ );
+}
+add_action( 'jetpack_module_more_info_connected_related-posts', 'jetpack_related_posts_more_info_connected' );
+
+function jetpack_related_posts_more_button() {
+ echo '<a class="button more-info-link" href="#">' . __( 'Learn More', 'jetpack' ) . '</a>';
+}
+add_action( 'jetpack_learn_more_button_related-posts', 'jetpack_related_posts_more_button' );
+// Related Posts: STOP
+
+// Markdown: START
+function jetpack_markdown_more_info() { ?>
+ <p><?php esc_html_e( 'Markdown lets you compose posts and comments with links, lists, and other styles using regular characters and punctuation marks. Markdown is used by writers and bloggers who want a quick and easy way to write rich text, without having to take their hands off the keyboard, and without learning a lot of complicated codes and shortcuts.', 'jetpack' ); ?></p>
+
+<?php
+}
+add_action( 'jetpack_module_more_info_markdown', 'jetpack_markdown_more_info' );
+
+function jetpack_markdown_more_link() {
+ echo '<a class="button-secondary more-info-link" href="http://en.support.wordpress.com/markdown/">' . esc_html__( 'Learn More', 'jetpack' ) . '</a>';
+}
+add_action( 'jetpack_learn_more_button_markdown', 'jetpack_markdown_more_link' );
+// Markdown: STOP
+
+// Site Verification Tools: START
+function jetpack_verification_tools_more_info() { ?>
+ <p><?php esc_html_e( 'Use these tools to verify that you own/control your website with other external services like Google, Bing and Pinterest.', 'jetpack' ); ?></p>
+ <p><?php printf( __( "Verifying your site allows you to access advanced features on these other services (e.g. Webmaster tools, or getting a verified badge). We'll just add an invisible %s tag to the source code of your homepage.", 'jetpack' ), '<code>meta</code>' ); ?></p>
+<?php
+}
+add_action( 'jetpack_module_more_info_verification-tools', 'jetpack_verification_tools_more_info' );
+
+function jetpack_verification_tools_more_link() {
+ echo '<a class="button-secondary more-info-link" href="http://support.wordpress.com/webmaster-tools/">' . __( 'Learn More', 'jetpack' ) . '</a>';
+}
+add_action( 'jetpack_learn_more_button_verification-tools', 'jetpack_verification_tools_more_link' );
+// Site Verification Tools: STOP
+
+// Custom Content Types: START
+function jetpack_custom_content_types_more_info() { ?>
+
+ <div class="jp-info-img">
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/custom-content-types.png' ) ?>" alt="<?php esc_attr_e( 'Custom Content Type', 'jetpack' ) ?>" width="300" height="150" />
+ </div>
+
+ <p><?php esc_html_e( 'Organize and display different types of content on your site, separate from posts and pages.', 'jetpack' ); ?></p>
+ <p><?php printf( __( 'To enable a custom content type, head over to <a href="%s">Settings &rarr; Writing &rarr; Your Custom Content Types</a> to activate either "Portfolio Projects” or “Testimonials” by checking the corresponding checkbox. You can now add projects and testimonials under the new "Portfolio” or “Testimonials” menu item in your sidebar.', 'jetpack' ), admin_url( 'options-writing.php#cpt-options' ) ); ?></p>
+ <p><?php printf( __( 'Once added, your custom content will be visible on your website at %s/portfolio/ or %s/testimonial/, or you may add them with <a href="http://jetpack.me/support/custom-content-types/" target="_blank">shortcodes</a>.', 'jetpack' ), get_site_url(), get_site_url() ); ?></p>
+<?php
+}
+add_action( 'jetpack_module_more_info_custom-content-types', 'jetpack_custom_content_types_more_info' );
+
+function jetpack_custom_content_types_more_link() {
+ echo '<a class="button-secondary more-info-link" href="http://support.wordpress.com/portfolios/">' . __( 'Learn More', 'jetpack' ) . '</a>';
+}
+add_action( 'jetpack_learn_more_button_custom-content-types', 'jetpack_custom_content_types_more_link' );
+// Custom Content Types: STOP
+
+// Site Icon: START
+function jetpack_custom_site_icon() { ?>
+
+
+ <div class="jp-info-img">
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/site-icon.png' ) ?>" alt="<?php esc_attr_e( 'Site Icon', 'jetpack' ) ?>" width="300" height="150" />
+ </div>
+
+ <p><?php esc_html_e( 'Site Icon lets you create an icon for your site. This icon will be used as favicon, mobile icon, and Tile on Windows 8 computers.', 'jetpack' ); ?></p>
+ <p><?php printf( __( 'To add a new icon to your site, head over to <a href="%s">Settings &rarr; General &rarr; Site Icon</a>, and upload an icon.', 'jetpack' ), admin_url( 'options-general.php#site-icon' ) ); ?></p>
+
+<?php
+}
+add_action( 'jetpack_module_more_info_site-icon', 'jetpack_custom_site_icon' );
+
+function jetpack_site_icon_more_link() {
+ echo '<a class="button-secondary more-info-link" href="http://jetpack.me/support/site-icon">' . __( 'Learn More', 'jetpack' ) . '</a>';
+}
+add_action( 'jetpack_learn_more_button_site-icon', 'jetpack_site_icon_more_link' );
+// Site Icon: STOP
+
+// Manage: Start
+function jetpack_custom_jetpack_manage() { ?>
+
+
+ <div class="jp-info-img">
+ <img class="jp-info-img" src="<?php echo plugins_url( basename( dirname( dirname( __FILE__ ) ) ) . '/images/screenshots/manage.png' ) ?>" alt="<?php esc_attr_e( 'Manage all of your WordPress sites, self-hosted or not, from WordPress.com', 'jetpack' ) ?>" width="300" height="150" />
+ </div>
+
+ <p><em><?php esc_html_e( 'Enabling Manage allows you to update your self-hosted WordPress sites along with any WordPress.com sites you have, all in one simple dashboard.', 'jetpack' ); ?></em></p>
+ <p><strong><?php _e( 'Plugins', 'jetpack' ); ?></strong><br />
+ <?php printf( __( 'Now you can update plugins, set plugins to automatically update, and activate or deactivate plugins on a per-site basis or in bulk from <a href="%s">wordpress.com/plugins</a>.', 'jetpack' ), 'https://wordpress.com/plugins' ); ?></p>
+
+ <p><strong><?php _e( 'Posts and Pages', 'jetpack' ); ?></strong><br />
+ <?php printf( __( 'Add a new post or page to any of your sites from a single interface.', 'jetpack' ) ); ?></p>
+
+<?php
+}
+add_action( 'jetpack_module_more_info_manage', 'jetpack_custom_jetpack_manage' );
+
+function jetpack_manage_more_link() {
+ echo '<a class="button-secondary more-info-link" href="http://jetpack.me/support/site-management/">' . __( 'Learn More', 'jetpack' ) . '</a>';
+}
+add_action( 'jetpack_learn_more_button_manage', 'jetpack_manage_more_link' );
+// Manage: STOP
diff --git a/plugins/jetpack/modules/monitor.php b/plugins/jetpack/modules/monitor.php
new file mode 100644
index 00000000..ecfa853c
--- /dev/null
+++ b/plugins/jetpack/modules/monitor.php
@@ -0,0 +1,156 @@
+<?php
+/**
+ * Module Name: Monitor
+ * Module Description: Receive notifications from Jetpack if your site goes offline — and when it it returns.
+ * Sort Order: 28
+ * Recommendation Order: 10
+ * First Introduced: 2.6
+ * Requires Connection: Yes
+ * Auto Activate: No
+ * Module Tags: Recommended
+ * Feature: Recommended
+ */
+
+add_action( 'jetpack_activate_module_monitor', array( Jetpack::init(), 'toggle_module_on_wpcom' ) );
+add_action( 'jetpack_deactivate_module_monitor', array( Jetpack::init(), 'toggle_module_on_wpcom' ) );
+
+class Jetpack_Monitor {
+
+ public $module = 'monitor';
+
+ function __construct() {
+ add_action( 'jetpack_modules_loaded', array( $this, 'jetpack_modules_loaded' ) );
+ add_action( 'jetpack_activate_module_monitor', array( $this, 'activate_module' ) );
+ }
+
+ public function activate_module() {
+ if ( Jetpack::is_user_connected() ) {
+ self::update_option_receive_jetpack_monitor_notification( true );
+ }
+ }
+
+ public function jetpack_modules_loaded() {
+ Jetpack::enable_module_configurable( $this->module );
+ Jetpack::module_configuration_load( $this->module, array( $this, 'jetpack_configuration_load' ) );
+ Jetpack::module_configuration_screen( $this->module, array( $this, 'jetpack_configuration_screen' ) );
+ }
+
+ public function jetpack_configuration_load() {
+ if ( Jetpack::is_user_connected() && ! self::is_active() ) {
+ Jetpack::deactivate_module( $this->module );
+ Jetpack::state( 'message', 'module_deactivated' );
+ wp_safe_redirect( Jetpack::admin_url( 'page=jetpack' ) );
+ die();
+ }
+ if ( ! empty( $_POST['action'] ) && $_POST['action'] == 'monitor-save' ) {
+ check_admin_referer( 'monitor-settings' );
+ $this->update_option_receive_jetpack_monitor_notification( isset( $_POST['receive_jetpack_monitor_notification'] ) );
+ Jetpack::state( 'message', 'module_configured' );
+ wp_safe_redirect( Jetpack::module_configuration_url( $this->module ) );
+ }
+ }
+
+ public function jetpack_configuration_screen() {
+ ?>
+ <p><?php esc_html_e( 'Nobody likes downtime, and that\'s why Jetpack Monitor is on the job, keeping tabs on your site by checking it every five minutes. As soon as any downtime is detected, you will receive an email notification alerting you to the issue. That way you can act quickly, to get your site back online again!', 'jetpack' ); ?>
+ <p><?php esc_html_e( 'We’ll also let you know as soon as your site is up and running, so you can keep an eye on total downtime.', 'jetpack'); ?></p>
+ <div class="narrow">
+ <?php if ( Jetpack::is_user_connected() && current_user_can( 'manage_options' ) ) : ?>
+ <?php $user_email = Jetpack::get_connected_user_email(); ?>
+ <form method="post" id="monitor-settings">
+ <input type="hidden" name="action" value="monitor-save" />
+ <?php wp_nonce_field( 'monitor-settings' ); ?>
+
+ <table id="menu" class="form-table">
+ <tr>
+ <th scope="row">
+ <?php _e( 'Notifications', 'jetpack' ); ?>
+ </th>
+ <td>
+ <label for="receive_jetpack_monitor_notification">
+ <input type="checkbox" name="receive_jetpack_monitor_notification" id="receive_jetpack_monitor_notification" value="receive_jetpack_monitor_notification"<?php checked( $this->user_receives_notifications() ); ?> />
+ <span><?php _e( 'Receive Monitor Email Notifications.' , 'jetpack'); ?></span>
+ </label>
+ <p class="description"><?php printf( __( 'Emails will be sent to %s (<a href="%s">Edit</a>)', 'jetpack' ), $user_email, 'https://wordpress.com/settings/account/'); ?></p>
+ </td>
+ </tr>
+ </table>
+ <?php submit_button(); ?>
+ </form>
+ <?php else : ?>
+ <p><?php _e( 'This profile is not currently linked to a WordPress.com Profile.', 'jetpack' ); ?></p>
+ <?php endif; ?>
+ </div>
+ <?php
+ }
+
+ public function is_active() {
+ Jetpack::load_xml_rpc_client();
+ $xml = new Jetpack_IXR_Client( array(
+ 'user_id' => get_current_user_id()
+ ) );
+ $xml->query( 'jetpack.monitor.isActive' );
+ if ( $xml->isError() ) {
+ wp_die( sprintf( '%s: %s', $xml->getErrorCode(), $xml->getErrorMessage() ) );
+ }
+ return $xml->getResponse();
+ }
+
+ public function update_option_receive_jetpack_monitor_notification( $value ) {
+ Jetpack::load_xml_rpc_client();
+ $xml = new Jetpack_IXR_Client( array(
+ 'user_id' => get_current_user_id()
+ ) );
+ $xml->query( 'jetpack.monitor.setNotifications', (bool) $value );
+
+ if ( $xml->isError() ) {
+ wp_die( sprintf( '%s: %s', $xml->getErrorCode(), $xml->getErrorMessage() ) );
+ }
+ return true;
+ }
+
+ public function user_receives_notifications() {
+ Jetpack::load_xml_rpc_client();
+ $xml = new Jetpack_IXR_Client( array(
+ 'user_id' => get_current_user_id()
+ ) );
+ $xml->query( 'jetpack.monitor.isUserInNotifications' );
+
+ if ( $xml->isError() ) {
+ wp_die( sprintf( '%s: %s', $xml->getErrorCode(), $xml->getErrorMessage() ) );
+ }
+ return $xml->getResponse();
+ }
+
+ public function activate_monitor() {
+ Jetpack::load_xml_rpc_client();
+ $xml = new Jetpack_IXR_Client( array(
+ 'user_id' => get_current_user_id()
+ ) );
+
+ $xml->query( 'jetpack.monitor.activate' );
+
+ if ( $xml->isError() ) {
+ wp_die( sprintf( '%s: %s', $xml->getErrorCode(), $xml->getErrorMessage() ) );
+ }
+ return true;
+ }
+
+ public function deactivate_monitor() {
+ Jetpack::load_xml_rpc_client();
+ $xml = new Jetpack_IXR_Client( array(
+ 'user_id' => get_current_user_id()
+ ) );
+
+ $xml->query( 'jetpack.monitor.deactivate' );
+
+ if ( $xml->isError() ) {
+ wp_die( sprintf( '%s: %s', $xml->getErrorCode(), $xml->getErrorMessage() ) );
+ }
+ return true;
+ }
+
+}
+
+new Jetpack_Monitor;
+
diff --git a/plugins/jetpack/modules/notes.php b/plugins/jetpack/modules/notes.php
index c103e80a..353bf6d0 100644
--- a/plugins/jetpack/modules/notes.php
+++ b/plugins/jetpack/modules/notes.php
@@ -1,11 +1,12 @@
<?php
/**
* Module Name: Notifications
- * Module Description: Monitor and manage your site's activity with Notifications in your Toolbar and on WordPress.com.
- * Sort Order: 1
+ * Module Description: Receive notification of site activity via the admin toolbar and your Mobile devices.
+ * Sort Order: 13
* First Introduced: 1.9
* Requires Connection: Yes
* Auto Activate: Yes
+ * Module Tags: Other
*/
if ( !defined( 'JETPACK_NOTES__CACHE_BUSTER' ) ) define( 'JETPACK_NOTES__CACHE_BUSTER', JETPACK__VERSION . '-' . gmdate( 'oW' ) );
@@ -48,9 +49,8 @@ class Jetpack_Notifications {
function wpcom_static_url($file) {
$i = hexdec( substr( md5( $file ), -1 ) ) % 2;
- $http = is_ssl() ? 'https' : 'http';
- $url = $http . '://s' . $i . '.wp.com' . $file;
- return $url;
+ $url = 'http://s' . $i . '.wp.com' . $file;
+ return set_url_scheme( $url );
}
// return the major version of Internet Explorer the viewer is using or false if it's not IE
@@ -60,7 +60,9 @@ class Jetpack_Notifications {
return $version;
}
- preg_match( '/MSIE (\d+)/', $_SERVER['HTTP_USER_AGENT'], $matches );
+ $user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '';
+
+ preg_match( '/MSIE (\d+)/', $user_agent, $matches );
$version = empty( $matches[1] ) ? null : $matches[1];
if ( empty( $version ) || !$version ) {
return false;
diff --git a/plugins/jetpack/modules/omnisearch.php b/plugins/jetpack/modules/omnisearch.php
index 31577d75..2d47a0aa 100644
--- a/plugins/jetpack/modules/omnisearch.php
+++ b/plugins/jetpack/modules/omnisearch.php
@@ -2,14 +2,15 @@
/**
* Module Name: Omnisearch
- * Module Description: A single search box, that lets you search many different things.
- * Sort Order: 8
+ * Module Description: Search your entire database from a single field in your Dashboard.
+ * Sort Order: 16
* First Introduced: 2.3
* Requires Connection: No
* Auto Activate: Yes
+ * Module Tags: Developers
*/
// Only do Jetpack Omnisearch if there isn't already a Core WP_Omnisearch Class.
-if ( ! class_exists( 'WP_Omnisearch' ) )
+if ( ! class_exists( 'WP_Omnisearch' ) ) {
require_once( dirname( __FILE__ ) . '/omnisearch/omnisearch-core.php' );
-
+}
diff --git a/plugins/jetpack/modules/omnisearch/omnisearch-core.php b/plugins/jetpack/modules/omnisearch/omnisearch-core.php
index f0d3fb84..32afdacf 100644
--- a/plugins/jetpack/modules/omnisearch/omnisearch-core.php
+++ b/plugins/jetpack/modules/omnisearch/omnisearch-core.php
@@ -49,9 +49,12 @@ class Jetpack_Omnisearch {
if ( wp_style_is( 'genericons', 'registered' ) ) {
$deps = array( 'genericons' );
}
-
- wp_register_style( 'omnisearch-admin', plugins_url( 'omnisearch.css', __FILE__ ), $deps );
- wp_register_style( 'omnisearch-jetpack', plugins_url( 'omnisearch-jetpack.css', __FILE__ ) );
+ if( is_rtl() ) {
+ wp_register_style( 'omnisearch-admin', plugins_url( 'rtl/omnisearch-rtl.css', __FILE__ ), $deps );
+ } else {
+ wp_register_style( 'omnisearch-admin', plugins_url( 'omnisearch.css', __FILE__ ), $deps );
+ }
+
}
function jetpack_admin_menu() {
diff --git a/plugins/jetpack/modules/omnisearch/omnisearch-jetpack-rtl.css b/plugins/jetpack/modules/omnisearch/omnisearch-jetpack-rtl.css
new file mode 100644
index 00000000..30b19eee
--- /dev/null
+++ b/plugins/jetpack/modules/omnisearch/omnisearch-jetpack-rtl.css
@@ -0,0 +1,10 @@
+
+ul#adminmenu a.wp-has-current-submenu:after,
+ul#adminmenu > li.current > a.current:after {
+ border-left-color:#8da94c;
+ display: none;
+}
+
+.omnisearch-results > li:first-child > h2 {
+ text-shadow: none;
+}
diff --git a/plugins/jetpack/modules/omnisearch/omnisearch-jetpack-rtl.min.css b/plugins/jetpack/modules/omnisearch/omnisearch-jetpack-rtl.min.css
new file mode 100644
index 00000000..1e1a9f76
--- /dev/null
+++ b/plugins/jetpack/modules/omnisearch/omnisearch-jetpack-rtl.min.css
@@ -0,0 +1 @@
+ul#adminmenu a.wp-has-current-submenu:after,ul#adminmenu>li.current>a.current:after{border-left-color:#8da94c;display:none}.omnisearch-results>li:first-child>h2{text-shadow:none} \ No newline at end of file
diff --git a/plugins/jetpack/modules/omnisearch/omnisearch-jetpack.css b/plugins/jetpack/modules/omnisearch/omnisearch-jetpack.css
index d100c403..fdf4f401 100644
--- a/plugins/jetpack/modules/omnisearch/omnisearch-jetpack.css
+++ b/plugins/jetpack/modules/omnisearch/omnisearch-jetpack.css
@@ -1,35 +1,10 @@
-.wp-admin #wpwrap {
- background: url('../../_inc/images/header-clouds.png') 200% 0 repeat-x;
-}
-
-@media print,
- (-o-min-device-pixel-ratio: 5/4),
- (-webkit-min-device-pixel-ratio: 1.25),
- (min-resolution: 120dpi) {
- #wpwrap {
- background: url('../../_inc/images/header-clouds-2x.png') 0 0 repeat-x;
- background-size: 1600px 400px;
- }
-}
-
ul#adminmenu a.wp-has-current-submenu:after,
ul#adminmenu > li.current > a.current:after {
border-right-color:#8da94c;
display: none;
}
-h2.page-title {
- color: #fff;
- text-shadow: 0 1px 1px rgba(0,0,0,0.5);
-}
-
-#results-title,
-.jump-to {
- color: #fff;
- text-shadow: 0 1px 1px rgba(0,0,0,0.5);
-}
-
.omnisearch-results > li:first-child > h2 {
text-shadow: none;
}
diff --git a/plugins/jetpack/modules/omnisearch/omnisearch-jetpack.min.css b/plugins/jetpack/modules/omnisearch/omnisearch-jetpack.min.css
new file mode 100644
index 00000000..9ed8ea06
--- /dev/null
+++ b/plugins/jetpack/modules/omnisearch/omnisearch-jetpack.min.css
@@ -0,0 +1 @@
+ul#adminmenu a.wp-has-current-submenu:after,ul#adminmenu>li.current>a.current:after{border-right-color:#8da94c;display:none}.omnisearch-results>li:first-child>h2{text-shadow:none} \ No newline at end of file
diff --git a/plugins/jetpack/modules/omnisearch/omnisearch-posts.php b/plugins/jetpack/modules/omnisearch/omnisearch-posts.php
index 61b3347d..55c875a2 100644
--- a/plugins/jetpack/modules/omnisearch/omnisearch-posts.php
+++ b/plugins/jetpack/modules/omnisearch/omnisearch-posts.php
@@ -10,6 +10,12 @@ class Jetpack_Omnisearch_Posts extends WP_List_Table {
function __construct( $post_type = 'post' ) {
$this->post_type = $post_type;
add_filter( 'omnisearch_results', array( $this, 'search'), 10, 2 );
+
+ // Push 'post_type_obj' to accepted fields for WP_List_Table (since WP 4.2)
+ global $wp_version;
+ if ( version_compare( $wp_version, '4.2-z', '>=' ) && $this->compat_fields && is_array( $this->compat_fields ) ) {
+ array_push( $this->compat_fields, 'post_type_obj', 'posts' );
+ }
}
function search( $results, $search_term ) {
@@ -26,7 +32,13 @@ class Jetpack_Omnisearch_Posts extends WP_List_Table {
$num_results = apply_filters( 'omnisearch_num_results', 5 );
- $this->posts = get_posts( array( 's' => $search_term, 'post_type' => $this->post_type, 'posts_per_page' => $num_results, 'post_status' => 'any' ) );
+ $this->posts = get_posts( array(
+ 's' => $search_term,
+ 'post_type' => $this->post_type,
+ 'posts_per_page' => $num_results,
+ 'post_status' => 'any',
+ 'suppress_filters' => false,
+ ) );
$this->prepare_items();
diff --git a/plugins/jetpack/modules/omnisearch/omnisearch-rtl.css b/plugins/jetpack/modules/omnisearch/omnisearch-rtl.css
new file mode 100644
index 00000000..4785457c
--- /dev/null
+++ b/plugins/jetpack/modules/omnisearch/omnisearch-rtl.css
@@ -0,0 +1,130 @@
+
+h2.page-title small {
+ font-size: 0.6em;
+ font-weight: 300;
+ font-style: italic;
+ opacity: 0.6;
+ margin-right: 0.5em;
+}
+
+form.omnisearch-form {
+ position: relative;
+}
+
+input.omnisearch {
+ border-radius: 0.25em;
+ font-size: 2.2em;
+ line-height: 1.35;
+ padding: 0.25em 0.5em 0.25em 2em;
+ width: 100%;
+}
+
+input.omnisearch::-webkit-search-cancel-button {
+ display: none;
+}
+
+button.omnisearch-submit {
+ background: transparent;
+ border: 0;
+ cursor: pointer;
+ display: block;
+ font-size: 2.45em;
+ padding: 0.3em 0.5em 0.1em;
+ text-align: center;
+ position: absolute;
+ left: 0;
+ bottom: 0;
+}
+
+button.omnisearch-submit::before {
+ font-family: 'Genericons', Noticons;
+ content: '\f400';
+}
+
+button.omnisearch-submit span {
+ display: none;
+}
+
+#results-title,
+.jump-to {
+ font-size: 1.2em;
+ line-height: 1.5;
+ float: right;
+ margin-top: 0;
+ padding-top: 2em;
+}
+
+#results-title,
+.jump-to strong {
+ font-weight: 600;
+}
+
+.jump-to {
+ float: left;
+ text-align: left;
+}
+
+.jump-to strong,
+.jump-to a {
+ color: inherit;
+ margin-right: 0.5em;
+ text-decoration: none;
+}
+
+.jump-to a:hover {
+ text-decoration: underline;
+}
+
+.back-to-top {
+ display: block;
+ float: left;
+ margin-top: 2.5em;
+}
+
+.omnisearch-results {
+
+}
+
+.omnisearch-results > li {
+ padding-top: 2.5em;
+}
+
+.omnisearch-results > li:first-child {
+ padding-top: 0;
+}
+
+.omnisearch-results .add-new-h2 {
+ display: inline;
+}
+
+.wp-list-table .column-snippet {
+ width: 65%;
+}
+
+.wp-list-table .column-date {
+ width: 15%;
+}
+
+.wp-list-table.comments .column-author {
+ width: 20%;
+}
+
+.wp-list-table.media th {
+ white-space: nowrap;
+}
+
+.wp-list-table.media .column-parent {
+ width: 15%;
+}
+
+.wp-list-table.media .column-comments span.vers {
+ display: block;
+}
+
+.tablenav {
+ height: 0;
+}
+
+.omnisearch-results .tablenav.top {
+ margin: 5px 0;
+}
diff --git a/plugins/jetpack/modules/omnisearch/omnisearch-rtl.min.css b/plugins/jetpack/modules/omnisearch/omnisearch-rtl.min.css
new file mode 100644
index 00000000..2234c900
--- /dev/null
+++ b/plugins/jetpack/modules/omnisearch/omnisearch-rtl.min.css
@@ -0,0 +1 @@
+h2.page-title small{font-size:.6em;font-weight:300;font-style:italic;opacity:.6;margin-right:.5em}form.omnisearch-form{position:relative}input.omnisearch{border-radius:.25em;font-size:2.2em;line-height:1.35;padding:.25em .5em .25em 2em;width:100%}input.omnisearch::-webkit-search-cancel-button{display:none}button.omnisearch-submit{background:0 0;border:0;cursor:pointer;display:block;font-size:2.45em;padding:.3em .5em .1em;text-align:center;position:absolute;left:0;bottom:0}button.omnisearch-submit::before{font-family:Genericons,Noticons;content:'\f400'}button.omnisearch-submit span{display:none}#results-title,.jump-to{font-size:1.2em;line-height:1.5;float:right;margin-top:0;padding-top:2em}#results-title,.jump-to strong{font-weight:600}.jump-to{float:left;text-align:left}.jump-to a,.jump-to strong{color:inherit;margin-right:.5em;text-decoration:none}.jump-to a:hover{text-decoration:underline}.back-to-top{display:block;float:left;margin-top:2.5em}.omnisearch-results>li{padding-top:2.5em}.omnisearch-results>li:first-child{padding-top:0}.omnisearch-results .add-new-h2{display:inline}.wp-list-table .column-snippet{width:65%}.wp-list-table .column-date{width:15%}.wp-list-table.comments .column-author{width:20%}.wp-list-table.media th{white-space:nowrap}.wp-list-table.media .column-parent{width:15%}.wp-list-table.media .column-comments span.vers{display:block}.tablenav{height:0}.omnisearch-results .tablenav.top{margin:5px 0} \ No newline at end of file
diff --git a/plugins/jetpack/modules/omnisearch/omnisearch.css b/plugins/jetpack/modules/omnisearch/omnisearch.css
index 6dc1784f..cd70d9d1 100644
--- a/plugins/jetpack/modules/omnisearch/omnisearch.css
+++ b/plugins/jetpack/modules/omnisearch/omnisearch.css
@@ -14,15 +14,11 @@ form.omnisearch-form {
input.omnisearch {
border-radius: 0.25em;
font-size: 2.2em;
- line-height: 1.25;
+ line-height: 1.35;
padding: 0.25em 2em 0.25em 0.5em;
width: 100%;
}
-.mp6 input.omnisearch {
- line-height: 1.35;
-}
-
input.omnisearch::-webkit-search-cancel-button {
display: none;
}
@@ -33,17 +29,13 @@ button.omnisearch-submit {
cursor: pointer;
display: block;
font-size: 2.45em;
- padding: 0.25em 0.5em 0;
+ padding: 0.3em 0.5em 0.1em;
text-align: center;
position: absolute;
right: 0;
bottom: 0;
}
-.mp6 button.omnisearch-submit {
- padding: 0.3em 0.5em 0.1em;
-}
-
button.omnisearch-submit::before {
font-family: 'Genericons', Noticons;
content: '\f400';
@@ -90,7 +82,7 @@ button.omnisearch-submit span {
}
.omnisearch-results {
-
+
}
.omnisearch-results > li {
@@ -136,4 +128,3 @@ button.omnisearch-submit span {
.omnisearch-results .tablenav.top {
margin: 5px 0;
}
-
diff --git a/plugins/jetpack/modules/omnisearch/omnisearch.min.css b/plugins/jetpack/modules/omnisearch/omnisearch.min.css
new file mode 100644
index 00000000..64419553
--- /dev/null
+++ b/plugins/jetpack/modules/omnisearch/omnisearch.min.css
@@ -0,0 +1 @@
+h2.page-title small{font-size:.6em;font-weight:300;font-style:italic;opacity:.6;margin-left:.5em}form.omnisearch-form{position:relative}input.omnisearch{border-radius:.25em;font-size:2.2em;line-height:1.35;padding:.25em 2em .25em .5em;width:100%}input.omnisearch::-webkit-search-cancel-button{display:none}button.omnisearch-submit{background:0 0;border:0;cursor:pointer;display:block;font-size:2.45em;padding:.3em .5em .1em;text-align:center;position:absolute;right:0;bottom:0}button.omnisearch-submit::before{font-family:Genericons,Noticons;content:'\f400'}button.omnisearch-submit span{display:none}#results-title,.jump-to{font-size:1.2em;line-height:1.5;float:left;margin-top:0;padding-top:2em}#results-title,.jump-to strong{font-weight:600}.jump-to{float:right;text-align:right}.jump-to a,.jump-to strong{color:inherit;margin-left:.5em;text-decoration:none}.jump-to a:hover{text-decoration:underline}.back-to-top{display:block;float:right;margin-top:2.5em}.omnisearch-results>li{padding-top:2.5em}.omnisearch-results>li:first-child{padding-top:0}.omnisearch-results .add-new-h2{display:inline}.wp-list-table .column-snippet{width:65%}.wp-list-table .column-date{width:15%}.wp-list-table.comments .column-author{width:20%}.wp-list-table.media th{white-space:nowrap}.wp-list-table.media .column-parent{width:15%}.wp-list-table.media .column-comments span.vers{display:block}.tablenav{height:0}.omnisearch-results .tablenav.top{margin:5px 0} \ No newline at end of file
diff --git a/plugins/jetpack/modules/omnisearch/rtl/omnisearch-jetpack-rtl.css b/plugins/jetpack/modules/omnisearch/rtl/omnisearch-jetpack-rtl.css
index 7ddf1404..e714cb67 100644
--- a/plugins/jetpack/modules/omnisearch/rtl/omnisearch-jetpack-rtl.css
+++ b/plugins/jetpack/modules/omnisearch/rtl/omnisearch-jetpack-rtl.css
@@ -1,19 +1,4 @@
-/* This file was automatically generated on Jun 19 2013 20:14:22 */
-
-
-.wp-admin #wpwrap {
- background: url('../../../_inc/images/header-clouds.png') -100% 0 repeat-x;
-}
-
-@media print,
- (-o-min-device-pixel-ratio: 5/4),
- (-webkit-min-device-pixel-ratio: 1.25),
- (min-resolution: 120dpi) {
- #wpwrap {
- background: url('../../../_inc/images/header-clouds-2x.png') 0 0 repeat-x;
- background-size: 1600px 400px;
- }
-}
+/* This file was automatically generated on Sep 29 2014 23:28:15 */
ul#adminmenu a.wp-has-current-submenu:after,
ul#adminmenu > li.current > a.current:after {
@@ -21,17 +6,6 @@ ul#adminmenu > li.current > a.current:after {
display: none;
}
-h2.page-title {
- color: #fff;
- text-shadow: 0 1px 1px rgba(0,0,0,0.5);
-}
-
-#results-title,
-.jump-to {
- color: #fff;
- text-shadow: 0 1px 1px rgba(0,0,0,0.5);
-}
-
.omnisearch-results > li:first-child > h2 {
text-shadow: none;
}
diff --git a/plugins/jetpack/modules/omnisearch/rtl/omnisearch-rtl.css b/plugins/jetpack/modules/omnisearch/rtl/omnisearch-rtl.css
index 50cb1d6f..18ce9833 100644
--- a/plugins/jetpack/modules/omnisearch/rtl/omnisearch-rtl.css
+++ b/plugins/jetpack/modules/omnisearch/rtl/omnisearch-rtl.css
@@ -1,4 +1,4 @@
-/* This file was automatically generated on Sep 05 2013 19:17:53 */
+/* This file was automatically generated on Sep 29 2014 23:28:15 */
h2.page-title small {
@@ -16,15 +16,11 @@ form.omnisearch-form {
input.omnisearch {
border-radius: 0.25em;
font-size: 2.2em;
- line-height: 1.25;
+ line-height: 1.35;
padding: 0.25em 0.5em 0.25em 2em;
width: 100%;
}
-.mp6 input.omnisearch {
- line-height: 1.35;
-}
-
input.omnisearch::-webkit-search-cancel-button {
display: none;
}
@@ -35,17 +31,13 @@ button.omnisearch-submit {
cursor: pointer;
display: block;
font-size: 2.45em;
- padding: 0.25em 0.5em 0;
+ padding: 0.3em 0.5em 0.1em;
text-align: center;
position: absolute;
left: 0;
bottom: 0;
}
-.mp6 button.omnisearch-submit {
- padding: 0.3em 0.5em 0.1em;
-}
-
button.omnisearch-submit::before {
font-family: 'Genericons', Noticons;
content: '\f400';
@@ -92,7 +84,7 @@ button.omnisearch-submit span {
}
.omnisearch-results {
-
+
}
.omnisearch-results > li {
@@ -138,4 +130,3 @@ button.omnisearch-submit span {
.omnisearch-results .tablenav.top {
margin: 5px 0;
}
-
diff --git a/plugins/jetpack/modules/photon.php b/plugins/jetpack/modules/photon.php
index e6ddc098..d2e9c934 100644
--- a/plugins/jetpack/modules/photon.php
+++ b/plugins/jetpack/modules/photon.php
@@ -1,11 +1,21 @@
<?php
/**
* Module Name: Photon
- * Module Description: Give your site a boost by loading images from the WordPress.com content delivery network.
- * Sort Order: 15
+ * Module Description: Accelerate your site by loading images from the WordPress.com CDN.
+ * Jumpstart Description: mirrors and serves your images from our free and fast image CDN, improving your site’s performance with no additional load on your servers.
+ * Sort Order: 25
+ * Recommendation Order: 1
* First Introduced: 2.0
* Requires Connection: Yes
* Auto Activate: No
+ * Module Tags: Photos and Videos, Appearance, Recommended
+ * Feature: Recommended, Jumpstart
*/
+Jetpack::dns_prefetch( array(
+ '//i0.wp.com',
+ '//i1.wp.com',
+ '//i2.wp.com',
+) );
+
Jetpack_Photon::instance(); \ No newline at end of file
diff --git a/plugins/jetpack/modules/photon/photon.js b/plugins/jetpack/modules/photon/photon.js
index 050e73b6..0485d85a 100644
--- a/plugins/jetpack/modules/photon/photon.js
+++ b/plugins/jetpack/modules/photon/photon.js
@@ -1,15 +1,27 @@
+/* jshint onevar: false */
+
(function($){
/**
* For images lacking explicit dimensions and needing them, try to add them.
*/
var restore_dims = function() {
- $( 'img[data-recalc-dims]' ).each( function() {
+ $( 'img[data-recalc-dims]' ).each( function recalc() {
+ var $this = $( this );
if ( this.complete ) {
+
+ // Support for lazy loading: if there is a lazy-src
+ // attribute and it's value is not the same as the current src we
+ // should wait until the image load event
+ if ( $this.data( 'lazy-src' ) && $this.attr( 'src' ) !== $this.data( 'lazy-src' ) ) {
+ $this.load( recalc );
+ return;
+ }
+
var width = this.width,
height = this.height;
if ( width && width > 0 && height && height > 0 ) {
- $( this ).attr( {
+ $this.attr( {
width: width,
height: height
} );
@@ -18,7 +30,7 @@
}
}
else {
- $( this ).load( arguments.callee );
+ $this.load( recalc );
}
} );
},
@@ -35,8 +47,9 @@
*/
$( document ).ready( restore_dims );
- if ( "on" in $.fn )
+ if ( 'on' in $.fn ) {
$( document.body ).on( 'post-load', restore_dims );
- else
+ } else {
$( document ).delegate( 'body', 'post-load', restore_dims );
-})(jQuery); \ No newline at end of file
+ }
+})(jQuery);
diff --git a/plugins/jetpack/modules/post-by-email.php b/plugins/jetpack/modules/post-by-email.php
index 41e19397..2184cefb 100644
--- a/plugins/jetpack/modules/post-by-email.php
+++ b/plugins/jetpack/modules/post-by-email.php
@@ -2,11 +2,12 @@
/**
* Module Name: Post by Email
- * Module Description: Publish posts to your blog directly from your personal email account.
+ * Module Description: Publish posts by email, using any device and email client.
* First Introduced: 2.0
- * Sort Order: 4
+ * Sort Order: 14
* Requires Connection: Yes
* Auto Activate: Yes
+ * Module Tags: Writing
*/
add_action( 'jetpack_modules_loaded', array( 'Jetpack_Post_By_Email', 'init' ) );
@@ -41,7 +42,7 @@ class Jetpack_Post_By_Email {
add_action( 'init', array( &$this, 'action_init' ) );
}
- function module_toggle() {
+ static function module_toggle() {
$jetpack = Jetpack::init();
$jetpack->sync->register( 'noop' );
}
@@ -66,7 +67,9 @@ class Jetpack_Post_By_Email {
function profile_scripts() {
wp_enqueue_script( 'post-by-email', plugins_url( 'post-by-email/post-by-email.js', __FILE__ ), array( 'jquery' ) );
wp_enqueue_style( 'post-by-email', plugins_url( 'post-by-email/post-by-email.css', __FILE__ ) );
- Jetpack::init()->admin_styles();
+ wp_style_add_data( 'post-by-email', 'jetpack-inline', true );
+ // Do we really need `admin_styles`? With the new admin UI, it's breaking some bits.
+ // Jetpack::init()->admin_styles();
}
function check_user_connection() {
diff --git a/plugins/jetpack/modules/post-by-email/post-by-email.js b/plugins/jetpack/modules/post-by-email/post-by-email.js
index 0f548e72..ed8df7fd 100644
--- a/plugins/jetpack/modules/post-by-email/post-by-email.js
+++ b/plugins/jetpack/modules/post-by-email/post-by-email.js
@@ -1,3 +1,5 @@
+/* global jetpack_post_by_email:true, ajaxurl */
+
jetpack_post_by_email = {
init: function() {
jQuery( '#jp-pbe-enable' ).click( jetpack_post_by_email.enable );
@@ -18,8 +20,7 @@ jetpack_post_by_email = {
},
handle_enabled: function( response ) {
- var enabled = false;
- var error;
+ var enabled = false, error;
try {
error = JSON.parse( response );
} catch ( e ) {
@@ -58,8 +59,7 @@ jetpack_post_by_email = {
},
handle_regenerated: function( response ) {
- var regenerated = false;
- var error;
+ var regenerated = false, error;
try {
error = JSON.parse( response );
} catch ( e ) {
@@ -95,15 +95,14 @@ jetpack_post_by_email = {
},
handle_disabled: function( response ) {
- var disabled = false;
- var error;
+ var disabled = false, error;
try {
error = JSON.parse( response );
} catch ( e ) {
disabled = true;
}
- if ( 'error' != error.response ) {
+ if ( 'error' !== error.response ) {
disabled = true;
}
diff --git a/plugins/jetpack/modules/post-by-email/post-by-email.min.css b/plugins/jetpack/modules/post-by-email/post-by-email.min.css
new file mode 100644
index 00000000..a4e020bb
--- /dev/null
+++ b/plugins/jetpack/modules/post-by-email/post-by-email.min.css
@@ -0,0 +1 @@
+#jp-pbe-error{display:none}#post-by-email:target .jetpack-inline-message{background-color:#fff} \ No newline at end of file
diff --git a/plugins/jetpack/modules/protect.php b/plugins/jetpack/modules/protect.php
new file mode 100644
index 00000000..af0759d2
--- /dev/null
+++ b/plugins/jetpack/modules/protect.php
@@ -0,0 +1,682 @@
+<?php
+/**
+ * Module Name: Protect
+ * Module Description: Adds brute force protection to your login page. Formerly BruteProtect.
+ * Sort Order: 1
+ * Recommendation Order: 4
+ * First Introduced: 3.4
+ * Requires Connection: Yes
+ * Auto Activate: Yes
+ * Module Tags: Recommended
+ * Feature: Recommended
+ */
+
+include_once JETPACK__PLUGIN_DIR . 'modules/protect/shared-functions.php';
+
+class Jetpack_Protect_Module {
+
+ private static $__instance = null;
+ public $api_key;
+ public $api_key_error;
+ public $whitelist;
+ public $whitelist_error;
+ public $whitelist_saved;
+ private $user_ip;
+ private $local_host;
+ private $api_endpoint;
+ public $last_request;
+ public $last_response_raw;
+ public $last_response;
+
+ /**
+ * Singleton implementation
+ *
+ * @return object
+ */
+ public static function instance() {
+ if ( ! is_a( self::$__instance, 'Jetpack_Protect_Module' ) )
+ self::$__instance = new Jetpack_Protect_Module();
+
+ return self::$__instance;
+ }
+
+ /**
+ * Registers actions
+ */
+ private function __construct() {
+ add_action( 'jetpack_activate_module_protect', array( $this, 'on_activation' ) );
+ add_action( 'init', array( $this, 'maybe_get_protect_key' ) );
+ add_action( 'jetpack_modules_loaded', array( $this, 'modules_loaded' ) );
+ add_action( 'login_head', array( $this, 'check_use_math' ) );
+ add_filter( 'authenticate', array( $this, 'check_preauth' ), 10, 3 );
+ add_action( 'wp_login', array( $this, 'log_successful_login' ), 10, 2 );
+ add_action( 'wp_login_failed', array( $this, 'log_failed_attempt' ) );
+
+ // This is a backup in case $pagenow fails for some reason
+ add_action( 'login_head', array( $this, 'check_login_ability' ) );
+
+ // Runs a script every day to clean up expired transients so they don't
+ // clog up our users' databases
+ require_once( JETPACK__PLUGIN_DIR . '/modules/protect/transient-cleanup.php' );
+ }
+
+ /**
+ * On module activation, try to get an api key
+ */
+ public function on_activation() {
+ update_site_option('jetpack_protect_activating', 'activating');
+ // Get BruteProtect's counter number
+ Jetpack_Protect_Module::protect_call( 'check_key' );
+ }
+
+ public function maybe_get_protect_key() {
+ if ( get_site_option('jetpack_protect_activating', false ) && ! get_site_option('jetpack_protect_key', false ) ) {
+ $this->get_protect_key();
+ delete_site_option( 'jetpack_protect_activating' );
+ }
+ }
+
+ /**
+ * Request an api key from wordpress.com
+ *
+ * @return bool | string
+ */
+ public function get_protect_key() {
+
+ $protect_blog_id = Jetpack_Protect_Module::get_main_blog_jetpack_id();
+
+ // If we can't find the the blog id, that means we are on multisite, and the main site never connected
+ // the protect api key is linked to the main blog id - instruct the user to connect their main blog
+ if ( ! $protect_blog_id ) {
+ $this->api_key_error = __( 'Your main blog is not connected to WordPress.com. Please connect to get an API key.', 'jetpack' );
+ return false;
+ }
+
+ $request = array(
+ 'jetpack_blog_id' => $protect_blog_id,
+ 'bruteprotect_api_key' => get_site_option( 'bruteprotect_api_key' ),
+ 'multisite' => '0',
+ );
+
+ // Send the number of blogs on the network if we are on multisite
+ if ( is_multisite() ) {
+ $request['multisite'] = get_blog_count();
+ if( ! $request['multisite'] ) {
+ global $wpdb;
+ $request['multisite'] = $wpdb->get_var( "SELECT COUNT(blog_id) as c FROM $wpdb->blogs WHERE spam = '0' AND deleted = '0' and archived = '0'" );
+ }
+ }
+
+ // Request the key
+ Jetpack::load_xml_rpc_client();
+ $xml = new Jetpack_IXR_Client( array(
+ 'user_id' => get_current_user_id()
+ ) );
+ $xml->query( 'jetpack.protect.requestKey', $request );
+
+ // Hmm, can't talk to wordpress.com
+ if ( $xml->isError() ) {
+ $code = $xml->getErrorCode();
+ $message = $xml->getErrorMessage();
+ $this->api_key_error = sprintf( __( 'Error connecting to WordPress.com. Code: %1$s, %2$s', 'jetpack'), $code, $message );
+ return false;
+ }
+
+ $response = $xml->getResponse();
+
+ // Hmm. Can't talk to the protect servers ( api.bruteprotect.com )
+ if ( ! isset( $response['data'] ) ) {
+ $this->api_key_error = __( 'No reply from Jetpack servers', 'jetpack' );
+ return false;
+ }
+
+ // There was an issue generating the key
+ if ( empty( $response['success'] ) ) {
+ $this->api_key_error = $response['data'];
+ return false;
+ }
+
+ // Key generation successful!
+ $active_plugins = Jetpack::get_active_plugins();
+
+ // We only want to deactivate BruteProtect if we successfully get a key
+ if ( in_array( 'bruteprotect/bruteprotect.php', $active_plugins ) ) {
+ Jetpack_Client_Server::deactivate_plugin( 'bruteprotect/bruteprotect.php', 'BruteProtect' );
+ }
+
+ $key = $response['data'];
+ update_site_option( 'jetpack_protect_key', $key );
+ return $key;
+ }
+
+ /**
+ * Called via WP action wp_login_failed to log failed attempt with the api
+ *
+ * Fires custom, plugable action jpp_log_failed_attempt with the IP
+ *
+ * @return void
+ */
+ function log_failed_attempt() {
+ /**
+ * Fires before every failed login attempt.
+ *
+ * @since 3.4.0
+ *
+ * @param string jetpack_protect_get_ip IP stored by Jetpack Protect.
+ */
+ do_action( 'jpp_log_failed_attempt', jetpack_protect_get_ip() );
+
+ if( isset( $_COOKIE['jpp_math_pass'] ) ) {
+
+ $transient = $this->get_transient( 'jpp_math_pass_' . $_COOKIE['jpp_math_pass'] );
+ $transient--;
+
+ if( !$transient || $transient < 1 ) {
+ $this->delete_transient( 'jpp_math_pass_' . $_COOKIE['jpp_math_pass'] );
+ setcookie('jpp_math_pass', 0, time() - DAY_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN, false);
+ } else {
+ $this->set_transient( 'jpp_math_pass_' . $_COOKIE['jpp_math_pass'], $transient, DAY_IN_SECONDS );
+ }
+
+ }
+ $this->protect_call( 'failed_attempt' );
+ }
+
+ /**
+ * Set up the Protect configuration page
+ */
+ public function modules_loaded() {
+ Jetpack::enable_module_configurable( __FILE__ );
+ Jetpack::module_configuration_load( __FILE__, array( $this, 'configuration_load' ) );
+ Jetpack::module_configuration_head( __FILE__, array( $this, 'configuration_head' ) );
+ Jetpack::module_configuration_screen( __FILE__, array( $this, 'configuration_screen' ) );
+ }
+
+ /**
+ * Logs a successful login back to our servers, this allows us to make sure we're not blocking
+ * a busy IP that has a lot of good logins along with some forgotten passwords. Also saves current user's ip
+ * to the ip address whitelist
+ */
+ public function log_successful_login( $user_login, $user ) {
+ // TODO: update whitelist
+ $this->protect_call( 'successful_login', array( 'roles' => $user->roles ) );
+ }
+
+
+ /**
+ * Checks for loginability BEFORE authentication so that bots don't get to go around the log in form.
+ *
+ * If we are using our math fallback, authenticate via math-fallback.php
+ *
+ * @param string $user
+ * @param string $username
+ * @param string $password
+ *
+ * @return string $user
+ */
+ function check_preauth( $user = 'Not Used By Protect', $username = 'Not Used By Protect', $password = 'Not Used By Protect' ) {
+
+ $this->check_login_ability( true );
+ $use_math = $this->get_transient( 'brute_use_math' );
+
+ if ( 1 == $use_math && isset( $_POST['log'] ) ) {
+ include_once dirname( __FILE__ ) . '/protect/math-fallback.php';
+ Jetpack_Protect_Math_Authenticate::math_authenticate();
+ }
+
+ return $user;
+ }
+
+ /**
+ * Get all IP headers so that we can process on our server...
+ *
+ * @return string
+ */
+ function get_headers() {
+ $ip_related_headers = array(
+ 'GD_PHP_HANDLER',
+ 'HTTP_AKAMAI_ORIGIN_HOP',
+ 'HTTP_CF_CONNECTING_IP',
+ 'HTTP_CLIENT_IP',
+ 'HTTP_FASTLY_CLIENT_IP',
+ 'HTTP_FORWARDED',
+ 'HTTP_FORWARDED_FOR',
+ 'HTTP_INCAP_CLIENT_IP',
+ 'HTTP_TRUE_CLIENT_IP',
+ 'HTTP_X_CLIENTIP',
+ 'HTTP_X_CLUSTER_CLIENT_IP',
+ 'HTTP_X_FORWARDED',
+ 'HTTP_X_FORWARDED_FOR',
+ 'HTTP_X_IP_TRAIL',
+ 'HTTP_X_REAL_IP',
+ 'HTTP_X_VARNISH',
+ 'REMOTE_ADDR'
+ );
+
+ foreach( $ip_related_headers as $header) {
+ if ( isset( $_SERVER[ $header ] ) ) {
+ $output[ $header ] = $_SERVER[ $header ];
+ }
+ }
+
+ return $output;
+ }
+
+ /*
+ * Checks if the IP address has been whitelisted
+ *
+ * @param string $ip
+ *
+ * @return bool
+ */
+ function ip_is_whitelisted( $ip ) {
+ // If we found an exact match in wp-config
+ if ( defined( 'JETPACK_IP_ADDRESS_OK' ) && JETPACK_IP_ADDRESS_OK == $ip ) {
+ return true;
+ }
+
+ $whitelist = get_site_option( 'jetpack_protect_whitelist', array() );
+
+ if ( ! empty( $whitelist ) ) :
+ foreach ( $whitelist as $item ) :
+ // If the IPs are an exact match
+ if ( ! $item->range && isset( $item->ip_address ) && $item->ip_address == $ip ) {
+ return true;
+ }
+
+ if ( $item->range && isset( $item->range_low ) && isset( $item->range_high ) ) {
+ if ( $this->ip_address_is_in_range( $ip, $item->range_low, $item->range_high ) ) {
+ return true;
+ }
+ }
+ endforeach;
+ endif;
+
+ return false;
+ }
+
+ /**
+ * Checks that a given IP address is within a given low - high range.
+ * Servers that support inet_pton will use that function to convert the ip to number,
+ * while other servers will use ip2long.
+ *
+ * NOTE: servers that do not support inet_pton cannot support ipv6.
+ *
+ * @param $ip
+ * @param $range_low
+ * @param $range_high
+ *
+ * @return bool
+ */
+ function ip_address_is_in_range( $ip, $range_low, $range_high ) {
+ // inet_pton will give us binary string of an ipv4 or ipv6
+ // we can then use strcmp to see if the address is in range
+ if ( function_exists( 'inet_pton' ) ) {
+ $ip_num = inet_pton( $ip );
+ $ip_low = inet_pton( $range_low );
+ $ip_high = inet_pton( $range_high );
+ if ( $ip_num && $ip_low && $ip_high && strcmp( $ip_num, $ip_low ) >= 0 && strcmp( $ip_num, $ip_high ) <= 0 ) {
+ return true;
+ }
+ // ip2long will give us an integer of an ipv4 address only. it will produce FALSE for ipv6
+ } else {
+ $ip_num = ip2long( $ip );
+ $ip_low = ip2long( $range_low );
+ $ip_high = ip2long( $range_high );
+ if ( $ip_num && $ip_low && $ip_high && $ip_num >= $ip_low && $ip_num <= $ip_high ) {
+ return true;
+ }
+ }
+
+ return false;
+
+ }
+
+ /**
+ * Checks the status for a given IP. API results are cached as transients
+ *
+ * @param bool $preauth Whether or not we are checking prior to authorization
+ *
+ * @return bool Either returns true, fires $this->kill_login, or includes a math fallback
+ */
+ function check_login_ability( $preauth = false ) {
+ $headers = $this->get_headers();
+ $header_hash = md5( json_encode( $headers ) );
+ $transient_name = 'jpp_li_' . $header_hash;
+ $transient_value = $this->get_transient( $transient_name );
+ $ip = jetpack_protect_get_ip();
+
+ if( jetpack_protect_ip_is_private( $ip ) ) {
+ return true;
+ }
+
+ if ( $this->ip_is_whitelisted( $ip ) ) {
+ return true;
+ }
+
+ // Check out our transients
+ if ( isset( $transient_value ) && 'ok' == $transient_value['status'] ) {
+ return true;
+ }
+
+ if ( isset( $transient_value ) && 'blocked' == $transient_value['status'] ) {
+ // There is a current block -- prevent login
+ $this->kill_login();
+ }
+
+ // If we've reached this point, this means that the IP isn't cached.
+ // Now we check with the Protect API to see if we should allow login
+ $response = $this->protect_call( $action = 'check_ip' );
+
+ if ( isset( $response['math'] ) && ! function_exists( 'brute_math_authenticate' ) ) {
+ include_once dirname( __FILE__ ) . '/protect/math-fallback.php';
+ }
+
+ if ( 'blocked' == $response['status'] ) {
+ $this->kill_login();
+ }
+
+ return true;
+ }
+
+ /*
+ * Kill a login attempt
+ */
+ function kill_login() {
+ $ip = jetpack_protect_get_ip();
+ /**
+ * Fires before every killed login.
+ *
+ * @since 3.4.0
+ *
+ * @param string $ip IP flagged by Jetpack Protect.
+ */
+ do_action( 'jpp_kill_login', $ip );
+ $help_url = 'http://jetpack.me/support/security/';
+
+ wp_die(
+ sprintf( __( 'Your IP (%1$s) has been flagged for potential security violations. <a href="%2$s">Find out more...</a>', 'jetpack' ), str_replace( 'http://', '', esc_url( 'http://' . $ip ) ), esc_url( $help_url ) ),
+ __( 'Login Blocked by Jetpack', 'jetpack' ),
+ array( 'response' => 403 )
+ );
+ }
+
+ /*
+ * Checks if the protect API call has failed, and if so initiates the math captcha fallback.
+ */
+ public function check_use_math() {
+ $use_math = $this->get_transient( 'brute_use_math' );
+ if ( $use_math ) {
+ include_once dirname( __FILE__ ) . '/protect/math-fallback.php';
+ new Jetpack_Protect_Math_Authenticate;
+ }
+ }
+
+ /**
+ * Get or delete API key
+ */
+ public function configuration_load() {
+
+ if ( isset( $_POST['action'] ) && $_POST['action'] == 'jetpack_protect_save_whitelist' && wp_verify_nonce( $_POST['_wpnonce'], 'jetpack-protect' ) ) {
+ $whitelist = str_replace( ' ', '', $_POST['whitelist'] );
+ $whitelist = explode( PHP_EOL, $whitelist);
+ $result = jetpack_protect_save_whitelist( $whitelist );
+ $this->whitelist_saved = ! is_wp_error( $result );
+ $this->whitelist_error = is_wp_error( $result );
+ }
+
+ if ( isset( $_POST['action'] ) && 'get_protect_key' == $_POST['action'] && wp_verify_nonce( $_POST['_wpnonce'], 'jetpack-protect' ) ) {
+ $result = $this->get_protect_key();
+ // Only redirect on success
+ // If it fails we need access to $this->api_key_error
+ if ( $result ) {
+ wp_safe_redirect( Jetpack::module_configuration_url( 'protect' ) );
+ }
+ }
+
+ $this->api_key = get_site_option( 'jetpack_protect_key', false );
+ $this->whitelist = get_site_option( 'jetpack_protect_whitelist', array() );
+ $this->user_ip = jetpack_protect_get_ip();
+ }
+
+ public function configuration_head() {
+ wp_enqueue_style( 'jetpack-protect' );
+ }
+
+ /**
+ * Prints the configuration screen
+ */
+ public function configuration_screen() {
+ require_once dirname( __FILE__ ) . '/protect/config-ui.php';
+ }
+
+ /**
+ * If we're in a multisite network, return the blog ID of the primary blog
+ *
+ * @return int
+ */
+ public function get_main_blog_id() {
+ if( ! is_multisite() ) {
+ return false;
+ }
+
+ global $current_site;
+ $primary_blog_id = $current_site->blog_id;
+
+ return $primary_blog_id;
+ }
+
+ /**
+ * Get jetpack blog id, or the jetpack blog id of the main blog in the main network
+ *
+ * @return int
+ */
+ public function get_main_blog_jetpack_id() {
+ if ( ! is_main_site() ) {
+ switch_to_blog( $this->get_main_blog_id() );
+ $id = Jetpack::get_option( 'id', false );
+ restore_current_blog();
+ } else {
+ $id = Jetpack::get_option( 'id' );
+ }
+ return $id;
+ }
+
+ public function check_api_key() {
+ $response = $this->protect_call( 'check_key' );
+
+ if ( isset( $response['ckval'] ) ) {
+ return true;
+ }
+
+ if ( isset( $response['error'] ) ) {
+
+ if ( $response[ 'error' ] == 'Invalid API Key' ) {
+ $this->api_key_error = __( 'Your API key is invalid', 'jetpack' );
+ }
+
+ if ( $response[ 'error' ] == 'API Key Required' ) {
+ $this->api_key_error = __( 'No API key', 'jetpack' );
+ }
+ }
+
+ $this->api_key_error = __( 'There was an error contacting Jetpack servers.', 'jetpack' );
+ return false;
+ }
+
+ /**
+ * Calls over to the api using wp_remote_post
+ *
+ * @param string $action 'check_ip', 'check_key', or 'failed_attempt'
+ * @param array $request Any custom data to post to the api
+ *
+ * @return array
+ */
+ function protect_call( $action = 'check_ip', $request = array() ) {
+ global $wp_version, $wpdb, $current_user;
+
+ $api_key = get_site_option( 'jetpack_protect_key' );
+
+ $user_agent = "WordPress/{$wp_version} | Jetpack/" . constant( 'JETPACK__VERSION' );
+
+ $request['action'] = $action;
+ $request['ip'] = jetpack_protect_get_ip();
+ $request['host'] = $this->get_local_host();
+ $request['headers'] = json_encode( $this->get_headers() );
+ $request['jetpack_version'] = constant( 'JETPACK__VERSION' );
+ $request['wordpress_version'] = strval( $wp_version );
+ $request['api_key'] = $api_key;
+ $request['multisite'] = "0";
+
+ if ( is_multisite() ) {
+ $request['multisite'] = get_blog_count();
+ }
+
+ $args = array(
+ 'body' => $request,
+ 'user-agent' => $user_agent,
+ 'httpversion' => '1.0',
+ 'timeout' => 15
+ );
+
+ $response_json = wp_remote_post( $this->get_api_host(), $args );
+ $this->last_response_raw = $response_json;
+ $headers = $this->get_headers();
+ $header_hash = md5( json_encode( $headers ) );
+ $transient_name = 'jpp_li_' . $header_hash;
+ $this->delete_transient( $transient_name );
+
+ if ( is_array( $response_json ) ) {
+ $response = json_decode( $response_json['body'], true );
+ }
+
+ if( isset( $response['blocked_attempts'] ) && $response['blocked_attempts'] ) {
+ update_site_option( 'jetpack_protect_blocked_attempts', $response['blocked_attempts'] );
+ }
+
+ if ( isset( $response['status'] ) && ! isset( $response['error'] ) ) {
+ $response['expire'] = time() + $response['seconds_remaining'];
+ $this->set_transient( $transient_name, $response, $response['seconds_remaining'] );
+ $this->delete_transient( 'brute_use_math' );
+ } else { // Fallback to Math Captcha if no response from API host
+ $this->set_transient( 'brute_use_math', 1, 600 );
+ $response['status'] = 'ok';
+ $response['math'] = true;
+ }
+
+ if ( isset( $response['error'] ) ) {
+ update_site_option( 'jetpack_protect_error', $response['error'] );
+ } else {
+ delete_site_option( 'jetpack_protect_error' );
+ }
+
+ return $response;
+ }
+
+
+
+ /**
+ * Wrapper for WordPress set_transient function, our version sets
+ * the transient on the main site in the network if this is a multisite network
+ *
+ * We do it this way (instead of set_site_transient) because of an issue where
+ * sitewide transients are always autoloaded
+ * https://core.trac.wordpress.org/ticket/22846
+ *
+ * @param string $transient Transient name. Expected to not be SQL-escaped. Must be
+ * 45 characters or fewer in length.
+ * @param mixed $value Transient value. Must be serializable if non-scalar.
+ * Expected to not be SQL-escaped.
+ * @param int $expiration Optional. Time until expiration in seconds. Default 0.
+ *
+ * @return bool False if value was not set and true if value was set.
+ */
+ function set_transient( $transient, $value, $expiration ) {
+ if ( is_multisite() && ! is_main_site() ) {
+ switch_to_blog( $this->get_main_blog_id() );
+ $return = set_transient( $transient, $value, $expiration );
+ restore_current_blog();
+ return $return;
+ }
+ return set_transient( $transient, $value, $expiration );
+ }
+
+ /**
+ * Wrapper for WordPress delete_transient function, our version deletes
+ * the transient on the main site in the network if this is a multisite network
+ *
+ * @param string $transient Transient name. Expected to not be SQL-escaped.
+ * @return bool true if successful, false otherwise
+ */
+ function delete_transient( $transient ) {
+ if ( is_multisite() && ! is_main_site() ) {
+ switch_to_blog( $this->get_main_blog_id() );
+ $return = delete_transient( $transient );
+ restore_current_blog();
+ return $return;
+ }
+ return delete_transient( $transient );
+ }
+
+ /**
+ * Wrapper for WordPress get_transient function, our version gets
+ * the transient on the main site in the network if this is a multisite network
+ *
+ * @param string $transient Transient name. Expected to not be SQL-escaped.
+ * @return mixed Value of transient.
+ */
+ function get_transient( $transient ) {
+ if ( is_multisite() && ! is_main_site() ) {
+ switch_to_blog( $this->get_main_blog_id() );
+ $return = get_transient( $transient );
+ restore_current_blog();
+ return $return;
+ }
+ return get_transient( $transient );
+ }
+
+ function get_api_host() {
+ if ( isset( $this->api_endpoint ) ) {
+ return $this->api_endpoint;
+ }
+
+ //Check to see if we can use SSL
+ $this->api_endpoint = Jetpack::fix_url_for_bad_hosts( JETPACK_PROTECT__API_HOST );
+
+ return $this->api_endpoint;
+ }
+
+ function get_local_host() {
+ if ( isset( $this->local_host ) ) {
+ return $this->local_host;
+ }
+
+ $uri = 'http://' . strtolower( $_SERVER['HTTP_HOST'] );
+
+ if ( is_multisite() ) {
+ $uri = network_home_url();
+ }
+
+ $uridata = parse_url( $uri );
+
+ $domain = $uridata['host'];
+
+ // If we still don't have the site_url, get it
+ if ( ! $domain ) {
+ $uri = get_site_url( 1 );
+ $uridata = parse_url( $uri );
+ $domain = $uridata['host'];
+ }
+
+ $this->local_host = $domain;
+
+ return $this->local_host;
+ }
+
+}
+
+Jetpack_Protect_Module::instance();
+
+if ( isset( $pagenow ) && 'wp-login.php' == $pagenow ) {
+ Jetpack_Protect_Module::check_login_ability();
+}
diff --git a/plugins/jetpack/modules/protect/config-ui.php b/plugins/jetpack/modules/protect/config-ui.php
new file mode 100644
index 00000000..ff9b2569
--- /dev/null
+++ b/plugins/jetpack/modules/protect/config-ui.php
@@ -0,0 +1,57 @@
+<?php if ( ! $this->api_key ) : // no api key, provide a button to get one ?>
+
+ <div class="protect-status attn">
+ <?php if( ! empty( $this->api_key_error ) ) : ?>
+ <p class="error"><?php echo $this->api_key_error; ?></p>
+ <p>
+ <a href="?page=jetpack-debugger"><?php echo __( 'Debug Jetpack for more information.', 'jetpack' ); ?></a>
+ </p>
+ <?php endif; ?>
+
+ <form method="post">
+ <?php wp_nonce_field( 'jetpack-protect' ); ?>
+ <input type='hidden' name='action' value='get_protect_key' />
+ <p class="submit">
+ <?php _e( 'An API key is needed for Jetpack Protect.', 'jetpack' ); ?>
+ <br /><br /><input type='submit' class='button-primary' value='<?php echo esc_attr( __( 'Get an API Key', 'jetpack' ) ); ?>' />
+ </p>
+ </form>
+ </div>
+
+<?php else : // api key is good, show white list options ?>
+
+ <?php
+ global $current_user;
+ $whitelist = jetpack_protect_format_whitelist( $this->whitelist ); // todo remove 'local' from schema when we merge next iteration on calypso
+ ?>
+ <div class="protect-whitelist">
+
+ <form id="editable-whitelist" method="post">
+ <h3><?php _e( 'Whitelist Management', 'jetpack' ); ?></h3>
+
+ <?php if( ! empty( $this->whitelist_error ) ) : ?>
+ <p class="error"><?php _e('One of your IP addresses was not valid.', 'jetpack'); ?></p>
+ <?php endif; ?>
+
+ <?php if( $this->whitelist_saved === true ) : ?>
+ <p class="success"><?php _e('Whitelist saved.', 'jetpack'); ?></p>
+ <?php endif; ?>
+
+ <p>
+ <?php _e( 'Whitelisting an IP address prevents it from ever being blocked by Jetpack.', 'jetpack' ); ?><br />
+ <strong><?php printf( __( 'Your current IP: %s', 'jetpack' ), $this->user_ip ); ?></strong>
+ </p>
+ <?php wp_nonce_field( 'jetpack-protect' ); ?>
+ <input type='hidden' name='action' value='jetpack_protect_save_whitelist' />
+ <textarea name="whitelist"><?php echo implode( PHP_EOL, $whitelist['local'] ); ?></textarea>
+ <p>
+ <em><?php _e('IPv4 and IPv6 are acceptable. <br />To specify a range, enter the low value and high value separated by a dash. Example: 12.12.12.1-12.12.12.100', 'jetpack' ); ?></em>
+ </p>
+ <p>
+ <input type='submit' class='button-primary' value='<?php echo esc_attr( __( 'Save', 'jetpack' ) ); ?>' />
+ </p>
+ </form>
+
+ </div>
+
+<?php endif; ?>
diff --git a/plugins/jetpack/modules/protect/math-fallback.php b/plugins/jetpack/modules/protect/math-fallback.php
new file mode 100644
index 00000000..ce99b699
--- /dev/null
+++ b/plugins/jetpack/modules/protect/math-fallback.php
@@ -0,0 +1,113 @@
+<?php
+
+if ( ! class_exists( 'Jetpack_Protect_Math_Authenticate' ) ) {
+ /*
+ * The math captcha fallback if we can't talk to the Protect API
+ */
+ class Jetpack_Protect_Math_Authenticate {
+
+ function __construct() {
+ add_action( 'login_form', array( $this, 'math_form' ) );
+ if( isset( $_POST[ 'jetpack_protect_process_math_form' ] ) ) {
+ add_action( 'init', array( $this, 'process_generate_math_page' ) );
+ }
+ }
+
+ /**
+ * Verifies that a user answered the math problem correctly while logging in.
+ *
+ * @return bool Returns true if the math is correct
+ * @throws Error if insuffient $_POST variables are present.
+ * @throws Error message if the math is wrong
+ */
+ static function math_authenticate() {
+ $salt = get_site_option( 'jetpack_protect_key' ) . get_site_option( 'admin_email' );
+ $ans = isset( $_POST['jetpack_protect_num'] ) ? (int) $_POST['jetpack_protect_num'] : '' ;
+ $salted_ans = sha1( $salt . $ans );
+ $correct_ans = isset( $_POST[ 'jetpack_protect_answer' ] ) ? $_POST[ 'jetpack_protect_answer' ] : '' ;
+
+ if( isset( $_COOKIE[ 'jpp_math_pass' ] ) ) {
+ $transient = Jetpack_Protect_Module::get_transient( 'jpp_math_pass_' . $_COOKIE[ 'jpp_math_pass' ] );
+ if( !$transient || $transient < 1 ) {
+ Jetpack_Protect_Math_Authenticate::generate_math_page();
+ }
+ return true;
+ }
+
+ if ( ! $correct_ans || !$_POST['jetpack_protect_num'] ) {
+ Jetpack_Protect_Math_Authenticate::generate_math_page();
+ } elseif ( $salted_ans != $correct_ans ) {
+ wp_die( __( '<strong>You failed to correctly answer the math problem.</strong> This is used to combat spam when the Jetpack Protect API is unavailable. Please use your browser\'s back button to return to the login form, press the "refresh" button to generate a new math problem, and try to log in again.', 'jetpack' ) );
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Creates an interim page to collect answers to a math captcha
+ *
+ * @return none, execution stopped
+ */
+ static function generate_math_page( $error = false ) {
+ $salt = get_site_option( 'jetpack_protect_key' ) . get_site_option( 'admin_email' );
+ $num1 = rand( 0, 10 );
+ $num2 = rand( 1, 10 );
+ $sum = $num1 + $num2;
+ $ans = sha1( $salt . $sum );
+ ob_start();
+ ?>
+ <h2><?php _e( 'Please solve this math problem to prove that you are not a bot. Once you solve it, you will need to log in again.', 'jetpack' ); ?></h2>
+ <?php if ($error): ?>
+ <h3><?php _e( 'Your answer was incorrect, please try again.', 'jetpack' ); ?></h3>
+ <?php endif ?>
+
+ <form action="<?php echo home_url(); ?>" method="post" accept-charset="utf-8">
+ <?php Jetpack_Protect_Math_Authenticate::math_form(); ?>
+ <input type="hidden" name="jetpack_protect_process_math_form" value="1" id="jetpack_protect_process_math_form" />
+ <p><input type="submit" value="Continue &rarr;"></p>
+ </form>
+ <?php
+ $mathage = ob_get_contents();
+ ob_end_clean();
+ wp_die( $mathage );
+ }
+
+ public function process_generate_math_page() {
+ $salt = get_site_option( 'jetpack_protect_key' ) . get_site_option( 'admin_email' );
+ $ans = (int)$_POST['jetpack_protect_num'];
+ $salted_ans = sha1( $salt . $ans );
+ $correct_ans = $_POST[ 'jetpack_protect_answer' ];
+
+ if ( $salted_ans != $correct_ans ) {
+ Jetpack_Protect_Math_Authenticate::generate_math_page(true);
+ } else {
+ $temp_pass = substr( sha1( rand( 1, 100000000 ) . get_site_option( 'jetpack_protect_key' ) ), 5, 25 );
+ Jetpack_Protect_Module::set_transient( 'jpp_math_pass_' . $temp_pass, 3, DAY_IN_SECONDS );
+ setcookie('jpp_math_pass', $temp_pass, time() + DAY_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN, false);
+ return true;
+ }
+ }
+
+ /**
+ * Requires a user to solve a simple equation. Added to any WordPress login form.
+ *
+ * @return VOID outputs html
+ */
+ static function math_form() {
+ $salt = get_site_option( 'jetpack_protect_key' ) . get_site_option( 'admin_email' );
+ $num1 = rand( 0, 10 );
+ $num2 = rand( 1, 10 );
+ $sum = $num1 + $num2;
+ $ans = sha1( $salt . $sum );
+ ?>
+ <div style="margin: 5px 0 20px;">
+ <strong>Prove your humanity: </strong>
+ <?php echo $num1 ?> &nbsp; + &nbsp; <?php echo $num2 ?> &nbsp; = &nbsp;
+ <input type="input" name="jetpack_protect_num" value="" size="2" />
+ <input type="hidden" name="jetpack_protect_answer" value="<?php echo $ans; ?>" />
+ </div>
+ <?php
+ }
+
+ }
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/protect/protect-dashboard-widget-rtl.css b/plugins/jetpack/modules/protect/protect-dashboard-widget-rtl.css
new file mode 100644
index 00000000..ce8e7172
--- /dev/null
+++ b/plugins/jetpack/modules/protect/protect-dashboard-widget-rtl.css
@@ -0,0 +1,117 @@
+/* loads inline on wp-admin in order to reduce http requests */
+
+#protect_dashboard_widget .inside {
+ margin: 0;
+ padding: 0;
+ text-align: center;
+}
+
+.jetpack-security * {
+ box-sizing: border-box;
+}
+
+/* alert msgs */
+#protect_dashboard_widget .msg {
+ color: #fff;
+ text-align: center;
+ padding: 10px;
+}
+
+#protect_dashboard_widget .msg.working {
+ background: #7BAC48;
+}
+
+#protect_dashboard_widget .msg.attn {
+ background: #d94f4f;
+}
+
+#protect_dashboard_widget .msg a {
+ color: #fff;
+ text-decoration: underline;
+}
+
+#protect_dashboard_widget .msg a:hover {
+ text-decoration: none;
+}
+
+#protect_dashboard_widget .msg .dashicons {
+ float: left;
+ text-decoration: none;
+ border-radius: 2px;
+}
+
+#protect_dashboard_widget .msg.working .dashicons {
+ color: #609643;
+}
+
+#protect_dashboard_widget .msg.working .dashicons:hover {
+ background: #609643;
+ color: #7BAC48;
+}
+
+#protect_dashboard_widget .msg.attn .dashicons {
+ color: #a93838;
+}
+
+#protect_dashboard_widget .msg.attn .dashicons:hover {
+ background: #a93838;
+ color: #d94f4f;
+}
+
+.blocked-attacks,
+.file-scanning {
+ position: relative;
+}
+
+.blocked-attacks {
+ background: #fafafa;
+ border-bottom: 1px #eee solid;
+ padding-bottom: 35px;
+}
+
+.jetpack-security-sharing {
+ width: 60px;
+ display: inline-block;
+ position: absolute;
+ left: 0;
+ top: 10px;
+}
+
+.jetpack-security-sharing a {
+ color: #dcdcdc;
+}
+
+.jetpack-security-sharing a:hover {
+ color: #cdcbcb;
+}
+
+.blocked-attacks h2,
+.blocked-attacks h3 {
+ color: #7BAC48;
+ font-family: "proxima-nova", "Open Sans", Helvetica, Arial, sans-serif;
+ font-weight: 300;
+}
+
+.blocked-attacks h2 {
+ font-size: 4em;
+ line-height: 110%;
+ margin: 0;
+ padding: 10px 12px 10px 12px;
+}
+
+.blocked-attacks h3 {
+ font-size: 1.1em;
+ line-height: 110%;
+ padding: 0 12px 10px 12px;
+ margin: 0;
+}
+
+.jetpack-protect-logo {
+ width: 50px;
+ position: relative;
+}
+
+.file-scanning {
+ margin-top: -30px;
+ padding: 0 12px;
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/protect/protect-dashboard-widget-rtl.min.css b/plugins/jetpack/modules/protect/protect-dashboard-widget-rtl.min.css
new file mode 100644
index 00000000..88097a0e
--- /dev/null
+++ b/plugins/jetpack/modules/protect/protect-dashboard-widget-rtl.min.css
@@ -0,0 +1 @@
+#protect_dashboard_widget .inside{margin:0;padding:0;text-align:center}.jetpack-security *{-moz-box-sizing:border-box;box-sizing:border-box}#protect_dashboard_widget .msg{color:#fff;text-align:center;padding:10px}#protect_dashboard_widget .msg.working{background:#7BAC48}#protect_dashboard_widget .msg.attn{background:#d94f4f}#protect_dashboard_widget .msg a{color:#fff;text-decoration:underline}#protect_dashboard_widget .msg a:hover{text-decoration:none}#protect_dashboard_widget .msg .dashicons{float:left;text-decoration:none;border-radius:2px}#protect_dashboard_widget .msg.working .dashicons{color:#609643}#protect_dashboard_widget .msg.working .dashicons:hover{background:#609643;color:#7BAC48}#protect_dashboard_widget .msg.attn .dashicons{color:#a93838}#protect_dashboard_widget .msg.attn .dashicons:hover{background:#a93838;color:#d94f4f}.blocked-attacks,.file-scanning{position:relative}.blocked-attacks{background:#fafafa;border-bottom:1px #eee solid;padding-bottom:35px}.jetpack-security-sharing{width:60px;display:inline-block;position:absolute;left:0;top:10px}.jetpack-security-sharing a{color:#dcdcdc}.jetpack-security-sharing a:hover{color:#cdcbcb}.blocked-attacks h2,.blocked-attacks h3{color:#7BAC48;font-family:proxima-nova,"Open Sans",Helvetica,Arial,sans-serif;font-weight:300}.blocked-attacks h2{font-size:4em;line-height:110%;margin:0;padding:10px 12px}.blocked-attacks h3{font-size:1.1em;line-height:110%;padding:0 12px 10px;margin:0}.jetpack-protect-logo{width:50px;position:relative}.file-scanning{margin-top:-30px;padding:0 12px} \ No newline at end of file
diff --git a/plugins/jetpack/modules/protect/protect-dashboard-widget.css b/plugins/jetpack/modules/protect/protect-dashboard-widget.css
new file mode 100644
index 00000000..b83f6022
--- /dev/null
+++ b/plugins/jetpack/modules/protect/protect-dashboard-widget.css
@@ -0,0 +1,117 @@
+/* loads inline on wp-admin in order to reduce http requests */
+
+#protect_dashboard_widget .inside {
+ margin: 0;
+ padding: 0;
+ text-align: center;
+}
+
+.jetpack-security * {
+ box-sizing: border-box;
+}
+
+/* alert msgs */
+#protect_dashboard_widget .msg {
+ color: #fff;
+ text-align: center;
+ padding: 10px;
+}
+
+#protect_dashboard_widget .msg.working {
+ background: #7BAC48;
+}
+
+#protect_dashboard_widget .msg.attn {
+ background: #d94f4f;
+}
+
+#protect_dashboard_widget .msg a {
+ color: #fff;
+ text-decoration: underline;
+}
+
+#protect_dashboard_widget .msg a:hover {
+ text-decoration: none;
+}
+
+#protect_dashboard_widget .msg .dashicons {
+ float: right;
+ text-decoration: none;
+ border-radius: 2px;
+}
+
+#protect_dashboard_widget .msg.working .dashicons {
+ color: #609643;
+}
+
+#protect_dashboard_widget .msg.working .dashicons:hover {
+ background: #609643;
+ color: #7BAC48;
+}
+
+#protect_dashboard_widget .msg.attn .dashicons {
+ color: #a93838;
+}
+
+#protect_dashboard_widget .msg.attn .dashicons:hover {
+ background: #a93838;
+ color: #d94f4f;
+}
+
+.blocked-attacks,
+.file-scanning {
+ position: relative;
+}
+
+.blocked-attacks {
+ background: #fafafa;
+ border-bottom: 1px #eee solid;
+ padding-bottom: 35px;
+}
+
+.jetpack-security-sharing {
+ width: 60px;
+ display: inline-block;
+ position: absolute;
+ right: 0;
+ top: 10px;
+}
+
+.jetpack-security-sharing a {
+ color: #dcdcdc;
+}
+
+.jetpack-security-sharing a:hover {
+ color: #cdcbcb;
+}
+
+.blocked-attacks h2,
+.blocked-attacks h3 {
+ color: #7BAC48;
+ font-family: "proxima-nova", "Open Sans", Helvetica, Arial, sans-serif;
+ font-weight: 300;
+}
+
+.blocked-attacks h2 {
+ font-size: 4em;
+ line-height: 110%;
+ margin: 0;
+ padding: 10px 12px 10px 12px;
+}
+
+.blocked-attacks h3 {
+ font-size: 1.1em;
+ line-height: 110%;
+ padding: 0 12px 10px 12px;
+ margin: 0;
+}
+
+.jetpack-protect-logo {
+ width: 50px;
+ position: relative;
+}
+
+.file-scanning {
+ margin-top: -30px;
+ padding: 0 12px;
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/protect/protect-dashboard-widget.min.css b/plugins/jetpack/modules/protect/protect-dashboard-widget.min.css
new file mode 100644
index 00000000..95406af8
--- /dev/null
+++ b/plugins/jetpack/modules/protect/protect-dashboard-widget.min.css
@@ -0,0 +1 @@
+#protect_dashboard_widget .inside{margin:0;padding:0;text-align:center}.jetpack-security *{-moz-box-sizing:border-box;box-sizing:border-box}#protect_dashboard_widget .msg{color:#fff;text-align:center;padding:10px}#protect_dashboard_widget .msg.working{background:#7BAC48}#protect_dashboard_widget .msg.attn{background:#d94f4f}#protect_dashboard_widget .msg a{color:#fff;text-decoration:underline}#protect_dashboard_widget .msg a:hover{text-decoration:none}#protect_dashboard_widget .msg .dashicons{float:right;text-decoration:none;border-radius:2px}#protect_dashboard_widget .msg.working .dashicons{color:#609643}#protect_dashboard_widget .msg.working .dashicons:hover{background:#609643;color:#7BAC48}#protect_dashboard_widget .msg.attn .dashicons{color:#a93838}#protect_dashboard_widget .msg.attn .dashicons:hover{background:#a93838;color:#d94f4f}.blocked-attacks,.file-scanning{position:relative}.blocked-attacks{background:#fafafa;border-bottom:1px #eee solid;padding-bottom:35px}.jetpack-security-sharing{width:60px;display:inline-block;position:absolute;right:0;top:10px}.jetpack-security-sharing a{color:#dcdcdc}.jetpack-security-sharing a:hover{color:#cdcbcb}.blocked-attacks h2,.blocked-attacks h3{color:#7BAC48;font-family:proxima-nova,"Open Sans",Helvetica,Arial,sans-serif;font-weight:300}.blocked-attacks h2{font-size:4em;line-height:110%;margin:0;padding:10px 12px}.blocked-attacks h3{font-size:1.1em;line-height:110%;padding:0 12px 10px;margin:0}.jetpack-protect-logo{width:50px;position:relative}.file-scanning{margin-top:-30px;padding:0 12px} \ No newline at end of file
diff --git a/plugins/jetpack/modules/protect/shared-functions.php b/plugins/jetpack/modules/protect/shared-functions.php
new file mode 100644
index 00000000..67c6ae58
--- /dev/null
+++ b/plugins/jetpack/modules/protect/shared-functions.php
@@ -0,0 +1,183 @@
+<?php
+/**
+ * These functions are shared by the Protect module and its related json-endpoints
+ */
+
+function jetpack_protect_format_whitelist( $whitelist = null ) {
+
+ if( ! $whitelist ) {
+ $whitelist = get_site_option( 'jetpack_protect_whitelist', array() );
+ }
+
+ $formatted = array(
+ 'local' => array(), // todo remove 'local' when we merge next iteration on calypso
+ );
+
+ foreach( $whitelist as $item ) {
+ if ( $item->range ) {
+ $formatted['local'][] = $item->range_low . ' - ' . $item->range_high;
+ } else {
+ $formatted['local'][] = $item->ip_address;
+ }
+ }
+
+ return $formatted;
+}
+
+function jetpack_protect_save_whitelist( $whitelist ) {
+ $whitelist_error = false;
+ $new_items = array();
+
+ if ( ! is_array( $whitelist ) ) {
+ return new WP_Error( 'invalid_parameters', __( 'Expecting an array', 'jetpack' ) );
+ }
+
+ // validate each item
+ foreach( $whitelist as $item ) {
+
+ $item = trim( $item );
+
+ if ( empty( $item ) ) {
+ continue;
+ }
+
+ $range = false;
+ if ( strpos( $item, '-') ) {
+ $item = explode( '-', $item );
+ $range = true;
+ }
+ $new_item = new stdClass();
+ $new_item->range = $range;
+
+ if ( ! empty( $range ) ) {
+
+ $low = trim( $item[0] );
+ $high = trim( $item[1] );
+
+ if ( ! filter_var( $low, FILTER_VALIDATE_IP ) || ! filter_var( $high, FILTER_VALIDATE_IP ) ) {
+ $whitelist_error = true;
+ break;
+ }
+
+ if ( ! jetpack_convert_ip_address( $low ) || ! jetpack_convert_ip_address( $high ) ) {
+ $whitelist_error = true;
+ break;
+ }
+
+ $new_item->range_low = $low;
+ $new_item->range_high = $high;
+
+ } else {
+
+ if ( ! filter_var( $item, FILTER_VALIDATE_IP ) ) {
+ $whitelist_error = true;
+ break;
+ }
+
+ if ( ! jetpack_convert_ip_address( $item ) ) {
+ $whitelist_error = true;
+ break;
+ }
+ $new_item->ip_address = $item;
+ }
+
+ $new_items[] = $new_item;
+
+ } // end item loop
+
+ if ( ! empty( $whitelist_error ) ) {
+ return new WP_Error( 'invalid_ip', __( 'One of your IP addresses was not valid.', 'jetpack' ) );
+ }
+
+ update_site_option( 'jetpack_protect_whitelist', $new_items );
+ return true;
+}
+
+function jetpack_protect_get_ip() {
+
+ $server_headers = array(
+ 'HTTP_CLIENT_IP',
+ 'HTTP_CF_CONNECTING_IP',
+ 'HTTP_X_FORWARDED_FOR',
+ 'HTTP_X_FORWARDED',
+ 'HTTP_X_CLUSTER_CLIENT_IP',
+ 'HTTP_FORWARDED_FOR',
+ 'HTTP_FORWARDED',
+ 'REMOTE_ADDR'
+ );
+
+ foreach( $server_headers as $key ) {
+
+ if ( ! array_key_exists( $key, $_SERVER ) ) {
+ continue;
+ }
+
+ foreach( explode( ',', $_SERVER[ $key ] ) as $ip ) {
+ $ip = trim( $ip ); // just to be safe
+
+ // Check for IPv4 IP cast as IPv6
+ if ( preg_match('/^::ffff:(\d+\.\d+\.\d+\.\d+)$/', $ip, $matches ) ) {
+ $ip = $matches[1];
+ }
+
+ // If the IP is in a private or reserved range, return REMOTE_ADDR to help prevent spoofing
+ if ( $ip == '127.0.0.1' || $ip == '::1' || jetpack_protect_ip_is_private( $ip ) ) {
+ return $_SERVER[ 'REMOTE_ADDR' ];
+ }
+ return $ip;
+ }
+ }
+}
+
+/**
+ * Checks an IP to see if it is within a private range
+ *
+ * @param int $ip
+ *
+ * @return bool
+ */
+function jetpack_protect_ip_is_private( $ip ) {
+
+ // we are dealing with ipv6, so we can simply rely on filter_var
+ if ( false === strpos( $ip, '.' ) ) {
+ return !filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE );
+ }
+
+ // we are dealing with ipv4
+ $private_ip4_addresses = array(
+ '10.0.0.0|10.255.255.255', // single class A network
+ '172.16.0.0|172.31.255.255', // 16 contiguous class B network
+ '192.168.0.0|192.168.255.255', // 256 contiguous class C network
+ '169.254.0.0|169.254.255.255', // Link-local address also referred to as Automatic Private IP Addressing
+ '127.0.0.0|127.255.255.255' // localhost
+ );
+ $long_ip = ip2long( $ip );
+ if ( -1 != $long_ip ) {
+ foreach ( $private_ip4_addresses as $pri_addr ) {
+ list ( $start, $end ) = explode( '|', $pri_addr );
+ if ( $long_ip >= ip2long( $start ) && $long_ip <= ip2long( $end ) ) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/**
+ * Uses inet_pton if available to convert an IP address to a binary string.
+ * If inet_pton is not available, ip2long will convert the address to an integer.
+ * Returns false if an invalid IP address is given.
+ *
+ * NOTE: ip2long will return false for any ipv6 address. servers that do not support
+ * inet_pton will not support ipv6
+ *
+ * @param $ip
+ *
+ * @return int|string|bool
+ */
+function jetpack_convert_ip_address( $ip ) {
+ if ( function_exists( 'inet_pton' ) ) {
+ return inet_pton( $ip );
+ }
+ return ip2long( $ip );
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/protect/transient-cleanup.php b/plugins/jetpack/modules/protect/transient-cleanup.php
new file mode 100644
index 00000000..4bb7e6a2
--- /dev/null
+++ b/plugins/jetpack/modules/protect/transient-cleanup.php
@@ -0,0 +1,56 @@
+<?php
+/*
+Adapted from Purge Transients by Seebz
+https://github.com/Seebz/Snippets/tree/master/Wordpress/plugins/purge-transients
+*/
+
+if ( ! function_exists('jp_purge_transients') ) {
+ function jp_purge_transients( $older_than = '7 days' ) {
+ global $wpdb;
+
+ $older_than_time = strtotime( '-' . $older_than );
+ if ( $older_than_time > time() || $older_than_time < 1 ) {
+ return false;
+ }
+
+ $sql = $wpdb->prepare( "
+ SELECT REPLACE(option_name, '_transient_timeout_jpp_', '') AS transient_name
+ FROM {$wpdb->options}
+ WHERE option_name LIKE '\_transient\_timeout\_jpp\__%%'
+ AND option_value < %d
+ ", $older_than_time );
+
+ $transients = $wpdb->get_col( $sql );
+
+ $options_names = array();
+
+ foreach( $transients as $transient ) {
+ $options_names[] = '_transient_jpp_' . $transient;
+ $options_names[] = '_transient_timeout_jpp_' . $transient;
+ }
+
+ if ($options_names) {
+ $option_names_string = implode( ', ', array_fill( 0, count( $options_names ), '%s') );
+ $delete_sql = "DELETE FROM {$wpdb->options} WHERE option_name IN ($option_names_string)";
+
+ $delete_sql = call_user_func_array( array($wpdb, 'prepare'), array_merge( array( $delete_sql ), $options_names ) );
+
+ $result = $wpdb->query( $delete_sql );
+ if ( !$result ) {
+ return false;
+ }
+ }
+
+ return;
+ }
+}
+
+
+function jp_purge_transients_activation() {
+ if ( !wp_next_scheduled( 'jp_purge_transients_cron' ) ) {
+ wp_schedule_event( time(), 'daily', 'jp_purge_transients_cron' );
+ }
+}
+add_action( 'admin_init', 'jp_purge_transients_activation' );
+
+add_action( 'jp_purge_transients_cron', 'jp_purge_transients' );
diff --git a/plugins/jetpack/modules/publicize.php b/plugins/jetpack/modules/publicize.php
index 3c8baa48..5cf7a8b5 100644
--- a/plugins/jetpack/modules/publicize.php
+++ b/plugins/jetpack/modules/publicize.php
@@ -1,11 +1,14 @@
<?php
/**
* Module Name: Publicize
- * Module Description: Connect your site to popular social networks and automatically share new posts with your friends.
- * Sort Order: 1
+ * Module Description: Share new posts on social media networks automatically.
+ * Sort Order: 10
+ * Recommendation Order: 7
* First Introduced: 2.0
* Requires Connection: Yes
* Auto Activate: Yes
+ * Module Tags: Social, Recommended
+ * Feature: Recommended
*/
class Jetpack_Publicize {
@@ -20,7 +23,7 @@ class Jetpack_Publicize {
if ( $this->in_jetpack && method_exists( 'Jetpack', 'module_configuration_load' ) ) {
Jetpack::enable_module_configurable( __FILE__ );
Jetpack::module_configuration_load( __FILE__, array( $this, 'jetpack_configuration_load' ) );
- Jetpack_Sync::sync_posts( __FILE__ );
+ add_action( 'init', array( $this, 'sync_posts_init' ), 999 );
}
require_once dirname( __FILE__ ) . '/publicize/publicize.php';
@@ -40,7 +43,7 @@ class Jetpack_Publicize {
if ( $this->in_jetpack) {
add_action( 'jetpack_activate_module_publicize', array( $this, 'module_state_toggle' ) );
add_action( 'jetpack_deactivate_module_publicize', array( $this, 'module_state_toggle' ) );
-
+ add_filter( 'jetpack_sync_post_module_custom_data', array( $this, 'sync_post_module_custom_data' ), 10, 2 );
// if sharedaddy isn't active, the sharing menu hasn't been added yet
$active = Jetpack::get_active_modules();
if ( in_array( 'publicize', $active ) && !in_array( 'sharedaddy', $active ) )
@@ -48,6 +51,27 @@ class Jetpack_Publicize {
}
}
+ function sync_posts_init() {
+ $post_types = array( 'post', 'page' );
+ $all_post_types = get_post_types();
+ foreach ( $all_post_types as $post_type ) {
+ // sync Custom Post Types that support publicize
+ if ( post_type_supports( $post_type, 'publicize' ) ) {
+ $post_types[] = $post_type;
+ }
+ }
+ Jetpack_Sync::sync_posts( __FILE__, array(
+ 'post_types' => $post_types,
+ ) );
+ }
+
+ function sync_post_module_custom_data( $custom_data, $post ) {
+ if ( post_type_supports( get_post_type( $post ), 'publicize' ) ) {
+ $custom_data['cpt_publicizeable'] = true;
+ }
+ return $custom_data;
+ }
+
function module_state_toggle() {
// extra check that we are on the JP blog, just incase
if ( class_exists( 'Jetpack' ) && $this->in_jetpack ) {
@@ -77,8 +101,8 @@ class Publicize_Util {
* @param int $length
* @return string
*/
- function crop_str( $string, $length = 256 ) {
- $string = wp_strip_all_tags( (string) $string, true ); // true: collapse Linear Whitespace into " "
+ public static function crop_str( $string, $length = 256 ) {
+ $string = Publicize_Util::sanitize_message( $string );
$length = absint( $length );
if ( mb_strlen( $string, 'UTF-8' ) <= $length ) {
@@ -282,4 +306,35 @@ class Publicize_Util {
}
return str_replace( $search, $replace, $string );
}
+
+ public static function sanitize_message( $message ) {
+ $message = preg_replace( '@<(script|style)[^>]*?>.*?</\\1>@si', '', $message );
+ $message = wp_kses( $message, array() );
+ $message = preg_replace('/[\r\n\t ]+/', ' ', $message);
+ $message = trim( $message );
+ $message = htmlspecialchars_decode( $message, ENT_QUOTES );
+ return $message;
+ }
}
+
+if( ! ( defined( 'IS_WPCOM' ) && IS_WPCOM ) && ! function_exists( 'publicize_init' ) ) {
+/**
+ * Helper for grabbing a Publicize object from the "front-end" (non-admin) of
+ * a site. Normally Publicize is only loaded in wp-admin, so there's a little
+ * set up that you might need to do if you want to use it on the front end.
+ * Just call this function and it returns a Publicize object.
+ *
+ * @return Publicize Object
+ */
+function publicize_init() {
+ global $publicize;
+
+ if ( ! class_exists( 'Publicize' ) ) {
+ require_once dirname( __FILE__ ) . '/publicize/publicize.php';
+ }
+
+ return $publicize;
+}
+
+}
+
diff --git a/plugins/jetpack/modules/publicize/assets/linkedin-logo.png b/plugins/jetpack/modules/publicize/assets/linkedin-logo.png
index 27018dcd..b480ce54 100644
--- a/plugins/jetpack/modules/publicize/assets/linkedin-logo.png
+++ b/plugins/jetpack/modules/publicize/assets/linkedin-logo.png
Binary files differ
diff --git a/plugins/jetpack/modules/publicize/assets/path-logo.png b/plugins/jetpack/modules/publicize/assets/path-logo.png
index 7e9bba25..0ccbfcff 100644
--- a/plugins/jetpack/modules/publicize/assets/path-logo.png
+++ b/plugins/jetpack/modules/publicize/assets/path-logo.png
Binary files differ
diff --git a/plugins/jetpack/modules/publicize/assets/publicize-fb-2x.png b/plugins/jetpack/modules/publicize/assets/publicize-fb-2x.png
new file mode 100644
index 00000000..9e679f4e
--- /dev/null
+++ b/plugins/jetpack/modules/publicize/assets/publicize-fb-2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/publicize/assets/publicize-google-2x.png b/plugins/jetpack/modules/publicize/assets/publicize-google-2x.png
new file mode 100644
index 00000000..f87ec18a
--- /dev/null
+++ b/plugins/jetpack/modules/publicize/assets/publicize-google-2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/publicize/assets/publicize-linkedin-2x.png b/plugins/jetpack/modules/publicize/assets/publicize-linkedin-2x.png
new file mode 100644
index 00000000..5418abff
--- /dev/null
+++ b/plugins/jetpack/modules/publicize/assets/publicize-linkedin-2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/publicize/assets/publicize-path-2x.png b/plugins/jetpack/modules/publicize/assets/publicize-path-2x.png
new file mode 100644
index 00000000..dbf83116
--- /dev/null
+++ b/plugins/jetpack/modules/publicize/assets/publicize-path-2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/publicize/assets/publicize-rtl.css b/plugins/jetpack/modules/publicize/assets/publicize-rtl.css
new file mode 100644
index 00000000..a713089e
--- /dev/null
+++ b/plugins/jetpack/modules/publicize/assets/publicize-rtl.css
@@ -0,0 +1,214 @@
+div#publicize-services-block {
+ display: block;
+ clear: both;
+ margin-bottom: 25px;
+ background-color: #fff;
+ padding: 25px 20px 5px 25px;
+ overflow: hidden;
+ max-width: 1200px;
+}
+
+/* Add the logos for the Publicize services */
+span.pub-logos {
+ float: right;
+ display: block;
+ width: 130px;
+ height: 75px;
+ margin-top: -18px;
+ margin-right: 5px;
+ vertical-align: top;
+}
+
+.left, .right{
+ width: 50%;
+ float: right;
+}
+
+div#facebook { background: url( publicize-fb-2x.png ) no-repeat; background-size: 32px 32px; padding-right: 42px;background-position: 0px 0px;padding-top:5px; }
+div#twitter { background: url( publicize-twitter-2x.png ) no-repeat; background-size: 32px 32px; padding-right: 42px;background-position: 0px 0px;padding-top:5px; }
+div#linkedin { background: url( publicize-linkedin-2x.png )no-repeat; background-size: 32px 32px; padding-right: 42px;background-position: 0px 0px;padding-top:5px; }
+div#tumblr { background: url( publicize-tumblr-2x.png ) no-repeat; background-size: 32px 32px; padding-right: 42px;background-position: 0px 0px;padding-top:5px; }
+div#path { background: url( publicize-path-2x.png ) no-repeat; background-size: 32px 32px; padding-right: 42px;background-position: 0px 0px;padding-top:5px; }
+div#google_plus { background: url( publicize-google-2x.png ) no-repeat; background-size: 32px 32px; padding-right: 42px;background-position: 0px 0px;padding-top:5px; }
+
+a.publicize-profile-link, a.publicize-profile-link:visited {
+ text-decoration: none;
+ font-weight: bold;
+}
+
+a.publicize-profile-link:hover {
+ color: #f1831e;
+}
+
+a.publicize-add-connection, a.publicize-add-connection:visited {
+ text-decoration: none;
+}
+
+a.publicize-add-connection:hover {
+ color: #f1831e;
+}
+
+div.publicize-service-entry {
+ clear: both;
+ margin-bottom: 10px;
+ padding: 10px 0 25px 0;
+ border-bottom: 1px #eee solid;
+ margin-left: 40px;
+ overflow: hidden;
+}
+
+div.publicize-service-entry:last-of-type{
+ border-width: 0px;
+}
+
+div.publicize-service-left {
+ display: inline-block;
+ width: 150px;
+ vertical-align: top;
+ min-height: 35px;
+}
+
+
+div.publicize-service-left a{
+ font-size: 24px;
+ text-decoration: none;
+}
+
+div.publicize-service-left a:hover{
+ text-decoration: underline;
+}
+
+div.publicize-service-right {
+ display: inline-block;
+ text-align: left;
+ float: left;
+ padding-top:5px;
+}
+
+div.publicize-service-right ul {
+ margin-top: 0;
+}
+
+div.publicize-service-right li {
+ list-style-type: none;
+ font-size: 14px;
+}
+
+.publicize-info {
+ display: inline-block;
+ width: 16px;
+ height: 16px;
+ background-image: url( info-2x.png );
+ background-size: 16px 16px;
+ text-indent: -99999px;
+ float: right;
+ cursor: help;
+ text-decoration: none;
+ margin-left: 10px;
+ margin-top:3px;
+ font-size: 10%;
+}
+
+.pub-disconnect-button {
+ -webkit-border-image: none;
+ border-bottom-color: #CCC;
+ border-bottom-style: none;
+ border-bottom-width: 0px;
+ border-right-color: #CCC;
+ border-right-style: none;
+ border-right-width: 0px;
+ border-left-color: #CCC;
+ border-left-style: none;
+ border-left-width: 0px;
+ border-top-color: #CCC;
+ border-top-style: none;
+ border-top-width: 0px;
+ color: #CCC;
+ cursor: auto;
+ display: inline;
+ font-family: sans-serif;
+ font-size: 20px;
+ font-style: normal;
+ font-weight: normal;
+ height: auto;
+ line-height: 22px;
+ list-style-image: none;
+ list-style-position: outside;
+ list-style-type: none;
+ margin-bottom: 0px;
+ margin-right: 0px;
+ margin-left: 0px;
+ margin-top: 0px;
+ outline-color: #CCC;
+ outline-style: none;
+ outline-width: 0px;
+ overflow-y: visible;
+ padding-bottom: 0px;
+ padding-right: 0px;
+ padding-left: 0px;
+ padding-top: 0px;
+ position: static;
+ left: auto;
+ text-align: right;
+ text-decoration: none;
+ top: auto;
+ vertical-align: baseline;
+ width: auto;
+ z-index: auto;
+}
+
+.pub-disconnect-button:hover {
+ color: #f1831e;
+}
+
+table#option-profile {
+ padding-bottom: 8px;
+}
+
+table#option-profile td {
+ font-family: "Lucida Grande",Verdana,Arial,sans-serif;
+ vertical-align: middle;
+}
+
+table#option-profile td.radio {
+ padding-left: 20px;
+}
+
+table#option-profile td.thumbnail {
+ padding-left: 20px;
+}
+
+table#option-profile td.details {
+ font-weight: bold; color: #333333
+}
+
+table#option-fb-fanpage td, table#option-fanpage td {
+ font-family: "Lucida Grande",Verdana,Arial,sans-serif;
+ vertical-align: middle;
+}
+
+table#option-fb-fanpage td.thumbnail, table#option-fanpage td.thumbnail {
+ padding: 5px 20px 5px 20px;
+}
+
+table#option-fb-fanpage td.details, table#option-fanpage td.details {
+ width: 130px;
+ padding-left: 10px;
+}
+
+table#option-fb-fanpage td.details span.name, table#option-fanpage td.details span.name {
+ font-weight: bold; color: #333333;
+}
+
+table#option-fb-fanpage td.details span.category, table#option-fanpage td.details span.category {
+ font-size: 10px; color: #888888;
+}
+
+input.fb-options {
+ font-family: "Lucida Grande",Verdana,Arial,sans-serif;
+ font-size: 12px;
+}
+
+.pub-connection-error {
+ color: #ff0000;
+}
diff --git a/plugins/jetpack/modules/publicize/assets/publicize-rtl.min.css b/plugins/jetpack/modules/publicize/assets/publicize-rtl.min.css
new file mode 100644
index 00000000..0653d716
--- /dev/null
+++ b/plugins/jetpack/modules/publicize/assets/publicize-rtl.min.css
@@ -0,0 +1 @@
+div#publicize-services-block{display:block;clear:both;margin-bottom:25px;background-color:#fff;padding:25px 20px 5px 25px;overflow:hidden;max-width:1200px}span.pub-logos{float:right;display:block;width:130px;height:75px;margin-top:-18px;margin-right:5px;vertical-align:top}.left,.right{width:50%;float:right}div#facebook{background:url(publicize-fb-2x.png) 0 0/32px 32px no-repeat;padding-right:42px;padding-top:5px}div#twitter{background:url(publicize-twitter-2x.png) 0 0/32px 32px no-repeat;padding-right:42px;padding-top:5px}div#linkedin{background:url(publicize-linkedin-2x.png)no-repeat 0 0/32px 32px;padding-right:42px;padding-top:5px}div#tumblr{background:url(publicize-tumblr-2x.png) 0 0/32px 32px no-repeat;padding-right:42px;padding-top:5px}div#path{background:url(publicize-path-2x.png) 0 0/32px 32px no-repeat;padding-right:42px;padding-top:5px}div#google_plus{background:url(publicize-google-2x.png) 0 0/32px 32px no-repeat;padding-right:42px;padding-top:5px}a.publicize-profile-link,a.publicize-profile-link:visited{text-decoration:none;font-weight:700}a.publicize-profile-link:hover{color:#f1831e}a.publicize-add-connection,a.publicize-add-connection:visited{text-decoration:none}a.publicize-add-connection:hover{color:#f1831e}div.publicize-service-entry{clear:both;margin-bottom:10px;padding:10px 0 25px;border-bottom:1px #eee solid;margin-left:40px;overflow:hidden}div.publicize-service-entry:last-of-type{border-width:0}div.publicize-service-left{display:inline-block;width:150px;vertical-align:top;min-height:35px}div.publicize-service-left a{font-size:24px;text-decoration:none}div.publicize-service-left a:hover{text-decoration:underline}div.publicize-service-right{display:inline-block;text-align:left;float:left;padding-top:5px}div.publicize-service-right ul{margin-top:0}div.publicize-service-right li{list-style-type:none;font-size:14px}.publicize-info{display:inline-block;width:16px;height:16px;background-image:url(info-2x.png);background-size:16px 16px;text-indent:-99999px;float:right;cursor:help;text-decoration:none;margin-left:10px;margin-top:3px;font-size:10%}.pub-disconnect-button{-webkit-border-image:none;border-color:#CCC;border-style:none;border-width:0;color:#CCC;cursor:auto;display:inline;font-family:sans-serif;font-size:20px;font-style:normal;font-weight:400;height:auto;line-height:22px;list-style:none;margin:0;outline:#CCC 0;overflow-y:visible;padding:0;position:static;left:auto;text-align:right;text-decoration:none;top:auto;vertical-align:baseline;width:auto;z-index:auto}.pub-disconnect-button:hover{color:#f1831e}table#option-profile{padding-bottom:8px}table#option-profile td{font-family:"Lucida Grande",Verdana,Arial,sans-serif;vertical-align:middle}table#option-profile td.radio,table#option-profile td.thumbnail{padding-left:20px}table#option-profile td.details{font-weight:700;color:#333}table#option-fanpage td,table#option-fb-fanpage td{font-family:"Lucida Grande",Verdana,Arial,sans-serif;vertical-align:middle}table#option-fanpage td.thumbnail,table#option-fb-fanpage td.thumbnail{padding:5px 20px}table#option-fanpage td.details,table#option-fb-fanpage td.details{width:130px;padding-left:10px}table#option-fanpage td.details span.name,table#option-fb-fanpage td.details span.name{font-weight:700;color:#333}table#option-fanpage td.details span.category,table#option-fb-fanpage td.details span.category{font-size:10px;color:#888}input.fb-options{font-family:"Lucida Grande",Verdana,Arial,sans-serif;font-size:12px}.pub-connection-error{color:red} \ No newline at end of file
diff --git a/plugins/jetpack/modules/publicize/assets/publicize-tumblr-2x.png b/plugins/jetpack/modules/publicize/assets/publicize-tumblr-2x.png
new file mode 100644
index 00000000..d7befda2
--- /dev/null
+++ b/plugins/jetpack/modules/publicize/assets/publicize-tumblr-2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/publicize/assets/publicize-twitter-2x.png b/plugins/jetpack/modules/publicize/assets/publicize-twitter-2x.png
new file mode 100644
index 00000000..0ba3dc87
--- /dev/null
+++ b/plugins/jetpack/modules/publicize/assets/publicize-twitter-2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/publicize/assets/publicize.css b/plugins/jetpack/modules/publicize/assets/publicize.css
index bb40425a..d9346edc 100644
--- a/plugins/jetpack/modules/publicize/assets/publicize.css
+++ b/plugins/jetpack/modules/publicize/assets/publicize.css
@@ -1,9 +1,11 @@
div#publicize-services-block {
- display: inline-block;
+ display: block;
clear: both;
margin-bottom: 25px;
background-color: #fff;
padding: 25px 25px 5px 20px;
+ overflow: hidden;
+ max-width: 1200px;
}
/* Add the logos for the Publicize services */
@@ -17,15 +19,21 @@ span.pub-logos {
vertical-align: top;
}
-span#facebook { background: url( facebook-logo.png ) 50% 19px no-repeat; background-size: 125px 41px; }
-span#twitter { background: url( twitter-logo.png ) 50% 19px no-repeat; background-size: 125px 47px; }
-span#linkedin { background: url( linkedin-logo.png ) 50% 19px no-repeat; background-size: 125px 47px; }
-span#tumblr { background: url( tumblr-logo.png ) 50% 19px no-repeat; background-size: 125px 47px; }
-span#path { background: url( path-logo.png ) 50% 19px no-repeat; background-size: 85px 32px; }
-span#google_plus { background: url( gplus.png ) 50% 19px no-repeat; background-size: 125px; }
+.left, .right{
+ width: 50%;
+ float: left;
+}
+
+div#facebook { background: url( publicize-fb-2x.png ) no-repeat; background-size: 32px 32px; padding-left: 42px;background-position: 0px 0px;padding-top:5px; }
+div#twitter { background: url( publicize-twitter-2x.png ) no-repeat; background-size: 32px 32px; padding-left: 42px;background-position: 0px 0px;padding-top:5px; }
+div#linkedin { background: url( publicize-linkedin-2x.png )no-repeat; background-size: 32px 32px; padding-left: 42px;background-position: 0px 0px;padding-top:5px; }
+div#tumblr { background: url( publicize-tumblr-2x.png ) no-repeat; background-size: 32px 32px; padding-left: 42px;background-position: 0px 0px;padding-top:5px; }
+div#path { background: url( publicize-path-2x.png ) no-repeat; background-size: 32px 32px; padding-left: 42px;background-position: 0px 0px;padding-top:5px; }
+div#google_plus { background: url( publicize-google-2x.png ) no-repeat; background-size: 32px 32px; padding-left: 42px;background-position: 0px 0px;padding-top:5px; }
a.publicize-profile-link, a.publicize-profile-link:visited {
text-decoration: none;
+ font-weight: bold;
}
a.publicize-profile-link:hover {
@@ -41,28 +49,40 @@ a.publicize-add-connection:hover {
}
div.publicize-service-entry {
- width: 100%;
clear: both;
margin-bottom: 10px;
+ padding: 10px 0 25px 0;
+ border-bottom: 1px #eee solid;
+ margin-right: 40px;
+ overflow: hidden;
+}
+
+div.publicize-service-entry:last-of-type{
+ border-width: 0px;
}
div.publicize-service-left {
display: inline-block;
width: 150px;
vertical-align: top;
+ min-height: 35px;
+}
+
+
+div.publicize-service-left a{
+ font-size: 24px;
+ text-decoration: none;
+}
+
+div.publicize-service-left a:hover{
+ text-decoration: underline;
}
div.publicize-service-right {
display: inline-block;
- margin-left: 5px;
- margin-top: 5px;
- width: 300px;
- padding: 10px;
- background-color: #f1f1f1;
- -moz-border-radius: 10px;
- -webkit-border-radius: 10px;
- border-radius: 10px;
- border: 1px solid #e5e5e5;
+ text-align: right;
+ float: right;
+ padding-top:5px;
}
div.publicize-service-right ul {
@@ -71,6 +91,7 @@ div.publicize-service-right ul {
div.publicize-service-right li {
list-style-type: none;
+ font-size: 14px;
}
.publicize-info {
@@ -80,8 +101,12 @@ div.publicize-service-right li {
background-image: url( info-2x.png );
background-size: 16px 16px;
text-indent: -99999px;
- float: right;
+ float: left;
cursor: help;
+ text-decoration: none;
+ margin-right: 10px;
+ margin-top:3px;
+ font-size: 10%;
}
.pub-disconnect-button {
@@ -102,7 +127,7 @@ div.publicize-service-right li {
cursor: auto;
display: inline;
font-family: sans-serif;
- font-size: 15px;
+ font-size: 20px;
font-style: normal;
font-weight: normal;
height: auto;
@@ -183,3 +208,7 @@ input.fb-options {
font-family: "Lucida Grande",Verdana,Arial,sans-serif;
font-size: 12px;
}
+
+.pub-connection-error {
+ color: #ff0000;
+}
diff --git a/plugins/jetpack/modules/publicize/assets/publicize.js b/plugins/jetpack/modules/publicize/assets/publicize.js
index 63e76540..9227dbd8 100644
--- a/plugins/jetpack/modules/publicize/assets/publicize.js
+++ b/plugins/jetpack/modules/publicize/assets/publicize.js
@@ -1,26 +1,30 @@
+/* jshint onevar: false, smarttabs: true */
+/* global tb_show, tb_pathToImage, ajaxurl, tb_init, tb_remove */
+/* global myblogsResponse, publicizeConnTestStart:true, publicizeConnTestComplete:true, publicizeConnRefreshClick:true */
+
var showOptionsPage;
jQuery( function( $ ) {
showOptionsPage = function( service, nonce, connection, blogId ) {
tb_show( null, null, null );
- $("body").append( "<div id='TB_load'><img src='" + tb_pathToImage + "' /></div>" );
+ $('body').append( '<div id=\'TB_load\'><img src=\'' + tb_pathToImage + '\' /></div>' );
$('#TB_load').show();
var query = '';
- if ( null != connection ) {
+ if ( connection ) {
query += '&connection=' + encodeURIComponent( connection );
}
- if ( 'undefined' != typeof( blogId ) && null != blogId ) {
+ if ( 'undefined' !== typeof( blogId ) && blogId ) {
query += '&blog_id=' + Number( blogId );
}
$.post( ajaxurl, 'action=publicize_' + service + '_options_page&_wpnonce=' + nonce + query, function( response ) {
- $("#TB_load").remove();
+ $('#TB_load').remove();
try {
var obj = jQuery.parseJSON( response );
- if ( null != obj && 'object' == typeof( obj ) ) {
+ if ( obj && 'object' === typeof( obj ) ) {
if ( obj.hasOwnProperty( 'fb_redirect' ) ) {
location.href = obj.fb_redirect + '&redirect_uri=' + encodeURIComponent( location.href );
return;
@@ -30,7 +34,7 @@ jQuery( function( $ ) {
// Do nothing and move on
}
- if ( response != '' ) {
+ if ( response ) {
var blogID = $( 'input[name=wpas_ajax_blog_id]' ).val();
var message = $( '<div id="wpas-ajax-' + blogID + '" class="wrap"></div>' ).append( response );
@@ -41,19 +45,19 @@ jQuery( function( $ ) {
tb_init( 'a.new-thickbox' );
$('#wpas-click-' + blogID).click();
- var tb_height = parseInt( $('#TB_ajaxContent').css('height') );
+ var tb_height = parseInt( $('#TB_ajaxContent').css('height'), 10 );
var content_height = $('#thickbox-content').height();
if ( content_height < tb_height ) {
var new_height = content_height + 15;
$('#TB_ajaxContent').css( 'height', new_height );
- var new_margin = parseInt( $('#TB_window').css( 'margin-top') ) + (tb_height - new_height) / 2 + 'px'
+ var new_margin = parseInt( $('#TB_window').css( 'margin-top'), 10 ) + (tb_height - new_height) / 2 + 'px';
$('#TB_window').css( 'margin-top', new_margin);
}
$('.save-options').unbind('click').click( function() {
- var sel = $( "input[name='option']:checked" );
- var global = $( "input[name='global']:checked" );
+ var sel = $( 'input[name=\'option\']:checked' );
+ var global = $( 'input[name=\'global\']:checked' );
var connection = $(this).data('connection');
var token = encodeURIComponent( sel.val() );
@@ -68,19 +72,24 @@ jQuery( function( $ ) {
global_nonce = global.val();
}
- $.post( ajaxurl, 'action=publicize_'+ service + '_options_save&connection=' + connection + '&selected_id=' + id + '&token=' + token + '&type=' + type + '&_wpnonce=' + nonce + '&global=' + global_conn + '&global_nonce=' + global_nonce, function( response ) {
+ $.post( ajaxurl, 'action=publicize_'+ service + '_options_save&connection=' + connection + '&selected_id=' + id + '&token=' + token + '&type=' + type + '&_wpnonce=' + nonce + '&global=' + global_conn + '&global_nonce=' + global_nonce, function( /*response*/ ) {
+ var frameNonce;
tb_remove();
- top.location = 'options-general.php?page=sharing';
+ frameNonce = document.location.search.match( /frame-nonce=([^&]+)/ );
+ if ( /inside-newdash=1/.test( document.location.search ) && frameNonce ) {
+ document.location = 'options-general.php?page=sharing&inside-newdash=1&frame-nonce' + frameNonce[1];
+ } else {
+ top.location = 'options-general.php?page=sharing';
+ }
} );
} );
}
}, 'html' );
- }
+ };
$( 'body' ).append( '<div id="wpas-message" style="display: none"></div>' );
- var messageDiv = $( '#wpas-message' );
$( '.wpas-posts' ).change( function() {
var inputs = $(this).parents( 'td:first' ).find( ':input' );
@@ -88,7 +97,7 @@ jQuery( function( $ ) {
var blogID = inputs.filter( '[name=wpas_ajax_blog_id]' ).val();
$( '#waiting_' + blogID ).show();
- $.post( ajaxurl, inputs.serialize() + '&action=wpas_post', function( response ) { myblogsResponse.call( _this, blogID, response ) }, 'html' );
+ $.post( ajaxurl, inputs.serialize() + '&action=wpas_post', function( response ) { myblogsResponse.call( _this, blogID, response ); }, 'html' );
} );
$( '.options' ).unbind('click').bind( 'click', function(e) {
@@ -98,11 +107,78 @@ jQuery( function( $ ) {
var service = $(this).attr('class').replace( 'options ', '' );
var blogId = null;
- if( 'undefined' != typeof( $(this).attr('id') ) )
- blogId = parseInt( $(this).attr('id').replace( 'options-', '' ) );
+ if ( 'undefined' !== typeof( $(this).attr('id') ) ) {
+ blogId = parseInt( $(this).attr('id').replace( 'options-', '' ), 10 );
+ }
var nonce = $(this).attr('href').replace( '#nonce=', '' );
var connection = $(this).data( 'connection' );
showOptionsPage.call( this, service, nonce, connection, blogId );
});
+
+ /**
+ * Kicks off tests for all connections
+ */
+ publicizeConnTestStart = function() {
+ $( '.pub-connection-test' )
+ .addClass( 'test-in-progress' );
+ $.post( ajaxurl, { action: 'test_publicize_conns' }, publicizeConnTestComplete );
+ };
+
+ publicizeConnRefreshClick = function( event ) {
+ event.preventDefault();
+ var popupURL = event.currentTarget.href;
+ var popupTitle = event.currentTarget.title;
+ // open a popup window
+ // when it is closed, kick off the tests again
+ var popupWin = window.open( popupURL, popupTitle, '' );
+ var popupWinTimer= window.setInterval( function() {
+ if ( popupWin.closed !== false ) {
+ window.clearInterval( popupWinTimer );
+ publicizeConnTestStart();
+ }
+ }, 500 );
+ };
+
+ publicizeConnTestComplete = function( response ) {
+ $( '.pub-connection-test' ).removeClass( 'test-in-progress' );
+
+ $.each( response.data, function( index, testResult ) {
+ // find the li for this connection
+ var testSelector = '#pub-connection-test-' + testResult.connectionID;
+ if ( testResult.connectionTestPassed ) {
+ $( testSelector )
+ .addClass( 'test-passed' )
+ .html( '' )
+ .removeClass( 'test-failed' );
+ } else {
+ $( testSelector )
+ .addClass( 'test-failed' )
+ .html( '<p><span class="pub-connection-error">' + testResult.connectionTestMessage + '</span></p>' )
+ .removeClass( 'test-passed' );
+
+ if ( testResult.userCanRefresh ) {
+ $( testSelector )
+ .append( '<br/>' );
+ $( '<a/>', {
+ 'class' : 'pub-refresh-button button',
+ 'title' : testResult.refreshText,
+ 'href' : testResult.refreshURL,
+ 'text' : testResult.refreshText,
+ 'target' : '_refresh_' + testResult.serviceName
+ } )
+ .appendTo( testSelector )
+ .click( publicizeConnRefreshClick );
+ }
+ }
+ } );
+ };
+
+ $( document ).ready( function() {
+ // If we have at least one .pub-connection-test div present, kick off the connection test
+ if ( $( '.pub-connection-test' ).length ) {
+ publicizeConnTestStart();
+ }
+ } );
+
} );
diff --git a/plugins/jetpack/modules/publicize/assets/publicize.min.css b/plugins/jetpack/modules/publicize/assets/publicize.min.css
new file mode 100644
index 00000000..5c6d7e0a
--- /dev/null
+++ b/plugins/jetpack/modules/publicize/assets/publicize.min.css
@@ -0,0 +1 @@
+div#publicize-services-block{display:block;clear:both;margin-bottom:25px;background-color:#fff;padding:25px 25px 5px 20px;overflow:hidden;max-width:1200px}span.pub-logos{float:left;display:block;width:130px;height:75px;margin-top:-18px;margin-left:5px;vertical-align:top}.left,.right{width:50%;float:left}div#facebook{background:url(publicize-fb-2x.png) 0 0/32px 32px no-repeat;padding-left:42px;padding-top:5px}div#twitter{background:url(publicize-twitter-2x.png) 0 0/32px 32px no-repeat;padding-left:42px;padding-top:5px}div#linkedin{background:url(publicize-linkedin-2x.png)no-repeat 0 0/32px 32px;padding-left:42px;padding-top:5px}div#tumblr{background:url(publicize-tumblr-2x.png) 0 0/32px 32px no-repeat;padding-left:42px;padding-top:5px}div#path{background:url(publicize-path-2x.png) 0 0/32px 32px no-repeat;padding-left:42px;padding-top:5px}div#google_plus{background:url(publicize-google-2x.png) 0 0/32px 32px no-repeat;padding-left:42px;padding-top:5px}a.publicize-profile-link,a.publicize-profile-link:visited{text-decoration:none;font-weight:700}a.publicize-profile-link:hover{color:#f1831e}a.publicize-add-connection,a.publicize-add-connection:visited{text-decoration:none}a.publicize-add-connection:hover{color:#f1831e}div.publicize-service-entry{clear:both;margin-bottom:10px;padding:10px 0 25px;border-bottom:1px #eee solid;margin-right:40px;overflow:hidden}div.publicize-service-entry:last-of-type{border-width:0}div.publicize-service-left{display:inline-block;width:150px;vertical-align:top;min-height:35px}div.publicize-service-left a{font-size:24px;text-decoration:none}div.publicize-service-left a:hover{text-decoration:underline}div.publicize-service-right{display:inline-block;text-align:right;float:right;padding-top:5px}div.publicize-service-right ul{margin-top:0}div.publicize-service-right li{list-style-type:none;font-size:14px}.publicize-info{display:inline-block;width:16px;height:16px;background-image:url(info-2x.png);background-size:16px 16px;text-indent:-99999px;float:left;cursor:help;text-decoration:none;margin-right:10px;margin-top:3px;font-size:10%}.pub-disconnect-button{-webkit-border-image:none;border-color:#CCC;border-style:none;border-width:0;color:#CCC;cursor:auto;display:inline;font-family:sans-serif;font-size:20px;font-style:normal;font-weight:400;height:auto;line-height:22px;list-style:none;margin:0;outline:#CCC 0;overflow-y:visible;padding:0;position:static;right:auto;text-align:left;text-decoration:none;top:auto;vertical-align:baseline;width:auto;z-index:auto}.pub-disconnect-button:hover{color:#f1831e}table#option-profile{padding-bottom:8px}table#option-profile td{font-family:"Lucida Grande",Verdana,Arial,sans-serif;vertical-align:middle}table#option-profile td.radio,table#option-profile td.thumbnail{padding-right:20px}table#option-profile td.details{font-weight:700;color:#333}table#option-fanpage td,table#option-fb-fanpage td{font-family:"Lucida Grande",Verdana,Arial,sans-serif;vertical-align:middle}table#option-fanpage td.thumbnail,table#option-fb-fanpage td.thumbnail{padding:5px 20px}table#option-fanpage td.details,table#option-fb-fanpage td.details{width:130px;padding-right:10px}table#option-fanpage td.details span.name,table#option-fb-fanpage td.details span.name{font-weight:700;color:#333}table#option-fanpage td.details span.category,table#option-fb-fanpage td.details span.category{font-size:10px;color:#888}input.fb-options{font-family:"Lucida Grande",Verdana,Arial,sans-serif;font-size:12px}.pub-connection-error{color:red} \ No newline at end of file
diff --git a/plugins/jetpack/modules/publicize/assets/rtl/publicize-rtl.css b/plugins/jetpack/modules/publicize/assets/rtl/publicize-rtl.css
index 509f8367..622c43ff 100644
--- a/plugins/jetpack/modules/publicize/assets/rtl/publicize-rtl.css
+++ b/plugins/jetpack/modules/publicize/assets/rtl/publicize-rtl.css
@@ -1,11 +1,13 @@
-/* This file was automatically generated on Sep 07 2013 23:01:10 */
+/* This file was automatically generated on Jan 15 2014 20:27:52 */
div#publicize-services-block {
- display: inline-block;
+ display: block;
clear: both;
margin-bottom: 25px;
background-color: #fff;
padding: 25px 20px 5px 25px;
+ overflow: hidden;
+ max-width: 1200px;
}
/* Add the logos for the Publicize services */
@@ -19,15 +21,21 @@ span.pub-logos {
vertical-align: top;
}
-span#facebook { background: url( ../facebook-logo.png ) 50% 19px no-repeat; background-size: 125px 41px; }
-span#twitter { background: url( ../twitter-logo.png ) 50% 19px no-repeat; background-size: 125px 47px; }
-span#linkedin { background: url( ../linkedin-logo.png ) 50% 19px no-repeat; background-size: 125px 47px; }
-span#tumblr { background: url( ../tumblr-logo.png ) 50% 19px no-repeat; background-size: 125px 47px; }
-span#path { background: url( ../path-logo.png ) 50% 19px no-repeat; background-size: 85px 32px; }
-span#google_plus { background: url( ../gplus.png ) 50% 19px no-repeat; background-size: 125px; }
+.left, .right{
+ width: 50%;
+ float: right;
+}
+
+div#facebook { background: url( ../publicize-fb-2x.png ) no-repeat; background-size: 32px 32px; padding-right: 42px;background-position: 0px 0px;padding-top:5px; }
+div#twitter { background: url( ../publicize-twitter-2x.png ) no-repeat; background-size: 32px 32px; padding-right: 42px;background-position: 0px 0px;padding-top:5px; }
+div#linkedin { background: url( ../publicize-linkedin-2x.png )no-repeat; background-size: 32px 32px; padding-right: 42px;background-position: 0px 0px;padding-top:5px; }
+div#tumblr { background: url( ../publicize-tumblr-2x.png ) no-repeat; background-size: 32px 32px; padding-right: 42px;background-position: 0px 0px;padding-top:5px; }
+div#path { background: url( ../publicize-path-2x.png ) no-repeat; background-size: 32px 32px; padding-right: 42px;background-position: 0px 0px;padding-top:5px; }
+div#google_plus { background: url( ../publicize-google-2x.png ) no-repeat; background-size: 32px 32px; padding-right: 42px;background-position: 0px 0px;padding-top:5px; }
a.publicize-profile-link, a.publicize-profile-link:visited {
text-decoration: none;
+ font-weight: bold;
}
a.publicize-profile-link:hover {
@@ -43,28 +51,40 @@ a.publicize-add-connection:hover {
}
div.publicize-service-entry {
- width: 100%;
clear: both;
margin-bottom: 10px;
+ padding: 10px 0 25px 0;
+ border-bottom: 1px #eee solid;
+ margin-left: 40px;
+ overflow: hidden;
+}
+
+div.publicize-service-entry:last-of-type{
+ border-width: 0px;
}
div.publicize-service-left {
display: inline-block;
width: 150px;
vertical-align: top;
+ min-height: 35px;
+}
+
+
+div.publicize-service-left a{
+ font-size: 24px;
+ text-decoration: none;
+}
+
+div.publicize-service-left a:hover{
+ text-decoration: underline;
}
div.publicize-service-right {
display: inline-block;
- margin-right: 5px;
- margin-top: 5px;
- width: 300px;
- padding: 10px;
- background-color: #f1f1f1;
- -moz-border-radius: 10px;
- -webkit-border-radius: 10px;
- border-radius: 10px;
- border: 1px solid #e5e5e5;
+ text-align: left;
+ float: left;
+ padding-top:5px;
}
div.publicize-service-right ul {
@@ -73,6 +93,7 @@ div.publicize-service-right ul {
div.publicize-service-right li {
list-style-type: none;
+ font-size: 14px;
}
.publicize-info {
@@ -82,8 +103,12 @@ div.publicize-service-right li {
background-image: url( ../info-2x.png );
background-size: 16px 16px;
text-indent: -99999px;
- float: left;
+ float: right;
cursor: help;
+ text-decoration: none;
+ margin-left: 10px;
+ margin-top:3px;
+ font-size: 10%;
}
.pub-disconnect-button {
@@ -104,7 +129,7 @@ div.publicize-service-right li {
cursor: auto;
display: inline;
font-family: sans-serif;
- font-size: 15px;
+ font-size: 20px;
font-style: normal;
font-weight: normal;
height: auto;
@@ -185,3 +210,7 @@ input.fb-options {
font-family: "Lucida Grande",Verdana,Arial,sans-serif;
font-size: 12px;
}
+
+.pub-connection-error {
+ color: #ff0000;
+}
diff --git a/plugins/jetpack/modules/publicize/assets/tumblr-logo.png b/plugins/jetpack/modules/publicize/assets/tumblr-logo.png
index 1ec62d39..ac26184e 100644
--- a/plugins/jetpack/modules/publicize/assets/tumblr-logo.png
+++ b/plugins/jetpack/modules/publicize/assets/tumblr-logo.png
Binary files differ
diff --git a/plugins/jetpack/modules/publicize/assets/twitter-logo.png b/plugins/jetpack/modules/publicize/assets/twitter-logo.png
index 6c7b89b3..f8ab3aa2 100644
--- a/plugins/jetpack/modules/publicize/assets/twitter-logo.png
+++ b/plugins/jetpack/modules/publicize/assets/twitter-logo.png
Binary files differ
diff --git a/plugins/jetpack/modules/publicize/enhanced-open-graph.php b/plugins/jetpack/modules/publicize/enhanced-open-graph.php
new file mode 100644
index 00000000..207756c1
--- /dev/null
+++ b/plugins/jetpack/modules/publicize/enhanced-open-graph.php
@@ -0,0 +1,122 @@
+<?php
+if ( ! class_exists( 'Jetpack_Media_Summary' ) && defined('IS_WPCOM') && IS_WPCOM )
+ include WP_CONTENT_DIR . '/lib/class.wpcom-media-summary.php';
+
+/**
+ * Better OG Image Tags for Image Post Formats
+ */
+function enhanced_og_image( $tags ) {
+ if ( !is_singular() || post_password_required() )
+ return $tags;
+
+ global $post;
+
+ // Always favor featured images.
+ if ( enhanced_og_has_featured_image( $post->ID ) )
+ return $tags;
+
+ $summary = Jetpack_Media_Summary::get( $post->ID );
+
+ if ( 'image' != $summary['type'] )
+ return $tags;
+
+ $tags['og:image'] = $summary['image'];
+ $tags['og:image:secure_url'] = $summary['secure']['image'];
+
+ return $tags;
+}
+add_filter( 'jetpack_open_graph_tags', 'enhanced_og_image' );
+
+/**
+ * Better OG Image Tags for Gallery Post Formats
+ */
+function enhanced_og_gallery( $tags ) {
+ if ( !is_singular() || post_password_required() )
+ return $tags;
+
+ global $post;
+
+ // Always favor featured images.
+ if ( enhanced_og_has_featured_image( $post->ID ) )
+ return $tags;
+
+ $summary = Jetpack_Media_Summary::get( $post->ID );
+
+ if ( 'gallery' != $summary['type'] )
+ return $tags;
+
+ if( !isset( $summary['images'] ) || !is_array( $summary['images'] ) || empty( $summary['images'] ) )
+ return $tags;
+
+ $images = $secures = array();
+ foreach ( $summary['images'] as $i => $image ) {
+ $images[] = $image['url'];
+ $secures[] = $summary['secure']['images'][$i]['url'];
+ }
+
+ $tags['og:image'] = $images;
+ $tags['og:image:secure_url'] = $secures;
+
+ return $tags;
+}
+add_filter( 'jetpack_open_graph_tags', 'enhanced_og_gallery' );
+
+/**
+ * Allows VideoPress, YouTube, and Vimeo videos to play inline on Facebook
+ */
+function enhanced_og_video( $tags ) {
+ if ( !is_singular() || post_password_required() )
+ return $tags;
+
+ global $post;
+
+ // Always favor featured images.
+ if ( enhanced_og_has_featured_image( $post->ID ) )
+ return $tags;
+
+ $summary = Jetpack_Media_Summary::get( $post->ID );
+
+ if ( 'video' != $summary['type'] ) {
+ if ( $summary['count']['video'] > 0 && $summary['count']['image'] < 1 ) {
+ $tags['og:image'] = $summary['image'];
+ $tags['og:image:secure_url'] = $summary['secure']['image'];
+ }
+ return $tags;
+ }
+
+ $tags['og:image'] = $summary['image'];
+ $tags['og:image:secure_url'] = $summary['secure']['image'];
+ $tags['og:video:type'] = 'application/x-shockwave-flash';
+
+ $video_url = $summary['video'];
+ $secure_video_url = $summary['secure']['video'];
+
+ if ( preg_match( '/((youtube|vimeo)\.com|youtu.be)/', $video_url ) ) {
+ if ( strstr( $video_url, 'youtube' ) ) {
+ $id = jetpack_get_youtube_id( $video_url );
+ $video_url = 'http://www.youtube.com/v/' . $id . '?version=3&autohide=1';
+ $secure_video_url = 'https://www.youtube.com/v/' . $id . '?version=3&autohide=1';
+ } else if ( strstr( $video_url, 'vimeo' ) ) {
+ preg_match( '|vimeo\.com/(\d+)/?$|i', $video_url, $match );
+ $id = (int) $match[1];
+ $video_url = 'http://vimeo.com/moogaloop.swf?clip_id=' . $id;
+ $secure_video_url = 'https://vimeo.com/moogaloop.swf?clip_id=' . $id;
+ }
+ }
+
+ $tags['og:video'] = $video_url;
+ $tags['og:video:secure_url'] = $secure_video_url;
+
+ if ( empty( $post->post_title ) )
+ $tags['og:title'] = sprintf( __( 'Video on %s', 'jetpack' ), get_option( 'blogname' ) );
+
+ return $tags;
+}
+add_filter( 'jetpack_open_graph_tags', 'enhanced_og_video' );
+
+function enhanced_og_has_featured_image( $post_id ) {
+ $featured = Jetpack_PostImages::from_thumbnail( $post_id, 200, 200 );
+ if ( !empty( $featured ) && count( $featured ) > 0 )
+ return true;
+ return false;
+}
diff --git a/plugins/jetpack/modules/publicize/publicize-jetpack.php b/plugins/jetpack/modules/publicize/publicize-jetpack.php
index 6a985b09..50746b49 100644
--- a/plugins/jetpack/modules/publicize/publicize-jetpack.php
+++ b/plugins/jetpack/modules/publicize/publicize-jetpack.php
@@ -5,6 +5,8 @@ class Publicize extends Publicize_Base {
function __construct() {
parent::__construct();
+ add_filter( 'jetpack_xmlrpc_methods', array( $this, 'register_update_publicize_connections_xmlrpc_method' ) );
+
add_action( 'load-settings_page_sharing', array( $this, 'admin_page_load' ), 9 );
add_action( 'wp_ajax_publicize_tumblr_options_page', array( $this, 'options_page_tumblr' ) );
@@ -12,18 +14,29 @@ class Publicize extends Publicize_Base {
add_action( 'wp_ajax_publicize_twitter_options_page', array( $this, 'options_page_twitter' ) );
add_action( 'wp_ajax_publicize_linkedin_options_page', array( $this, 'options_page_linkedin' ) );
add_action( 'wp_ajax_publicize_path_options_page', array( $this, 'options_page_path' ) );
+ add_action( 'wp_ajax_publicize_google_plus_options_page', array( $this, 'options_page_google_plus' ) );
add_action( 'wp_ajax_publicize_tumblr_options_save', array( $this, 'options_save_tumblr' ) );
add_action( 'wp_ajax_publicize_facebook_options_save', array( $this, 'options_save_facebook' ) );
add_action( 'wp_ajax_publicize_twitter_options_save', array( $this, 'options_save_twitter' ) );
add_action( 'wp_ajax_publicize_linkedin_options_save', array( $this, 'options_save_linkedin' ) );
add_action( 'wp_ajax_publicize_path_options_save', array( $this, 'options_save_path' ) );
+ add_action( 'wp_ajax_publicize_google_plus_options_save', array( $this, 'options_save_google_plus' ) );
add_action( 'load-settings_page_sharing', array( $this, 'force_user_connection' ) );
-
+
add_filter( 'publicize_checkbox_default', array( $this, 'publicize_checkbox_default' ), 10, 4 );
add_action( 'transition_post_status', array( $this, 'save_publicized' ), 10, 3 );
+
+ add_filter( 'jetpack_twitter_cards_site_tag', array( $this, 'enhaced_twitter_cards_site_tag' ) );
+
+ add_action( 'publicize_save_meta', array( $this, 'save_publicized_twitter_account' ), 10, 4 );
+ add_action( 'publicize_save_meta', array( $this, 'save_publicized_facebook_account' ), 10, 4 );
+
+ add_filter( 'jetpack_sharing_twitter_via', array( $this, 'get_publicized_twitter_account' ), 10, 2 );
+
+ include_once ( JETPACK__PLUGIN_DIR . 'modules/publicize/enhanced-open-graph.php' );
}
function force_user_connection() {
@@ -39,7 +52,8 @@ class Publicize extends Publicize_Base {
global $publicize_ui;
remove_action( 'pre_admin_screen_sharing', array( $publicize_ui, 'admin_page' ) );
- Jetpack::init()->admin_styles();
+ // Do we really need `admin_styles`? With the new admin UI, it's breaking some bits.
+ // Jetpack::init()->admin_styles();
add_action( 'pre_admin_screen_sharing', array( $this, 'admin_page_warning' ), 1 );
}
@@ -56,7 +70,7 @@ class Publicize extends Publicize_Base {
<div class="jetpack-text-container">
<h4>
<p><?php printf(
- esc_html( wptexturize( __( "To use Publicize, you'll need to link your %s account to your WordPress.com account using the button to the right.", 'jetpack' ) ) ),
+ esc_html( wptexturize( __( "To use Publicize, you'll need to link your %s account to your WordPress.com account using the link below.", 'jetpack' ) ) ),
'<strong>' . esc_html( $blog_name ) . '</strong>'
); ?></p>
<p><?php echo esc_html( wptexturize( __( "If you don't have a WordPress.com account yet, you can sign up for free in just a few seconds.", 'jetpack' ) ) ); ?></p>
@@ -70,6 +84,32 @@ class Publicize extends Publicize_Base {
<?php
}
+ /**
+ * Remove a Publicize connection
+ */
+ function disconnect( $service_name, $connection_id, $_blog_id = false, $_user_id = false, $force_delete = false ) {
+ Jetpack::load_xml_rpc_client();
+ $xml = new Jetpack_IXR_Client();
+ $xml->query( 'jetpack.deletePublicizeConnection', $connection_id );
+
+ if ( ! $xml->isError() ) {
+ Jetpack_Options::update_option( 'publicize_connections', $xml->getResponse() );
+ } else {
+ return false;
+ }
+ }
+
+ function receive_updated_publicize_connections( $publicize_connections ) {
+ Jetpack_Options::update_option( 'publicize_connections', $publicize_connections );
+ return true;
+ }
+
+ function register_update_publicize_connections_xmlrpc_method( $methods ) {
+ return array_merge( $methods, array(
+ 'jetpack.updatePublicizeConnections' => array( $this, 'receive_updated_publicize_connections' ),
+ ) );
+ }
+
function get_connections( $service_name, $_blog_id = false, $_user_id = false ) {
$connections = Jetpack_Options::get_option( 'publicize_connections' );
$connections_to_return = array();
@@ -132,15 +172,15 @@ class Publicize extends Publicize_Base {
break;
case 'completed':
- // Jetpack blog requests Publicize Connections via new XML-RPC method
Jetpack::load_xml_rpc_client();
$xml = new Jetpack_IXR_Client();
$xml->query( 'jetpack.fetchPublicizeConnections' );
- if ( !$xml->isError() ) {
+ if ( ! $xml->isError() ) {
$response = $xml->getResponse();
Jetpack_Options::update_option( 'publicize_connections', $response );
}
+
break;
case 'delete':
@@ -149,24 +189,21 @@ class Publicize extends Publicize_Base {
check_admin_referer( 'keyring-request', 'kr_nonce' );
check_admin_referer( "keyring-request-$service_name", 'nonce' );
- Jetpack::load_xml_rpc_client();
- $xml = new Jetpack_IXR_Client();
- $xml->query( 'jetpack.deletePublicizeConnection', $id );
+ $this->disconnect( $service_name, $id );
- if ( !$xml->isError() ) {
- $response = $xml->getResponse();
- Jetpack_Options::update_option( 'publicize_connections', $response );
- }
add_action( 'admin_notices', array( $this, 'display_disconnected' ) );
break;
}
}
+ // Do we really need `admin_styles`? With the new admin UI, it's breaking some bits.
// Errors encountered on WordPress.com's end are passed back as a code
+ /*
if ( isset( $_GET['action'] ) && 'error' == $_GET['action'] ) {
// Load Jetpack's styles to handle the box
Jetpack::init()->admin_styles();
}
+ */
}
function display_connection_error() {
@@ -266,12 +303,12 @@ class Publicize extends Publicize_Base {
function refresh_url( $service_name ) {
return add_query_arg( array(
'action' => 'request',
- 'service' => $service_name,
+ 'service' => $service_name,
'kr_nonce' => wp_create_nonce( 'keyring-request' ),
'refresh' => 1,
'for' => 'publicize',
'nonce' => wp_create_nonce( "keyring-request-$service_name" ),
- ), menu_page_url( 'sharing', false ) );
+ ), admin_url( 'options-general.php?page=sharing' ) );
}
function disconnect_url( $service_name, $id ) {
@@ -289,11 +326,12 @@ class Publicize extends Publicize_Base {
$filter = 'all';
$services = array(
- 'facebook' => array(),
- 'twitter' => array(),
- 'linkedin' => array(),
- 'tumblr' => array(),
- 'path' => array(),
+ 'facebook' => array(),
+ 'twitter' => array(),
+ 'linkedin' => array(),
+ 'tumblr' => array(),
+ 'path' => array(),
+ 'google_plus' => array(),
);
if ( 'all' == $filter ) {
@@ -317,6 +355,45 @@ class Publicize extends Publicize_Base {
// Stub only. Doesn't need to do anything on Jetpack Client
}
+ function test_connection( $service_name, $connection ) {
+ $connection_test_passed = true;
+ $connection_test_message = '';
+ $user_can_refresh = false;
+
+ $id = $this->get_connection_id( $connection );
+
+ Jetpack::load_xml_rpc_client();
+ $xml = new Jetpack_IXR_Client();
+ $xml->query( 'jetpack.testPublicizeConnection', $id );
+
+ if ( $xml->isError() ) {
+ $xml_response = $xml->getResponse();
+ $connection_test_message = $xml_response['faultString'];
+ $connection_test_passed = false;
+ }
+
+ // Bail if all is well
+ if ( $connection_test_passed ) {
+ return true;
+ }
+
+ // Set up refresh if the user can
+ $user_can_refresh = current_user_can( $this->GLOBAL_CAP );
+ if ( $user_can_refresh ) {
+ $nonce = wp_create_nonce( "keyring-request-" . $service_name );
+ $refresh_text = sprintf( _x( 'Refresh connection with %s', 'Refresh connection with {social media service}', 'jetpack' ), $this->get_service_label( $service_name ) );
+ $refresh_url = $this->refresh_url( $service_name );
+ }
+
+ $error_data = array(
+ 'user_can_refresh' => $user_can_refresh,
+ 'refresh_text' => $refresh_text,
+ 'refresh_url' => $refresh_url
+ );
+
+ return new WP_Error( 'pub_conn_test_failed', $connection_test_message, $error_data );
+ }
+
/**
* Save a flag locally to indicate that this post has already been Publicized via the selected
* connections.
@@ -572,10 +649,12 @@ class Publicize extends Publicize_Base {
function options_page_twitter() { Publicize_UI::options_page_other( 'twitter' ); }
function options_page_linkedin() { Publicize_UI::options_page_other( 'linkedin' ); }
function options_page_path() { Publicize_UI::options_page_other( 'path' ); }
+ function options_page_google_plus() { Publicize_UI::options_page_other( 'google_plus' ); }
function options_save_twitter() { $this->options_save_other( 'twitter' ); }
function options_save_linkedin() { $this->options_save_other( 'linkedin' ); }
function options_save_path() { $this->options_save_other( 'path' ); }
+ function options_save_google_plus() { $this->options_save_other( 'google_plus' ); }
function options_save_other( $service_name ) {
// Nonce check
@@ -583,74 +662,73 @@ class Publicize extends Publicize_Base {
$this->globalization();
}
- function is_expired( $expires = false ) {
- $hour_in_seconds = 3600;
- if ( !$expires )
- return false; // No expires value, assume it's a permanent token
- if ( '0000-00-00 00:00:00' == $expires )
- return false; // Doesn't expire
- if ( ( time() + $hour_in_seconds ) > strtotime( $expires ) )
- return true; // Token's expiry time has passed, or will pass before $window
- return false;
+ /**
+ * Already-published posts should not be Publicized by default. This filter sets checked to
+ * false if a post has already been published.
+ */
+ function publicize_checkbox_default( $checked, $post_id, $name, $connection ) {
+ if ( 'publish' == get_post_status( $post_id ) )
+ return false;
+
+ return $checked;
}
- function refresh_tokens_message() {
- global $post;
- $post_id = $post ? $post->ID : 0;
-
- $services = $this->get_services( 'all' );
-
- // Same core nonce works for all services
- $keyring_nonce = wp_create_nonce( 'keyring-request' );
- $expired_tokens = false;
-
- if ( is_array( $services ) && count( $services ) ) {
- foreach ( $services as $name => $service ) {
- if ( $connections = $this->get_connections( $name ) ) {
-
- foreach ( $connections as $connection ) {
-
- $cmeta = $this->get_connection_meta( $connection );
-
- // If the token for this connection is expired, or expires soon, then warn
- if ( !$this->is_expired( $cmeta['expires'] ) ) {
- continue;
- }
-
- if ( !$expired_tokens ) {
- ?>
- <div class="error below-h2 publicize-token-refresh-message">
- <p><?php echo esc_html( __( 'Before you hit Publish, please refresh your connection to make sure we can Publicize your post:' , 'jetpack') ); ?></p>
- <?php
- $expired_tokens = true;
- }
- // No need to request for a specific token id, since the token store detects duplication and updates a single token per service
- $nonce = wp_create_nonce( "keyring-request-" . $name );
- $url = $this->refresh_url( $name );
- ?>
- <p style="text-align: center;" id="publicize-token-refresh-<?php echo esc_attr( $name ); ?>" class="publicize-token-refresh-button">
- <a href="<?php echo esc_url( $url ); ?>" class="button" target="_refresh_<?php echo esc_attr( $name ); ?>">
- <?php printf( __( 'Refresh connection with %s' , 'jetpack'), Publicize::get_service_label( $name ) ); ?>
- </a>
- </p><?php
- }
- }
+ /**
+ * If there's only one shared connection to Twitter set it as twitter:site tag.
+ */
+ function enhaced_twitter_cards_site_tag( $tag ) {
+ $custom_site_tag = get_option( 'jetpack-twitter-cards-site-tag' );
+ if( ! empty( $custom_site_tag ) )
+ return $tag;
+ if ( ! $this->is_enabled('twitter') )
+ return $tag;
+ $connections = $this->get_connections( 'twitter' );
+ foreach ( $connections as $connection ) {
+ $connection_meta = $this->get_connection_meta( $connection );
+ if ( 0 == $connection_meta['connection_data']['user_id'] ) {
+ // If the connection is shared
+ return $this->get_display_name( 'twitter', $connection );
}
}
+ return $tag;
+ }
- if ( $expired_tokens ) {
- echo '</div>';
+ function save_publicized_twitter_account( $submit_post, $post_id, $service_name, $connection ) {
+ if ( 'twitter' == $service_name && $submit_post ) {
+ $connection_meta = $this->get_connection_meta( $connection );
+ $publicize_twitter_user = get_post_meta( $post_id, '_publicize_twitter_user' );
+ if ( empty( $publicize_twitter_user ) || 0 != $connection_meta['connection_data']['user_id'] ) {
+ update_post_meta( $post_id, '_publicize_twitter_user', $this->get_display_name( 'twitter', $connection ) );
+ }
}
}
-
- /**
- * Already-published posts should not be Publicized by default. This filter sets checked to
- * false if a post has already been published.
- */
- function publicize_checkbox_default( $checked, $post_id, $name, $connection ) {
- if ( 'publish' == get_post_status( $post_id ) )
- return false;
- return $checked;
+ function get_publicized_twitter_account( $account, $post_id ) {
+ if ( ! empty( $account ) ) {
+ return $account;
+ }
+ $account = get_post_meta( $post_id, '_publicize_twitter_user', true );
+ if ( ! empty( $account ) ) {
+ return $account;
+ }
+ return '';
+ }
+
+ /**
+ * Save the Publicized Facebook account when publishing a post
+ * Use only Personal accounts, not Facebook Pages
+ */
+ function save_publicized_facebook_account( $submit_post, $post_id, $service_name, $connection ) {
+ $connection_meta = $this->get_connection_meta( $connection );
+ if ( 'facebook' == $service_name && isset( $connection_meta['connection_data']['meta']['facebook_profile'] ) && $submit_post ) {
+ $publicize_facebook_user = get_post_meta( $post_id, '_publicize_facebook_user' );
+ if ( empty( $publicize_facebook_user ) || 0 != $connection_meta['connection_data']['user_id'] ) {
+ $profile_link = $this->get_profile_link( 'facebook', $connection );
+
+ if ( false !== $profile_link ) {
+ update_post_meta( $post_id, '_publicize_facebook_user', $profile_link );
+ }
+ }
+ }
}
}
diff --git a/plugins/jetpack/modules/publicize/publicize.php b/plugins/jetpack/modules/publicize/publicize.php
index 0070e5e0..6a4afecb 100644
--- a/plugins/jetpack/modules/publicize/publicize.php
+++ b/plugins/jetpack/modules/publicize/publicize.php
@@ -67,6 +67,9 @@ abstract class Publicize_Base {
// then check meta and publicze based on that. stage 3 implemented on wpcom
add_action( 'transition_post_status', array( $this, 'flag_post_for_publicize' ), 10, 3 );
add_action( 'save_post', array( &$this, 'save_meta' ), 20, 2 );
+
+ // Connection test callback
+ add_action( 'wp_ajax_test_publicize_conns', array( $this, 'test_publicize_conns' ) );
}
/**
@@ -80,6 +83,8 @@ abstract class Publicize_Base {
abstract function get_connections( $service, $_blog_id = false, $_user_id = false );
abstract function get_connection( $service, $id, $_blog_id = false, $_user_id = false );
abstract function flag_post_for_publicize( $new_status, $old_status, $post );
+ abstract function test_connection( $service_name, $connection );
+ abstract function disconnect( $service, $connection_id, $_blog_id = false, $_user_id = false, $force_delete = false );
/**
* Shared Functions
@@ -92,15 +97,22 @@ abstract class Publicize_Base {
$cmeta = $this->get_connection_meta( $c );
if ( isset( $cmeta['connection_data']['meta']['link'] ) ) {
+ if ( 'facebook' == $service_name && 0 === strpos( parse_url( $cmeta['connection_data']['meta']['link'], PHP_URL_PATH ), '/app_scoped_user_id/' ) ) {
+ // App-scoped Facebook user IDs are not usable profile links
+ return false;
+ }
+
return $cmeta['connection_data']['meta']['link'];
} elseif ( 'facebook' == $service_name && isset( $cmeta['connection_data']['meta']['facebook_page'] ) ) {
- return 'http://facebook.com/' . $cmeta['connection_data']['meta']['facebook_page'];
- } elseif ( 'facebook' == $service_name ) {
- return 'http://www.facebook.com/' . $cmeta['external_id'];
+ return 'https://www.facebook.com/' . $cmeta['connection_data']['meta']['facebook_page'];
} elseif ( 'tumblr' == $service_name && isset( $cmeta['connection_data']['meta']['tumblr_base_hostname'] ) ) {
return 'http://' . $cmeta['connection_data']['meta']['tumblr_base_hostname'];
} elseif ( 'twitter' == $service_name ) {
- return 'http://twitter.com/' . substr( $cmeta['external_display'], 1 ); // Has a leading '@'
+ return 'https://twitter.com/' . substr( $cmeta['external_display'], 1 ); // Has a leading '@'
+ } elseif ( 'google_plus' == $service_name && isset( $cmeta['connection_data']['meta']['google_plus_page'] ) ) {
+ return 'https://plus.google.com/' . $cmeta['connection_data']['meta']['google_plus_page'];
+ } elseif ( 'google_plus' == $service_name ) {
+ return 'https://plus.google.com/' . $cmeta['external_id'];
} else if ( 'linkedin' == $service_name ) {
if ( !isset( $cmeta['connection_data']['meta']['profile_url'] ) ) {
return false;
@@ -147,6 +159,9 @@ abstract class Publicize_Base {
case 'linkedin':
return 'LinkedIn';
break;
+ case 'google_plus':
+ return 'Google+';
+ break;
case 'twitter':
case 'facebook':
case 'tumblr':
@@ -302,6 +317,9 @@ abstract class Publicize_Base {
// This was a wp-admin request, so we need to check the state of checkboxes
if ( $from_web ) {
+ // delete stray service-based post meta
+ delete_post_meta( $post_id, $this->POST_SKIP . $service_name );
+
// We *unchecked* this stream from the admin page, or it's set to readonly, or it's a new addition
if ( empty( $_POST[$this->ADMIN_PAGE]['submit'][$unique_id] ) ) {
// Also make sure that the service-specific input isn't there.
@@ -311,6 +329,9 @@ abstract class Publicize_Base {
// Nothing seems to be checked, so we're going to mark this one to be skipped
update_post_meta( $post_id, $this->POST_SKIP . $unique_id, 1 );
continue;
+ } else {
+ // clean up any stray post meta
+ delete_post_meta( $post_id, $this->POST_SKIP . $unique_id );
}
} else {
// The checkbox for this connection is explicitly checked -- make sure we DON'T skip it
@@ -346,4 +367,51 @@ abstract class Publicize_Base {
return post_type_supports( $post_type, 'publicize' );
}
+
+ /**
+ * Runs tests on all the connections and returns the results to the caller
+ */
+ function test_publicize_conns() {
+ $test_results = array();
+
+ foreach ( (array) $this->get_services( 'connected' ) as $service_name => $connections ) {
+ foreach ( $connections as $connection ) {
+
+ $id = $this->get_connection_id( $connection );
+
+ $connection_test_passed = true;
+ $connection_test_message = __( 'This connection is working correctly.' , 'jetpack' );
+ $user_can_refresh = false;
+ $refresh_text = '';
+ $refresh_url = '';
+
+ $connection_test_result = true;
+ if ( method_exists( $this, 'test_connection' ) ) {
+ $connection_test_result = $this->test_connection( $service_name, $connection );
+ }
+
+ if ( is_wp_error( $connection_test_result ) ) {
+ $connection_test_passed = false;
+ $connection_test_message = $connection_test_result->get_error_message();
+ $error_data = $connection_test_result->get_error_data();
+
+ $user_can_refresh = $error_data['user_can_refresh'];
+ $refresh_text = $error_data['refresh_text'];
+ $refresh_url = $error_data['refresh_url'];
+ }
+
+ $test_results[] = array(
+ 'connectionID' => $id,
+ 'serviceName' => $service_name,
+ 'connectionTestPassed' => $connection_test_passed,
+ 'connectionTestMessage' => esc_attr( $connection_test_message ),
+ 'userCanRefresh' => $user_can_refresh,
+ 'refreshText' => esc_attr( $refresh_text ),
+ 'refreshURL' => $refresh_url
+ );
+ }
+ }
+
+ wp_send_json_success( $test_results );
+ }
}
diff --git a/plugins/jetpack/modules/publicize/ui.php b/plugins/jetpack/modules/publicize/ui.php
index 1011f7c0..7d946766 100644
--- a/plugins/jetpack/modules/publicize/ui.php
+++ b/plugins/jetpack/modules/publicize/ui.php
@@ -60,20 +60,31 @@ class Publicize_UI {
array( 'jquery', 'thickbox' ),
'20121019'
);
+ if( is_rtl() ) {
+ wp_enqueue_style( 'publicize', plugins_url( 'assets/rtl/publicize-rtl.css', __FILE__ ), array(), '20120925' );
+ } else {
+ wp_enqueue_style( 'publicize', plugins_url( 'assets/publicize.css', __FILE__ ), array(), '20120925' );
+ }
- wp_enqueue_style(
- 'publicize',
- plugins_url( 'assets/publicize.css', __FILE__ ),
- array(),
- '20120925'
- );
add_thickbox();
}
public static function connected_notice( $service_name ) { ?>
<div class='updated'>
- <p><?php printf( __( 'You have successfully connected your blog with your %s account.', 'jetpack' ), Publicize::get_service_label( $service_name ) ); ?></p>
+ <p><?php
+
+ if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
+ $platform = __( 'WordPress.com', 'jetpack' );
+ } else {
+ $platform = __( 'Jetpack', 'jetpack' );
+ }
+
+ printf(
+ __( 'You have successfully connected your %1$s account with %2$s.', '1: Service Name (Facebook, Twitter, ...), 2. WordPress.com or Jetpack', 'jetpack' ),
+ Publicize::get_service_label( $service_name ),
+ $platform
+ ); ?></p>
</div><?php
}
@@ -115,14 +126,25 @@ class Publicize_UI {
<div id="publicize-services-block">
<?php
- foreach ( $this->publicize->get_services( 'all' ) as $name => $service ) :
+ $services = $this->publicize->get_services( 'all' );
+ $total_num_of_services = count ( $services );
+ $service_num = 0;?>
+
+ <div class='left'>
+
+ <?php
+ foreach ( $services as $name => $service ) :
$connect_url = $this->publicize->connect_url( $name );
+ if ( $service_num == ( round ( ( $total_num_of_services / 2 ), 0 ) ) )
+ echo "</div><div class='right'>";
+ $service_num++;
?>
- <div class="publicize-service-entry">
+ <div class="publicize-service-entry" <?php if ( $service_num > 0 ): ?>class="connected"<?php endif; ?> >
<div id="<?php echo esc_attr( $name ); ?>" class="publicize-service-left">
- <a href="<?php echo esc_url( $connect_url ); ?>" target="_top"><span class="pub-logos" id="<?php echo esc_attr( $name ); ?>">&nbsp;</span></a>
+ <a href="<?php echo esc_url( $connect_url ); ?>" id="service-link-<?php echo esc_attr( $name ); ?>" target="_top"><?php echo $this->publicize->get_service_label( $name ); ?></a>
</div>
+
<div class="publicize-service-right">
<?php if ( $this->publicize->is_enabled( $name ) && $connections = $this->publicize->get_connections( $name ) ) : ?>
<ul>
@@ -150,7 +172,8 @@ class Publicize_UI {
</script>
<?php endif; ?>
- <li>
+ <li class="publicize-connection" data-connection-id="<?php echo esc_attr( $id ); ?>">
+ <?php esc_html_e( 'Connected as:', 'jetpack' ); ?>
<?php
if ( !empty( $profile_link ) ) : ?>
<a class="publicize-profile-link" href="<?php echo esc_url( $profile_link ); ?>" target="_top">
@@ -171,6 +194,10 @@ class Publicize_UI {
<?php else : ?>
<a class="pub-disconnect-button" title="<?php esc_html_e( 'Disconnect', 'jetpack' ); ?>" href="<?php echo esc_url( $disconnect_url ); ?>" target="_top">×</a>
<?php endif; ?>
+
+ <br/>
+ <div class="pub-connection-test test-in-progress" id="pub-connection-test-<?php echo esc_attr( $id ); ?>" >
+ </div>
</li>
<?php
@@ -178,7 +205,18 @@ class Publicize_UI {
?>
</ul>
<?php endif; ?>
- <a id="<?php echo esc_attr( $name ); ?>" class="publicize-add-connection" href="<?php echo esc_url( $connect_url); ?>" target="_top"><?php echo esc_html( sprintf( __( 'Add new %s connection.', 'jetpack' ), $this->publicize->get_service_label( $name ) ) ); ?></a>
+
+
+
+ <?php
+ $connections = $this->publicize->get_connections( $name );
+ if ( empty ( $connections ) ) { ?>
+ <a id="<?php echo esc_attr( $name ); ?>" class="publicize-add-connection button" href="<?php echo esc_url( $connect_url ); ?>" target="_top"><?php echo esc_html( __( 'Connect', 'jetpack' ) ); ?></a>
+ <?php } else { ?>
+ <a id="<?php echo esc_attr( $name ); ?>" class="publicize-add-connection button add-new" href="<?php echo esc_url( $connect_url ); ?>" target="_top"><?php echo esc_html( __( 'Add New', 'jetpack' ) ); ?></a>
+ <?php } ?>
+
+
<?php
$help = apply_filters( 'publicize_help_text_' . $name, false );
if ( $help ) {
@@ -188,10 +226,10 @@ class Publicize_UI {
</div>
</div>
<?php endforeach; ?>
+ </div>
<script>
(function($){
- $('.pub-disconnect-button').on('click', function(e){
- if ( confirm( '<?php echo esc_js( __( 'Are you sure you want to stop Publicizing posts to this connection?', 'jetpack' ) ); ?>' ) ) {
+ $('.pub-disconnect-button').on('click', function(e){ if ( confirm( '<?php echo esc_js( __( 'Are you sure you want to stop Publicizing posts to this connection?', 'jetpack' ) ); ?>' ) ) {
return true;
} else {
e.preventDefault();
@@ -341,7 +379,13 @@ jQuery( function($) {
authClick = true;
$(this).after( '<img src="images/loading.gif" class="alignleft" style="margin: 0 .5em" />' );
$.ajaxSetup( { async: false } );
- autosave();
+
+ if ( window.wp && window.wp.autosave ) {
+ window.wp.autosave.server.triggerSave();
+ } else {
+ autosave();
+ }
+
return true;
} );
@@ -350,6 +394,78 @@ jQuery( function($) {
fakebox = '<input id="wpas-submit-' + service + '" type="hidden" value="1" name="wpas[submit][' + service + ']" />';
$( '#add-publicize-check' ).append( fakebox );
} );
+
+ publicizeConnTestStart = function() {
+ $( '#pub-connection-tests' )
+ .removeClass( 'below-h2' )
+ .removeClass( 'error' )
+ .removeClass( 'publicize-token-refresh-message' )
+ .addClass( 'test-in-progress' )
+ .html( '' );
+ $.post( ajaxurl, { action: 'test_publicize_conns' }, publicizeConnTestComplete );
+ }
+
+ publicizeConnRefreshClick = function( event ) {
+ event.preventDefault();
+ var popupURL = event.currentTarget.href;
+ var popupTitle = event.currentTarget.title;
+ // open a popup window
+ // when it is closed, kick off the tests again
+ var popupWin = window.open( popupURL, popupTitle, '' );
+ var popupWinTimer= window.setInterval( function() {
+ if ( popupWin.closed !== false ) {
+ window.clearInterval( popupWinTimer );
+ publicizeConnTestStart();
+ }
+ }, 500 );
+ }
+
+ publicizeConnTestComplete = function( response ) {
+ var testsSelector = $( '#pub-connection-tests' );
+ testsSelector
+ .removeClass( 'test-in-progress' )
+ .removeClass( 'below-h2' )
+ .removeClass( 'error' )
+ .removeClass( 'publicize-token-refresh-message' )
+ .html( '' );
+
+ // If any of the tests failed, show some stuff
+ var somethingShownAlready = false;
+ $.each( response.data, function( index, testResult ) {
+ // find the li for this connection
+ if ( ! testResult.connectionTestPassed ) {
+ if ( ! somethingShownAlready ) {
+ testsSelector
+ .addClass( 'below-h2' )
+ .addClass( 'error' )
+ .addClass( 'publicize-token-refresh-message' )
+ .append( "<p><?php echo esc_html( __( 'Before you hit Publish, please refresh the following connection(s) to make sure we can Publicize your post:', 'jetpack' ) ); ?></p>" );
+ somethingShownAlready = true;
+ }
+
+ if ( testResult.userCanRefresh ) {
+ testsSelector.append( '<p/>' );
+ $( '<a/>', {
+ 'class' : 'pub-refresh-button button',
+ 'title' : testResult.refreshText,
+ 'href' : testResult.refreshURL,
+ 'text' : testResult.refreshText,
+ 'target' : '_refresh_' + testResult.serviceName
+ } )
+ .appendTo( testsSelector.children().last() )
+ .click( publicizeConnRefreshClick );
+ }
+ }
+ } );
+ }
+
+ $( document ).ready( function() {
+ // If we have the #pub-connection-tests div present, kick off the connection test
+ if ( $( '#pub-connection-tests' ).length ) {
+ publicizeConnTestStart();
+ }
+ } );
+
} );
</script>
@@ -447,7 +563,11 @@ jQuery( function($) {
// Should we be skipping this one?
$skip = (
- get_post_meta( $post->ID, $this->publicize->POST_SKIP . $unique_id, true )
+ (
+ in_array( $post->post_status, array( 'publish', 'draft', 'future' ) )
+ &&
+ get_post_meta( $post->ID, $this->publicize->POST_SKIP . $unique_id, true )
+ )
||
(
is_array( $connection )
@@ -534,9 +654,9 @@ jQuery( function($) {
<a href="#" class="hide-if-no-js" id="publicize-form-hide"><?php _e( 'Hide', 'jetpack' ); ?></a>
<input type="hidden" name="wpas[0]" value="1" />
- </div> <?php // #publicize-form
-
- $this->publicize->refresh_tokens_message();
+ </div>
+ <div id="pub-connection-tests"></div>
+ <?php // #publicize-form
$publicize_form = ob_get_clean();
else :
@@ -570,10 +690,10 @@ jQuery( function($) {
endif;
?>
- <span id="publicize-defaults"><strong><?php echo join( '</strong>, <strong>', array_map( 'esc_html', $active ) ); ?></strong></span>
+ <span id="publicize-defaults"><strong><?php echo join( '</strong>, <strong>', array_map( 'esc_html', $active ) ); ?></strong></span><br />
<?php if ( 0 < count( $services ) ) : ?>
- <a href="#" id="publicize-form-edit"><?php _e( 'Edit', 'jetpack' ); ?></a>&nbsp;<a href="<?php echo admin_url( 'options-general.php?page=sharing' ); ?>" target="_blank"><?php _e( 'Settings', 'jetpack' ); ?></a><br />
+ <a href="#" id="publicize-form-edit"><?php _e( 'Edit Details', 'jetpack' ); ?></a>&nbsp;<a href="<?php echo admin_url( 'options-general.php?page=sharing' ); ?>" target="_blank"><?php _e( 'Settings', 'jetpack' ); ?></a><br />
<?php else : ?>
<a href="#" id="publicize-disconnected-form-show"><?php _e( 'Show', 'jetpack' ); ?></a><br />
<?php endif; ?>
diff --git a/plugins/jetpack/modules/random-redirect.php b/plugins/jetpack/modules/random-redirect.php
index 2c568dbf..88c13090 100644
--- a/plugins/jetpack/modules/random-redirect.php
+++ b/plugins/jetpack/modules/random-redirect.php
@@ -1,43 +1,6 @@
<?php
-/*
-Plugin Name: Random Redirect
-Plugin URI: http://wordpress.org/extend/plugins/random-redirect/
-Description: Allows you to create a link to yourblog.example.com/?random which will redirect someone to a random post on your blog, in a StumbleUpon-like fashion.
-Version: 1.2-wpcom
-Author: Matt Mullenweg
-Author URI: http://photomatt.net/
-*/
-
-function matt_random_redirect() {
- // Acceptables URL formats: /[...]/?random=[post type], /?random, /&random, /&random=1
- if ( ! isset( $_GET['random'] ) && ! in_array( strtolower( $_SERVER['REQUEST_URI'] ), array( '/&random', '/&random=1' ) ) )
- return;
-
- // Ignore requests that include more than just the random parameter.
- if ( ! empty( $_POST ) || ( isset( $_GET['random'] ) && count( $_GET ) > 1 ) )
- return;
-
- // Persistent AppEngine abuse. ORDER BY RAND is expensive.
- if ( strstr( $_SERVER['HTTP_USER_AGENT'], 'AppEngine-Google' ) )
- wp_die( 'Please <a href="http://en.support.wordpress.com/contact/">contact support</a>' );
-
- // Use the post type of the current page as the context for the random lookup.
- $post_type = get_post_type();
-
- // /?random should always show a random post, even if the home page is a static page.
- if ( '/' == $_SERVER['DOCUMENT_URI'] )
- $post_type = 'post';
- else
- $post_type = get_post_type();
-
- if ( ! $post_type )
- $post_type = 'post';
-
- global $wpdb;
- $random_id = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type = %s AND post_password = '' AND post_status = 'publish' ORDER BY RAND() LIMIT 1", $post_type ) );
- $permalink = get_permalink( $random_id );
- wp_safe_redirect( $permalink );
- exit;
-}
-
-add_action( 'template_redirect', 'matt_random_redirect' );
+/**
+ * Deprecated. No longer needed.
+ *
+ * @package Jetpack
+ */
diff --git a/plugins/jetpack/modules/related-posts.php b/plugins/jetpack/modules/related-posts.php
new file mode 100644
index 00000000..6aac9d22
--- /dev/null
+++ b/plugins/jetpack/modules/related-posts.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * Module Name: Related Posts
+ * Module Description: Display links to your related content under posts and pages.
+ * Jumpstart Description: keep visitors engaged on your blog by highlighting relevant and new content at the bottom of each published post.
+ * First Introduced: 2.9
+ * Sort Order: 29
+ * Recommendation Order: 9
+ * Requires Connection: Yes
+ * Auto Activate: No
+ * Module Tags: Recommended
+ * Feature: Recommended, Jumpstart
+ */
+class Jetpack_RelatedPosts_Module {
+ /**
+ * Class variables
+ */
+ private static $__instance = null;
+
+ /**
+ * Singleton implementation
+ *
+ * @return object
+ */
+ public static function instance() {
+ if ( ! is_a( self::$__instance, 'Jetpack_RelatedPosts_Module' ) )
+ self::$__instance = new Jetpack_RelatedPosts_Module();
+
+ return self::$__instance;
+ }
+
+ /**
+ * Register actions and filters
+ *
+ * @uses add_action, add_filter
+ * @return null
+ */
+ private function __construct() {
+ add_action( 'jetpack_module_loaded_related-posts', array( $this, 'action_on_load' ) );
+ add_action( 'jetpack_activate_module_related-posts', array( $this, 'action_on_activate' ) );
+ }
+
+ /**
+ * This action triggers when module is activated.
+ *
+ * @uses Jetpack::init, Jetpack_Sync::reindex_needed, Jetpack_Sync::reindex_trigger
+ * @return null
+ */
+ public function action_on_activate() {
+ if ( Jetpack::init()->sync->reindex_needed() ) {
+ Jetpack::init()->sync->reindex_trigger();
+ }
+ }
+
+ /**
+ * This action triggers if the module is in an active state, load related posts and options.
+ *
+ * @uses Jetpack_RelatedPosts::init, is_admin, Jetpack::enable_module_configurable, Jetpack::module_configuration_load, Jetpack_Sync::sync_posts
+ * @return null
+ */
+ public function action_on_load() {
+ require_once 'related-posts/jetpack-related-posts.php';
+ Jetpack_RelatedPosts::init();
+
+ if ( is_admin() ) {
+ // Enable "Configure" button on module card
+ Jetpack::enable_module_configurable( __FILE__ );
+ Jetpack::module_configuration_load( __FILE__, array( $this, 'module_configuration_load' ) );
+
+ // Sync new posts
+ Jetpack_Sync::sync_posts( __FILE__ );
+ }
+ }
+
+ /**
+ * Redirect configure button to Settings > Reading
+ *
+ * @uses wp_safe_redirect, admin_url
+ * @return null
+ */
+ public function module_configuration_load() {
+ wp_safe_redirect( admin_url( 'options-reading.php#jetpack_relatedposts' ) );
+ exit;
+ }
+
+}
+
+// Do it.
+Jetpack_RelatedPosts_Module::instance();
diff --git a/plugins/jetpack/modules/related-posts/jetpack-related-posts.php b/plugins/jetpack/modules/related-posts/jetpack-related-posts.php
new file mode 100644
index 00000000..4be69953
--- /dev/null
+++ b/plugins/jetpack/modules/related-posts/jetpack-related-posts.php
@@ -0,0 +1,1126 @@
+<?php
+class Jetpack_RelatedPosts {
+ const VERSION = '20150408';
+ const SHORTCODE = 'jetpack-related-posts';
+
+ /**
+ * Creates and returns a static instance of Jetpack_RelatedPosts.
+ *
+ * @return Jetpack_RelatedPosts
+ */
+ public static function init() {
+ static $instance = NULL;
+
+ if ( ! $instance ) {
+ if ( class_exists('WPCOM_RelatedPosts') && method_exists( 'WPCOM_RelatedPosts', 'init' ) ) {
+ $instance = WPCOM_RelatedPosts::init();
+ } else {
+ $instance = new Jetpack_RelatedPosts(
+ get_current_blog_id(),
+ Jetpack_Options::get_option( 'id' )
+ );
+ }
+ }
+
+ return $instance;
+ }
+
+ /**
+ * Creates and returns a static instance of Jetpack_RelatedPosts_Raw.
+ *
+ * @return Jetpack_RelatedPosts
+ */
+ public static function init_raw() {
+ static $instance = NULL;
+
+ if ( ! $instance ) {
+ if ( class_exists('WPCOM_RelatedPosts') && method_exists( 'WPCOM_RelatedPosts', 'init_raw' ) ) {
+ $instance = WPCOM_RelatedPosts::init_raw();
+ } else {
+ $instance = new Jetpack_RelatedPosts_Raw(
+ get_current_blog_id(),
+ Jetpack_Options::get_option( 'id' )
+ );
+ }
+ }
+
+ return $instance;
+ }
+
+ protected $_blog_id_local;
+ protected $_blog_id_wpcom;
+ protected $_options;
+ protected $_allow_feature_toggle;
+ protected $_blog_charset;
+ protected $_convert_charset;
+ protected $_previous_post_id;
+ protected $_found_shortcode = false;
+
+ /**
+ * Constructor for Jetpack_RelatedPosts.
+ *
+ * @param int $blog_id_local
+ * @param int $blog_id_wpcom
+ * @uses get_option, add_action, apply_filters
+ * @return null
+ */
+ public function __construct( $blog_id_local, $blog_id_wpcom ) {
+ $this->_blog_id_local = $blog_id_local;
+ $this->_blog_id_wpcom = $blog_id_wpcom;
+ $this->_blog_charset = get_option( 'blog_charset' );
+ $this->_convert_charset = ( function_exists( 'iconv' ) && ! preg_match( '/^utf\-?8$/i', $this->_blog_charset ) );
+
+ add_action( 'admin_init', array( $this, 'action_admin_init' ) );
+ add_action( 'wp', array( $this, 'action_frontend_init' ) );
+ }
+
+ /**
+ * =================
+ * ACTIONS & FILTERS
+ * =================
+ */
+
+ /**
+ * Add a checkbox field to Settings > Reading for enabling related posts.
+ *
+ * @action admin_init
+ * @uses add_settings_field, __, register_setting, add_action
+ * @return null
+ */
+ public function action_admin_init() {
+
+ // Add the setting field [jetpack_relatedposts] and place it in Settings > Reading
+ add_settings_field( 'jetpack_relatedposts', '<span id="jetpack_relatedposts">' . __( 'Related posts', 'jetpack' ) . '</span>', array( $this, 'print_setting_html' ), 'reading' );
+ register_setting( 'reading', 'jetpack_relatedposts', array( $this, 'parse_options' ) );
+ add_action('admin_head', array( $this, 'print_setting_head' ) );
+
+ if( 'options-reading.php' == $GLOBALS['pagenow'] ) {
+ // Enqueue style for live preview on the reading settings page
+ $this->_enqueue_assets( false, true );
+ }
+ }
+
+ /**
+ * Load related posts assets if it's a elegiable frontend page or execute search and return JSON if it's an endpoint request.
+ *
+ * @global $_GET
+ * @action wp
+ * @uses add_shortcode, get_the_ID
+ * @returns null
+ */
+ public function action_frontend_init() {
+ // Add a shortcode handler that outputs nothing, this gets overridden later if we can display related content
+ add_shortcode( self::SHORTCODE, array( $this, 'get_target_html_unsupported' ) );
+
+ if ( ! $this->_enabled_for_request() )
+ return;
+
+ if ( isset( $_GET['relatedposts'] ) ) {
+ $excludes = array();
+ if ( isset( $_GET['relatedposts_exclude'] ) ) {
+ $excludes = explode( ',', $_GET['relatedposts_exclude'] );
+ }
+
+ $this->_action_frontend_init_ajax( $excludes );
+ } else {
+ if ( isset( $_GET['relatedposts_hit'] ) ) {
+ $this->_log_click( $_GET['relatedposts_origin'], get_the_ID(), $_GET['relatedposts_position'] );
+ $this->_previous_post_id = (int) $_GET['relatedposts_origin'];
+ }
+
+ $this->_action_frontend_init_page();
+ }
+
+ }
+
+ /**
+ * Adds a target to the post content to load related posts into if a shortcode for it did not already exist.
+ *
+ * @filter the_content
+ * @param string $content
+ * @returns string
+ */
+ public function filter_add_target_to_dom( $content ) {
+ if ( !$this->_found_shortcode ) {
+ $content .= "\n" . $this->get_target_html();
+ }
+
+ return $content;
+ }
+
+ /**
+ * Looks for our shortcode on the unfiltered content, this has to execute early.
+ *
+ * @filter the_content
+ * @param string $content
+ * @uses has_shortcode
+ * @returns string
+ */
+ public function test_for_shortcode( $content ) {
+ $this->_found_shortcode = has_shortcode( $content, self::SHORTCODE );
+
+ return $content;
+ }
+
+ /**
+ * Returns the HTML for the related posts section.
+ *
+ * @uses esc_html__, apply_filters
+ * @returns string
+ */
+ public function get_target_html() {
+ $options = $this->get_options();
+
+ if ( $options['show_headline'] ) {
+ $headline = sprintf(
+ '<h3 class="jp-relatedposts-headline"><em>%s</em></h3>',
+ esc_html__( 'Related', 'jetpack' )
+ );
+ } else {
+ $headline = '';
+ }
+
+ $headline = apply_filters( 'jetpack_relatedposts_filter_headline', $headline );
+
+ if ( $this->_previous_post_id ) {
+ $exclude = "data-exclude='{$this->_previous_post_id}'";
+ } else {
+ $exclude = "";
+ }
+
+ return <<<EOT
+<div id='jp-relatedposts' class='jp-relatedposts' $exclude>
+ $headline
+</div>
+EOT;
+ }
+
+ /**
+ * Returns the HTML for the related posts section if it's running in the loop or other instances where we don't support related posts.
+ *
+ * @returns string
+ */
+ public function get_target_html_unsupported() {
+ return "\n\n<!-- Jetpack Related Posts is not supported in this context. -->\n\n";
+ }
+
+ /**
+ * ========================
+ * PUBLIC UTILITY FUNCTIONS
+ * ========================
+ */
+
+ /**
+ * Gets options set for Jetpack_RelatedPosts and merge with defaults.
+ *
+ * @uses Jetpack_Options::get_option, apply_filters
+ * @return array
+ */
+ public function get_options() {
+ if ( null === $this->_options ) {
+ $this->_options = Jetpack_Options::get_option( 'relatedposts' );
+ if ( !is_array( $this->_options ) )
+ $this->_options = array();
+ if ( !isset( $this->_options['enabled'] ) )
+ $this->_options['enabled'] = true;
+ if ( !isset( $this->_options['show_headline'] ) )
+ $this->_options['show_headline'] = true;
+ if ( !isset( $this->_options['show_thumbnails'] ) )
+ $this->_options['show_thumbnails'] = false;
+ if ( empty( $this->_options['size'] ) || (int)$this->_options['size'] < 1 )
+ $this->_options['size'] = 3;
+
+ $this->_options = apply_filters( 'jetpack_relatedposts_filter_options', $this->_options );
+ }
+
+ return $this->_options;
+ }
+
+ /**
+ * Parses input and returnes normalized options array.
+ *
+ * @param array $input
+ * @uses self::get_options
+ * @return array
+ */
+ public function parse_options( $input ) {
+ $current = $this->get_options();
+
+ if ( !is_array( $input ) )
+ $input = array();
+
+ if ( isset( $input['enabled'] ) && '1' == $input['enabled'] ) {
+ $current['enabled'] = true;
+ $current['show_headline'] = ( isset( $input['show_headline'] ) && '1' == $input['show_headline'] );
+ $current['show_thumbnails'] = ( isset( $input['show_thumbnails'] ) && '1' == $input['show_thumbnails'] );
+ } else {
+ $current['enabled'] = false;
+ }
+
+ if ( isset( $input['size'] ) && (int)$input['size'] > 0 )
+ $current['size'] = (int)$input['size'];
+ else
+ $current['size'] = null;
+
+ return $current;
+ }
+
+ /**
+ * HTML for admin settings page.
+ *
+ * @uses self::get_options, checked, esc_html__
+ * @returns null
+ */
+ public function print_setting_html() {
+ $options = $this->get_options();
+
+ $ui_settings_template = <<<EOT
+<ul id="settings-reading-relatedposts-customize">
+ <li>
+ <label><input name="jetpack_relatedposts[show_headline]" type="checkbox" value="1" %s /> %s</label>
+ </li>
+ <li>
+ <label><input name="jetpack_relatedposts[show_thumbnails]" type="checkbox" value="1" %s /> %s</label>
+ </li>
+</ul>
+<div id='settings-reading-relatedposts-preview'>
+ %s
+ <div id="jp-relatedposts" class="jp-relatedposts"></div>
+</div>
+EOT;
+ $ui_settings = sprintf(
+ $ui_settings_template,
+ checked( $options['show_headline'], true, false ),
+ esc_html__( 'Show a "Related" header to more clearly separate the related section from posts', 'jetpack' ),
+ checked( $options['show_thumbnails'], true, false ),
+ esc_html__( 'Use a large and visually striking layout', 'jetpack' ),
+ esc_html__( 'Preview:', 'jetpack' )
+ );
+
+ if ( !$this->_allow_feature_toggle() ) {
+ $template = <<<EOT
+<input type="hidden" name="jetpack_relatedposts[enabled]" value="1" />
+%s
+EOT;
+ printf(
+ $template,
+ $ui_settings
+ );
+ } else {
+ $template = <<<EOT
+<ul id="settings-reading-relatedposts">
+ <li>
+ <label><input type="radio" name="jetpack_relatedposts[enabled]" value="0" class="tog" %s /> %s</label>
+ </li>
+ <li>
+ <label><input type="radio" name="jetpack_relatedposts[enabled]" value="1" class="tog" %s /> %s</label>
+ %s
+ </li>
+</ul>
+EOT;
+ printf(
+ $template,
+ checked( $options['enabled'], false, false ),
+ esc_html__( 'Hide related content after posts', 'jetpack' ),
+ checked( $options['enabled'], true, false ),
+ esc_html__( 'Show related content after posts', 'jetpack' ),
+ $ui_settings
+ );
+ }
+ }
+
+ /**
+ * Head JS/CSS for admin settings page.
+ *
+ * @uses esc_html__
+ * @returns null
+ */
+ public function print_setting_head() {
+
+ // only dislay the Related Posts JavaScript on the Reading Settings Admin Page
+ $current_screen = get_current_screen();
+ if( 'options-reading' != $current_screen->id )
+ return;
+
+ $related_headline = sprintf(
+ '<h3 class="jp-relatedposts-headline"><em>%s</em></h3>',
+ esc_html__( 'Related', 'jetpack' )
+ );
+
+ $href_params = 'class="jp-relatedposts-post-a" href="#jetpack_relatedposts" rel="nofollow" data-origin="0" data-position="0"';
+ $related_with_images = <<<EOT
+<div class="jp-relatedposts-items jp-relatedposts-items-visual">
+ <div class="jp-relatedposts-post jp-relatedposts-post0 jp-relatedposts-post-thumbs" data-post-id="0" data-post-format="image">
+ <a $href_params>
+ <img class="jp-relatedposts-post-img" src="http://jetpackme.files.wordpress.com/2014/08/1-wpios-ipad-3-1-viewsite.png?w=350&amp;h=200&amp;crop=1" width="350" alt="Big iPhone/iPad Update Now Available" scale="0">
+ </a>
+ <h4 class="jp-relatedposts-post-title">
+ <a $href_params>Big iPhone/iPad Update Now Available</a>
+ </h4>
+ <p class="jp-relatedposts-post-excerpt">Big iPhone/iPad Update Now Available</p>
+ <p class="jp-relatedposts-post-context">In "Mobile"</p>
+ </div>
+ <div class="jp-relatedposts-post jp-relatedposts-post1 jp-relatedposts-post-thumbs" data-post-id="0" data-post-format="image">
+ <a $href_params>
+ <img class="jp-relatedposts-post-img" src="http://jetpackme.files.wordpress.com/2014/08/wordpress-com-news-wordpress-for-android-ui-update2.jpg?w=350&amp;h=200&amp;crop=1" width="350" alt="The WordPress for Android App Gets a Big Facelift" scale="0">
+ </a>
+ <h4 class="jp-relatedposts-post-title">
+ <a $href_params>The WordPress for Android App Gets a Big Facelift</a>
+ </h4>
+ <p class="jp-relatedposts-post-excerpt">The WordPress for Android App Gets a Big Facelift</p>
+ <p class="jp-relatedposts-post-context">In "Mobile"</p>
+ </div>
+ <div class="jp-relatedposts-post jp-relatedposts-post2 jp-relatedposts-post-thumbs" data-post-id="0" data-post-format="image">
+ <a $href_params>
+ <img class="jp-relatedposts-post-img" src="http://jetpackme.files.wordpress.com/2014/08/videopresswedding.jpg?w=350&amp;h=200&amp;crop=1" width="350" alt="Upgrade Focus: VideoPress For Weddings" scale="0">
+ </a>
+ <h4 class="jp-relatedposts-post-title">
+ <a $href_params>Upgrade Focus: VideoPress For Weddings</a>
+ </h4>
+ <p class="jp-relatedposts-post-excerpt">Upgrade Focus: VideoPress For Weddings</p>
+ <p class="jp-relatedposts-post-context">In "Upgrade"</p>
+ </div>
+</div>
+EOT;
+ $related_with_images = str_replace( "\n", '', $related_with_images );
+ $related_without_images = <<<EOT
+<div class="jp-relatedposts-items jp-relatedposts-items-minimal">
+ <p class="jp-relatedposts-post jp-relatedposts-post0" data-post-id="0" data-post-format="image">
+ <span class="jp-relatedposts-post-title"><a $href_params>Big iPhone/iPad Update Now Available</a></span>
+ <span class="jp-relatedposts-post-context">In "Mobile"</span>
+ </p>
+ <p class="jp-relatedposts-post jp-relatedposts-post1" data-post-id="0" data-post-format="image">
+ <span class="jp-relatedposts-post-title"><a $href_params>The WordPress for Android App Gets a Big Facelift</a></span>
+ <span class="jp-relatedposts-post-context">In "Mobile"</span>
+ </p>
+ <p class="jp-relatedposts-post jp-relatedposts-post2" data-post-id="0" data-post-format="image">
+ <span class="jp-relatedposts-post-title"><a $href_params>Upgrade Focus: VideoPress For Weddings</a></span>
+ <span class="jp-relatedposts-post-context">In "Upgrade"</span>
+ </p>
+</div>
+EOT;
+ $related_without_images = str_replace( "\n", '', $related_without_images );
+
+ if ( $this->_allow_feature_toggle() ) {
+ $extra_css = '#settings-reading-relatedposts-customize { padding-left:2em; margin-top:.5em; }';
+ } else {
+ $extra_css = '';
+ }
+
+ echo <<<EOT
+<style type="text/css">
+ #settings-reading-relatedposts .disabled { opacity:.5; filter:Alpha(opacity=50); }
+ #settings-reading-relatedposts-preview .jp-relatedposts { background:#fff; padding:.5em; width:75%; }
+ $extra_css
+</style>
+<script type="text/javascript">
+ jQuery( document ).ready( function($) {
+ var update_ui = function() {
+ var is_enabled = true;
+ if ( 'radio' == $( 'input[name="jetpack_relatedposts[enabled]"]' ).attr('type') ) {
+ if ( '0' == $( 'input[name="jetpack_relatedposts[enabled]"]:checked' ).val() ) {
+ is_enabled = false;
+ }
+ }
+ if ( is_enabled ) {
+ $( '#settings-reading-relatedposts-customize' )
+ .removeClass( 'disabled' )
+ .find( 'input' )
+ .attr( 'disabled', false );
+ $( '#settings-reading-relatedposts-preview' )
+ .removeClass( 'disabled' );
+ } else {
+ $( '#settings-reading-relatedposts-customize' )
+ .addClass( 'disabled' )
+ .find( 'input' )
+ .attr( 'disabled', true );
+ $( '#settings-reading-relatedposts-preview' )
+ .addClass( 'disabled' );
+ }
+ };
+
+ var update_preview = function() {
+ var html = '';
+ if ( $( 'input[name="jetpack_relatedposts[show_headline]"]:checked' ).size() ) {
+ html += '$related_headline';
+ }
+ if ( $( 'input[name="jetpack_relatedposts[show_thumbnails]"]:checked' ).size() ) {
+ html += '$related_with_images';
+ } else {
+ html += '$related_without_images';
+ }
+ $( '#settings-reading-relatedposts-preview .jp-relatedposts' )
+ .html( html )
+ .show();
+ };
+
+ // Update on load
+ update_preview();
+ update_ui();
+
+ // Update on change
+ $( '#settings-reading-relatedposts-customize input' )
+ .change( update_preview );
+ $( '#settings-reading-relatedposts' )
+ .find( 'input.tog' )
+ .change( update_ui );
+ });
+</script>
+EOT;
+ }
+
+ /**
+ * Gets an array of related posts that match the given post_id.
+ *
+ * @param int $post_id
+ * @param array $args - params to use when building ElasticSearch filters to narrow down the search domain.
+ * @uses self::get_options, get_post_type, wp_parse_args, apply_filters
+ * @return array
+ */
+ public function get_for_post_id( $post_id, array $args ) {
+ $options = $this->get_options();
+
+ if ( ! empty( $args['size'] ) )
+ $options['size'] = $args['size'];
+
+ if ( ! $options['enabled'] || 0 == (int)$post_id || empty( $options['size'] ) )
+ return array();
+
+ $defaults = array(
+ 'size' => (int)$options['size'],
+ 'post_type' => get_post_type( $post_id ),
+ 'post_formats' => array(),
+ 'has_terms' => array(),
+ 'date_range' => array(),
+ 'exclude_post_ids' => array(),
+ );
+ $args = wp_parse_args( $args, $defaults );
+ $args = apply_filters( 'jetpack_relatedposts_filter_args', $args, $post_id );
+
+ $filters = $this->_get_es_filters_from_args( $post_id, $args );
+ $filters = apply_filters( 'jetpack_relatedposts_filter_filters', $filters, $post_id );
+
+ $results = $this->_get_related_posts( $post_id, $args['size'], $filters );
+ return apply_filters( 'jetpack_relatedposts_returned_results', $results, $post_id );
+ }
+
+ /**
+ * =========================
+ * PRIVATE UTILITY FUNCTIONS
+ * =========================
+ */
+
+ /**
+ * Creates an array of ElasticSearch filters based on the post_id and args.
+ *
+ * @param int $post_id
+ * @param array $args
+ * @uses apply_filters, get_post_types, get_post_format_strings
+ * @return array
+ */
+ protected function _get_es_filters_from_args( $post_id, array $args ) {
+ $filters = array();
+
+ $args['has_terms'] = apply_filters( 'jetpack_relatedposts_filter_has_terms', $args['has_terms'], $post_id );
+ if ( ! empty( $args['has_terms'] ) ) {
+ foreach( (array)$args['has_terms'] as $term ) {
+ if ( mb_strlen( $term->taxonomy ) ) {
+ switch ( $term->taxonomy ) {
+ case 'post_tag':
+ $tax_fld = 'tag.slug';
+ break;
+ case 'category':
+ $tax_fld = 'category.slug';
+ break;
+ default:
+ $tax_fld = 'taxonomy.' . $term->taxonomy . '.slug';
+ break;
+ }
+ $filters[] = array( 'term' => array( $tax_fld => $term->slug ) );
+ }
+ }
+ }
+
+ $args['post_type'] = apply_filters( 'jetpack_relatedposts_filter_post_type', $args['post_type'], $post_id );
+ $valid_post_types = get_post_types();
+ if ( is_array( $args['post_type'] ) ) {
+ $sanitized_post_types = array();
+ foreach ( $args['post_type'] as $pt ) {
+ if ( in_array( $pt, $valid_post_types ) )
+ $sanitized_post_types[] = $pt;
+ }
+ if ( ! empty( $sanitized_post_types ) )
+ $filters[] = array( 'terms' => array( 'post_type' => $sanitized_post_types ) );
+ } else if ( in_array( $args['post_type'], $valid_post_types ) && 'all' != $args['post_type'] ) {
+ $filters[] = array( 'term' => array( 'post_type' => $args['post_type'] ) );
+ }
+
+ $args['post_formats'] = apply_filters( 'jetpack_relatedposts_filter_post_formats', $args['post_formats'], $post_id );
+ $valid_post_formats = get_post_format_strings();
+ $sanitized_post_formats = array();
+ foreach ( $args['post_formats'] as $pf ) {
+ if ( array_key_exists( $pf, $valid_post_formats ) ) {
+ $sanitized_post_formats[] = $pf;
+ }
+ }
+ if ( ! empty( $sanitized_post_formats ) ) {
+ $filters[] = array( 'terms' => array( 'post_format' => $sanitized_post_formats ) );
+ }
+
+ $args['date_range'] = apply_filters( 'jetpack_relatedposts_filter_date_range', $args['date_range'], $post_id );
+ if ( is_array( $args['date_range'] ) && ! empty( $args['date_range'] ) ) {
+ $args['date_range'] = array_map( 'intval', $args['date_range'] );
+ if ( !empty( $args['date_range']['from'] ) && !empty( $args['date_range']['to'] ) ) {
+ $filters[] = array(
+ 'range' => array(
+ 'date_gmt' => $this->_get_coalesced_range( $args['date_range'] ),
+ )
+ );
+ }
+ }
+
+ $args['exclude_post_ids'] = apply_filters( 'jetpack_relatedposts_filter_exclude_post_ids', $args['exclude_post_ids'], $post_id );
+ if ( !empty( $args['exclude_post_ids'] ) && is_array( $args['exclude_post_ids'] ) ) {
+ foreach ( $args['exclude_post_ids'] as $exclude_post_id) {
+ $exclude_post_id = (int)$exclude_post_id;
+
+ if ( $exclude_post_id > 0 )
+ $filters[] = array( 'not' => array( 'term' => array( 'post_id' => $exclude_post_id ) ) );
+ }
+ }
+
+ return $filters;
+ }
+
+ /**
+ * Takes a range and coalesces it into a month interval bracketed by a time as determined by the blog_id to enhance caching.
+ *
+ * @param array $date_range
+ * @return array
+ */
+ protected function _get_coalesced_range( array $date_range ) {
+ $now = time();
+ $coalesce_time = $this->_blog_id_wpcom % 86400;
+ $current_time = $now - strtotime( 'today', $now );
+
+ if ( $current_time < $coalesce_time && '01' == date( 'd', $now ) ) {
+ // Move back 1 period
+ return array(
+ 'from' => date( 'Y-m-01', strtotime( '-1 month', $date_range['from'] ) ) . ' ' . date( 'H:i:s', $coalesce_time ),
+ 'to' => date( 'Y-m-01', $date_range['to'] ) . ' ' . date( 'H:i:s', $coalesce_time ),
+ );
+ } else {
+ // Use current period
+ return array(
+ 'from' => date( 'Y-m-01', $date_range['from'] ) . ' ' . date( 'H:i:s', $coalesce_time ),
+ 'to' => date( 'Y-m-01', strtotime( '+1 month', $date_range['to'] ) ) . ' ' . date( 'H:i:s', $coalesce_time ),
+ );
+ }
+ }
+
+ /**
+ * Generate and output ajax response for related posts API call.
+ * NOTE: Calls exit() to end all further processing after payload has been outputed.
+ *
+ * @param array $excludes array of post_ids to exclude
+ * @uses send_nosniff_header, self::get_for_post_id, get_the_ID
+ * @return null
+ */
+ protected function _action_frontend_init_ajax( array $excludes ) {
+ define( 'DOING_AJAX', true );
+
+ header( 'Content-type: application/json; charset=utf-8' ); // JSON can only be UTF-8
+ send_nosniff_header();
+
+ $related_posts = $this->get_for_post_id(
+ get_the_ID(),
+ array(
+ 'exclude_post_ids' => $excludes,
+ )
+ );
+
+ $options = $this->get_options();
+
+ $response = array(
+ 'version' => self::VERSION,
+ 'show_thumbnails' => (bool) $options['show_thumbnails'],
+ 'items' => array(),
+ );
+
+ if ( count( $related_posts ) == $options['size'] )
+ $response['items'] = $related_posts;
+
+ echo json_encode( $response );
+
+ exit();
+ }
+
+ /**
+ * Returns a UTF-8 encoded array of post information for the given post_id
+ *
+ * @param int $post_id
+ * @param int $position
+ * @param int $origin The post id that this is related to
+ * @uses get_post, get_permalink, remove_query_arg, get_post_format, apply_filters
+ * @return array
+ */
+ protected function _get_related_post_data_for_post( $post_id, $position, $origin ) {
+ $post = get_post( $post_id );
+
+ return array(
+ 'id' => $post->ID,
+ 'url' => get_permalink( $post->ID ),
+ 'url_meta' => array( 'origin' => $origin, 'position' => $position ),
+ 'title' => $this->_to_utf8( $this->_get_title( $post->post_title, $post->post_content ) ),
+ 'date' => get_the_date( '', $post->ID ),
+ 'format' => get_post_format( $post->ID ),
+ 'excerpt' => $this->_to_utf8( $this->_get_excerpt( $post->post_excerpt, $post->post_content ) ),
+ 'context' => apply_filters(
+ 'jetpack_relatedposts_filter_post_context',
+ $this->_to_utf8( $this->_generate_related_post_context( $post->ID ) ),
+ $post->ID
+ ),
+ 'img' => $this->_generate_related_post_image_params( $post->ID ),
+ );
+ }
+
+ /**
+ * Returns either the title or a small excerpt to use as title for post.
+ *
+ * @param string $post_title
+ * @param string $post_content
+ * @uses strip_shortcodes, wp_trim_words, __
+ * @return string
+ */
+ protected function _get_title( $post_title, $post_content ) {
+ if ( ! empty( $post_title ) ) {
+ return wp_strip_all_tags( $post_title );
+ }
+
+ $post_title = wp_trim_words( wp_strip_all_tags( strip_shortcodes( $post_content ) ), 5, '…' );
+ if ( ! empty( $post_title ) ) {
+ return $post_title;
+ }
+
+ return __( 'Untitled Post', 'jetpack' );
+ }
+
+ /**
+ * Returns a plain text post excerpt for title attribute of links.
+ *
+ * @param string $post_excerpt
+ * @param string $post_content
+ * @uses strip_shortcodes, wp_strip_all_tags, wp_trim_words
+ * @return string
+ */
+ protected function _get_excerpt( $post_excerpt, $post_content ) {
+ if ( empty( $post_excerpt ) )
+ $excerpt = $post_content;
+ else
+ $excerpt = $post_excerpt;
+
+ return wp_trim_words( wp_strip_all_tags( strip_shortcodes( $excerpt ) ), 50, '…' );
+ }
+
+ /**
+ * Generates the thumbnail image to be used for the post. Uses the
+ * image as returned by Jetpack_PostImages::get_image()
+ *
+ * @param int $post_id
+ * @uses self::get_options, apply_filters, Jetpack_PostImages::get_image, Jetpack_PostImages::fit_image_url
+ * @return string
+ */
+ protected function _generate_related_post_image_params( $post_id ) {
+ $options = $this->get_options();
+ $image_params = array(
+ 'src' => '',
+ 'width' => 0,
+ 'height' => 0,
+ );
+
+ if ( ! $options['show_thumbnails'] ) {
+ return $image_params;
+ }
+
+ $thumbnail_size = apply_filters(
+ 'jetpack_relatedposts_filter_thumbnail_size',
+ array( 'width' => 350, 'height' => 200 )
+ );
+ if ( !is_array( $thumbnail_size ) ) {
+ $thumbnail_size = array(
+ 'width' => (int)$thumbnail_size,
+ 'height' => (int)$thumbnail_size
+ );
+ }
+
+ // Try to get post image
+ if ( class_exists( 'Jetpack_PostImages' ) ) {
+ $img_url = '';
+ $post_image = Jetpack_PostImages::get_image(
+ $post_id,
+ $thumbnail_size
+ );
+
+ if ( is_array($post_image) ) {
+ $img_url = $post_image['src'];
+ } elseif ( class_exists( 'Jetpack_Media_Summary' ) ) {
+ $media = Jetpack_Media_Summary::get( $post_id );
+
+ if ( is_array($media) && !empty( $media['image'] ) ) {
+ $img_url = $media['image'];
+ }
+ }
+
+ if ( !empty( $img_url ) ) {
+ $image_params['width'] = $thumbnail_size['width'];
+ $image_params['height'] = $thumbnail_size['height'];
+ $image_params['src'] = Jetpack_PostImages::fit_image_url(
+ $img_url,
+ $thumbnail_size['width'],
+ $thumbnail_size['height']
+ );
+ }
+ }
+
+ return $image_params;
+ }
+
+ /**
+ * Returns the string UTF-8 encoded
+ *
+ * @param string $text
+ * @return string
+ */
+ protected function _to_utf8( $text ) {
+ if ( $this->_convert_charset ) {
+ return iconv( $this->_blog_charset, 'UTF-8', $text );
+ } else {
+ return $text;
+ }
+ }
+
+ /**
+ * =============================================
+ * PROTECTED UTILITY FUNCTIONS EXTENDED BY WPCOM
+ * =============================================
+ */
+
+ /**
+ * Workhorse method to return array of related posts matched by ElasticSearch.
+ *
+ * @param int $post_id
+ * @param int $size
+ * @param array $filters
+ * @uses wp_remote_post, is_wp_error, get_option, wp_remote_retrieve_body, get_post, add_query_arg, remove_query_arg, get_permalink, get_post_format, apply_filters
+ * @return array
+ */
+ protected function _get_related_posts( $post_id, $size, array $filters ) {
+ $hits = $this->_filter_non_public_posts(
+ $this->_get_related_post_ids(
+ $post_id,
+ $size,
+ $filters
+ )
+ );
+
+ $hits = apply_filters( 'jetpack_relatedposts_filter_hits', $hits, $post_id );
+
+ $related_posts = array();
+ foreach ( $hits as $i => $hit ) {
+ $related_posts[] = $this->_get_related_post_data_for_post( $hit['id'], $i, $post_id );
+ }
+ return $related_posts;
+ }
+
+ /**
+ * Get array of related posts matched by ElasticSearch.
+ *
+ * @param int $post_id
+ * @param int $size
+ * @param array $filters
+ * @uses wp_remote_post, is_wp_error, wp_remote_retrieve_body, get_post_meta, update_post_meta
+ * @return array
+ */
+ protected function _get_related_post_ids( $post_id, $size, array $filters ) {
+ $now_ts = time();
+ $cache_meta_key = '_jetpack_related_posts_cache';
+
+ $body = array(
+ 'size' => (int) $size,
+ );
+
+ if ( !empty( $filters ) )
+ $body['filter'] = array( 'and' => $filters );
+
+ // Load all cached values
+ $cache = get_post_meta( $post_id, $cache_meta_key, true );
+ if ( empty( $cache ) )
+ $cache = array();
+
+ // Build cache key
+ $cache_key = md5( serialize( $body ) );
+
+ // Cache is valid! Return cached value.
+ if ( isset( $cache[ $cache_key ] ) && is_array( $cache[ $cache_key ] ) && $cache[ $cache_key ][ 'expires' ] > $now_ts ) {
+ return $cache[ $cache_key ][ 'payload' ];
+ }
+
+ $response = wp_remote_post(
+ "https://public-api.wordpress.com/rest/v1/sites/{$this->_blog_id_wpcom}/posts/$post_id/related/",
+ array(
+ 'timeout' => 10,
+ 'user-agent' => 'jetpack_related_posts',
+ 'sslverify' => true,
+ 'body' => $body,
+ )
+ );
+
+ // Oh no... return nothing don't cache errors.
+ if ( is_wp_error( $response ) ) {
+ if ( isset( $cache[ $cache_key ] ) && is_array( $cache[ $cache_key ] ) )
+ return $cache[ $cache_key ][ 'payload' ]; // return stale
+ else
+ return array();
+ }
+
+ $results = json_decode( wp_remote_retrieve_body( $response ), true );
+ $related_posts = array();
+ if ( is_array( $results ) && !empty( $results['hits'] ) ) {
+ foreach( $results['hits'] as $hit ) {
+ $related_posts[] = array(
+ 'id' => $hit['fields']['post_id'],
+ );
+ }
+ }
+
+ // Copy all valid cache values
+ $new_cache = array();
+ foreach ( $cache as $k => $v ) {
+ if ( is_array( $v ) && $v[ 'expires' ] > $now_ts ) {
+ $new_cache[ $k ] = $v;
+ }
+ }
+
+ // Set new cache value if valid
+ if ( !empty( $related_posts ) ) {
+ $new_cache[ $cache_key ] = array(
+ 'expires' => 12 * HOUR_IN_SECONDS + $now_ts,
+ 'payload' => $related_posts,
+ );
+ }
+
+ // Update cache
+ update_post_meta( $post_id, $cache_meta_key, $new_cache );
+
+ return $related_posts;
+ }
+
+ /**
+ * Filter out any hits that are not public anymore.
+ *
+ * @param array $related_posts
+ * @uses get_post_stati, get_post_status
+ * @return array
+ */
+ protected function _filter_non_public_posts( array $related_posts ) {
+ $public_stati = get_post_stati( array( 'public' => true ) );
+
+ $filtered = array();
+ foreach ( $related_posts as $hit ) {
+ if ( in_array( get_post_status( $hit['id'] ), $public_stati ) ) {
+ $filtered[] = $hit;
+ }
+ }
+ return $filtered;
+ }
+
+ /**
+ * Generates a context for the related content (second line in related post output).
+ * Order of importance:
+ * - First category (Not 'Uncategorized')
+ * - First post tag
+ * - Number of comments
+ *
+ * @param int $post_id
+ * @uses get_the_category, get_the_terms, get_comments_number, number_format_i18n, __, _n
+ * @return string
+ */
+ protected function _generate_related_post_context( $post_id ) {
+ $categories = get_the_category( $post_id );
+ if ( is_array( $categories ) ) {
+ foreach ( $categories as $category ) {
+ if ( 'uncategorized' != $category->slug && '' != trim( $category->name ) ) {
+ $post_cat_context = sprintf(
+ _x( 'In "%s"', 'in {category/tag name}', 'jetpack' ),
+ $category->name
+ );
+ return apply_filters( 'jetpack_relatedposts_post_category_context', $post_cat_context, $category );
+ }
+ }
+ }
+
+ $tags = get_the_terms( $post_id, 'post_tag' );
+ if ( is_array( $tags ) ) {
+ foreach ( $tags as $tag ) {
+ if ( '' != trim( $tag->name ) ) {
+ $post_tag_context = sprintf(
+ _x( 'In "%s"', 'in {category/tag name}', 'jetpack' ),
+ $tag->name
+ );
+ return apply_filters( 'jetpack_relatedposts_post_tag_context', $post_tag_context, $tag );
+ }
+ }
+ }
+
+ $comment_count = get_comments_number( $post_id );
+ if ( $comment_count > 0 ) {
+ return sprintf(
+ _n( 'With 1 comment', 'With %s comments', $comment_count, 'jetpack' ),
+ number_format_i18n( $comment_count )
+ );
+ }
+
+ return __( 'Similar post', 'jetpack' );
+ }
+
+ /**
+ * Logs clicks for clickthrough analysis and related result tuning.
+ *
+ * @return null
+ */
+ protected function _log_click( $post_id, $to_post_id, $link_position ) {
+
+ }
+
+ /**
+ * Determines if the current post is able to use related posts.
+ *
+ * @uses self::get_options, is_admin, is_single, apply_filters
+ * @return bool
+ */
+ protected function _enabled_for_request() {
+ // Default to enabled
+ $enabled = true;
+
+ // Must have feature enabled
+ $options = $this->get_options();
+ if ( ! $options['enabled'] ) {
+ $enabled = false;
+ }
+
+ // Only run for frontend pages
+ if ( is_admin() ) {
+ $enabled = false;
+ }
+
+ // Only run for standalone posts
+ if ( ! is_single() ) {
+ $enabled = false;
+ }
+
+ // Allow filters to override
+ return apply_filters( 'jetpack_relatedposts_filter_enabled_for_request', $enabled );
+ }
+
+ /**
+ * Adds filters and enqueues assets.
+ *
+ * @uses self::_enqueue_assets, self::_setup_shortcode, add_filter
+ * @return null
+ */
+ protected function _action_frontend_init_page() {
+ $this->_enqueue_assets( true, true );
+ $this->_setup_shortcode();
+
+ add_filter( 'the_content', array( $this, 'filter_add_target_to_dom' ), 40 );
+ }
+
+ /**
+ * Enqueues assets needed to do async loading of related posts.
+ *
+ * @uses wp_enqueue_script, wp_enqueue_style, plugins_url
+ * @return null
+ */
+ protected function _enqueue_assets( $script, $style ) {
+ if ( $script )
+ wp_enqueue_script( 'jetpack_related-posts', plugins_url( 'related-posts.js', __FILE__ ), array( 'jquery' ), self::VERSION );
+ if ( $style ){
+ if( is_rtl() ) {
+ wp_enqueue_style( 'jetpack_related-posts', plugins_url( 'rtl/related-posts-rtl.css', __FILE__ ), array(), self::VERSION );
+ } else {
+ wp_enqueue_style( 'jetpack_related-posts', plugins_url( 'related-posts.css', __FILE__ ), array(), self::VERSION );
+ }
+ }
+ }
+
+ /**
+ * Sets up the shortcode processing.
+ *
+ * @uses add_filter, add_shortcode
+ * @return null
+ */
+ protected function _setup_shortcode() {
+ add_filter( 'the_content', array( $this, 'test_for_shortcode' ), 0 );
+
+ add_shortcode( self::SHORTCODE, array( $this, 'get_target_html' ) );
+ }
+
+ protected function _allow_feature_toggle() {
+ if ( null === $this->_allow_feature_toggle ) {
+ $this->_allow_feature_toggle = apply_filters( 'jetpack_relatedposts_filter_allow_feature_toggle', false );
+ }
+ return $this->_allow_feature_toggle;
+ }
+}
+
+class Jetpack_RelatedPosts_Raw extends Jetpack_RelatedPosts {
+ protected $_query_name;
+
+ /**
+ * Allows callers of this class to tag each query with a unique name for tracking purposes.
+ *
+ * @param string $name
+ * @return Jetpack_RelatedPosts_Raw
+ */
+ public function set_query_name( $name ) {
+ $this->_query_name = (string) $name;
+ return $this;
+ }
+
+ /**
+ * The raw related posts class can be used by other plugins or themes
+ * to get related content. This class wraps the existing RelatedPosts
+ * logic thus we never want to add anything to the DOM or do anything
+ * for event hooks. We will also not present any settings for this
+ * class and keep it enabled as calls to this class is done
+ * programmatically.
+ */
+ public function action_admin_init() {}
+ public function action_frontend_init() {}
+ public function get_options() {
+ return array(
+ 'enabled' => true,
+ );
+ }
+
+ /**
+ * Workhorse method to return array of related posts ids matched by ElasticSearch.
+ *
+ * @param int $post_id
+ * @param int $size
+ * @param array $filters
+ * @uses wp_remote_post, is_wp_error, wp_remote_retrieve_body
+ * @return array
+ */
+ protected function _get_related_posts( $post_id, $size, array $filters ) {
+ $hits = $this->_filter_non_public_posts(
+ $this->_get_related_post_ids(
+ $post_id,
+ $size,
+ $filters
+ )
+ );
+
+ return $hits;
+ }
+}
diff --git a/plugins/jetpack/modules/related-posts/related-posts.css b/plugins/jetpack/modules/related-posts/related-posts.css
new file mode 100644
index 00000000..e0ba3ac2
--- /dev/null
+++ b/plugins/jetpack/modules/related-posts/related-posts.css
@@ -0,0 +1,199 @@
+/**
+ * Styles for Jetpack related posts
+ */
+
+/* Container */
+
+div#jp-relatedposts {
+ display: none;
+ padding-top: 1em;
+ margin: 1em 0;
+ position: relative;
+}
+
+div.jp-relatedposts:after {
+ content: '';
+ display: block;
+ clear: both;
+}
+
+/* Headline above related posts section, labeled "Related" */
+
+div#jp-relatedposts h3.jp-relatedposts-headline {
+ margin: 0 0 1em 0;
+ display: inline-block;
+ float: left;
+ font-size: 9pt;
+ font-weight: bold;
+ font-family: inherit;
+}
+
+div#jp-relatedposts h3.jp-relatedposts-headline em:before {
+ content: "";
+ display: block;
+ width: 100%;
+ min-width: 30px;
+ border-top: 1px solid #ddd;
+ border-top: 1px solid rgba(0,0,0,.2);
+ margin-bottom: 1em;
+}
+
+div#jp-relatedposts h3.jp-relatedposts-headline em {
+ font-style: normal;
+ font-weight: bold;
+}
+
+/* Related posts items (wrapping items) */
+
+div#jp-relatedposts div.jp-relatedposts-items {
+ clear: left;
+}
+
+div#jp-relatedposts div.jp-relatedposts-items-visual {
+ margin-right: -20px;
+}
+
+/* Related posts item */
+
+div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post {
+ float: left;
+ width: 33%;
+ margin: 0 0 1em; /* Needs to be same as the main outer wrapper for Related Posts */
+ box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+}
+
+div#jp-relatedposts div.jp-relatedposts-items-visual .jp-relatedposts-post {
+ padding-right: 20px;
+ /*cursor: pointer;*/
+ filter: alpha(opacity=80);
+ -moz-opacity: .8;
+ opacity: .8;
+}
+
+div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post:nth-child(3n+4),
+div#jp-relatedposts div.jp-relatedposts-items-visual .jp-relatedposts-post:nth-child(3n+4) {
+ clear: both;
+}
+
+div#jp-relatedposts div.jp-relatedposts-items div.jp-relatedposts-post:hover .jp-relatedposts-post-title a {
+ text-decoration: underline;
+}
+
+div#jp-relatedposts div.jp-relatedposts-items div.jp-relatedposts-post:hover {
+ filter: alpha(opacity=100);
+ -moz-opacity: 1;
+ opacity: 1;
+}
+
+/* Related posts item content */
+
+div#jp-relatedposts div.jp-relatedposts-items-visual h4.jp-relatedposts-post-title,
+div#jp-relatedposts div.jp-relatedposts-items p {
+ font-size: 14px;
+ line-height: 20px;
+ margin: 0;
+}
+div#jp-relatedposts div.jp-relatedposts-items-visual div.jp-relatedposts-post-nothumbs {
+ position:relative;
+}
+div#jp-relatedposts div.jp-relatedposts-items-visual div.jp-relatedposts-post-nothumbs a.jp-relatedposts-post-aoverlay {
+ position:absolute;
+ top:0;
+ bottom:0;
+ left:0;
+ right:0;
+ display:block;
+}
+
+div#jp-relatedposts div.jp-relatedposts-items p {
+ margin-bottom: 0;
+}
+
+div#jp-relatedposts div.jp-relatedposts-items-visual h4.jp-relatedposts-post-title {
+ text-transform: none;
+ margin: 0;
+ font-family: inherit;
+ display: block;
+ max-width: 100%;
+}
+
+div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post .jp-relatedposts-post-title a {
+ font-size: inherit;
+ font-weight: normal;
+ text-decoration: none;
+ filter: alpha(opacity=100);
+ -moz-opacity: 1;
+ opacity: 1;
+}
+
+div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post .jp-relatedposts-post-title a:hover {
+ text-decoration: underline;
+}
+
+div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post img.jp-relatedposts-post-img,
+div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post span {
+ display: block;
+ max-width: 90%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+div#jp-relatedposts div.jp-relatedposts-items-visual .jp-relatedposts-post img.jp-relatedposts-post-img,
+div#jp-relatedposts div.jp-relatedposts-items-visual .jp-relatedposts-post span {
+ max-width: 100%;
+}
+
+div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post .jp-relatedposts-post-date,
+div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post .jp-relatedposts-post-context {
+ opacity: .6;
+}
+
+/* Hide the date by default, but leave the element there if a theme wants to use css to make it visible. */
+.jp-relatedposts-items .jp-relatedposts-post .jp-relatedposts-post-date {
+ display: none;
+}
+
+/* Behavior when there are thumbnails in visual mode */
+div#jp-relatedposts div.jp-relatedposts-items-visual div.jp-relatedposts-post-thumbs p.jp-relatedposts-post-excerpt {
+ display: none;
+}
+
+/* Behavior when there are no thumbnails in visual mode */
+div#jp-relatedposts div.jp-relatedposts-items-visual div.jp-relatedposts-post-nothumbs p.jp-relatedposts-post-excerpt {
+ overflow: hidden;
+}
+div#jp-relatedposts div.jp-relatedposts-items-visual div.jp-relatedposts-post-nothumbs span {
+ margin-bottom: 1em;
+}
+
+/**
+ * Responsive
+ */
+
+@media only screen and (max-width: 640px) {
+
+ div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post {
+ width: 50%;
+ }
+
+ div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post:nth-child(3n) {
+ clear: left;
+ }
+
+ div#jp-relatedposts div.jp-relatedposts-items-visual {
+ margin-right: 20px;
+ }
+
+}
+
+@media only screen and (max-width: 320px) {
+
+ div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post {
+ width: 100%;
+ clear: both;
+ margin: 0 0 1em;
+ }
+
+}
diff --git a/plugins/jetpack/modules/related-posts/related-posts.js b/plugins/jetpack/modules/related-posts/related-posts.js
new file mode 100644
index 00000000..45a8db8c
--- /dev/null
+++ b/plugins/jetpack/modules/related-posts/related-posts.js
@@ -0,0 +1,192 @@
+/* jshint onevar: false */
+
+/**
+ * Load related posts
+ */
+(function($) {
+ var jprp = {
+ response: null,
+
+ /**
+ * Utility get related posts JSON endpoint from URLs
+ *
+ * @param string URL (optional)
+ * @return string endpoint URL
+ */
+ getEndpointURL: function( URL ) {
+ var locationObject = document.location;
+
+ if ( 'string' === typeof( URL ) && URL.match( /^https?:\/\// ) ) {
+ locationObject = document.createElement( 'a' );
+ locationObject.href = URL;
+ }
+
+ var args = 'relatedposts=1';
+ if ( ! $( '#jp-relatedposts' ).data( 'exclude' ) ) {
+ args += '&relatedposts_exclude=' + $( '#jp-relatedposts' ).data( 'exclude' );
+ }
+
+ var pathname = locationObject.pathname;
+ if ( '/' !== pathname[0] ) {
+ pathname = '/' + pathname;
+ }
+
+ if ( '' === locationObject.search ) {
+ return pathname + '?' + args;
+ } else {
+ return pathname + locationObject.search + '&' + args;
+ }
+ },
+
+ getAnchor: function( post, classNames ) {
+ var anchor_title = post.title;
+ if ( '' !== ( '' + post.excerpt ) ) {
+ anchor_title += '\n\n' + post.excerpt;
+ }
+
+ var anchor = $( '<a>' );
+
+ anchor.attr({
+ 'class': classNames,
+ 'href': post.url,
+ 'title': anchor_title,
+ 'rel': 'nofollow',
+ 'data-origin': post.url_meta.origin,
+ 'data-position': post.url_meta.position
+ });
+
+ var anchor_html = $( '<div>' ).append( anchor ).html();
+ return [
+ anchor_html.substring( 0, anchor_html.length-4 ),
+ '</a>'
+ ];
+ },
+
+ generateMinimalHtml: function( posts ) {
+ var self = this;
+ var html = '';
+
+ $.each( posts, function( index, post ) {
+ var anchor = self.getAnchor( post, 'jp-relatedposts-post-a' );
+ var classes = 'jp-relatedposts-post jp-relatedposts-post' + index;
+
+ html += '<p class="' + classes + '" data-post-id="' + post.id + '" data-post-format="' + post.format + '">';
+ html += '<span class="jp-relatedposts-post-title">' + anchor[0] + post.title + anchor[1] + '</span>';
+ html += '<span class="jp-relatedposts-post-date">' + post.date + '</span>';
+ html += '<span class="jp-relatedposts-post-context">' + post.context + '</span>';
+ html += '</p>';
+ } );
+ return '<div class="jp-relatedposts-items jp-relatedposts-items-minimal">' + html + '</div>';
+ },
+
+ generateVisualHtml: function( posts ) {
+ var self = this;
+ var html = '';
+
+ $.each( posts, function( index, post ) {
+ var anchor = self.getAnchor( post, 'jp-relatedposts-post-a' );
+ var classes = 'jp-relatedposts-post jp-relatedposts-post' + index;
+ if ( ! post.img.src ) {
+ classes += ' jp-relatedposts-post-nothumbs';
+ } else {
+ classes += ' jp-relatedposts-post-thumbs';
+ }
+
+ html += '<div class="' + classes + '" data-post-id="' + post.id + '" data-post-format="' + post.format + '">';
+ if ( post.img.src ) {
+ html += anchor[0] + '<img class="jp-relatedposts-post-img" src="' + post.img.src + '" width="' + post.img.width + '" alt="' + post.title + '" />' + anchor[1];
+ } else {
+ var anchor_overlay = self.getAnchor( post, 'jp-relatedposts-post-a jp-relatedposts-post-aoverlay' );
+ html += anchor_overlay[0] + anchor_overlay[1];
+ }
+ html += '<h4 class="jp-relatedposts-post-title">' + anchor[0] + post.title + anchor[1] + '</h4>';
+ html += '<p class="jp-relatedposts-post-excerpt">' + post.excerpt + '</p>';
+ html += '<p class="jp-relatedposts-post-date">' + post.date + '</p>';
+ html += '<p class="jp-relatedposts-post-context">' + post.context + '</p>';
+ html += '</div>';
+ } );
+ return '<div class="jp-relatedposts-items jp-relatedposts-items-visual">' + html + '</div>';
+ },
+
+ /**
+ * We want to set a max height on the excerpt however we want to set
+ * this according to the natual pacing of the page as we never want to
+ * cut off a line of text in the middle so we need to do some detective
+ * work.
+ */
+ setVisualExcerptHeights: function() {
+ var elements = $( '#jp-relatedposts .jp-relatedposts-post-nothumbs .jp-relatedposts-post-excerpt' );
+
+ if ( 0 >= elements.length ) {
+ return;
+ }
+
+ var fontSize = parseInt( elements.first().css( 'font-size' ), 10 ),
+ lineHeight = parseInt( elements.first().css( 'line-height' ), 10 );
+
+ // Show 5 lines of text
+ elements.css(
+ 'max-height',
+ ( 5 * lineHeight / fontSize ) + 'em'
+ );
+ },
+
+ getTrackedUrl: function( anchor ) {
+ var args = 'relatedposts_hit=1';
+ args += '&relatedposts_origin=' + $( anchor ).data( 'origin' );
+ args += '&relatedposts_position=' + $( anchor ).data( 'position' );
+
+ var pathname = anchor.pathname;
+ if ( '/' !== pathname[0] ) {
+ pathname = '/' + pathname;
+ }
+
+ if ( '' === anchor.search ) {
+ return pathname + '?' + args;
+ } else {
+ return pathname + anchor.search + '&' + args;
+ }
+ },
+
+ cleanupTrackedUrl: function() {
+ if ( 'function' !== typeof history.replaceState ) {
+ return;
+ }
+
+ var cleaned_search = document.location.search.replace( /\brelatedposts_[a-z]+=[0-9]*&?\b/gi, '' );
+ if ( '?' === cleaned_search ) {
+ cleaned_search = '';
+ }
+ if ( document.location.search !== cleaned_search ) {
+ history.replaceState( {}, document.title, document.location.pathname + cleaned_search );
+ }
+ }
+ };
+
+ $( function() {
+ jprp.cleanupTrackedUrl();
+
+ $.getJSON( jprp.getEndpointURL(), function( response ) {
+ if ( 0 === response.items.length || 0 === $( '#jp-relatedposts' ).length ) {
+ return;
+ }
+
+ jprp.response = response;
+
+ var html = '';
+ if ( !response.show_thumbnails ) {
+ html = jprp.generateMinimalHtml( response.items );
+ } else {
+ html = jprp.generateVisualHtml( response.items );
+ }
+
+ $( '#jp-relatedposts' ).append( html );
+ jprp.setVisualExcerptHeights();
+ $( '#jp-relatedposts' ).show();
+
+ $( '#jp-relatedposts a.jp-relatedposts-post-a' ).click(function() {
+ this.href = jprp.getTrackedUrl( this );
+ });
+ } );
+ } );
+})(jQuery);
diff --git a/plugins/jetpack/modules/related-posts/rtl/related-posts-rtl.css b/plugins/jetpack/modules/related-posts/rtl/related-posts-rtl.css
new file mode 100644
index 00000000..f50c41f3
--- /dev/null
+++ b/plugins/jetpack/modules/related-posts/rtl/related-posts-rtl.css
@@ -0,0 +1,190 @@
+/* This file was automatically generated on Dec 01 2014 22:02:36 */
+
+/**
+ * Styles for Jetpack related posts
+ */
+
+/* Container */
+
+div#jp-relatedposts {
+ display: none;
+ padding-top: 1em;
+ margin: 1em 0;
+ position: relative;
+}
+
+div.jp-relatedposts:after {
+ content: '';
+ display: block;
+ clear: both;
+}
+
+/* Headline above related posts section, labeled "Related" */
+
+div#jp-relatedposts h3.jp-relatedposts-headline {
+ margin: 0 0 1em 0;
+ display: inline-block;
+ float: right;
+ font-size: 9pt;
+ font-weight: bold;
+ font-family: inherit;
+}
+
+div#jp-relatedposts h3.jp-relatedposts-headline em:before {
+ content: "";
+ display: block;
+ width: 100%;
+ min-width: 30px;
+ border-top: 1px solid #ddd;
+ border-top: 1px solid rgba(0,0,0,.2);
+ margin-bottom: 1em;
+}
+
+div#jp-relatedposts h3.jp-relatedposts-headline em {
+ font-style: normal;
+ font-weight: bold;
+}
+
+/* Related posts items (wrapping items) */
+
+div#jp-relatedposts div.jp-relatedposts-items {
+ clear: right;
+}
+
+div#jp-relatedposts div.jp-relatedposts-items-visual {
+ margin-left: -20px;
+}
+
+/* Related posts item */
+
+div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post {
+ float: right;
+ width: 33%;
+ margin: 0 0 1em; /* Needs to be same as the main outer wrapper for Related Posts */
+ box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+}
+
+div#jp-relatedposts div.jp-relatedposts-items-visual .jp-relatedposts-post {
+ padding-left: 20px;
+ /*cursor: pointer;*/
+ filter: alpha(opacity=80);
+ -moz-opacity: .8;
+ opacity: .8;
+}
+
+div#jp-relatedposts div.jp-relatedposts-items div.jp-relatedposts-post:hover .jp-relatedposts-post-title a {
+ text-decoration: underline;
+}
+
+div#jp-relatedposts div.jp-relatedposts-items div.jp-relatedposts-post:hover {
+ filter: alpha(opacity=100);
+ -moz-opacity: 1;
+ opacity: 1;
+}
+
+/* Related posts item content */
+
+div#jp-relatedposts div.jp-relatedposts-items-visual h4.jp-relatedposts-post-title,
+div#jp-relatedposts div.jp-relatedposts-items p {
+ font-size: 14px;
+ line-height: 20px;
+ margin: 0;
+}
+div#jp-relatedposts div.jp-relatedposts-items-visual div.jp-relatedposts-post-nothumbs {
+ position:relative;
+}
+div#jp-relatedposts div.jp-relatedposts-items-visual div.jp-relatedposts-post-nothumbs a.jp-relatedposts-post-aoverlay {
+ position:absolute;
+ top:0;
+ bottom:0;
+ right:0;
+ left:0;
+ display:block;
+}
+
+div#jp-relatedposts div.jp-relatedposts-items p {
+ margin-bottom: 0;
+}
+
+div#jp-relatedposts div.jp-relatedposts-items-visual h4.jp-relatedposts-post-title {
+ text-transform: none;
+ margin: 0;
+ font-family: inherit;
+ display: block;
+ max-width: 100%;
+}
+
+div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post .jp-relatedposts-post-title a {
+ font-size: inherit;
+ font-weight: normal;
+ text-decoration: none;
+ filter: alpha(opacity=100);
+ -moz-opacity: 1;
+ opacity: 1;
+}
+
+div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post .jp-relatedposts-post-title a:hover {
+ text-decoration: underline;
+}
+
+div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post img.jp-relatedposts-post-img,
+div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post span {
+ display: block;
+ max-width: 90%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+div#jp-relatedposts div.jp-relatedposts-items-visual .jp-relatedposts-post img.jp-relatedposts-post-img,
+div#jp-relatedposts div.jp-relatedposts-items-visual .jp-relatedposts-post span {
+ max-width: 100%;
+}
+
+div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post .jp-relatedposts-post-context {
+ opacity: .6;
+}
+
+/* Behavior when there are thumbnails in visual mode */
+div#jp-relatedposts div.jp-relatedposts-items-visual div.jp-relatedposts-post-thumbs p.jp-relatedposts-post-excerpt {
+ display: none;
+}
+
+/* Behavior when there are no thumbnails in visual mode */
+div#jp-relatedposts div.jp-relatedposts-items-visual div.jp-relatedposts-post-nothumbs p.jp-relatedposts-post-excerpt {
+ overflow: hidden;
+}
+div#jp-relatedposts div.jp-relatedposts-items-visual div.jp-relatedposts-post-nothumbs span {
+ margin-bottom: 1em;
+}
+
+/**
+ * Responsive
+ */
+
+@media only screen and (max-width: 640px) {
+
+ div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post {
+ width: 50%;
+ }
+
+ div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post:nth-child(3n) {
+ clear: right;
+ }
+
+ div#jp-relatedposts div.jp-relatedposts-items-visual {
+ margin-left: 20px;
+ }
+
+}
+
+@media only screen and (max-width: 320px) {
+
+ div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post {
+ width: 100%;
+ clear: both;
+ margin: 0 0 1em;
+ }
+
+}
diff --git a/plugins/jetpack/modules/sharedaddy.php b/plugins/jetpack/modules/sharedaddy.php
index 0cb830e2..e7613e12 100644
--- a/plugins/jetpack/modules/sharedaddy.php
+++ b/plugins/jetpack/modules/sharedaddy.php
@@ -1,12 +1,16 @@
<?php
/**
* Module Name: Sharing
- * Module Description: The most super duper sharing tool on the interwebs. Share content with Facebook, Twitter, and many more.
- * Sort Order: 5
+ * Module Description: Allow visitors to share your content on Facebook, Twitter, and more with a click.
+ * Jumpstart Description: Twitter, Facebook and Google+ buttons at the bottom of each post, making it easy for visitors to share your content.
+ * Sort Order: 7
+ * Recommendation Order: 6
* First Introduced: 1.1
* Major Changes In: 1.2
* Requires Connection: No
* Auto Activate: Yes
+ * Module Tags: Social, Recommended
+ * Feature: Recommended, Jumpstart
*/
if ( !function_exists( 'sharing_init' ) )
@@ -15,11 +19,11 @@ if ( !function_exists( 'sharing_init' ) )
add_action( 'jetpack_modules_loaded', 'sharedaddy_loaded' );
function sharedaddy_loaded() {
- Jetpack::enable_module_configurable( __FILE__ );
- Jetpack::module_configuration_load( __FILE__, 'sharedaddy_configuration_load' );
+ Jetpack::enable_module_configurable( __FILE__ );
+ Jetpack::module_configuration_load( __FILE__, 'sharedaddy_configuration_load' );
}
function sharedaddy_configuration_load() {
- wp_safe_redirect( menu_page_url( 'sharing', false ) . "#sharing-buttons" );
- exit;
+ wp_safe_redirect( menu_page_url( 'sharing', false ) . "#sharing-buttons" );
+ exit;
}
diff --git a/plugins/jetpack/modules/sharedaddy/admin-sharing-rtl.css b/plugins/jetpack/modules/sharedaddy/admin-sharing-rtl.css
new file mode 100644
index 00000000..bd429ef7
--- /dev/null
+++ b/plugins/jetpack/modules/sharedaddy/admin-sharing-rtl.css
@@ -0,0 +1,402 @@
+/**
+ * Sharedaddy Admin Styles
+ */
+
+#services-config {
+ min-width: 700px;
+ width: 100%;
+ float: right;
+}
+
+#services-config h3 {
+ font-weight: normal;
+ font-size: 15px;
+ margin: 0;
+ padding: 8px 10px;
+ overflow: hidden;
+ white-space: nowrap;
+ color: #464646;
+}
+
+#available-services, #enabled-services, #live-preview {
+ padding: 0;
+ width: 100%;
+ padding-top: 20px;
+ border-spacing: 0;
+}
+
+#enabled-services .ui-sortable {
+ min-height: 50px;
+}
+
+#enabled-services {
+ padding-bottom: 20px;
+}
+
+#available-services, #enabled-services {
+ border-bottom: 2px solid #cccccc;
+}
+
+#live-preview {
+ border-bottom: 1px solid #dfdfdf;
+ padding-bottom: 60px;
+}
+
+#available-services h3, #enabled-services h3, #live-preview h3 {
+ padding: 0px;
+ margin-top: 0px;
+ margin-bottom: 1em;
+}
+
+body.settings_page_sharing .description {
+ width: 180px;
+ vertical-align: top;
+}
+
+body.settings_page_sharing .description p {
+ font-size: 13px;
+ font-style: italic;
+}
+
+body.settings_page_sharing .services {
+ padding: 0px 20px;
+ vertical-align: top;
+}
+
+body.settings_page_sharing .services ul li {
+ float: right;
+ cursor: move;
+}
+
+body.settings_page_sharing .services ul li.divider {
+ border: none;
+ padding: 0;
+ background: none;
+ cursor: default;
+}
+
+body.settings_page_sharing ul.services-hidden {
+ margin-bottom: 0;
+}
+
+/* Generic style */
+#available-services .service, #enabled-services .service {
+ margin-left: 10px;
+ padding: 5px 5px 5px 10px;
+ border-radius: 3px;
+ border: 1px solid #bbb;
+ background: #f8f8f8;
+ background-repeat: no-repeat;
+ background-position: center center;
+}
+
+#available-services .service:hover, #enabled-services .service:hover {
+ background: #fff;
+ border: 1px solid #bbb;
+ box-shadow: 0 1px 3px rgba(0,0,0,0.2);
+}
+
+/* Generic style icons */
+li.service span:before {
+ color: #555;
+ display: inline-block;
+ -webkit-font-smoothing: antialiased;
+ font: normal 16px/1 'Noticons', 'Genericons';
+ vertical-align: top;
+ position: relative;
+ top: 1px;
+ margin-left: 3px;
+ width: 16px;
+ height: 16px;
+ text-align: center;
+}
+li.service.share-print span:before {
+ content: '\f469';
+}
+li.service.share-digg span:before {
+ content: '\f221';
+}
+li.service.share-email span:before {
+ content: '\f410';
+}
+li.service.share-linkedin span:before {
+ content: '\f207';
+}
+li.service.share-twitter span:before {
+ content: '\f202';
+}
+li.service.share-reddit span:before {
+ content: '\f222';
+}
+li.service.share-tumblr span:before {
+ content: '\f214';
+}
+li.service.share-stumbleupon span:before {
+ content: '\f223';
+}
+li.service.share-pocket span:before {
+ content: '\f224';
+}
+li.service.share-pinterest span:before {
+ content: '\f209';
+}
+li.service.share-google-plus-1 span:before {
+ content: '\f218';
+}
+li.service.share-facebook span:before {
+ content: '\f204';
+}
+li.service.share-press-this span:before { /* Fixme: remove this button in favor of reblog */
+ content: '\f205';
+}
+
+
+/**
+ * Preview section
+ */
+
+body.settings_page_sharing ul.preview {
+ float: right;
+ margin: 0px;
+}
+
+body.settings_page_sharing ul.preview li.preview-item, body.settings_page_sharing ul.preview li.preview-item a {
+ cursor: default;
+ text-decoration: none;
+}
+
+div.sd-social-icon ul.preview li.preview-item a span,
+div.sd-social-icon .inner li.preview-item a span {
+ display: none;
+}
+
+div.sd-social-icon ul.preview li.preview-item.preview-custom a span {
+ display: inline-block;
+
+}
+
+.services .preview li.share-custom a {
+ text-decoration: none;
+}
+
+.services ul li.end-fix {
+ clear:both;
+ float:none;
+ visibility:hidden;
+ padding:0;
+ margin:0;
+ height:20px;
+ width:0;
+}
+
+#enabled-services h2{
+ font-size:20px;
+ padding-top:0px;
+ font-weight: normal !important;
+ color: #999;
+}
+
+body.settings_page_sharing #live-preview h2 {
+ font-size:20px;
+ font-weight: normal !important;
+ color: #e3e3e3;
+}
+
+body.settings_page_sharing .clearing {
+ clear: both;
+}
+
+body.settings_page_sharing .options .options-left {
+ float: right;
+}
+
+body.settings_page_sharing .input label {
+ font-size: 11px;
+ line-height: 16px;
+}
+
+body.settings_page_sharing .advanced-form {
+ padding: 10px 10px 8px 14px;
+ margin-right: -24px;
+ display: none;
+ border-top: 1px #e3e3e3 solid;
+ margin-top:4px;
+}
+
+body.settings_page_sharing .utility {
+ float: left;
+ padding-top:10px;
+ padding-left: 10px;
+ font-size: 10px;
+}
+
+body.settings_page_sharing .advanced input[type=submit] {
+ float: right;
+ margin-top:10px;
+ margin-left: 10px;
+}
+
+.services li.dropzone {
+ border: 1px dashed #999;
+ border-radius: 3px;
+ background: #e3e3e3;
+ margin-left: 10px;
+ padding: 5px;
+ height: 18px;
+}
+
+.advanced-form .form-table th {
+ width: auto !important;
+}
+
+.advanced-form .button-secondary {
+ margin-top: 0 !important;
+}
+
+#hidden-drop-target {
+ background: #e1e1e1;
+ border: 1px solid #cdcdcd;
+ width: 29%;
+ padding: 10px;
+ vertical-align: top;
+}
+
+#hidden-drop-target p {
+ font-size: 13px;
+ font-style: italic;
+ margin: 0 0 10px 0;
+}
+
+
+/* Official button previews */
+.preview li.preview-item {
+ background-position: 0px 5px;
+ cursor: default;
+}
+
+.preview .option-smart-on {
+ margin: 3px 0 0 5px;
+}
+
+.preview-digg .option-smart-on {
+ background: url(images/smart-digg.png) no-repeat top right;
+ background-size: 76px 17px;
+ width:76px;
+ height:17px;
+ margin-top: 2px;
+}
+
+.preview-reddit .option-smart-on {
+ background: url(images/smart-reddit.png) no-repeat top right;
+ background-size: 104px 21px;
+ width:104px;
+ height:21px;
+}
+
+.preview-stumbleupon .option-smart-on {
+ background: url(images/smart-stumbleupon.png) no-repeat top right;
+ background-size: 74px 18px;
+ width: 74px;
+ height: 18px;
+ margin-top: 1px;
+}
+
+.preview-facebook .option-smart-on {
+ background: url(images/smart-like.png) no-repeat top right;
+ background-size: 85px 20px;
+ width:85px;
+ height:20px;
+}
+
+.preview-twitter .option-smart-on {
+ background: url(images/smart-twitter.png?1) no-repeat top right;
+ background-size: 92px 20px;
+ width:92px;
+ height:20px;
+}
+
+.preview-linkedin .option-smart-on {
+ background: url(images/linkedin-smart.png) no-repeat top center;
+ background-size: 99px 18px;
+ width:99px;
+ height:18px;
+ margin-top: 1px;
+}
+
+.preview-google-plus-1 .option-smart-on {
+ background: url(images/smart-googleplus1.png) no-repeat top right;
+ background-size: 96px 20px;
+ width: 96px;
+ height: 20px;
+}
+
+.preview-tumblr .option-smart-on {
+ background: url(images/smart-tumblr.png) no-repeat top right;
+ background-size: 62px 20px;
+ width: 62px;
+ height: 20px;
+}
+
+.preview-pinterest .option-smart-on {
+ background: url(images/smart-pinterest.png) no-repeat top right;
+ background-size: 39px 20px;
+ width: 39px;
+ height: 20px;
+}
+
+.preview-pocket .option-smart-on {
+ background: url(images/smart-pocket.png) no-repeat top right;
+ background-size: 60px 20px;
+ width: 60px;
+ height: 20px;
+}
+
+
+/**
+ * Overflow sharing dialog
+ */
+
+.services .sharing-hidden li {
+ background-color: transparent;
+}
+
+.sharing-hidden li.share-end {
+ clear: both;
+ height: 0;
+ padding: 0px !important;
+ margin: 0px !important;
+ width: 0;
+ visibility: hidden;
+ float: none;
+}
+
+.preview .sharing-label {
+ font-weight: bold;
+ border: 0;
+ padding: 4px 0 0 6px;
+}
+
+#services-config a.remove {
+ background: #ddd;
+ color: #fff;
+ padding: 0px 4px 2px;
+ border-radius: 15px;
+ -moz-border-radius: 15px;
+ -webkit-border-radius: 15px;
+ text-decoration: none;
+ font-weight: bold;
+ font-size: 10px;
+}
+
+#services-config a.remove:hover {
+ background: #f00;
+}
+
+.sd-social-icon .inner a.sd-button span,
+.sd-social-icon .inner a.share-icon span {
+ display: inline-block;
+ overflow: hidden;
+ width: 0;
+ text-indent: 100%;
+}
+
diff --git a/plugins/jetpack/modules/sharedaddy/admin-sharing-rtl.min.css b/plugins/jetpack/modules/sharedaddy/admin-sharing-rtl.min.css
new file mode 100644
index 00000000..6272dc02
--- /dev/null
+++ b/plugins/jetpack/modules/sharedaddy/admin-sharing-rtl.min.css
@@ -0,0 +1 @@
+#services-config{min-width:700px;width:100%;float:right}#services-config h3{font-weight:400;font-size:15px;margin:0;padding:8px 10px;overflow:hidden;white-space:nowrap;color:#464646}#available-services,#enabled-services,#live-preview{padding:20px 0 0;width:100%;border-spacing:0}#enabled-services .ui-sortable{min-height:50px}#enabled-services{padding-bottom:20px}#available-services,#enabled-services{border-bottom:2px solid #ccc}#live-preview{border-bottom:1px solid #dfdfdf;padding-bottom:60px}#available-services h3,#enabled-services h3,#live-preview h3{padding:0;margin-top:0;margin-bottom:1em}body.settings_page_sharing .description{width:180px;vertical-align:top}body.settings_page_sharing .description p{font-size:13px;font-style:italic}body.settings_page_sharing .services{padding:0 20px;vertical-align:top}body.settings_page_sharing .services ul li{float:right;cursor:move}body.settings_page_sharing .services ul li.divider{border:none;padding:0;background:0 0;cursor:default}body.settings_page_sharing ul.services-hidden{margin-bottom:0}#available-services .service,#enabled-services .service{margin-left:10px;padding:5px 5px 5px 10px;border-radius:3px;border:1px solid #bbb;background:center center no-repeat #f8f8f8}#available-services .service:hover,#enabled-services .service:hover{background:#fff;border:1px solid #bbb;box-shadow:0 1px 3px rgba(0,0,0,.2)}li.service span:before{color:#555;display:inline-block;-webkit-font-smoothing:antialiased;font:400 16px/1 Noticons,Genericons;vertical-align:top;position:relative;top:1px;margin-left:3px;width:16px;height:16px;text-align:center}li.service.share-print span:before{content:'\f469'}li.service.share-digg span:before{content:'\f221'}li.service.share-email span:before{content:'\f410'}li.service.share-linkedin span:before{content:'\f207'}li.service.share-twitter span:before{content:'\f202'}li.service.share-reddit span:before{content:'\f222'}li.service.share-tumblr span:before{content:'\f214'}li.service.share-stumbleupon span:before{content:'\f223'}li.service.share-pocket span:before{content:'\f224'}li.service.share-pinterest span:before{content:'\f209'}li.service.share-google-plus-1 span:before{content:'\f218'}li.service.share-facebook span:before{content:'\f204'}li.service.share-press-this span:before{content:'\f205'}body.settings_page_sharing ul.preview{float:right;margin:0}body.settings_page_sharing ul.preview li.preview-item,body.settings_page_sharing ul.preview li.preview-item a{cursor:default;text-decoration:none}div.sd-social-icon .inner li.preview-item a span,div.sd-social-icon ul.preview li.preview-item a span{display:none}div.sd-social-icon ul.preview li.preview-item.preview-custom a span{display:inline-block}.services .preview li.share-custom a{text-decoration:none}.services ul li.end-fix{clear:both;float:none;visibility:hidden;padding:0;margin:0;height:20px;width:0}#enabled-services h2{font-size:20px;padding-top:0;font-weight:400!important;color:#999}body.settings_page_sharing #live-preview h2{font-size:20px;font-weight:400!important;color:#e3e3e3}body.settings_page_sharing .clearing{clear:both}body.settings_page_sharing .options .options-left{float:right}body.settings_page_sharing .input label{font-size:11px;line-height:16px}body.settings_page_sharing .advanced-form{padding:10px 10px 8px 14px;margin-right:-24px;display:none;border-top:1px #e3e3e3 solid;margin-top:4px}body.settings_page_sharing .utility{float:left;padding-top:10px;padding-left:10px;font-size:10px}body.settings_page_sharing .advanced input[type=submit]{float:right;margin-top:10px;margin-left:10px}.services li.dropzone{border:1px dashed #999;border-radius:3px;background:#e3e3e3;margin-left:10px;padding:5px;height:18px}.advanced-form .form-table th{width:auto!important}.advanced-form .button-secondary{margin-top:0!important}#hidden-drop-target{background:#e1e1e1;border:1px solid #cdcdcd;width:29%;padding:10px;vertical-align:top}#hidden-drop-target p{font-size:13px;font-style:italic;margin:0 0 10px}.preview li.preview-item{background-position:0 5px;cursor:default}.preview .option-smart-on{margin:3px 0 0 5px}.preview-digg .option-smart-on{background:url(images/smart-digg.png) top right/76px 17px no-repeat;width:76px;height:17px;margin-top:2px}.preview-reddit .option-smart-on{background:url(images/smart-reddit.png) top right/104px 21px no-repeat;width:104px;height:21px}.preview-stumbleupon .option-smart-on{background:url(images/smart-stumbleupon.png) top right/74px 18px no-repeat;width:74px;height:18px;margin-top:1px}.preview-facebook .option-smart-on{background:url(images/smart-like.png) top right/85px 20px no-repeat;width:85px;height:20px}.preview-twitter .option-smart-on{background:url(images/smart-twitter.png?1) top right/92px 20px no-repeat;width:92px;height:20px}.preview-linkedin .option-smart-on{background:url(images/linkedin-smart.png) top center/99px 18px no-repeat;width:99px;height:18px;margin-top:1px}.preview-google-plus-1 .option-smart-on{background:url(images/smart-googleplus1.png) top right/96px 20px no-repeat;width:96px;height:20px}.preview-tumblr .option-smart-on{background:url(images/smart-tumblr.png) top right/62px 20px no-repeat;width:62px;height:20px}.preview-pinterest .option-smart-on{background:url(images/smart-pinterest.png) top right/39px 20px no-repeat;width:39px;height:20px}.preview-pocket .option-smart-on{background:url(images/smart-pocket.png) top right/60px 20px no-repeat;width:60px;height:20px}.services .sharing-hidden li{background-color:transparent}.sharing-hidden li.share-end{clear:both;height:0;padding:0!important;margin:0!important;width:0;visibility:hidden;float:none}.preview .sharing-label{font-weight:700;border:0;padding:4px 0 0 6px}#services-config a.remove{background:#ddd;color:#fff;padding:0 4px 2px;border-radius:15px;-moz-border-radius:15px;-webkit-border-radius:15px;text-decoration:none;font-weight:700;font-size:10px}#services-config a.remove:hover{background:red}.sd-social-icon .inner a.sd-button span,.sd-social-icon .inner a.share-icon span{display:inline-block;overflow:hidden;width:0;text-indent:100%} \ No newline at end of file
diff --git a/plugins/jetpack/modules/sharedaddy/admin-sharing.css b/plugins/jetpack/modules/sharedaddy/admin-sharing.css
index 620d6fc3..dd4982e4 100644
--- a/plugins/jetpack/modules/sharedaddy/admin-sharing.css
+++ b/plugins/jetpack/modules/sharedaddy/admin-sharing.css
@@ -1,215 +1,181 @@
+/**
+ * Sharedaddy Admin Styles
+ */
+
#services-config {
- background: #f1f1f1;
- border: 1px #e3e3e3 solid;
- border-radius: 6px;
- -moz-border-radius: 6px;
- -webkit-border-radius: 6px;
- margin-top:15px;
min-width: 700px;
width: 100%;
float: left;
- margin-bottom: 25px;
}
-#available-services,#enabled-services,#live-preview{
- padding:20px 20px 0px 20px;
+#services-config h3 {
+ font-weight: normal;
+ font-size: 15px;
+ margin: 0;
+ padding: 8px 10px;
+ overflow: hidden;
+ white-space: nowrap;
+ color: #464646;
+}
+
+#available-services, #enabled-services, #live-preview {
+ padding: 0;
width: 100%;
+ padding-top: 20px;
+ border-spacing: 0;
+}
+
+#enabled-services .ui-sortable {
+ min-height: 50px;
}
#enabled-services {
- padding: 20px;
+ padding-bottom: 20px;
}
-#live-preview {
- padding: 20px 20px 10px 20px;
+#available-services, #enabled-services {
+ border-bottom: 2px solid #cccccc;
}
-#available-services{
- border-bottom: 1px #e3e3e3 solid;
+#live-preview {
+ border-bottom: 1px solid #dfdfdf;
+ padding-bottom: 60px;
}
-#available-services h3,#enabled-services h3,#live-preview h3{
+#available-services h3, #enabled-services h3, #live-preview h3 {
padding: 0px;
margin-top: 0px;
+ margin-bottom: 1em;
}
-.description{
+body.settings_page_sharing .description {
width: 180px;
vertical-align: top;
}
-.description p{
- font-size: 11px;
+body.settings_page_sharing .description p {
+ font-size: 13px;
+ font-style: italic;
}
-.services {
+body.settings_page_sharing .services {
padding: 0px 20px;
vertical-align: top;
}
-.services ul{
-}
-
-.services ul li {
+body.settings_page_sharing .services ul li {
float: left;
- border: 1px #e3e3e3 solid;
- border-radius: 6px;
- -moz-border-radius: 6px;
- -webkit-border-radius: 6px;
- padding: 5px 10px 5px 24px;
- margin-right: 5px !important;
cursor: move;
}
-.services ul li.divider {
+body.settings_page_sharing .services ul li.divider {
border: none;
padding: 0;
background: none;
cursor: default;
}
-.preview {
- float: left !important;
- width: 98%;
+body.settings_page_sharing ul.services-hidden {
+ margin-bottom: 0;
}
-.services ul.preview li, .services ul.archive li {
- border: none;
+/* Generic style */
+#available-services .service, #enabled-services .service {
+ margin-right: 10px;
+ padding: 5px 10px 5px 5px;
+ border-radius: 3px;
+ border: 1px solid #bbb;
+ background: #f8f8f8;
+ background-repeat: no-repeat;
+ background-position: center center;
}
-
-.services ul li#facebook, #available-services .preview-facebook div.option-smart-off{background: #FFF url(images/facebook.png) no-repeat 4px 5px;}
-.services ul li#twitter, #available-services .preview-twitter div.option-smart-off{background: #FFF url(images/twitter.png?1) no-repeat 4px 5px;}
-.services ul li#wordpress, #available-services .preview-wordpress{background: #FFF url(images/wordpress.png) no-repeat 4px 5px;}
-.services ul li#digg, #available-services .preview-digg div.option-smart-off{background: #FFF url(images/digg.png) no-repeat 4px 5px;}
-.services ul li#reddit, #available-services .preview-reddit div.option-smart-off{background: #FFF url(images/reddit.png) no-repeat 4px 5px;}
-.services ul li#stumbleupon, #available-services .preview-stumbleupon div.option-smart-off{background: #FFF url(images/stumbleupon.png) no-repeat 4px 5px;}
-.services ul li#email, #available-services .preview-email{background: #FFF url(images/email.png) no-repeat 4px 5px; padding-right: 10px;}
-.services ul li#print, #available-services .preview-print{background: #FFF url(images/print.png) no-repeat 4px 5px; padding-right: 10px;}
-.services ul li#press-this, #available-services .preview-press-this{background: #FFF url(images/wordpress.png) no-repeat 4px 5px; padding-right: 10px;}
-.services ul li#linkedin, #available-services .preview-linkedin div.option-smart-off{background: #FFF url(images/linkedin.png) no-repeat 4px 5px;}
-.services ul li#tumblr,#available-services .preview-tumblr{background: #FFF url(images/tumblr.png) no-repeat 4px 5px; padding-right: 10px;}
-.services ul li#google-plus-1,#available-services .preview-google-plus-1{background: #FFF url(images/googleplus1.png) no-repeat 4px 5px; padding-right: 10px;}
-.services ul li#pinterest,#available-services .preview-pinterest{background: #FFF url(images/pinterest.png) no-repeat 5px 6px; padding-right: 10px;}
-.services ul li#pocket,#available-services .preview-pocket{background: #FFF url(images/pocket.png) no-repeat 4px 5px; padding-right: 10px;}
-.services ul li#kindle,#available-services .preview-kindle{background: #FFF url(images/kindle.png) no-repeat 4px 5px; padding-right: 10px;}
-.services ul li.share-custom, #available-services .preview-custom{background: #FFF url(images/custom.png) no-repeat 4px 5px; no-repeat 4px 5px; padding-right: 10px;}
-
-
-
-/****************************************************************************/
-
-.preview li.preview-item {
- margin: 0 15px 0 0;
- background-position: 0px 5px;
- padding: 5px 0px 5px 20px;
- border: none;
- cursor: default;
+#available-services .service:hover, #enabled-services .service:hover {
+ background: #fff;
+ border: 1px solid #bbb;
+ box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}
-.preview li.preview-digg,
-.preview li.preview-reddit,
-.preview li.preview-stumbleupon,
-.preview li.preview-facebook,
-.preview li.preview-twitter,
-.preview li.preview-linkedin,
-.preview li.preview-tumblr {
- padding: 0;
+/* Generic style icons */
+li.service span:before {
+ color: #555;
+ display: inline-block;
+ -webkit-font-smoothing: antialiased;
+ font: normal 16px/1 'Noticons', 'Genericons';
+ vertical-align: top;
+ position: relative;
+ top: 1px;
+ margin-right: 3px;
+ width: 16px;
+ height: 16px;
+ text-align: center;
}
-
-.preview-digg .option-smart-on {
- background: #FFF url(images/smart-digg.png) no-repeat top left;
- background-size: 76px 17px;
- width:76px;
- height:17px;
- margin-top: 2px;
+li.service.share-print span:before {
+ content: '\f469';
}
-
-.preview-reddit .option-smart-on {
- background: #FFF url(images/smart-reddit.png) no-repeat top left;
- background-size: 104px 21px;
- width:104px;
- height:21px;
+li.service.share-digg span:before {
+ content: '\f221';
}
-
-.preview-stumbleupon .option-smart-on {
- background: #FFF url(images/smart-stumbleupon.png) no-repeat top left;
- background-size: 74px 18px;
- width: 74px;
- height: 18px;
- margin-top: 1px;
+li.service.share-email span:before {
+ content: '\f410';
}
-
-.preview-facebook .option-smart-on {
- background: #FFF url(images/smart-like.png) no-repeat top left;
- background-size: 50px 20px;
- width:50px;
- height:20px;
+li.service.share-linkedin span:before {
+ content: '\f207';
}
-
-.preview-twitter .option-smart-on {
- background: #FFF url(images/smart-twitter.png?1) no-repeat top left;
- background-size: 92px 20px;
- width:92px;
- height:20px;
+li.service.share-twitter span:before {
+ content: '\f202';
}
-
-.preview-linkedin .option-smart-on {
- background: #FFF url(images/linkedin-smart.png) no-repeat top center;
- background-size: 99px 18px;
- width:99px;
- height:18px;
- margin-top: 1px;
+li.service.share-reddit span:before {
+ content: '\f222';
}
-
-.preview-google-plus-1 .option-smart-on {
- background: #FFF url(images/smart-googleplus1.png) no-repeat top left;
- background-size: 96px 20px;
- width: 96px;
- height: 20px;
+li.service.share-tumblr span:before {
+ content: '\f214';
}
-
-.preview-tumblr .option-smart-on {
- background: #FFF url(images/smart-tumblr.png) no-repeat top left;
- background-size: 62px 20px;
- width: 62px;
- height: 20px;
+li.service.share-stumbleupon span:before {
+ content: '\f223';
+}
+li.service.share-pocket span:before {
+ content: '\f224';
+}
+li.service.share-pinterest span:before {
+ content: '\f209';
+}
+li.service.share-google-plus-1 span:before {
+ content: '\f218';
+}
+li.service.share-facebook span:before {
+ content: '\f204';
+}
+li.service.share-press-this span:before { /* Fixme: remove this button in favor of reblog */
+ content: '\f205';
}
-.preview-pinterest .option-smart-on {
- background: #FFF url(images/smart-pinterest.png) no-repeat top left;
- background-size: 58px 20px;
- width: 58px;
- height: 20px;
+
+/**
+ * Preview section
+ */
+
+body.settings_page_sharing ul.preview {
+ float: left;
+ margin: 0px;
}
-.preview-pinterest .option-smart-on {
- background: #FFF url(images/smart-pinterest.png) no-repeat top left;
- background-size: 58px 20px;
- width: 58px;
- height: 20px;
+body.settings_page_sharing ul.preview li.preview-item, body.settings_page_sharing ul.preview li.preview-item a {
+ cursor: default;
+ text-decoration: none;
}
-.preview-pocket .option-smart-on {
- background: #FFF url(images/smart-pocket.png) no-repeat top left;
- background-size: 60px 20px;
- width: 60px;
- height: 20px;
+div.sd-social-icon ul.preview li.preview-item a span,
+div.sd-social-icon .inner li.preview-item a span {
+ display: none;
}
-.services .preview li.share-custom {
- border-radius: 6px;
- -moz-border-radius: 6px;
- -webkit-border-radius: 6px;
- background:url("images/sharing-hidden.png") no-repeat scroll 0px center #FFFFFF;
- float: left;
- line-height: 22px;
- padding: 0 8px 0 21px;
- margin: 1px 0 0 0;
+div.sd-social-icon ul.preview li.preview-item.preview-custom a span {
+ display: inline-block;
+
}
.services .preview li.share-custom a {
- color: #333;
text-decoration: none;
}
@@ -223,11 +189,6 @@
width:0;
}
-#enabled-services{
- border-top: 1px #FFF solid;
- border-bottom: 1px #e3e3e3 solid;
-}
-
#enabled-services h2{
font-size:20px;
padding-top:0px;
@@ -235,57 +196,53 @@
color: #999;
}
-#live-preview h2{
+body.settings_page_sharing #live-preview h2 {
font-size:20px;
font-weight: normal !important;
color: #e3e3e3;
}
-#live-preview{
- background: #FFF;
- border-bottom-left-radius:6px 6px;
- border-bottom-right-radius:6px 6px;
- -moz-border-radius-bottomleft: 6px;
- -moz-border-radius-bottomright: 6px;
+body.settings_page_sharing .clearing {
+ clear: both;
}
-.clearing{
- clear: both;
+body.settings_page_sharing .options .options-left {
+ float: left;
}
- .options .options-left{
- float: left;
- }
-
- .input label{
- font-size: 11px;
- line-height: 16px;
- }
-
- .advanced-form {
- padding: 10px 14px 8px 10px;
- margin-left: -24px;
- display: none;
- border-top: 1px #e3e3e3 solid;
- margin-top:4px;
- }
-
- .utility{
- float: right;
- padding-top:10px;
- padding-right: 10px;
- font-size: 10px;
- }
-
- .advanced input[type=submit]{
- float: left;
- margin-top:10px;
- margin-right: 10px;
- }
+body.settings_page_sharing .input label {
+ font-size: 11px;
+ line-height: 16px;
+}
+
+body.settings_page_sharing .advanced-form {
+ padding: 10px 14px 8px 10px;
+ margin-left: -24px;
+ display: none;
+ border-top: 1px #e3e3e3 solid;
+ margin-top:4px;
+}
+
+body.settings_page_sharing .utility {
+ float: right;
+ padding-top:10px;
+ padding-right: 10px;
+ font-size: 10px;
+}
+
+body.settings_page_sharing .advanced input[type=submit] {
+ float: left;
+ margin-top:10px;
+ margin-right: 10px;
+}
.services li.dropzone {
border: 1px dashed #999;
+ border-radius: 3px;
background: #e3e3e3;
+ margin-right: 10px;
+ padding: 5px;
+ height: 18px;
}
.advanced-form .form-table th {
@@ -296,51 +253,121 @@
margin-top: 0 !important;
}
-#share-drop-target {
-}
-
#hidden-drop-target {
background: #e1e1e1;
border: 1px solid #cdcdcd;
- border-radius: 6px;
- -moz-border-radius: 6px;
- -webkit-border-radius: 6px;
width: 29%;
padding: 10px;
vertical-align: top;
}
#hidden-drop-target p {
- font-size: 10px;
+ font-size: 13px;
+ font-style: italic;
margin: 0 0 10px 0;
+}
+
+
+/* Official button previews */
+.preview li.preview-item {
+ background-position: 0px 5px;
+ cursor: default;
+}
+
+.preview .option-smart-on {
+ margin: 3px 5px 0 0;
+}
+
+.preview-digg .option-smart-on {
+ background: url(images/smart-digg.png) no-repeat top left;
+ background-size: 76px 17px;
+ width:76px;
+ height:17px;
+ margin-top: 2px;
+}
+
+.preview-reddit .option-smart-on {
+ background: url(images/smart-reddit.png) no-repeat top left;
+ background-size: 104px 21px;
+ width:104px;
+ height:21px;
+}
+
+.preview-stumbleupon .option-smart-on {
+ background: url(images/smart-stumbleupon.png) no-repeat top left;
+ background-size: 74px 18px;
+ width: 74px;
+ height: 18px;
+ margin-top: 1px;
+}
+
+.preview-facebook .option-smart-on {
+ background: url(images/smart-like.png) no-repeat top left;
+ background-size: 85px 20px;
+ width:85px;
+ height:20px;
+}
+
+.preview-twitter .option-smart-on {
+ background: url(images/smart-twitter.png?1) no-repeat top left;
+ background-size: 92px 20px;
+ width:92px;
+ height:20px;
+}
+
+.preview-linkedin .option-smart-on {
+ background: url(images/linkedin-smart.png) no-repeat top center;
+ background-size: 99px 18px;
+ width:99px;
+ height:18px;
+ margin-top: 1px;
+}
+.preview-google-plus-1 .option-smart-on {
+ background: url(images/smart-googleplus1.png) no-repeat top left;
+ background-size: 96px 20px;
+ width: 96px;
+ height: 20px;
}
-.sharing-hidden .inner {
- position: absolute;
- border: 2px solid #6e6e6e;
- padding: 15px 0px;
- background: #fff;
+.preview-tumblr .option-smart-on {
+ background: url(images/smart-tumblr.png) no-repeat top left;
+ background-size: 62px 20px;
+ width: 62px;
+ height: 20px;
}
+.preview-pinterest .option-smart-on {
+ background: url(images/smart-pinterest.png) no-repeat top left;
+ background-size: 39px 20px;
+ width: 39px;
+ height: 20px;
+}
-.sharing-hidden ul {
- margin: 0 !important;
+.preview-pocket .option-smart-on {
+ background: url(images/smart-pocket.png) no-repeat top left;
+ background-size: 60px 20px;
+ width: 60px;
+ height: 20px;
}
+
+/**
+ * Overflow sharing dialog
+ */
+
.services .sharing-hidden li {
- margin: 0px 10px 0px 10px;
background-color: transparent;
}
.sharing-hidden li.share-end {
- clear: both;
- height: 0;
- padding: 0px !important;
- margin: 0px !important;
- width: 0;
- visibility: hidden;
- float: none;
+ clear: both;
+ height: 0;
+ padding: 0px !important;
+ margin: 0px !important;
+ width: 0;
+ visibility: hidden;
+ float: none;
}
.preview .sharing-label {
@@ -365,88 +392,11 @@
background: #f00;
}
+.sd-social-icon .inner a.sd-button span,
+.sd-social-icon .inner a.share-icon span {
+ display: inline-block;
+ overflow: hidden;
+ width: 0;
+ text-indent: 100%;
+}
-
-
-@media print,
- (-o-min-device-pixel-ratio: 5/4),
- (-webkit-min-device-pixel-ratio: 1.25),
- (min-resolution: 120dpi) {
-
- .services ul li#facebook, #available-services .preview-facebook div.option-smart-off{background: #FFF url(images/facebook@2x.png) no-repeat 4px 5px;}
- .services ul li#twitter, #available-services .preview-twitter div.option-smart-off{background: #FFF url(images/twitter@2x.png?1) no-repeat 4px 5px;}
- .services ul li#wordpress, #available-services .preview-wordpress{background: #FFF url(images/wordpress@2x.png?1) no-repeat 4px 5px;}
- .services ul li#digg, #available-services .preview-digg div.option-smart-off{background: #FFF url(images/digg@2x.png) no-repeat 4px 5px;}
- .services ul li#reddit, #available-services .preview-reddit div.option-smart-off{background: #FFF url(images/reddit@2x.png) no-repeat 4px 5px;}
- .services ul li#stumbleupon, #available-services .preview-stumbleupon div.option-smart-off{background: #FFF url(images/stumbleupon@2x.png) no-repeat 4px 5px;}
- .services ul li#email, #available-services .preview-email{background: #FFF url(images/email@2x.png) no-repeat 4px 5px; padding-right: 10px;}
- .services ul li#print, #available-services .preview-print{background: #FFF url(images/print@2x.png) no-repeat 4px 5px; padding-right: 10px;}
- .services ul li#press-this, #available-services .preview-press-this{background: #FFF url(images/wordpress@2x.png) no-repeat 4px 5px; padding-right: 10px;}
- .services ul li#linkedin, #available-services .preview-linkedin div.option-smart-off{background: #FFF url(images/linkedin@2x.png) no-repeat 4px 5px;}
- .services ul li#tumblr,#available-services .preview-tumblr{background: #FFF url(images/tumblr@2x.png) no-repeat 4px 5px; padding-right: 10px;}
- .services ul li#google-plus-1,#available-services .preview-google-plus-1{background: #FFF url(images/googleplus1@2x.png) no-repeat 4px 5px; padding-right: 10px;}
- .services ul li#pinterest,#available-services .preview-pinterest{background: #FFF url(images/pinterest@2x.png) no-repeat 4px 5px; padding-right: 10px;}
- .services ul li#pocket,#available-services .preview-pocket{background: #FFF url(images/pocket@2x.png) no-repeat 4px 5px; padding-right: 10px;}
- .services ul li#kindle,#available-services .preview-kindle{background: #FFF url(images/kindle@2x.png) no-repeat 4px 5px; padding-right: 10px;}
- .services ul li.share-custom, #available-services .preview-custom{background: #FFF url(images/custom@2x.png) no-repeat 4px 5px; no-repeat 4px 5px; padding-right: 10px;}
-
- .services ul li#facebook, #available-services .preview-facebook div.option-smart-off,
- .services ul li#twitter, #available-services .preview-twitter div.option-smart-off,
- .services ul li#wordpress, #available-services .preview-wordpress,
- .services ul li#digg, #available-services .preview-digg div.option-smart-off,
- .services ul li#reddit, #available-services .preview-reddit div.option-smart-off,
- .services ul li#stumbleupon, #available-services .preview-stumbleupon div.option-smart-off,
- .services ul li#email, #available-services .preview-email,
- .services ul li#print, #available-services .preview-print,
- .services ul li#press-this, #available-services .preview-press-this,
- .services ul li#linkedin, #available-services .preview-linkedin div.option-smart-off,
- .services ul li#tumblr,#available-services .preview-tumblr,
- .services ul li#google-plus-1,#available-services .preview-google-plus-1,
- .services ul li#pinterest,#available-services .preview-pinterest,
- .services ul li#pocket,#available-services .preview-pocket,
- .services ul li#kindle,#available-services .preview-kindle,
- .services ul li.share-custom, #available-services .preview-custom{
- background-size: 16px 16px;
- }
-
- .preview-digg .option-smart-on {
- background-image: url(images/smart-digg@2x.png);
- }
-
- .preview-reddit .option-smart-on {
- background-image: url(images/smart-reddit@2x.png);
- }
-
- .preview-stumbleupon .option-smart-on {
- background-image: url(images/smart-stumbleupon@2x.png);
- }
-
- .preview-facebook .option-smart-on {
- background-image: url(images/smart-like@2x.png);
- }
-
- .preview-twitter .option-smart-on {
- background-image: url(images/smart-twitter@2x.png);
- }
-
- .preview-linkedin .option-smart-on {
- background-image: url(images/linkedin-smart@2x.png);
- }
-
- .preview-google-plus-1 .option-smart-on {
- background-image: url(images/smart-googleplus1@2x.png);
- }
-
- .preview-tumblr .option-smart-on {
- background-image: url(images/smart-tumblr@2x.png);
- }
-
- .preview-pinterest .option-smart-on {
- background-image: url(images/smart-pinterest@2x.png);
- }
-
- .preview-pocket .option-smart-on {
- background-image: url(images/smart-pocket@2x.png);
- }
-
-} \ No newline at end of file
diff --git a/plugins/jetpack/modules/sharedaddy/admin-sharing.js b/plugins/jetpack/modules/sharedaddy/admin-sharing.js
index b396ef60..ad30eb6f 100644
--- a/plugins/jetpack/modules/sharedaddy/admin-sharing.js
+++ b/plugins/jetpack/modules/sharedaddy/admin-sharing.js
@@ -1,3 +1,6 @@
+/* jshint onevar: false, smarttabs: true */
+/* global sharing_loading_icon */
+
(function($) {
$( document ).ready(function() {
function enable_share_button() {
@@ -36,7 +39,7 @@
var handler_item_enter = function() {
$( original ).data( 'hasitem', true );
clearTimeout( $( original ).data( 'timer2' ) );
- }
+ };
var handler_original_leave = function() {
$( original ).data( 'hasoriginal', false );
@@ -75,15 +78,15 @@
}
function update_preview() {
- var item;
var button_style = $( '#button_style' ).val();
// Clear the live preview
$( '#live-preview ul.preview li' ).remove();
// Add label
- if ( $( '#save-enabled-shares input[name=visible]' ).val() != '' || $( '#save-enabled-shares input[name=hidden]' ).val() != '' )
+ if ( $( '#save-enabled-shares input[name=visible]' ).val() || $( '#save-enabled-shares input[name=hidden]' ).val() ) {
$( '#live-preview ul.preview' ).append( $( '#live-preview ul.archive .sharing-label' ).clone() );
+ }
// Re-insert all the enabled items
$( 'ul.services-enabled li' ).each( function() {
@@ -94,14 +97,14 @@
} );
// Add any hidden items
- if ( $( '#save-enabled-shares input[name=hidden]' ).val() != '' ) {
+ if ( $( '#save-enabled-shares input[name=hidden]' ).val() ) {
// Add share button
$( '#live-preview ul.preview' ).append( $( '#live-preview ul.archive .share-more' ).parent().clone() );
$( '.sharing-hidden ul li' ).remove();
// Add hidden items into the inner panel
- $( 'ul.services-hidden li' ).each( function( pos, item ) {
+ $( 'ul.services-hidden li' ).each( function( /*pos, item*/ ) {
if ( $( this ).hasClass( 'service' ) ) {
var service = $( this ).attr( 'id' );
$( '.sharing-hidden .inner ul' ).append( $( '#live-preview ul.archive .preview-' + service ).clone() );
@@ -115,22 +118,22 @@
$( '#live-preview li.advanced' ).removeClass( 'no-icon' );
// Button style
- if ( 'icon' == button_style ) {
- $( '#live-preview ul.preview div span' ).html( '&nbsp;' ).parent().addClass( 'no-text' ); // Remove text label
+ if ( 'icon' === button_style ) {
+ $( '#live-preview ul.preview div span, .sharing-hidden .inner ul div span' ).html( '&nbsp;' ).parent().addClass( 'no-text' );
$( '#live-preview div.sharedaddy' ).addClass( 'sd-social-icon' );
- } else if ( 'official' == button_style ) {
- $( '#live-preview ul.preview .advanced' ).each( function( i ) {
+ } else if ( 'official' === button_style ) {
+ $( '#live-preview ul.preview .advanced, .sharing-hidden .inner ul .advanced' ).each( function( /*i*/ ) {
if ( !$( this ).hasClass( 'preview-press-this' ) && !$( this ).hasClass( 'preview-email' ) && !$( this ).hasClass( 'preview-print' ) && !$( this ).hasClass( 'share-custom' ) ) {
$( this ).find( '.option a span' ).html( '' ).parent().removeClass( 'sd-button' ).parent().attr( 'class', 'option option-smart-on' );
}
} );
- } else if ( 'text' == button_style ) {
+ } else if ( 'text' === button_style ) {
$( '#live-preview li.advanced' ).addClass( 'no-icon' );
}
}
- function sharing_option_changed() {
+ window.sharing_option_changed = function() {
var item = this;
// Loading icon
@@ -158,10 +161,11 @@
$( item ).parents( 'li:first' ).removeAttr( 'style' );
} );
- if ( $( item ).is( ':submit' ) === true )
+ if ( $( item ).is( ':submit' ) === true ) {
return false;
+ }
return true;
- }
+ };
function showExtraOptions( service ) {
jQuery( '.' + service + '-extra-options' ).css( { backgroundColor: '#ffffcc' } ).fadeIn();
@@ -227,25 +231,25 @@
}
$( '#enabled-services .services ul' ).sortable( {
- receive: function( event, ui ) {
+ receive: function( /*event, ui*/ ) {
save_services();
},
stop: function() {
save_services();
$( 'li.service' ).enableSelection(); // Fixes a problem with Chrome
},
- over: function( event, ui ) {
+ over: function( /*event, ui*/ ) {
$( this ).find( 'ul' ).addClass( 'dropping' );
// Ensure the 'end-fix' is at the end
- $( '#enabled-services li.end-fix' ).remove()
+ $( '#enabled-services li.end-fix' ).remove();
$( '#enabled-services ul' ).append( '<li class="end-fix"></li>' );
},
- out: function( event, ui ) {
+ out: function( /*event, ui*/ ) {
$( this ).find( 'ul' ).removeClass( 'dropping' );
// Ensure the 'end-fix' is at the end
- $( '#enabled-services li.end-fix' ).remove()
+ $( '#enabled-services li.end-fix' ).remove();
$( '#enabled-services ul' ).append( '<li class="end-fix"></li>' );
},
helper: function( event, ui ) {
@@ -253,7 +257,7 @@
return ui.clone();
},
- start: function( event, ui ) {
+ start: function( /*event, ui*/ ) {
// Make sure that the advanced section is closed
$( '.advanced-form' ).hide();
$( 'li.service' ).disableSelection(); // Fixes a problem with Chrome
@@ -279,6 +283,98 @@
}
} );
+ // Accessibility keyboard shortcurts
+ $( '.service' ).on( 'keydown', function ( e ) {
+
+ // Reposition if one of the directional keys is pressed
+ switch ( e.keyCode ) {
+ case 13: keyboardDragDrop( $( this ) ); break; // Enter
+ case 32: keyboardDragDrop( $( this ) ); break; // Space
+ case 37: keyboardChangeOrder( $( this ), 'left' ); break; // Left
+ case 39: keyboardChangeOrder( $( this ), 'right' ); break; // Right
+ default: return true; // Exit and bubble
+ }
+
+ e.preventDefault();
+ });
+
+ function keyboardChangeOrder( $this, dir ) {
+
+ var thisParent = $this.parent(),
+ thisParentsChildren = thisParent.find( 'li' ),
+ thisPosition = thisParentsChildren.index( $this ) + 1,
+ totalChildren = thisParentsChildren.length - 1,
+ thisService;
+
+ // No need to be able to sort order for the "Available Services" section
+ if ( thisParent.hasClass( 'services-available' ) ) {
+ return;
+ }
+
+ if ( 'left' === dir ) {
+ if ( 1 === thisPosition ) {
+ return;
+ }
+
+ // Find service to left
+ var prevSibling = $this.prev();
+
+ // Detach this service from DOM
+ thisService = $this.detach();
+
+ // Move it to the appropriate area and add focus back to service
+ prevSibling.before( thisService );
+
+ // Add focus
+ prevSibling.prev().focus();
+ }
+
+ if ( 'right' === dir ) {
+ if ( thisPosition === totalChildren ) {
+ return;
+ }
+
+ // Find service to left
+ var nextSibling = $this.next();
+
+ // Detach this service from DOM
+ thisService = $this.detach();
+
+ // Move it to the appropriate area and add focus back to service
+ nextSibling.after( thisService );
+
+ // Add focus
+ nextSibling.next().focus();
+ }
+
+ //Save changes
+ save_services();
+ }
+
+ function keyboardDragDrop( $this ) {
+
+ var dropzone,
+ thisParent = $this.parent();
+
+ // Rotate through 3 available dropzones
+ if ( thisParent.hasClass( 'services-available' ) ) {
+ dropzone = 'services-enabled';
+ } else if ( thisParent.hasClass( 'services-enabled' ) ) {
+ dropzone = 'services-hidden';
+ } else {
+ dropzone = 'services-available';
+ }
+
+ // Detach this service from DOM
+ var thisService = $this.detach();
+
+ // Move it to the appropriate area and add focus back to service
+ $( '.' + dropzone ).prepend( thisService ).find( 'li:first-child' ).focus();
+
+ //Save changes
+ save_services();
+ }
+
// Live preview 'hidden' button
$( '.preview-hidden a' ).click( function() {
$( this ).parent().find( '.preview' ).toggle();
@@ -295,7 +391,7 @@
success: function( response ) {
$( '#new-service-form img' ).hide();
- if ( response == '1' ) {
+ if ( ( '' + response ) === '1' ) {
$( '#new-service-form .inerror' ).removeClass( 'inerror' ).addClass( 'error' );
$( '#new-service-form .error' ).show();
$( '#new-service-form input[type=submit]' ).prop( 'disabled', false );
@@ -315,7 +411,7 @@
$( this ).parents( 'li:first' ).css( 'backgroundImage', 'url("' + sharing_loading_icon + '")' );
// Save
- form.ajaxSubmit( function( response ) {
+ form.ajaxSubmit( function( /*response*/ ) {
// Remove the item
form.parents( 'li:first' ).fadeOut( function() {
$( this ).remove();
@@ -335,7 +431,7 @@
} ).change();
$( 'input[name=sharing_label]' ).blur( function() {
- $('#live-preview h3.sd-title').html( $( '<div/>' ).text( $( this ).val() ).html() );
+ $('#live-preview h3.sd-title').text( $( '<div/>' ).text( $( this ).val() ).html() );
} );
init_handlers();
diff --git a/plugins/jetpack/modules/sharedaddy/admin-sharing.min.css b/plugins/jetpack/modules/sharedaddy/admin-sharing.min.css
new file mode 100644
index 00000000..3ce68a3c
--- /dev/null
+++ b/plugins/jetpack/modules/sharedaddy/admin-sharing.min.css
@@ -0,0 +1 @@
+#services-config{min-width:700px;width:100%;float:left}#services-config h3{font-weight:400;font-size:15px;margin:0;padding:8px 10px;overflow:hidden;white-space:nowrap;color:#464646}#available-services,#enabled-services,#live-preview{padding:20px 0 0;width:100%;border-spacing:0}#enabled-services .ui-sortable{min-height:50px}#enabled-services{padding-bottom:20px}#available-services,#enabled-services{border-bottom:2px solid #ccc}#live-preview{border-bottom:1px solid #dfdfdf;padding-bottom:60px}#available-services h3,#enabled-services h3,#live-preview h3{padding:0;margin-top:0;margin-bottom:1em}body.settings_page_sharing .description{width:180px;vertical-align:top}body.settings_page_sharing .description p{font-size:13px;font-style:italic}body.settings_page_sharing .services{padding:0 20px;vertical-align:top}body.settings_page_sharing .services ul li{float:left;cursor:move}body.settings_page_sharing .services ul li.divider{border:none;padding:0;background:0 0;cursor:default}body.settings_page_sharing ul.services-hidden{margin-bottom:0}#available-services .service,#enabled-services .service{margin-right:10px;padding:5px 10px 5px 5px;border-radius:3px;border:1px solid #bbb;background:center center no-repeat #f8f8f8}#available-services .service:hover,#enabled-services .service:hover{background:#fff;border:1px solid #bbb;box-shadow:0 1px 3px rgba(0,0,0,.2)}li.service span:before{color:#555;display:inline-block;-webkit-font-smoothing:antialiased;font:400 16px/1 Noticons,Genericons;vertical-align:top;position:relative;top:1px;margin-right:3px;width:16px;height:16px;text-align:center}li.service.share-print span:before{content:'\f469'}li.service.share-digg span:before{content:'\f221'}li.service.share-email span:before{content:'\f410'}li.service.share-linkedin span:before{content:'\f207'}li.service.share-twitter span:before{content:'\f202'}li.service.share-reddit span:before{content:'\f222'}li.service.share-tumblr span:before{content:'\f214'}li.service.share-stumbleupon span:before{content:'\f223'}li.service.share-pocket span:before{content:'\f224'}li.service.share-pinterest span:before{content:'\f209'}li.service.share-google-plus-1 span:before{content:'\f218'}li.service.share-facebook span:before{content:'\f204'}li.service.share-press-this span:before{content:'\f205'}body.settings_page_sharing ul.preview{float:left;margin:0}body.settings_page_sharing ul.preview li.preview-item,body.settings_page_sharing ul.preview li.preview-item a{cursor:default;text-decoration:none}div.sd-social-icon .inner li.preview-item a span,div.sd-social-icon ul.preview li.preview-item a span{display:none}div.sd-social-icon ul.preview li.preview-item.preview-custom a span{display:inline-block}.services .preview li.share-custom a{text-decoration:none}.services ul li.end-fix{clear:both;float:none;visibility:hidden;padding:0;margin:0;height:20px;width:0}#enabled-services h2{font-size:20px;padding-top:0;font-weight:400!important;color:#999}body.settings_page_sharing #live-preview h2{font-size:20px;font-weight:400!important;color:#e3e3e3}body.settings_page_sharing .clearing{clear:both}body.settings_page_sharing .options .options-left{float:left}body.settings_page_sharing .input label{font-size:11px;line-height:16px}body.settings_page_sharing .advanced-form{padding:10px 14px 8px 10px;margin-left:-24px;display:none;border-top:1px #e3e3e3 solid;margin-top:4px}body.settings_page_sharing .utility{float:right;padding-top:10px;padding-right:10px;font-size:10px}body.settings_page_sharing .advanced input[type=submit]{float:left;margin-top:10px;margin-right:10px}.services li.dropzone{border:1px dashed #999;border-radius:3px;background:#e3e3e3;margin-right:10px;padding:5px;height:18px}.advanced-form .form-table th{width:auto!important}.advanced-form .button-secondary{margin-top:0!important}#hidden-drop-target{background:#e1e1e1;border:1px solid #cdcdcd;width:29%;padding:10px;vertical-align:top}#hidden-drop-target p{font-size:13px;font-style:italic;margin:0 0 10px}.preview li.preview-item{background-position:0 5px;cursor:default}.preview .option-smart-on{margin:3px 5px 0 0}.preview-digg .option-smart-on{background:url(images/smart-digg.png) top left/76px 17px no-repeat;width:76px;height:17px;margin-top:2px}.preview-reddit .option-smart-on{background:url(images/smart-reddit.png) top left/104px 21px no-repeat;width:104px;height:21px}.preview-stumbleupon .option-smart-on{background:url(images/smart-stumbleupon.png) top left/74px 18px no-repeat;width:74px;height:18px;margin-top:1px}.preview-facebook .option-smart-on{background:url(images/smart-like.png) top left/85px 20px no-repeat;width:85px;height:20px}.preview-twitter .option-smart-on{background:url(images/smart-twitter.png?1) top left/92px 20px no-repeat;width:92px;height:20px}.preview-linkedin .option-smart-on{background:url(images/linkedin-smart.png) top center/99px 18px no-repeat;width:99px;height:18px;margin-top:1px}.preview-google-plus-1 .option-smart-on{background:url(images/smart-googleplus1.png) top left/96px 20px no-repeat;width:96px;height:20px}.preview-tumblr .option-smart-on{background:url(images/smart-tumblr.png) top left/62px 20px no-repeat;width:62px;height:20px}.preview-pinterest .option-smart-on{background:url(images/smart-pinterest.png) top left/39px 20px no-repeat;width:39px;height:20px}.preview-pocket .option-smart-on{background:url(images/smart-pocket.png) top left/60px 20px no-repeat;width:60px;height:20px}.services .sharing-hidden li{background-color:transparent}.sharing-hidden li.share-end{clear:both;height:0;padding:0!important;margin:0!important;width:0;visibility:hidden;float:none}.preview .sharing-label{font-weight:700;border:0;padding:4px 6px 0 0}#services-config a.remove{background:#ddd;color:#fff;padding:0 4px 2px;border-radius:15px;-moz-border-radius:15px;-webkit-border-radius:15px;text-decoration:none;font-weight:700;font-size:10px}#services-config a.remove:hover{background:red}.sd-social-icon .inner a.sd-button span,.sd-social-icon .inner a.share-icon span{display:inline-block;overflow:hidden;width:0;text-indent:100%} \ No newline at end of file
diff --git a/plugins/jetpack/modules/sharedaddy/images/after-the-deadline@2x.png b/plugins/jetpack/modules/sharedaddy/images/after-the-deadline@2x.png
index 8c5858c0..d06bd260 100644
--- a/plugins/jetpack/modules/sharedaddy/images/after-the-deadline@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/after-the-deadline@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/comments@2x.png b/plugins/jetpack/modules/sharedaddy/images/comments@2x.png
index 7558243c..f1c8fbf9 100644
--- a/plugins/jetpack/modules/sharedaddy/images/comments@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/comments@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/contact-form@2x.png b/plugins/jetpack/modules/sharedaddy/images/contact-form@2x.png
index 504450fd..2c38752c 100644
--- a/plugins/jetpack/modules/sharedaddy/images/contact-form@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/contact-form@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/custom.png b/plugins/jetpack/modules/sharedaddy/images/custom.png
index 6d2f495e..46adefa4 100644
--- a/plugins/jetpack/modules/sharedaddy/images/custom.png
+++ b/plugins/jetpack/modules/sharedaddy/images/custom.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/custom@2x.png b/plugins/jetpack/modules/sharedaddy/images/custom@2x.png
index 57521606..9bbfcfb6 100644
--- a/plugins/jetpack/modules/sharedaddy/images/custom@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/custom@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/designfloat.png b/plugins/jetpack/modules/sharedaddy/images/designfloat.png
index 62e8f32d..e2110bcc 100644
--- a/plugins/jetpack/modules/sharedaddy/images/designfloat.png
+++ b/plugins/jetpack/modules/sharedaddy/images/designfloat.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/digg.png b/plugins/jetpack/modules/sharedaddy/images/digg.png
index 8524fa53..dc98382c 100644
--- a/plugins/jetpack/modules/sharedaddy/images/digg.png
+++ b/plugins/jetpack/modules/sharedaddy/images/digg.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/digg@2x.png b/plugins/jetpack/modules/sharedaddy/images/digg@2x.png
index db79f166..f9bd8a74 100644
--- a/plugins/jetpack/modules/sharedaddy/images/digg@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/digg@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/divider.png b/plugins/jetpack/modules/sharedaddy/images/divider.png
index 709e7f97..00f427ad 100644
--- a/plugins/jetpack/modules/sharedaddy/images/divider.png
+++ b/plugins/jetpack/modules/sharedaddy/images/divider.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/divider@2x.png b/plugins/jetpack/modules/sharedaddy/images/divider@2x.png
index 1c985389..901cf653 100644
--- a/plugins/jetpack/modules/sharedaddy/images/divider@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/divider@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/draggy.png b/plugins/jetpack/modules/sharedaddy/images/draggy.png
index fcdd3989..b4633d29 100644
--- a/plugins/jetpack/modules/sharedaddy/images/draggy.png
+++ b/plugins/jetpack/modules/sharedaddy/images/draggy.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/draggy@2x.png b/plugins/jetpack/modules/sharedaddy/images/draggy@2x.png
index 03c3ee91..133483ad 100644
--- a/plugins/jetpack/modules/sharedaddy/images/draggy@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/draggy@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/email.png b/plugins/jetpack/modules/sharedaddy/images/email.png
index e7f69f6d..6753619a 100644
--- a/plugins/jetpack/modules/sharedaddy/images/email.png
+++ b/plugins/jetpack/modules/sharedaddy/images/email.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/email@2x.png b/plugins/jetpack/modules/sharedaddy/images/email@2x.png
index 13f658c2..6a6f70d2 100644
--- a/plugins/jetpack/modules/sharedaddy/images/email@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/email@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/ember.png b/plugins/jetpack/modules/sharedaddy/images/ember.png
index 4ab956e0..47461ece 100644
--- a/plugins/jetpack/modules/sharedaddy/images/ember.png
+++ b/plugins/jetpack/modules/sharedaddy/images/ember.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/enhanced-distribution@2x.png b/plugins/jetpack/modules/sharedaddy/images/enhanced-distribution@2x.png
index 59912d76..694dba27 100644
--- a/plugins/jetpack/modules/sharedaddy/images/enhanced-distribution@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/enhanced-distribution@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/feed.png b/plugins/jetpack/modules/sharedaddy/images/feed.png
index b0f72ffe..9eeeffd3 100644
--- a/plugins/jetpack/modules/sharedaddy/images/feed.png
+++ b/plugins/jetpack/modules/sharedaddy/images/feed.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/googleplus1.png b/plugins/jetpack/modules/sharedaddy/images/googleplus1.png
index a2963ece..7f07e5bc 100644
--- a/plugins/jetpack/modules/sharedaddy/images/googleplus1.png
+++ b/plugins/jetpack/modules/sharedaddy/images/googleplus1.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/googleplus1@2x.png b/plugins/jetpack/modules/sharedaddy/images/googleplus1@2x.png
index 6f59661d..41c0096f 100644
--- a/plugins/jetpack/modules/sharedaddy/images/googleplus1@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/googleplus1@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/icon-facebook-2x.png b/plugins/jetpack/modules/sharedaddy/images/icon-facebook-2x.png
index faed26b0..3f2723fa 100644
--- a/plugins/jetpack/modules/sharedaddy/images/icon-facebook-2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/icon-facebook-2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/icon-facebook.png b/plugins/jetpack/modules/sharedaddy/images/icon-facebook.png
index 8b5ce251..bb9edab4 100644
--- a/plugins/jetpack/modules/sharedaddy/images/icon-facebook.png
+++ b/plugins/jetpack/modules/sharedaddy/images/icon-facebook.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/icon-googleplus-2x.png b/plugins/jetpack/modules/sharedaddy/images/icon-googleplus-2x.png
new file mode 100644
index 00000000..60dd1c03
--- /dev/null
+++ b/plugins/jetpack/modules/sharedaddy/images/icon-googleplus-2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/icon-googleplus.png b/plugins/jetpack/modules/sharedaddy/images/icon-googleplus.png
new file mode 100644
index 00000000..ee687af1
--- /dev/null
+++ b/plugins/jetpack/modules/sharedaddy/images/icon-googleplus.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/icon-twitter-2x.png b/plugins/jetpack/modules/sharedaddy/images/icon-twitter-2x.png
index 85f2f34c..a9a90141 100644
--- a/plugins/jetpack/modules/sharedaddy/images/icon-twitter-2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/icon-twitter-2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/icon-wordpress-2x.png b/plugins/jetpack/modules/sharedaddy/images/icon-wordpress-2x.png
index 4d81cabc..23439d93 100644
--- a/plugins/jetpack/modules/sharedaddy/images/icon-wordpress-2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/icon-wordpress-2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/icon-wordpress.png b/plugins/jetpack/modules/sharedaddy/images/icon-wordpress.png
index 86f1bd35..1ff384a0 100644
--- a/plugins/jetpack/modules/sharedaddy/images/icon-wordpress.png
+++ b/plugins/jetpack/modules/sharedaddy/images/icon-wordpress.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/kindle.png b/plugins/jetpack/modules/sharedaddy/images/kindle.png
index 4756d459..a8b235c6 100644
--- a/plugins/jetpack/modules/sharedaddy/images/kindle.png
+++ b/plugins/jetpack/modules/sharedaddy/images/kindle.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/kindle@2x.png b/plugins/jetpack/modules/sharedaddy/images/kindle@2x.png
index 66fa00f8..dfbcbec3 100644
--- a/plugins/jetpack/modules/sharedaddy/images/kindle@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/kindle@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/linkedin-horizontal.png b/plugins/jetpack/modules/sharedaddy/images/linkedin-horizontal.png
index 92816042..a55a3e60 100644
--- a/plugins/jetpack/modules/sharedaddy/images/linkedin-horizontal.png
+++ b/plugins/jetpack/modules/sharedaddy/images/linkedin-horizontal.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/linkedin-horizontal@2x.png b/plugins/jetpack/modules/sharedaddy/images/linkedin-horizontal@2x.png
index f8402fb6..cd400275 100644
--- a/plugins/jetpack/modules/sharedaddy/images/linkedin-horizontal@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/linkedin-horizontal@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/linkedin-nocount.png b/plugins/jetpack/modules/sharedaddy/images/linkedin-nocount.png
index 4a09a2d1..a5d4baeb 100644
--- a/plugins/jetpack/modules/sharedaddy/images/linkedin-nocount.png
+++ b/plugins/jetpack/modules/sharedaddy/images/linkedin-nocount.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/linkedin-nocount@2x.png b/plugins/jetpack/modules/sharedaddy/images/linkedin-nocount@2x.png
index f995d57a..ad599e67 100644
--- a/plugins/jetpack/modules/sharedaddy/images/linkedin-nocount@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/linkedin-nocount@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/linkedin-smart.png b/plugins/jetpack/modules/sharedaddy/images/linkedin-smart.png
index 92816042..a55a3e60 100644
--- a/plugins/jetpack/modules/sharedaddy/images/linkedin-smart.png
+++ b/plugins/jetpack/modules/sharedaddy/images/linkedin-smart.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/linkedin-smart@2x.png b/plugins/jetpack/modules/sharedaddy/images/linkedin-smart@2x.png
index f8402fb6..cd400275 100644
--- a/plugins/jetpack/modules/sharedaddy/images/linkedin-smart@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/linkedin-smart@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/linkedin-vertical.png b/plugins/jetpack/modules/sharedaddy/images/linkedin-vertical.png
index c5edb5e2..24bc27d4 100644
--- a/plugins/jetpack/modules/sharedaddy/images/linkedin-vertical.png
+++ b/plugins/jetpack/modules/sharedaddy/images/linkedin-vertical.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/linkedin-vertical@2x.png b/plugins/jetpack/modules/sharedaddy/images/linkedin-vertical@2x.png
index 06dcf8bc..3e6216e5 100644
--- a/plugins/jetpack/modules/sharedaddy/images/linkedin-vertical@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/linkedin-vertical@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/linkedin.png b/plugins/jetpack/modules/sharedaddy/images/linkedin.png
index 79e3570c..ee860f7f 100644
--- a/plugins/jetpack/modules/sharedaddy/images/linkedin.png
+++ b/plugins/jetpack/modules/sharedaddy/images/linkedin.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/linkedin@2x.png b/plugins/jetpack/modules/sharedaddy/images/linkedin@2x.png
index b626250b..7139d05f 100644
--- a/plugins/jetpack/modules/sharedaddy/images/linkedin@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/linkedin@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/more.png b/plugins/jetpack/modules/sharedaddy/images/more.png
index efe3bc7c..eb5bb625 100644
--- a/plugins/jetpack/modules/sharedaddy/images/more.png
+++ b/plugins/jetpack/modules/sharedaddy/images/more.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/more@2x.png b/plugins/jetpack/modules/sharedaddy/images/more@2x.png
index a55e8e79..931e9caf 100644
--- a/plugins/jetpack/modules/sharedaddy/images/more@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/more@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/pinterest.png b/plugins/jetpack/modules/sharedaddy/images/pinterest.png
index cd5e6940..d170d748 100644
--- a/plugins/jetpack/modules/sharedaddy/images/pinterest.png
+++ b/plugins/jetpack/modules/sharedaddy/images/pinterest.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/pinterest@2x.png b/plugins/jetpack/modules/sharedaddy/images/pinterest@2x.png
index 5efebd91..5229524f 100644
--- a/plugins/jetpack/modules/sharedaddy/images/pinterest@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/pinterest@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/pocket.png b/plugins/jetpack/modules/sharedaddy/images/pocket.png
index e6e11849..cba4e662 100644
--- a/plugins/jetpack/modules/sharedaddy/images/pocket.png
+++ b/plugins/jetpack/modules/sharedaddy/images/pocket.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/pocket@2x.png b/plugins/jetpack/modules/sharedaddy/images/pocket@2x.png
index 72fdbfe3..2512c887 100644
--- a/plugins/jetpack/modules/sharedaddy/images/pocket@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/pocket@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/print.png b/plugins/jetpack/modules/sharedaddy/images/print.png
index 5f4c53ba..71fa6bf6 100644
--- a/plugins/jetpack/modules/sharedaddy/images/print.png
+++ b/plugins/jetpack/modules/sharedaddy/images/print.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/print@2x.png b/plugins/jetpack/modules/sharedaddy/images/print@2x.png
index 7fa0c2a2..bb6b4027 100644
--- a/plugins/jetpack/modules/sharedaddy/images/print@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/print@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/reddit.png b/plugins/jetpack/modules/sharedaddy/images/reddit.png
index 25a849f8..d6644565 100644
--- a/plugins/jetpack/modules/sharedaddy/images/reddit.png
+++ b/plugins/jetpack/modules/sharedaddy/images/reddit.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/reddit@2x.png b/plugins/jetpack/modules/sharedaddy/images/reddit@2x.png
index 03d005ae..11a3f2c3 100644
--- a/plugins/jetpack/modules/sharedaddy/images/reddit@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/reddit@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/rss.png b/plugins/jetpack/modules/sharedaddy/images/rss.png
index 0f06c7f1..7c92968f 100644
--- a/plugins/jetpack/modules/sharedaddy/images/rss.png
+++ b/plugins/jetpack/modules/sharedaddy/images/rss.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/rss@2x.png b/plugins/jetpack/modules/sharedaddy/images/rss@2x.png
index 812b9098..f007bf2e 100644
--- a/plugins/jetpack/modules/sharedaddy/images/rss@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/rss@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/share-bg.png b/plugins/jetpack/modules/sharedaddy/images/share-bg.png
index bfd196ff..03c2d2bd 100644
--- a/plugins/jetpack/modules/sharedaddy/images/share-bg.png
+++ b/plugins/jetpack/modules/sharedaddy/images/share-bg.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/sharing-hidden.png b/plugins/jetpack/modules/sharedaddy/images/sharing-hidden.png
index c87f825e..3458c7bd 100644
--- a/plugins/jetpack/modules/sharedaddy/images/sharing-hidden.png
+++ b/plugins/jetpack/modules/sharedaddy/images/sharing-hidden.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/sharing-hidden@2x.png b/plugins/jetpack/modules/sharedaddy/images/sharing-hidden@2x.png
index c8129fbc..5924c4af 100644
--- a/plugins/jetpack/modules/sharedaddy/images/sharing-hidden@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/sharing-hidden@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/smart-digg.png b/plugins/jetpack/modules/sharedaddy/images/smart-digg.png
index 8753421c..6f564b7d 100644
--- a/plugins/jetpack/modules/sharedaddy/images/smart-digg.png
+++ b/plugins/jetpack/modules/sharedaddy/images/smart-digg.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/smart-digg@2x.png b/plugins/jetpack/modules/sharedaddy/images/smart-digg@2x.png
index 1a76fd5e..6468a53e 100644
--- a/plugins/jetpack/modules/sharedaddy/images/smart-digg@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/smart-digg@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/smart-facebook.png b/plugins/jetpack/modules/sharedaddy/images/smart-facebook.png
index 18de01f7..799e0986 100644
--- a/plugins/jetpack/modules/sharedaddy/images/smart-facebook.png
+++ b/plugins/jetpack/modules/sharedaddy/images/smart-facebook.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/smart-facebook@2x.png b/plugins/jetpack/modules/sharedaddy/images/smart-facebook@2x.png
index 7fa8606c..bc277c2f 100644
--- a/plugins/jetpack/modules/sharedaddy/images/smart-facebook@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/smart-facebook@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/smart-googleplus1.png b/plugins/jetpack/modules/sharedaddy/images/smart-googleplus1.png
index 13e257fa..8fd1a836 100644
--- a/plugins/jetpack/modules/sharedaddy/images/smart-googleplus1.png
+++ b/plugins/jetpack/modules/sharedaddy/images/smart-googleplus1.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/smart-googleplus1@2x.png b/plugins/jetpack/modules/sharedaddy/images/smart-googleplus1@2x.png
index 5bbb092b..1708c484 100644
--- a/plugins/jetpack/modules/sharedaddy/images/smart-googleplus1@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/smart-googleplus1@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/smart-like.png b/plugins/jetpack/modules/sharedaddy/images/smart-like.png
index e1ac8263..368a6c11 100644
--- a/plugins/jetpack/modules/sharedaddy/images/smart-like.png
+++ b/plugins/jetpack/modules/sharedaddy/images/smart-like.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/smart-like@2x.png b/plugins/jetpack/modules/sharedaddy/images/smart-like@2x.png
index 4b99fa57..7ad4d638 100644
--- a/plugins/jetpack/modules/sharedaddy/images/smart-like@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/smart-like@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/smart-pinterest.png b/plugins/jetpack/modules/sharedaddy/images/smart-pinterest.png
index 16138cfc..ac78d5ad 100644
--- a/plugins/jetpack/modules/sharedaddy/images/smart-pinterest.png
+++ b/plugins/jetpack/modules/sharedaddy/images/smart-pinterest.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/smart-pinterest@2x.png b/plugins/jetpack/modules/sharedaddy/images/smart-pinterest@2x.png
index aab464d6..ea03b942 100644
--- a/plugins/jetpack/modules/sharedaddy/images/smart-pinterest@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/smart-pinterest@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/smart-pocket.png b/plugins/jetpack/modules/sharedaddy/images/smart-pocket.png
index 69721f79..4a368a35 100644
--- a/plugins/jetpack/modules/sharedaddy/images/smart-pocket.png
+++ b/plugins/jetpack/modules/sharedaddy/images/smart-pocket.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/smart-pocket@2x.png b/plugins/jetpack/modules/sharedaddy/images/smart-pocket@2x.png
index 9257926b..b84a0d90 100644
--- a/plugins/jetpack/modules/sharedaddy/images/smart-pocket@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/smart-pocket@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/smart-reddit.png b/plugins/jetpack/modules/sharedaddy/images/smart-reddit.png
index a8c4c6e6..5afa0aa6 100644
--- a/plugins/jetpack/modules/sharedaddy/images/smart-reddit.png
+++ b/plugins/jetpack/modules/sharedaddy/images/smart-reddit.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/smart-reddit@2x.png b/plugins/jetpack/modules/sharedaddy/images/smart-reddit@2x.png
index 5b1fa3eb..da4b569b 100644
--- a/plugins/jetpack/modules/sharedaddy/images/smart-reddit@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/smart-reddit@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/smart-stumbleupon@2x.png b/plugins/jetpack/modules/sharedaddy/images/smart-stumbleupon@2x.png
index 82f3b88c..a807aef8 100644
--- a/plugins/jetpack/modules/sharedaddy/images/smart-stumbleupon@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/smart-stumbleupon@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/smart-tumblr.png b/plugins/jetpack/modules/sharedaddy/images/smart-tumblr.png
index ca902bdc..147975e1 100644
--- a/plugins/jetpack/modules/sharedaddy/images/smart-tumblr.png
+++ b/plugins/jetpack/modules/sharedaddy/images/smart-tumblr.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/smart-tumblr@2x.png b/plugins/jetpack/modules/sharedaddy/images/smart-tumblr@2x.png
index e5b39877..b73b9a26 100644
--- a/plugins/jetpack/modules/sharedaddy/images/smart-tumblr@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/smart-tumblr@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/smart-twitter@2x.png b/plugins/jetpack/modules/sharedaddy/images/smart-twitter@2x.png
index fcf26f40..929bf63c 100644
--- a/plugins/jetpack/modules/sharedaddy/images/smart-twitter@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/smart-twitter@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/stumbleupon@2x.png b/plugins/jetpack/modules/sharedaddy/images/stumbleupon@2x.png
index 8e05201d..49e479fc 100644
--- a/plugins/jetpack/modules/sharedaddy/images/stumbleupon@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/stumbleupon@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/tumblr.png b/plugins/jetpack/modules/sharedaddy/images/tumblr.png
index cc4775c6..d248cd09 100644
--- a/plugins/jetpack/modules/sharedaddy/images/tumblr.png
+++ b/plugins/jetpack/modules/sharedaddy/images/tumblr.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/tumblr@2x.png b/plugins/jetpack/modules/sharedaddy/images/tumblr@2x.png
index 31ee7847..f991236c 100644
--- a/plugins/jetpack/modules/sharedaddy/images/tumblr@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/tumblr@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/twitter@2x.png b/plugins/jetpack/modules/sharedaddy/images/twitter@2x.png
index cd4a0967..aa666e66 100644
--- a/plugins/jetpack/modules/sharedaddy/images/twitter@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/twitter@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/wordpress.png b/plugins/jetpack/modules/sharedaddy/images/wordpress.png
index c07bdb72..94e92823 100644
--- a/plugins/jetpack/modules/sharedaddy/images/wordpress.png
+++ b/plugins/jetpack/modules/sharedaddy/images/wordpress.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/images/wordpress@2x.png b/plugins/jetpack/modules/sharedaddy/images/wordpress@2x.png
index 563b5cbc..2da25ffc 100644
--- a/plugins/jetpack/modules/sharedaddy/images/wordpress@2x.png
+++ b/plugins/jetpack/modules/sharedaddy/images/wordpress@2x.png
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/screenshot-1.jpg b/plugins/jetpack/modules/sharedaddy/screenshot-1.jpg
index ec13343c..dd4becc7 100644
--- a/plugins/jetpack/modules/sharedaddy/screenshot-1.jpg
+++ b/plugins/jetpack/modules/sharedaddy/screenshot-1.jpg
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/screenshot-2.jpg b/plugins/jetpack/modules/sharedaddy/screenshot-2.jpg
index 2679d8b5..dabb35e3 100644
--- a/plugins/jetpack/modules/sharedaddy/screenshot-2.jpg
+++ b/plugins/jetpack/modules/sharedaddy/screenshot-2.jpg
Binary files differ
diff --git a/plugins/jetpack/modules/sharedaddy/sharedaddy.php b/plugins/jetpack/modules/sharedaddy/sharedaddy.php
index cefecf75..56b1cd41 100644
--- a/plugins/jetpack/modules/sharedaddy/sharedaddy.php
+++ b/plugins/jetpack/modules/sharedaddy/sharedaddy.php
@@ -11,15 +11,65 @@ Plugin URI: http://en.blog.wordpress.com/2010/08/24/more-ways-to-share/
require_once plugin_dir_path( __FILE__ ).'sharing.php';
function sharing_email_send_post( $data ) {
- $content = sprintf( __( '%1$s (%2$s) thinks you may be interested in the following post:'."\n\n", 'jetpack' ), $data['name'], $data['source'] );
+
+ $content = sharing_email_send_post_content( $data );
+ $headers[] = sprintf( 'From: %1$s <%2$s>', $data['name'], $data['source'] );
+
+ wp_mail( $data['target'], '['.__( 'Shared Post', 'jetpack' ).'] '.$data['post']->post_title, $content, $headers );
+}
+
+
+/* Checks for spam using akismet if available. */
+/* Return $data as it if email about to be send out is not spam. */
+function sharing_email_check_for_spam_via_akismet( $data ) {
+
+ if ( ! function_exists( 'akismet_http_post' ) && ! method_exists( 'Akismet', 'http_post' ) )
+ return $data;
+
+ // Prepare the body_request for akismet
+ $body_request = array(
+ 'blog' => get_option( 'home' ),
+ 'permalink' => get_permalink( $data['post']->ID ),
+ 'comment_type' => 'share',
+ 'comment_author' => $data['name'],
+ 'comment_author_email' => $data['source'],
+ 'comment_content' => sharing_email_send_post_content( $data ),
+ 'user_agent' => ( isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : null ),
+ );
+
+ if ( method_exists( 'Akismet', 'http_post' ) ) {
+ $body_request['user_ip'] = Akismet::get_ip_address();
+ $response = Akismet::http_post( build_query( $body_request ), 'comment-check' );
+ } else {
+ global $akismet_api_host, $akismet_api_port;
+ $body_request['user_ip'] = ( isset( $_SERVER['REMOTE_ADDR'] ) ? $_SERVER['REMOTE_ADDR'] : null );
+ $response = akismet_http_post( build_query( $body_request ), $akismet_api_host, '/1.1/comment-check', $akismet_api_port );
+ }
+
+ // The Response is spam lets not send the email.
+ if ( ! empty( $response ) && isset( $response[1] ) && 'true' == trim( $response[1] ) ) { // 'true' is spam
+ return false; // don't send the email
+ }
+ return $data;
+}
+
+function sharing_email_send_post_content( $data ) {
+ $content = sprintf( __( '%1$s (%2$s) thinks you may be interested in the following post:', 'jetpack' ), $data['name'], $data['source'] );
+ $content .= "\n\n";
$content .= $data['post']->post_title."\n";
$content .= get_permalink( $data['post']->ID )."\n";
-
- wp_mail( $data['target'], '['.__( 'Shared Post', 'jetpack' ).'] '.$data['post']->post_title, $content );
+ return $content;
}
function sharing_add_meta_box() {
$post_types = get_post_types( array( 'public' => true ) );
+ /**
+ * Filter the Sharing Meta Box title.
+ *
+ * @since 2.2.0
+ *
+ * @param string $var Sharing Meta Box title. Default is "Sharing".
+ */
$title = apply_filters( 'sharing_meta_box_title', __( 'Sharing', 'jetpack' ) );
foreach( $post_types as $post_type ) {
add_meta_box( 'sharing_meta', $title, 'sharing_meta_box_content', $post_type, 'advanced', 'high' );
@@ -27,6 +77,13 @@ function sharing_add_meta_box() {
}
function sharing_meta_box_content( $post ) {
+ /**
+ * Fires before the sharing meta box content.
+ *
+ * @since 2.2.0
+ *
+ * @param WP_Post $post The post to share.
+ */
do_action( 'start_sharing_meta_box_content', $post );
$disabled = get_post_meta( $post->ID, 'sharing_disabled', true ); ?>
@@ -40,6 +97,13 @@ function sharing_meta_box_content( $post ) {
</p>
<?php
+ /**
+ * Fires after the sharing meta box content.
+ *
+ * @since 2.2.0
+ *
+ * @param WP_Post $post The post to share.
+ */
do_action( 'end_sharing_meta_box_content', $post );
}
@@ -48,7 +112,7 @@ function sharing_meta_box_save( $post_id ) {
return $post_id;
// Record sharing disable
- if ( isset( $_POST['post_type'] ) && ( 'post' == $_POST['post_type'] || 'page' == $_POST['post_type'] ) ) {
+ if ( isset( $_POST['post_type'] ) && ( $post_type_object = get_post_type_object( $_POST['post_type'] ) ) && $post_type_object->public ) {
if ( current_user_can( 'edit_post', $post_id ) ) {
if ( isset( $_POST['sharing_status_hidden'] ) ) {
if ( !isset( $_POST['enable_post_sharing'] ) ) {
@@ -88,7 +152,7 @@ function sharing_add_plugin_settings($links, $file) {
}
function sharing_restrict_to_single( $services ) {
- // This removes Press This from non-multisite blogs - doesnt make much sense
+ // This removes Press This from non-multisite blogs - doesn't make much sense
if ( is_multisite() === false ) {
unset( $services['press-this'] );
}
@@ -139,6 +203,7 @@ add_action( 'init', 'sharing_init' );
add_action( 'admin_init', 'sharing_add_meta_box' );
add_action( 'save_post', 'sharing_meta_box_save' );
add_action( 'sharing_email_send_post', 'sharing_email_send_post' );
+add_filter( 'sharing_email_can_send', 'sharing_email_check_for_spam_via_akismet' );
add_action( 'sharing_global_options', 'sharing_global_resources', 30 );
add_action( 'sharing_admin_update', 'sharing_global_resources_save' );
add_filter( 'sharing_services', 'sharing_restrict_to_single' );
@@ -148,4 +213,4 @@ add_filter( 'plugin_row_meta', 'sharing_add_plugin_settings', 10, 2 );
if ( defined( 'RECAPTCHA_PRIVATE_KEY' ) ) {
add_action( 'sharing_email_dialog', 'sharing_email_dialog' );
add_filter( 'sharing_email_check', 'sharing_email_check', 10, 3 );
-} \ No newline at end of file
+}
diff --git a/plugins/jetpack/modules/sharedaddy/sharing-service.php b/plugins/jetpack/modules/sharedaddy/sharing-service.php
index 80f4d8de..2f992d72 100644
--- a/plugins/jetpack/modules/sharedaddy/sharing-service.php
+++ b/plugins/jetpack/modules/sharedaddy/sharing-service.php
@@ -39,12 +39,13 @@ class Sharing_Service {
/**
* Gets a list of all available service names and classes
*/
- private function get_all_services() {
+ public function get_all_services( $include_custom = true ) {
// Default services
+ // if you update this list, please update the REST API tests
+ // in bin/tests/api/suites/SharingTest.php
$services = array(
'email' => 'Share_Email',
'print' => 'Share_Print',
- 'digg' => 'Share_Digg',
'facebook' => 'Share_Facebook',
'linkedin' => 'Share_LinkedIn',
'reddit' => 'Share_Reddit',
@@ -57,12 +58,21 @@ class Sharing_Service {
'pocket' => 'Share_Pocket',
);
- // Add any custom services in
- $options = $this->get_global_options();
- foreach ( (array)$options['custom'] AS $custom_id ) {
- $services[$custom_id] = 'Share_Custom';
+ if ( $include_custom ) {
+ // Add any custom services in
+ $options = $this->get_global_options();
+ foreach ( (array) $options['custom'] AS $custom_id ) {
+ $services[$custom_id] = 'Share_Custom';
+ }
}
+ /**
+ * Filters the list of available Sharing Services.
+ *
+ * @since 1.1.0
+ *
+ * @param array $services Array of all available Sharing Services.
+ */
return apply_filters( 'sharing_services', $services );
}
@@ -81,6 +91,9 @@ class Sharing_Service {
// Add a new custom service
$options['global']['custom'][] = $service_id;
+ if ( false !== $this->global ) {
+ $this->global['custom'][] = $service_id;
+ }
update_option( 'sharing-options', $options );
@@ -120,6 +133,21 @@ class Sharing_Service {
// Ensure we don't have the same ones in hidden and visible
$hidden = array_diff( $hidden, $visible );
+ /**
+ * Control the state of the list of sharing services.
+ *
+ * @since 1.1.0
+ *
+ * @param array $args {
+ * Array of options describing the state of the sharing services.
+ *
+ * @type array $services List of all available service names and classes.
+ * @type array $available Validated list of all available service names and classes.
+ * @type array $hidden List of services hidden behind a "More" button.
+ * @type array $visible List of visible services.
+ * @type array $this->get_blog_services() Array of Sharing Services currently enabled.
+ * }
+ */
do_action( 'sharing_get_services_state', array(
'services' => $services,
'available' => $available,
@@ -142,12 +170,19 @@ class Sharing_Service {
$global = $options['global'];
// Default services
- if ( !is_array( $enabled ) ) {
+ if ( ! is_array( $enabled ) ) {
$enabled = array(
'visible' => array(),
'hidden' => array()
);
+ /**
+ * Filters the list of default Sharing Services.
+ *
+ * @since 1.1.0
+ *
+ * @param array $enabled Array of default Sharing Services.
+ */
$enabled = apply_filters( 'sharing_default_services', $enabled );
}
@@ -166,6 +201,13 @@ class Sharing_Service {
}
}
+ /**
+ * Filters the list of enabled Sharing Services.
+ *
+ * @since 1.1.0
+ *
+ * @param array $blog Array of enabled Sharing Services.
+ */
$blog = apply_filters( 'sharing_services_enabled', $blog );
// Add CSS for NASCAR
@@ -198,13 +240,20 @@ class Sharing_Service {
// Defaults
$options['global'] = array(
- 'button_style' => 'icon-text',
+ 'button_style' => 'icon',
'sharing_label' => $this->default_sharing_label,
'open_links' => 'same',
- 'show' => array( 'post', 'page' ),
+ 'show' => array(),
'custom' => isset( $options['global']['custom'] ) ? $options['global']['custom'] : array()
);
+ /**
+ * Filters global sharing settings.
+ *
+ * @since 1.1.0
+ *
+ * @param array $options['global'] Array of global sharing settings.
+ */
$options['global'] = apply_filters( 'sharing_default_global', $options['global'] );
// Validate options and set from our data
@@ -242,8 +291,6 @@ class Sharing_Service {
if ( $data['show'] = array_intersect( $data['show'], $shows ) ) {
$options['global']['show'] = $data['show'];
}
- } else {
- $options['global']['show'] = array();
}
update_option( 'sharing-options', $options );
@@ -288,9 +335,23 @@ class Sharing_Service {
$options = get_option( 'sharing-options' );
// No options yet
- if ( !is_array( $options ) )
+ if ( ! is_array( $options ) ) {
$options = array();
+ }
+ /**
+ * Get the state of a sharing button.
+ *
+ * @since 1.1.0
+ *
+ * @param array $args {
+ * State of a sharing button.
+ *
+ * @type string $id Service ID.
+ * @type array $options Array of all sharing options.
+ * @type array $service Details about a service.
+ * }
+ */
do_action( 'sharing_get_button_state', array( 'id' => $id, 'options' => $options, 'service' => $service ) );
$options[$id] = $service->get_options();
@@ -400,26 +461,66 @@ function sharing_register_post_for_share_counts( $post_id ) {
$jetpack_sharing_counts[ (int) $post_id ] = get_permalink( $post_id );
}
+function sharing_maybe_enqueue_scripts() {
+ $sharer = new Sharing_Service();
+ $global_options = $sharer->get_global_options();
+
+ $enqueue = false;
+ if ( is_singular() && in_array( get_post_type(), $global_options['show'] ) ) {
+ $enqueue = true;
+ } elseif ( in_array( 'index', $global_options['show'] ) && ( is_home() || is_front_page() || is_archive() || is_search() || in_array( get_post_type(), $global_options['show'] ) ) ) {
+ $enqueue = true;
+ }
+
+ /**
+ * Filter to decide when sharing scripts should be enqueued.
+ *
+ * @since 3.2.0
+ *
+ * @param bool $enqueue Decide if the sharing scripts should be enqueued.
+ */
+ return (bool) apply_filters( 'sharing_enqueue_scripts', $enqueue );
+}
+
function sharing_add_footer() {
global $jetpack_sharing_counts;
- if ( apply_filters( 'sharing_js', true ) ) {
-
- if ( is_array( $jetpack_sharing_counts ) && count( $jetpack_sharing_counts ) ) :
+ /**
+ * Filter all Javascript output by the sharing module.
+ *
+ * @since 1.1.0
+ *
+ * @param bool true Control whether the sharing module should add any Javascript to the site. Default to true.
+ */
+ if ( apply_filters( 'sharing_js', true ) && sharing_maybe_enqueue_scripts() ) {
+
+ /**
+ * Filter the display of sharing counts next to the sharing buttons.
+ *
+ * @since 3.2.0
+ *
+ * @param bool true Control the display of counters next to the sharing buttons. Default to true.
+ */
+ if ( apply_filters( 'jetpack_sharing_counts', true ) && is_array( $jetpack_sharing_counts ) && count( $jetpack_sharing_counts ) ) :
$sharing_post_urls = array_filter( $jetpack_sharing_counts );
if ( $sharing_post_urls ) :
?>
<script type="text/javascript">
- WPCOM_sharing_counts = <?php echo json_encode( array_flip( $sharing_post_urls ) ); ?>
+ window.WPCOM_sharing_counts = <?php echo json_encode( array_flip( $sharing_post_urls ) ); ?>;
+ window.WPCOM_site_ID = <?php echo defined( 'IS_WPCOM' ) && IS_WPCOM ? get_current_blog_id() : Jetpack_Options::get_option( 'id', 0 ); ?>;
</script>
<?php
endif;
endif;
wp_enqueue_script( 'sharing-js' );
- $recaptcha__options = array( 'lang' => get_base_recaptcha_lang_code() );
- wp_localize_script('sharing-js', 'recaptcha_options', $recaptcha__options);
+ $sharing_js_options = array(
+ 'lang' => get_base_recaptcha_lang_code(),
+ /** This filter is documented in modules/sharedaddy/sharing-service.php */
+ 'counts' => apply_filters( 'jetpack_sharing_counts', true )
+ );
+ wp_localize_script( 'sharing-js', 'sharing_js_options', $sharing_js_options);
}
$sharer = new Sharing_Service();
@@ -437,8 +538,16 @@ function sharing_add_header() {
$service->display_header();
}
- if ( count( $enabled['all'] ) > 0 )
- wp_enqueue_style( 'sharedaddy', plugin_dir_url( __FILE__ ) .'sharing.css', array(), JETPACK__VERSION );
+ if ( count( $enabled['all'] ) > 0 && sharing_maybe_enqueue_scripts() ) {
+ // @todo: Remove this opt-out filter in the future
+ if ( ( ! defined( 'IS_WPCOM' ) ) || ( ! IS_WPCOM ) || apply_filters( 'wpl_sharing_2014_1', true ) ) {
+ wp_enqueue_style( 'sharedaddy', plugin_dir_url( __FILE__ ) .'sharing.css', array(), JETPACK__VERSION );
+ wp_enqueue_style( 'genericons' );
+ } else {
+ wp_enqueue_style( 'sharedaddy', plugin_dir_url( __FILE__ ) .'sharing-legacy.css', array(), JETPACK__VERSION );
+ }
+ }
+
}
add_action( 'wp_head', 'sharing_add_header', 1 );
@@ -463,7 +572,7 @@ function sharing_display( $text = '', $echo = false ) {
if ( empty( $post ) )
return $text;
- if ( is_preview() ) {
+ if ( is_preview() || is_admin() ) {
return $text;
}
@@ -503,12 +612,19 @@ function sharing_display( $text = '', $echo = false ) {
if ( !is_feed() ) {
if ( is_singular() && in_array( get_post_type(), $global['show'] ) ) {
$show = true;
- } elseif ( in_array( 'index', $global['show'] ) && ( is_home() || is_archive() || is_search() ) ) {
+ } elseif ( in_array( 'index', $global['show'] ) && ( is_home() || is_archive() || is_search() || in_array( get_post_type(), $global['show'] ) ) ) {
$show = true;
}
}
- // Pass through a filter for final say so
+ /**
+ * Filter to decide if sharing buttons should be displayed.
+ *
+ * @since 1.1.0
+ *
+ * @param
+ * @param WP_Post $post The post to share.
+ */
$show = apply_filters( 'sharing_show', $show, $post );
// Disabled for this post?
@@ -517,6 +633,13 @@ function sharing_display( $text = '', $echo = false ) {
if ( !empty( $switched_status ) )
$show = false;
+ // Private post?
+ $post_status = get_post_status( $post->ID );
+
+ if ( $post_status == 'private' ) {
+ $show = false;
+ }
+
// Allow to be used on P2 ajax requests for latest posts.
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && isset( $_REQUEST['action'] ) && 'get_latest_posts' == $_REQUEST['action'] )
$show = true;
@@ -524,6 +647,13 @@ function sharing_display( $text = '', $echo = false ) {
$sharing_content = '';
if ( $show ) {
+ /**
+ * Filters the list of enabled Sharing Services.
+ *
+ * @since 2.2.3
+ *
+ * @param array $sharer->get_blog_services() Array of Sharing Services currently enabled.
+ */
$enabled = apply_filters( 'sharing_enabled', $sharer->get_blog_services() );
if ( count( $enabled['all'] ) > 0 ) {
@@ -593,7 +723,12 @@ function sharing_display( $text = '', $echo = false ) {
$sharing_content .= '</div></div></div>';
// Register our JS
- wp_register_script( 'sharing-js', plugin_dir_url( __FILE__ ).'sharing.js', array( 'jquery' ), '20121205' );
+ if ( defined( 'JETPACK__VERSION' ) ) {
+ $ver = JETPACK__VERSION;
+ } else {
+ $ver = '20141212';
+ }
+ wp_register_script( 'sharing-js', plugin_dir_url( __FILE__ ).'sharing.js', array( 'jquery' ), $ver );
add_action( 'wp_footer', 'sharing_add_footer' );
}
}
diff --git a/plugins/jetpack/modules/sharedaddy/sharing-sources.php b/plugins/jetpack/modules/sharedaddy/sharing-sources.php
index 1599eba9..a047de35 100644
--- a/plugins/jetpack/modules/sharedaddy/sharing-sources.php
+++ b/plugins/jetpack/modules/sharedaddy/sharing-sources.php
@@ -3,18 +3,16 @@
abstract class Sharing_Source {
public $button_style;
public $smart;
- protected $open_links;
+ protected $open_link_in_new;
protected $id;
public function __construct( $id, array $settings ) {
$this->id = $id;
+ $this->open_link_in_new = apply_filters( 'jetpack_open_sharing_in_new_window', true );
if ( isset( $settings['button_style'] ) )
$this->button_style = $settings['button_style'];
- if ( isset( $settings['open_links'] ) )
- $this->open_links = $settings['open_links'];
-
if ( isset( $settings['smart'] ) )
$this->smart = $settings['smart'];
}
@@ -35,38 +33,60 @@ abstract class Sharing_Source {
return apply_filters( 'sharing_permalink', get_permalink( $post_id ), $post_id, $this->id );
}
+ public function get_share_title( $post_id ) {
+ $post = get_post( $post_id );
+ $title = apply_filters( 'sharing_title', $post->post_title, $post_id, $this->id );
+
+ return html_entity_decode( wp_kses( $title, null ) );
+ }
+
public function has_custom_button_style() {
return false;
}
public function get_link( $url, $text, $title, $query = '', $id = false ) {
+ $args = func_get_args();
$klasses = array( 'share-'.$this->get_class(), 'sd-button' );
- if ( $this->button_style == 'icon' || $this->button_style == 'icon-text' )
+ if ( 'icon' == $this->button_style || 'icon-text' == $this->button_style )
$klasses[] = 'share-icon';
- if ( $this->button_style == 'icon' ) {
- $text = '';
+ if ( 'icon' == $this->button_style ) {
+ $text = $title;
$klasses[] = 'no-text';
+
+ if ( true == $this->open_link_in_new )
+ $text .= __( ' (Opens in new window)', 'jetpack' );
}
+ $id = apply_filters( 'jetpack_sharing_display_id', $id, $this, $args );
+ $url = apply_filters( 'sharing_display_link', $url, $this, $id, $args ); // backwards compatibility
+ $url = apply_filters( 'jetpack_sharing_display_link', $url, $this, $id, $args );
+ $query = apply_filters( 'jetpack_sharing_display_query', $query, $this, $id, $args );
+
if ( !empty( $query ) ) {
- if ( stripos( $url, '?' ) === false )
+ if ( false === stripos( $url, '?' ) )
$url .= '?'.$query;
else
$url .= '&amp;'.$query;
}
- if ( $this->button_style == 'text' )
+ if ( 'text' == $this->button_style )
$klasses[] = 'no-icon';
+ $klasses = apply_filters( 'jetpack_sharing_display_classes', $klasses, $this, $id, $args );
+ $title = apply_filters( 'jetpack_sharing_display_title', $title, $this, $id, $args );
+ $text = apply_filters( 'jetpack_sharing_display_text', $text, $this, $id, $args );
+
return sprintf(
- '<a rel="nofollow" class="%s" href="%s"%s title="%s"%s><span>%s</span></a>',
+ '<a rel="nofollow" data-shared="%s" class="%s" href="%s"%s title="%s"><span%s>%s</span></a>',
+ ( $id ? esc_attr( $id ) : '' ),
implode( ' ', $klasses ),
$url,
- ( $this->open_links == 'new' ) ? ' target="_blank"' : '',
+ ( true == $this->open_link_in_new ) ? ' target="_blank"' : '',
$title,
- ( $id ? ' id="' . esc_attr( $id ) . '"' : '' ),
+ ( 'icon' == $this->button_style ) ? '></span><span class="sharing-screen-reader-text"' : '',
+
$text
);
}
@@ -84,21 +104,22 @@ abstract class Sharing_Source {
return false;
}
- public function display_preview() {
+ public function display_preview( $echo = true, $force_smart = false, $button_style = null ) {
$text = '&nbsp;';
- if ( !$this->smart )
- if ( $this->button_style != 'icon' )
+ $button_style = ( ! empty( $button_style ) ) ? $button_style : $this->button_style;
+ if ( !$this->smart && ! $force_smart )
+ if ( $button_style != 'icon' )
$text = $this->get_name();
$klasses = array( 'share-'.$this->get_class(), 'sd-button' );
- if ( $this->button_style == 'icon' || $this->button_style == 'icon-text' )
+ if ( $button_style == 'icon' || $button_style == 'icon-text' )
$klasses[] = 'share-icon';
- if ( $this->button_style == 'icon' )
+ if ( $button_style == 'icon' )
$klasses[] = 'no-text';
- if ( $this->button_style == 'text' )
+ if ( $button_style == 'text' )
$klasses[] = 'no-icon';
$link = sprintf(
@@ -107,10 +128,13 @@ abstract class Sharing_Source {
$this->get_name(),
$text
);
- ?>
- <div class="option option-smart-<?php echo $this->smart ? 'on' : 'off'; ?>">
- <?php echo $link; ?>
- </div><?php
+
+ $smart = ( $this->smart || $force_smart ) ? 'on' : 'off';
+ $return = "<div class='option option-smart-$smart'>$link</div>";
+ if ( $echo )
+ echo $return;
+
+ return $return;
}
public function get_total( $post = false ) {
@@ -149,6 +173,9 @@ abstract class Sharing_Source {
}
public function js_dialog( $name, $params = array() ) {
+ if ( true !== $this->open_link_in_new )
+ return;
+
$defaults = array(
'menubar' => 1,
'resizable' => 1,
@@ -163,9 +190,13 @@ abstract class Sharing_Source {
$opts = implode( ',', $opts );
?>
<script type="text/javascript">
+ var windowOpen;
jQuery(document).on( 'ready post-load', function(){
jQuery( 'a.share-<?php echo $name; ?>' ).on( 'click', function() {
- window.open( jQuery(this).attr( 'href' ), 'wpcom<?php echo $name; ?>', '<?php echo $opts; ?>' );
+ if ( 'undefined' !== typeof windowOpen ){ // If there's another sharing window open, close it.
+ windowOpen.close();
+ }
+ windowOpen = window.open( jQuery(this).attr( 'href' ), 'wpcom<?php echo $name; ?>', '<?php echo $opts; ?>' );
return false;
});
});
@@ -187,6 +218,7 @@ abstract class Sharing_Advanced_Source extends Sharing_Source {
class Share_Email extends Sharing_Source {
var $shortname = 'email';
+ var $genericon = '\f410';
public function __construct( $id, array $settings ) {
parent::__construct( $id, $settings );
@@ -214,12 +246,17 @@ class Share_Email extends Sharing_Source {
if ( isset( $post_data['target_email'] ) && is_email( $post_data['target_email'] ) )
$target_email = $post_data['target_email'];
- if ( isset( $post_data['source_name'] ) )
+ if ( isset( $post_data['source_name'] ) && strlen( $post_data['source_name'] ) < 200 ) {
$source_name = $post_data['source_name'];
+ } elseif ( isset( $post_data['source_name'] ) ) {
+ $source_name = substr( $post_data['source_name'], 0, 200 );
+ } else {
+ $source_name = '';
+ }
// Test email
$error = 1; // Failure in data
- if ( $source_email && $target_email && $source_name ) {
+ if ( empty( $post_data['source_f_name'] ) && $source_email && $target_email && $source_name ) {
if ( apply_filters( 'sharing_email_check', true, $post, $post_data ) ) {
$data = array(
'post' => $post,
@@ -227,7 +264,7 @@ class Share_Email extends Sharing_Source {
'target' => $target_email,
'name' => $source_name
);
-
+ // todo: implement an error message when email doesn't get sent.
if ( ( $data = apply_filters( 'sharing_email_can_send', $data ) ) !== false ) {
// Record stats
parent::process_request( $data['post'], $post_data );
@@ -277,7 +314,7 @@ class Share_Email extends Sharing_Source {
<div id="sharing_email" style="display: none;">
<form action="<?php echo esc_url( $_SERVER['REQUEST_URI'] ); ?>" method="post">
<label for="target_email"><?php _e( 'Send to Email Address', 'jetpack' ) ?></label>
- <input type="text" name="target_email" id="target_email" value="" />
+ <input type="email" name="target_email" id="target_email" value="" />
<?php if ( is_user_logged_in() ) : ?>
<input type="hidden" name="source_name" value="<?php echo esc_attr( $current_user->display_name ); ?>" />
@@ -288,15 +325,18 @@ class Share_Email extends Sharing_Source {
<input type="text" name="source_name" id="source_name" value="" />
<label for="source_email"><?php _e( 'Your Email Address', 'jetpack' ) ?></label>
- <input type="text" name="source_email" id="source_email" value="" />
+ <input type="email" name="source_email" id="source_email" value="" />
<?php endif; ?>
-
+ <input type="text" id="jetpack-source_f_name" name="source_f_name" class="input" value="" size="25" autocomplete="off" />
+ <script> document.getElementById('jetpack-source_f_name').value = ''; </script>
<?php do_action( 'sharing_email_dialog', 'jetpack' ); ?>
- <img style="float: right; display: none" class="loading" src="<?php echo apply_filters( 'jetpack_static_url', plugin_dir_url( __FILE__ ) . 'images/loading.gif' ); ?>" alt="loading" width="16" height="16" />
- <input type="submit" value="<?php _e( 'Send Email', 'jetpack' ); ?>" class="sharing_send" />
- <a href="#cancel" class="sharing_cancel"><?php _e( 'Cancel', 'jetpack' ); ?></a>
+ <img style="float: right; display: none" class="loading" src="<?php
+ /** This filter is documented in modules/shortcodes/audio.php */
+ echo apply_filters( 'jetpack_static_url', plugin_dir_url( __FILE__ ) . 'images/loading.gif' ); ?>" alt="loading" width="16" height="16" />
+ <input type="submit" value="<?php esc_attr_e( 'Send Email', 'jetpack' ); ?>" class="sharing_send" />
+ <a rel="nofollow" href="#cancel" class="sharing_cancel"><?php _e( 'Cancel', 'jetpack' ); ?></a>
<div class="errors errors-1" style="display: none;">
<?php _e( 'Post was not sent - check your email addresses!', 'jetpack' ); ?>
@@ -317,7 +357,8 @@ class Share_Email extends Sharing_Source {
class Share_Twitter extends Sharing_Source {
var $shortname = 'twitter';
- // 'https://dev.twitter.com/docs/api/1.1/get/help/configuration' ( 2013/06/24 ) short_url_length is 22
+ var $genericon = '\f202';
+ // 'https://dev.twitter.com/rest/reference/get/help/configuration' ( 2015/02/06 ) short_url_length is 22, short_url_length_https is 23
var $short_url_length = 24;
public function __construct( $id, array $settings ) {
@@ -335,7 +376,24 @@ class Share_Twitter extends Sharing_Source {
function sharing_twitter_via( $post ) {
// Allow themes to customize the via
- return apply_filters( 'jetpack_sharing_twitter_via', '', $post->ID );
+ $twitter_site_tag_value = apply_filters( 'jetpack_twitter_cards_site_tag', '', array() );
+
+ /*
+ * Hack to remove the unwanted behavior of adding 'via @jetpack' which
+ * was introduced with the adding of the Twitter cards.
+ * This should be a temporary solution until a better method is setup.
+ */
+ if( 'jetpack' == $twitter_site_tag_value ) {
+ $twitter_site_tag_value = '';
+ }
+
+ $twitter_site_tag_value = apply_filters( 'jetpack_sharing_twitter_via', $twitter_site_tag_value, $post->ID );
+
+ // Strip out anything other than a letter, number, or underscore.
+ // This will prevent the inadvertent inclusion of an extra @, as well as normalizing the handle.
+ $twitter_site_tag_value = preg_replace( '/[^\da-z_]+/i', '', $twitter_site_tag_value );
+
+ return $twitter_site_tag_value;
}
public function get_related_accounts( $post ) {
@@ -361,27 +419,30 @@ class Share_Twitter extends Sharing_Source {
if ( $via ) {
$via = '&via=' . rawurlencode( $via );
-
- $related = $this->get_related_accounts( $post );
- if ( ! empty( $related ) && $related !== $via )
- $via .= '&related=' . rawurlencode( $related );
} else {
$via = '';
}
+ $related = $this->get_related_accounts( $post );
+ if ( ! empty( $related ) && $related !== $via ) {
+ $via .= '&related=' . rawurlencode( $related );
+ }
+
$share_url = $this->get_share_url( $post->ID );
+ $post_title = $this->get_share_title( $post->ID );
if ( $this->smart ) {
- return '<div class="twitter_button"><iframe allowtransparency="true" frameborder="0" scrolling="no" src="' . esc_url( $this->http() . '://platform.twitter.com/widgets/tweet_button.html?url=' . rawurlencode( $share_url ) . '&counturl=' . rawurlencode( str_replace( 'https://', 'http://', get_permalink( $post->ID ) ) ) . '&count=horizontal&text=' . rawurlencode( $post->post_title . ':' ) . $via ) . '" style="width:101px; height:20px;"></iframe></div>';
+ return '<div class="twitter_button"><iframe allowtransparency="true" frameborder="0" scrolling="no" src="' . esc_url( $this->http() . '://platform.twitter.com/widgets/tweet_button.html?url=' . rawurlencode( $share_url ) . '&counturl=' . rawurlencode( get_permalink( $post->ID ) ) . '&count=horizontal&text=' . rawurlencode( $post_title . ':' ) . $via ) . '" style="width:101px; height:20px;"></iframe></div>';
} else {
- if ( 'icon-text' == $this->button_style || 'text' == $this->button_style )
+ if ( apply_filters( 'jetpack_register_post_for_share_counts', true, $post->ID, 'twitter' ) ) {
sharing_register_post_for_share_counts( $post->ID );
+ }
return $this->get_link( get_permalink( $post->ID ), _x( 'Twitter', 'share to', 'jetpack' ), __( 'Click to share on Twitter', 'jetpack' ), 'share=twitter', 'sharing-twitter-' . $post->ID );
}
}
public function process_request( $post, array $post_data ) {
- $post_title = $post->post_title;
+ $post_title = $this->get_share_title( $post->ID );
$post_link = $this->get_share_url( $post->ID );
if ( function_exists( 'mb_stripos' ) ) {
@@ -393,20 +454,18 @@ class Share_Twitter extends Sharing_Source {
}
$via = $this->sharing_twitter_via( $post );
+ $related = $this->get_related_accounts( $post );
if ( $via ) {
- $related = $this->get_related_accounts( $post );
- if ( $related === $via )
+ $sig = " via @$via";
+ if ( $related === $via ) {
$related = false;
-
- $sig = " via @$via";
+ }
} else {
- $via = false;
- $related = false;
- $sig = '';
+ $via = false;
+ $sig = '';
}
-
- $suffix_length = $this->short_url_length + $strlen( " {$sig}" );
+ $suffix_length = $this->short_url_length + $strlen( $sig );
// $sig is handled by twitter in their 'via' argument.
// $post_link is handled by twitter in their 'url' argument.
if ( 140 < $strlen( $post_title ) + $suffix_length ) {
@@ -422,7 +481,7 @@ class Share_Twitter extends Sharing_Source {
$url = $post_link;
$twitter_url = add_query_arg(
urlencode_deep( array_filter( compact( 'via', 'related', 'text', 'url' ) ) ),
- sprintf( '%s://twitter.com/intent/tweet', $this->http() )
+ 'https://twitter.com/intent/tweet'
);
// Redirect to Twitter
@@ -441,6 +500,7 @@ class Share_Twitter extends Sharing_Source {
class Share_Stumbleupon extends Sharing_Source {
var $shortname = 'stumbleupon';
+ var $genericon = '\f223';
public function __construct( $id, array $settings ) {
parent::__construct( $id, $settings );
@@ -460,13 +520,13 @@ class Share_Stumbleupon extends Sharing_Source {
public function get_display( $post ) {
if ( $this->smart )
- return '<div class="stumbleupon_button"><iframe src="http://www.stumbleupon.com/badge/embed/1/?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&amp;title=' . rawurlencode( $post->post_title ) . '" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:74px; height: 18px;" allowTransparency="true"></iframe></div>';
+ return '<div class="stumbleupon_button"><iframe src="http://www.stumbleupon.com/badge/embed/1/?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&amp;title=' . rawurlencode( $this->get_share_title( $post->ID ) ) . '" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:74px; height: 18px;" allowTransparency="true"></iframe></div>';
else
return $this->get_link( get_permalink( $post->ID ), _x( 'StumbleUpon', 'share to', 'jetpack' ), __( 'Click to share on StumbleUpon', 'jetpack' ), 'share=stumbleupon' );
}
public function process_request( $post, array $post_data ) {
- $stumbleupon_url = $this->http() . '://www.stumbleupon.com/submit?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&title=' . rawurlencode( $post->post_title );
+ $stumbleupon_url = $this->http() . '://www.stumbleupon.com/submit?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&title=' . rawurlencode( $this->get_share_title( $post->ID ) );
// Record stats
parent::process_request( $post, $post_data );
@@ -479,6 +539,7 @@ class Share_Stumbleupon extends Sharing_Source {
class Share_Reddit extends Sharing_Source {
var $shortname = 'reddit';
+ var $genericon = '\f222';
public function __construct( $id, array $settings ) {
parent::__construct( $id, $settings );
@@ -494,13 +555,13 @@ class Share_Reddit extends Sharing_Source {
public function get_display( $post ) {
if ( $this->smart )
- return '<div class="reddit_button"><iframe src="http://www.reddit.com/static/button/button1.html?width=120&amp;url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&amp;title=' . rawurlencode( $post->post_title ) . '" height="22" width="120" scrolling="no" frameborder="0"></iframe></div>';
+ return '<div class="reddit_button"><iframe src="' . $this->http() . '://www.reddit.com/static/button/button1.html?width=120&amp;url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&amp;title=' . rawurlencode( $this->get_share_title( $post->ID ) ) . '" height="22" width="120" scrolling="no" frameborder="0"></iframe></div>';
else
- return $this->get_link( get_permalink( $post->ID ), __( 'Reddit', 'share to', 'jetpack' ), __( 'Click to share on Reddit', 'jetpack' ), 'share=reddit' );
+ return $this->get_link( get_permalink( $post->ID ), _x( 'Reddit', 'share to', 'jetpack' ), __( 'Click to share on Reddit', 'jetpack' ), 'share=reddit' );
}
public function process_request( $post, array $post_data ) {
- $reddit_url = 'http://reddit.com/submit?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&title=' . rawurlencode( $post->post_title );
+ $reddit_url = $this->http() . '://reddit.com/submit?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&title=' . rawurlencode( $this->get_share_title( $post->ID ) );
// Record stats
parent::process_request( $post, $post_data );
@@ -511,64 +572,9 @@ class Share_Reddit extends Sharing_Source {
}
}
-class Share_Digg extends Sharing_Source {
- var $shortname = 'digg';
- public function __construct( $id, array $settings ) {
- parent::__construct( $id, $settings );
-
- if ( 'official' == $this->button_style )
- $this->smart = true;
- else
- $this->smart = false;
- }
-
- public function get_name() {
- return __( 'Digg', 'jetpack' );
- }
-
- public function has_custom_button_style() {
- return $this->smart;
- }
-
- public function get_display( $post ) {
- if ( $this->smart ) {
- $url = $this->get_link( 'http://digg.com/submit?url='. rawurlencode( $this->get_share_url( $post->ID ) ) . '&amp;title=' . rawurlencode( $post->post_title ), 'Digg', __( 'Click to Digg this post', 'jetpack' ) );
- return '<div class="digg_button">' . str_replace( 'class="', 'class="DiggThisButton DiggCompact ', $url ) . '</div>';
- } else {
- return $this->get_link( get_permalink( $post->ID ), _x( 'Digg', 'share to', 'jetpack' ), __( 'Click to Digg this post', 'jetpack' ), 'share=digg' );
- }
- }
-
- public function process_request( $post, array $post_data ) {
- $digg_url = 'http://digg.com/submit?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&title=' . rawurlencode( $post->post_title );
-
- // Record stats
- parent::process_request( $post, $post_data );
-
- // Redirect to Digg
- wp_redirect( $digg_url );
- die();
- }
-
- public function display_header() {
- if ( $this->smart ) {
-?>
-<script type="text/javascript">
-(function() {
- var s = document.createElement('SCRIPT'), s1 = document.getElementsByTagName('SCRIPT')[0];
- s.type = 'text/javascript';
- s.async = true;
- s.src = 'http://widgets.digg.com/buttons.js';
- s1.parentNode.insertBefore(s, s1);
-})();
-</script>
-<?php
- }
- }
-}
-
class Share_LinkedIn extends Sharing_Source {
var $shortname = 'linkedin';
+ var $genericon = '\f207';
public function __construct( $id, array $settings ) {
parent::__construct( $id, $settings );
@@ -595,8 +601,9 @@ class Share_LinkedIn extends Sharing_Source {
else
$display = $this->get_link( get_permalink( $post->ID ), _x( 'LinkedIn', 'share to', 'jetpack' ), __( 'Click to share on LinkedIn', 'jetpack' ), 'share=linkedin', 'sharing-linkedin-' . $post->ID );
- if ( 'icon-text' == $this->button_style || 'text' == $this->button_style )
+ if ( apply_filters( 'jetpack_register_post_for_share_counts', true, $post->ID, 'linkedin' ) ) {
sharing_register_post_for_share_counts( $post->ID );
+ }
return $display;
}
@@ -606,11 +613,11 @@ class Share_LinkedIn extends Sharing_Source {
$post_link = $this->get_share_url( $post->ID );
// Using the same URL as the official button, which is *not* LinkedIn's documented sharing link
- // http://www.linkedin.com/cws/share?url={url}&token=&isFramed=false
+ // https://www.linkedin.com/cws/share?url={url}&token=&isFramed=false
$linkedin_url = add_query_arg( array(
'url' => rawurlencode( $post_link ),
- ), 'http://www.linkedin.com/cws/share?token=&isFramed=false' );
+ ), 'https://www.linkedin.com/cws/share?token=&isFramed=false' );
// Record stats
parent::process_request( $post, $post_data );
@@ -626,7 +633,7 @@ class Share_LinkedIn extends Sharing_Source {
} else {
?><script type="text/javascript">
jQuery( document ).ready( function() {
- jQuery.getScript( 'http://platform.linkedin.com/in.js?async=true', function success() {
+ jQuery.getScript( '//platform.linkedin.com/in.js?async=true', function success() {
IN.init();
});
});
@@ -641,6 +648,7 @@ class Share_LinkedIn extends Sharing_Source {
class Share_Facebook extends Sharing_Source {
var $shortname = 'facebook';
+ var $genericon = '\f204';
private $share_type = 'default';
public function __construct( $id, array $settings ) {
@@ -693,48 +701,17 @@ class Share_Facebook extends Sharing_Source {
public function get_display( $post ) {
$share_url = $this->get_share_url( $post->ID );
if ( $this->smart ) {
- $url = $this->http() . '://www.facebook.com/plugins/like.php?href=' . rawurlencode( $share_url ) . '&amp;layout=button_count&amp;show_faces=false&amp;action=like&amp;colorscheme=light&amp;height=21';
-
- // Default widths to suit English
- $inner_w = 90;
-
- // Locale-specific widths/overrides
- $widths = array(
- 'bg_BG' => 120,
- 'cs_CZ' => 135,
- 'de_DE' => 120,
- 'da_DK' => 120,
- 'es_ES' => 122,
- 'es_LA' => 110,
- 'fi_FI' => 100,
- 'it_IT' => 100,
- 'ja_JP' => 100,
- 'nl_NL' => 130,
- 'ru_RU' => 128,
- );
-
- $widths = apply_filters( 'sharing_facebook_like_widths', $widths );
-
- $locale = $this->guess_locale_from_lang( get_locale() );
- if ( $locale ) {
- $url .= '&amp;locale=' . $locale;
-
- if ( isset( $widths[$locale] ) ) {
- $inner_w = $widths[$locale];
- }
- }
-
- $url .= '&amp;width='.$inner_w;
- return '<div class="like_button"><iframe src="'.$url.'" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:'.( $inner_w + 6 ).'px; height:21px;" allowTransparency="true"></iframe></div>';
+ return '<div class="fb-share-button" data-href="' . esc_attr( $share_url ) . '" data-layout="button_count"></div>';
}
- if ( 'icon-text' == $this->button_style || 'text' == $this->button_style )
+ if ( apply_filters( 'jetpack_register_post_for_share_counts', true, $post->ID, 'facebook' ) ) {
sharing_register_post_for_share_counts( $post->ID );
+ }
return $this->get_link( get_permalink( $post->ID ), _x( 'Facebook', 'share to', 'jetpack' ), __( 'Share on Facebook', 'jetpack' ), 'share=facebook', 'sharing-facebook-' . $post->ID );
}
public function process_request( $post, array $post_data ) {
- $fb_url = $this->http() . '://www.facebook.com/sharer.php?u=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&t=' . rawurlencode( $post->post_title );
+ $fb_url = $this->http() . '://www.facebook.com/sharer.php?u=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&t=' . rawurlencode( $this->get_share_title( $post->ID ) );
// Record stats
parent::process_request( $post, $post_data );
@@ -746,11 +723,16 @@ class Share_Facebook extends Sharing_Source {
public function display_footer() {
$this->js_dialog( $this->shortname );
+ if ( $this->smart ) {
+ $locale = $this->guess_locale_from_lang( get_locale() );
+ ?><div id="fb-root"></div><script>(function(d, s, id) { var js, fjs = d.getElementsByTagName(s)[0]; if (d.getElementById(id)) return; js = d.createElement(s); js.id = id; js.src = '//connect.facebook.net/<?php echo $locale; ?>/sdk.js#xfbml=1&appId=249643311490&version=v2.3'; fjs.parentNode.insertBefore(js, fjs); }(document, 'script', 'facebook-jssdk'));</script><?php
+ }
}
}
class Share_Print extends Sharing_Source {
var $shortname = 'print';
+ var $genericon = '\f469';
public function __construct( $id, array $settings ) {
parent::__construct( $id, $settings );
@@ -771,6 +753,7 @@ class Share_Print extends Sharing_Source {
class Share_PressThis extends Sharing_Source {
var $shortname = 'pressthis';
+ var $genericon = '\f205';
public function __construct( $id, array $settings ) {
parent::__construct( $id, $settings );
@@ -787,7 +770,24 @@ class Share_PressThis extends Sharing_Source {
public function process_request( $post, array $post_data ) {
global $current_user;
- $blogs = get_blogs_of_user( $current_user->ID );
+ $primary_blog = (int) get_user_meta( $current_user->ID, 'primary_blog', true );
+ if ( $primary_blog ) {
+ $primary_blog_details = get_blog_details( $primary_blog );
+ } else {
+ $primary_blog_details = false;
+ }
+
+ if ( $primary_blog_details ) {
+ $blogs = array( $primary_blog_details );
+ } elseif ( function_exists( 'get_active_blogs_for_user' ) ) {
+ $blogs = get_active_blogs_for_user();
+ if ( empty( $blogs ) ) {
+ $blogs = get_blogs_of_user( $current_user->ID );
+ }
+ } else {
+ $blogs = get_blogs_of_user( $current_user->ID );
+ }
+
if ( empty( $blogs ) ) {
wp_safe_redirect( get_permalink( $post->ID ) );
die();
@@ -795,7 +795,7 @@ class Share_PressThis extends Sharing_Source {
$blog = current( $blogs );
- $url = $blog->siteurl.'/wp-admin/press-this.php?u='.rawurlencode( $this->get_share_url( $post->ID ) ).'&t='.rawurlencode( $post->post_title ).'&v=4';
+ $url = $blog->siteurl.'/wp-admin/press-this.php?u='.rawurlencode( $this->get_share_url( $post->ID ) ).'&t='.rawurlencode( $this->get_share_title( $post->ID ) );
if ( isset( $_GET['sel'] ) )
$url .= '&s='.rawurlencode( $_GET['sel'] );
@@ -815,6 +815,7 @@ class Share_PressThis extends Sharing_Source {
class Share_GooglePlus1 extends Sharing_Source {
var $shortname = 'googleplus1';
+ var $genericon = '\f218';
private $state = false;
public function __construct( $id, array $settings ) {
@@ -902,7 +903,7 @@ class Share_Custom extends Sharing_Advanced_Source {
var $shortname;
public function get_class() {
- return 'custom';
+ return 'custom share-custom-' . sanitize_html_class( strtolower( $this->name ) );
}
public function __construct( $id, array $settings ) {
@@ -915,9 +916,23 @@ class Share_Custom extends Sharing_Advanced_Source {
$this->shortname = preg_replace( '/[^a-z0-9]*/', '', $settings['name'] );
}
- if ( isset( $settings['icon'] ) )
+ if ( isset( $settings['icon'] ) ) {
$this->icon = $settings['icon'];
+ $new_icon = esc_url_raw( wp_specialchars_decode( $this->icon, ENT_QUOTES ) );
+ $i = 0;
+ while ( $new_icon != $this->icon ) {
+ if ( $i > 5 ) {
+ $this->icon = false;
+ break;
+ } else {
+ $this->icon = $new_icon;
+ $new_icon = esc_url_raw( wp_specialchars_decode( $this->icon, ENT_QUOTES ) );
+ }
+ $i++;
+ }
+ }
+
if ( isset( $settings['url'] ) )
$this->url = $settings['url'];
}
@@ -927,7 +942,7 @@ class Share_Custom extends Sharing_Advanced_Source {
}
public function get_display( $post ) {
- $str = $this->get_link( get_permalink( $post->ID ), esc_html( $this->name ), __( 'Click to share', 'jetpack' ), 'share='.$this->id );
+ $str = $this->get_link( get_permalink( $post->ID ), esc_html( $this->name ), sprintf( __( 'Click to share on %s', 'jetpack' ), esc_attr( $this->name ) ), 'share='.$this->id );
return str_replace( '<span>', '<span style="' . esc_attr( 'background-image:url("' . addcslashes( esc_url_raw( $this->icon ), '"' ) . '");' ) . '">', $str );
}
@@ -935,7 +950,7 @@ class Share_Custom extends Sharing_Advanced_Source {
$url = str_replace( '&amp;', '&', $this->url );
$url = str_replace( '%post_url%', rawurlencode( $this->get_share_url( $post->ID ) ), $url );
$url = str_replace( '%post_full_url%', rawurlencode( get_permalink( $post->ID ) ), $url );
- $url = str_replace( '%post_title%', rawurlencode( $post->post_title ), $url );
+ $url = str_replace( '%post_title%', rawurlencode( $this->get_share_title( $post->ID ) ), $url );
if ( strpos( $url, '%post_tags%' ) !== false ) {
$tags = get_the_tags( $post->ID );
@@ -994,7 +1009,7 @@ class Share_Custom extends Sharing_Advanced_Source {
<tr>
<th scope="row"></th>
<td>
- <input class="button-secondary" type="submit" value="<?php _e( 'Save', 'jetpack' ); ?>" />
+ <input class="button-secondary" type="submit" value="<?php esc_attr_e( 'Save', 'jetpack' ); ?>" />
<a href="#" class="remove"><small><?php _e( 'Remove Service', 'jetpack' ); ?></small></a>
</td>
</tr>
@@ -1027,7 +1042,7 @@ class Share_Custom extends Sharing_Advanced_Source {
);
}
- public function display_preview() {
+ public function display_preview( $echo = true, $force_smart = false, $button_style = null ) {
$opts = $this->get_options();
$text = '&nbsp;';
@@ -1049,10 +1064,10 @@ class Share_Custom extends Sharing_Advanced_Source {
$klasses[] = 'no-icon';
$link = sprintf(
- '<a rel="nofollow" class="%s" href="javascript:void(0);return false;" title="%s"><span style="background-image:url(%s) !important;background-position:left center;background-repeat:no-repeat;">%s</span></a>',
+ '<a rel="nofollow" class="%s" href="javascript:void(0);return false;" title="%s"><span style="background-image:url(&quot;%s&quot;) !important;background-position:left center;background-repeat:no-repeat;">%s</span></a>',
implode( ' ', $klasses ),
$this->get_name(),
- esc_url( $opts['icon'] ),
+ addcslashes( esc_url_raw( $opts['icon'] ), '"' ),
$text
);
?>
@@ -1062,9 +1077,9 @@ class Share_Custom extends Sharing_Advanced_Source {
}
}
-
class Share_Tumblr extends Sharing_Source {
var $shortname = 'tumblr';
+ var $genericon = '\f214';
public function __construct( $id, array $settings ) {
parent::__construct( $id, $settings );
if ( 'official' == $this->button_style )
@@ -1080,10 +1095,10 @@ class Share_Tumblr extends Sharing_Source {
public function get_display( $post ) {
if ( $this->smart ) {
$target = '';
- if ( 'new' == $this->open_links )
+ if ( true == $this->open_link_in_new )
$target = '_blank';
- return '<a target="' . $target . '" href="http://www.tumblr.com/share/link/?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&name=' . rawurlencode( $post->post_title ) . '" title="Share on Tumblr" style="display:inline-block; text-indent:-9999px; overflow:hidden; width:62px; height:20px; background:url(\'http://platform.tumblr.com/v1/share_2.png\') top left no-repeat transparent;">Share on Tumblr</a>';
+ return '<a target="' . $target . '" href="http://www.tumblr.com/share/link/?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&name=' . rawurlencode( $this->get_share_title( $post->ID ) ) . '" title="' . __( 'Share on Tumblr', 'jetpack' ) . '" style="display:inline-block; text-indent:-9999px; overflow:hidden; width:62px; height:20px; background:url(\'//platform.tumblr.com/v1/share_2.png\') top left no-repeat transparent;">' . __( 'Share on Tumblr', 'jetpack' ) . '</a>';
} else {
return $this->get_link( get_permalink( $post->ID ), _x( 'Tumblr', 'share to', 'jetpack' ), __( 'Click to share on Tumblr', 'jetpack' ), 'share=tumblr' );
}
@@ -1094,14 +1109,14 @@ class Share_Tumblr extends Sharing_Source {
parent::process_request( $post, $post_data );
// Redirect to Tumblr's sharing endpoint (a la their bookmarklet)
- $url = 'http://www.tumblr.com/share?v=3&u=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&t=' . rawurlencode( $post->post_title ) . '&s=';
+ $url = 'http://www.tumblr.com/share?v=3&u=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&t=' . rawurlencode( $this->get_share_title( $post->ID ) ) . '&s=';
wp_redirect( $url );
die();
}
// http://www.tumblr.com/share?v=3&u=URL&t=TITLE&s=
public function display_footer() {
if ( $this->smart ) {
- ?><script type="text/javascript" src="http://platform.tumblr.com/v1/share.js"></script><?php
+ ?><script type="text/javascript" src="//platform.tumblr.com/v1/share.js"></script><?php
} else {
$this->js_dialog( $this->shortname, array( 'width' => 450, 'height' => 450 ) );
}
@@ -1110,6 +1125,7 @@ class Share_Tumblr extends Sharing_Source {
class Share_Pinterest extends Sharing_Source {
var $shortname = 'pinterest';
+ var $genericon = '\f209';
public function __construct( $id, array $settings ) {
parent::__construct( $id, $settings );
@@ -1124,50 +1140,20 @@ class Share_Pinterest extends Sharing_Source {
return __( 'Pinterest', 'jetpack' );
}
- public function get_post_image( $content ) {
- $image = '';
+ public function get_display( $post ) {
+ $share_url = 'http://pinterest.com/pin/create/button/?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&description=' . rawurlencode( $post->post_title );
+ $display = '';
- if ( class_exists( 'Jetpack_PostImages' ) ) {
- // Use the full stack of methods to find an image, except for HTML, which can cause loops
- $img = Jetpack_PostImages::get_image( $content->ID );
- if ( !empty( $img['src'] ) )
- return $img['src'];
- }
+ if ( $this->smart )
+ $display .= sprintf( '<div class="pinterest_button"><a href="%s" data-pin-do="buttonBookmark" data-pin-config="beside"><img src="//assets.pinterest.com/images/pidgets/pinit_fg_en_rect_gray_20.png" /></a></div>', esc_url( $share_url ) );
+ else
+ $display = $this->get_link( get_permalink( $post->ID ), _x( 'Pinterest', 'share to', 'jetpack' ), __( 'Click to share on Pinterest', 'jetpack' ), 'share=pinterest', 'sharing-pinterest-' . $post->ID );
- // If we have to fall back to the following, we only do a few basic image checks
- $content = $content->post_content;
- if ( function_exists('has_post_thumbnail') && has_post_thumbnail() ) {
- $thumb_id = get_post_thumbnail_id();
- $thumb = wp_get_attachment_image_src( $thumb_id, 'full' );
-
- // This shouldn't be necessary, since has_post_thumbnail() is true,
- // but... see http://wordpress.org/support/topic/jetpack-youtube-embeds
- if ( ! $thumb ) return '';
-
- $image = remove_query_arg( array('w', 'h'), $thumb[0] );
- } else if ( preg_match_all('/<img (.+?)>/', $content, $matches) ) {
- foreach ( $matches[1] as $attrs ) {
- $media = $img = array();
- foreach ( wp_kses_hair( $attrs, array( 'http', 'https' ) ) as $attr )
- $img[$attr['name']] = $attr['value'];
- if ( !isset( $img['src'] ) || 0 !== strpos( $img['src'], 'http' ) ) {
- continue;
- }
- else {
- $image = htmlspecialchars_decode( $img['src'] );
- break;
- }
- }
+ if ( apply_filters( 'jetpack_register_post_for_share_counts', true, $post->ID, 'linkedin' ) ) {
+ sharing_register_post_for_share_counts( $post->ID );
}
- return $image;
- }
-
- public function get_display( $post ) {
- if ( $this->smart )
- return '<div class="pinterest_button"><a href="' . esc_url( 'http://pinterest.com/pin/create/button/?url='. rawurlencode( $this->get_share_url( $post->ID ) ) . '&description=' . rawurlencode( $post->post_title ) . '&media=' . rawurlencode( esc_url_raw( $this->get_post_image( $post ) ) ) ) . '" class="pin-it-button" count-layout="horizontal"> '. __( 'Pin It', 'jetpack') .'</a></div>';
- else
- return $this->get_link( get_permalink( $post->ID ), _x( 'Pinterest', 'share to', 'jetpack' ), __( 'Click to share on Pinterest', 'jetpack' ), 'share=pinterest' );
+ return $display;
}
public function process_request( $post, array $post_data ) {
@@ -1176,7 +1162,7 @@ class Share_Pinterest extends Sharing_Source {
// If we're triggering the multi-select panel, then we don't need to redirect to Pinterest
if ( !isset( $_GET['js_only'] ) ) {
- $pinterest_url = esc_url_raw( 'http://pinterest.com/pin/create/button/?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&description=' . rawurlencode( $post->post_title ) . '&media=' . rawurlencode( esc_url_raw( $this->get_post_image( $post ) ) ) );
+ $pinterest_url = esc_url_raw( 'http://pinterest.com/pin/create/button/?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&description=' . rawurlencode( $this->get_share_title( $post->ID ) ) );
wp_redirect( $pinterest_url );
} else {
echo '// share count bumped';
@@ -1193,6 +1179,7 @@ class Share_Pinterest extends Sharing_Source {
var s = document.createElement("script");
s.type = "text/javascript";
s.async = true;
+ s.setAttribute('data-pin-hover', true);
s.src = window.location.protocol + "//assets.pinterest.com/js/pinit.js";
var x = document.getElementsByTagName("script")[0];
x.parentNode.insertBefore(s, x);
@@ -1227,6 +1214,7 @@ class Share_Pinterest extends Sharing_Source {
class Share_Pocket extends Sharing_Source {
var $shortname = 'pocket';
+ var $genericon = '\f224';
public function __construct( $id, array $settings ) {
parent::__construct( $id, $settings );
@@ -1245,7 +1233,7 @@ class Share_Pocket extends Sharing_Source {
// Record stats
parent::process_request( $post, $post_data );
- $pocket_url = esc_url_raw( 'https://getpocket.com/save/?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&title=' . rawurlencode( $post->post_title ) );
+ $pocket_url = esc_url_raw( 'https://getpocket.com/save/?url=' . rawurlencode( $this->get_share_url( $post->ID ) ) . '&title=' . rawurlencode( $this->get_share_title( $post->ID ) ) );
wp_redirect( $pocket_url );
exit;
}
diff --git a/plugins/jetpack/modules/sharedaddy/sharing.css b/plugins/jetpack/modules/sharedaddy/sharing.css
index 1d1719c8..3b8bbaad 100644
--- a/plugins/jetpack/modules/sharedaddy/sharing.css
+++ b/plugins/jetpack/modules/sharedaddy/sharing.css
@@ -1,465 +1,622 @@
-li.share-print a.sd-button > spandiv.sharedaddy ul,
-div.sharedaddy li {
- margin: 0;
- padding: 0;
- list-style: none;
- border: none;
- background: none;
+/**
+ * Sharedaddy Base Styles
+ *
+ * Contains styles for modules, containers, buttons
+ */
+
+
+/* Master container */
+#jp-post-flair {
+ padding-top: .5em;
}
+
+/* Overall Sharedaddy block title */
div.sharedaddy,
#content div.sharedaddy,
#main div.sharedaddy {
- font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
- font-size: 12px;
clear: both;
}
-div.sharedaddy,
-div.sharedaddy div {
- -webkit-border-radius: 0 !important;
- -moz-border-radius: 0 !important;
- border-radius: 0 !important;
-}
-
-div.sharedaddy h3,
-#content div.sharedaddy h3,
-#main div.sharedaddy h3,
-#primary div.sharedaddy h3 {
- font-size: 12px;
- font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
- margin: 3px 0;
- padding: 0;
- text-transform: none;
- letter-spacing: 0;
- line-height: 1;
+div.sharedaddy h3.sd-title {
+ margin: 0 0 1em 0;
+ display: inline-block;
+ line-height: 1.2;
+ font-size: 9pt;
font-weight: bold;
- width: 15.625%; /* 100px / 640px */ float: left;
- position: static;
- background: none;
- border: none;
}
-/* @noflip */
-.rtl div.sharedaddy h3,
-.rtl #content div.sharedaddy h3,
-.rtl #main div.sharedaddy h3,
-.rtl #primary div.sharedaddy h3 {
- float: right;
- text-align: right;
+div.sharedaddy h3.sd-title:before {
+ content: "";
+ display: block;
+ width: 100%;
+ min-width: 30px;
+ border-top: 1px solid #ddd;
+ margin-bottom: 1em;
}
-div.sharedaddy ul,
-div.sharedaddy li {
- margin: 0 !important;
- padding: 0 !important;
- text-indent: 0;
+body.highlander-light h3.sd-title:before {
+ border-top: 1px solid rgba(0,0,0,.2);
}
-div.sharedaddy li::before {
- content: "";
+body.highlander-dark h3.sd-title:before {
+ border-top: 1px solid rgba(255,255,255,.4);
}
-div.sharedaddy div.pd-rating {
- margin: 0;
- min-height: 23px;
+
+/* Sharing services list */
+.sd-content ul {
+ padding: 0 !important;
+ margin: 0 0 .7em 0 !important;
+ list-style: none !important;
}
-div.sharedaddy a,
-div.sharedaddy a:link,
-div.sharedaddy a:visited {
- font-style: normal;
+.sd-content ul li {
+ display: inline-block;
}
-/* ClearFix trick */
+.sd-block.sd-gplus {
+ margin: 0 0 .5em 0;
+}
-div.sharedaddy:before,
-div.sharedaddy:after,
-div.sharedaddy .sd-block:before,
-div.sharedaddy .sd-block:after,
-div.sharedaddy ul:before,
-div.sharedaddy ul:after {
- content: "\0020";
- display: block;
- height: 0;
- overflow: hidden;
+.sd-gplus .sd-content {
+ font-size: 12px;
}
-div.sharedaddy:after,
-div.sharedaddy .sd-block:after,
-div.sharedaddy ul:after {
- clear: both;
+
+/* Buttons */
+.sd-social-icon .sd-content ul li a.sd-button,
+.sd-social-text .sd-content ul li a.sd-button,
+.sd-content ul li a.sd-button,
+.sd-content ul li .option a.share-ustom, /* Ugh. */
+.sd-content ul li.preview-item div.option.option-smart-off a,
+.sd-content ul li.advanced a.share-more,
+.sd-social-icon-text .sd-content ul li a.sd-button,
+.sd-social-official .sd-content>ul>li>a.sd-button,
+#sharing_email .sharing_send,
+.sd-social-official .sd-content>ul>li .digg_button >a { /* official Digg button no longer works, needs cleaning */
+ text-decoration: none !important;
+ display: inline-block;
+ margin: 0 5px 5px 0;
+ font-size: 12px;
+ font-family: "Open Sans", sans-serif;
+ font-weight: normal;
+ border-radius: 3px;
+ color: #777 !important;
+ background: #f8f8f8;
+ border: 1px solid #cccccc;
+ box-shadow: 0 1px 0 rgba(0,0,0,.08);
+ text-shadow: none;
+ line-height: 23px;
+ padding: 1px 8px 0px 5px;
}
-div.sharedaddy,
-div.sharedaddy .sd-block,
-div.sharedaddy ul {
- zoom: 1;
+.sd-social-text .sd-content ul li a.sd-button span,
+.sd-content ul li a.sd-button>span,
+.sd-content ul li .option a.share-ustom span, /* Ugh. */
+.sd-content ul li.preview-item div.option.option-smart-off a span,
+.sd-content ul li.advanced a.share-more span,
+.sd-social-icon-text .sd-content ul li a.sd-button>span,
+.sd-social-official .sd-content>ul>li>a.sd-button span,
+.sd-social-official .sd-content>ul>li .digg_button >a span { /* official Digg button no longer works, needs cleaning */
+ line-height: 23px;
}
-/* =Base Styles
--------------------------------------------------------------- */
-div.sharedaddy div.sd-block {
- border-top: 1px solid #ddd;
- border-top: 1px solid rgba(0,0,0,.13);
- padding: 10px 0 5px;
- margin: 0;
- width: 100% !important;
+/* Our gray buttons should be smaller when seen with the official ones */
+.sd-social-official .sd-content>ul>li>a.sd-button,
+.sd-social-official .sd-content .sharing-hidden .inner>ul>li>a.sd-button,
+.sd-social-official .sd-content>ul>li .digg_button>a,
+.sd-social-official .sd-content .sharing-hidden .inner>ul>li .digg_button>a {
+ line-height: 17px;
+ box-shadow: none; /* No shadow on gray buttons between the official ones */
+ vertical-align: top;
}
-div.sharedaddy.sharedaddy-dark .sd-block {
- border-top-color: #222;
- border-top-color: rgba(50,50,50,.5);
+.sd-social-official .sd-content>ul>li>a.sd-button:before,
+.sd-social-official .sd-content>ul>li .digg_button>a:before,
+.sd-social-official .sd-content .sharing-hidden .inner>ul>li>a.sd-button:before,
+.sd-social-official .sd-content .sharing-hidden .inner>ul>li .digg_button>a:before {
+ margin-bottom: -1px;
+ top: 0;
}
-div.sharedaddy .sd-content {
- width: 82.125%; /* 530px / 640px */
- float: right;
- margin: -2px 0 0 0;
+.sd-social-icon .sd-content ul li a.sd-button:hover,
+.sd-social-icon .sd-content ul li a.sd-button:active,
+.sd-social-text .sd-content ul li a.sd-button:hover,
+.sd-social-text .sd-content ul li a.sd-button:active,
+.sd-social-icon-text .sd-content ul li a.sd-button:hover,
+.sd-social-icon-text .sd-content ul li a.sd-button:active,
+.sd-social-official .sd-content>ul>li>a.sd-button:hover,
+.sd-social-official .sd-content>ul>li>a.sd-button:active,
+.sd-social-official .sd-content>ul>li .digg_button>a:hover,
+.sd-social-official .sd-content>ul>li .digg_button>a:active {
+ color: #555;
+ background: #fafafa;
+ border: 1px solid #999999;
}
-div.sharedaddy .sd-content ul {
- margin: 0;
+.sd-social-icon .sd-content ul li a.sd-button:active,
+.sd-social-text .sd-content ul li a.sd-button:active,
+.sd-social-icon-text .sd-content ul li a.sd-button:active,
+.sd-social-official .sd-content>ul>li>a.sd-button:active,
+.sd-social-official .sd-content>ul>li .digg_button>a:active {
+ box-shadow: inset 0 1px 0 rgba(0,0,0,.16);
}
-div.sharedaddy .sd-content li {
- float: left;
- margin: 0 5px 5px 0 !important;
- display: block;
-}
-/* @noflip */
-.rtl div.sharedaddy .sd-content {
- float: right;
+/* All icons */
+.sd-content ul li a.sd-button:before {
+ display: inline-block;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ font: normal 16px/1 'Genericons';
+ vertical-align: top;
+ position: relative;
+ top: 3px;
+ text-align: center;
}
-/* @noflip */
-.rtl div.sharedaddy .sd-content li {
- float: right;
- margin: 0 0 5px 5px !important;
+.sd-content ul li {
+ margin: 0 !important;
+ padding: 0;
}
-/* Base Button .sd-button */
+/* Text + icon & Official */
+.sd-social-icon-text .sd-content ul li a span,
+.sd-social-official .sd-content ul li a.sd-button span,
+.sd-content ul li.preview-item a.sd-button span {
+ margin-left: 3px;
+}
+.sd-content ul li.preview-item.no-icon a.sd-button span {
+ margin-left: 0;
+}
-div.sharedaddy a.sd-button {
- margin: 0;
- padding: 0;
+/* Text only */
+.sd-social-text .sd-content ul li a:before,
+.sd-content ul li.no-icon a:before {
+ display: none;
+}
+body .sd-social-text .sd-content ul li.share-custom a span,
+body .sd-content ul li.share-custom.no-icon a span {
+ background-image: none;
+ background-position: -500px -500px !important; /* hack to work around !important inline style */
+ background-repeat: no-repeat !important;
+ padding-left: 0;
+ height: 0;
+ line-height: inherit;
+}
+
+.sd-social-icon .sd-content ul li a.share-more {
+ position: relative;
+ top: 2px;
+}
+.sd-social-icon .sd-content ul li a.share-more span {
+ margin-left: 3px;
+}
+
+
+/* Individual icons */
+.sd-social-icon .sd-content ul li.share-print a:before,
+.sd-social-text .sd-content ul li.share-print a:before,
+.sd-content ul li.share-print div.option.option-smart-off a:before,
+.sd-social-icon-text .sd-content li.share-print a:before,
+.sd-social-official .sd-content li.share-print a:before {
+ content: '\f469';
+}
+
+.sd-social-icon .sd-content ul li.share-email a:before,
+.sd-social-text .sd-content ul li.share-email a:before,
+.sd-content ul li.share-email div.option.option-smart-off a:before,
+.sd-social-icon-text .sd-content li.share-email a:before,
+.sd-social-official .sd-content li.share-email a:before {
+ content: '\f410';
+}
+.sd-social-icon .sd-content ul li.share-linkedin a:before,
+.sd-social-text .sd-content ul li.share-linkedin a:before,
+.sd-content ul li.share-linkedin div.option.option-smart-off a:before,
+.sd-social-icon-text .sd-content li.share-linkedin a:before {
+ content: '\f207';
+}
+.sd-social-icon .sd-content ul li.share-twitter a:before,
+.sd-social-text .sd-content ul li.share-twitter a:before,
+.sd-content ul li.share-twitter div.option.option-smart-off a:before,
+.sd-social-icon-text .sd-content li.share-twitter a:before {
+ content: '\f202';
+}
+.sd-social-icon .sd-content ul li.share-reddit a:before,
+.sd-social-text .sd-content ul li.share-reddit a:before,
+.sd-content ul li.share-reddit div.option.option-smart-off a:before,
+.sd-social-icon-text .sd-content li.share-reddit a:before {
+ content: '\f222';
+}
+.sd-social-icon .sd-content ul li.share-tumblr a:before,
+.sd-social-text .sd-content ul li.share-tumblr a:before,
+.sd-content ul li.share-tumblr div.option.option-smart-off a:before,
+.sd-social-icon-text .sd-content li.share-tumblr a:before {
+ content: '\f214';
+}
+.sd-social-icon .sd-content ul li.share-stumbleupon a:before,
+.sd-social-text .sd-content ul li.share-stumbleupon a:before,
+.sd-content ul li.share-stumbleupon div.option.option-smart-off a:before,
+.sd-social-icon-text .sd-content li.share-stumbleupon a:before {
+ content: '\f223';
+}
+.sd-social-icon .sd-content ul li.share-pocket a:before,
+.sd-social-text .sd-content ul li.share-pocket a:before,
+.sd-content ul li.share-pocket div.option.option-smart-off a:before,
+.sd-social-icon-text .sd-content li.share-pocket a:before {
+ content: '\f224';
+}
+.sd-social-icon .sd-content ul li.share-pinterest a:before,
+.sd-social-text .sd-content ul li.share-pinterest a:before,
+.sd-content ul li.share-pinterest div.option.option-smart-off a:before,
+.sd-social-icon-text .sd-content li.share-pinterest a:before {
+ content: '\f209';
+}
+.sd-social-icon .sd-content ul li.share-google-plus-1 a:before,
+.sd-social-text .sd-content ul li.share-google-plus-1 a:before,
+.sd-content ul li.share-google-plus-1 div.option.option-smart-off a:before,
+.sd-social-icon-text .sd-content li.share-google-plus-1 a:before {
+ content: '\f218';
+}
+.sd-social-icon .sd-content ul li.share-facebook a:before,
+.sd-social-text .sd-content ul li.share-facebook a:before,
+.sd-content ul li.share-facebook div.option.option-smart-off a:before,
+.sd-social-icon-text .sd-content li.share-facebook a:before {
+ content: '\f204';
+}
+.sd-social-icon .sd-content ul li.share-press-this a:before,
+.sd-social-text .sd-content ul li.share-press-this a:before,
+.sd-content ul li.share-press-this div.option.option-smart-off a:before,
+.sd-social-icon-text .sd-content li.share-press-this a:before,
+.sd-social-official .sd-content li.share-press-this a:before {
+ content: '\f205';
+}
+.sd-social-official .sd-content li.share-press-this a:before {
+ color: #2ba1cb;
+}
+.sd-social-icon .sd-content ul a.share-more:before,
+.sd-social-text .sd-content ul a.share-more:before,
+.sd-content ul li.advanced a.share-more:before,
+.sd-social-icon-text .sd-content a.share-more:before,
+.sd-social-official .sd-content a.share-more:before {
+ content: '\f415';
+}
+.sd-social-official .sd-content a.share-more:before {
+ color: #2ba1cb;
+}
+
+
+/* Share count */
+.sd-social .sd-button .share-count {
+ background: #2ea2cc;
+ color: #fff;
+ -moz-border-radius: 10px;
+ border-radius: 10px;
display: inline-block;
- background: #efefef;
- background: -moz-linear-gradient(top, #f7f7f7 0%, #efefef 100%);
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f7f7f7), color-stop(100%,#efefef));
- background: -webkit-linear-gradient(top, #f7f7f7 0%,#efefef 100%);
- background: -o-linear-gradient(top, #f7f7f7 0%,#efefef 100%);
- background: -ms-linear-gradient(top, #f7f7f7 0%,#efefef 100%);
- background: linear-gradient(top, #f7f7f7 0%,#efefef 100%);
- border-radius: 3px;
- border: 1px solid #ddd !important;
- box-shadow: inset 0 1px 0 #fff;
- color: #000 !important;
- text-decoration: none;
+ text-align: center;
+ font-size: 10px;
+ padding: 1px 3px;
line-height: 1;
- font-size: 12px;
- font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
- font-weight: normal;
}
-div.sharedaddy a.sd-button:hover {
- color: #000;
- text-shadow: 0 1px 0 #fff;
- border-color: #ccc;
- background: #eee;
- background: -moz-linear-gradient(top, #efefef 0%, #eee 100%);
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#efefef), color-stop(100%,#eee));
- background: -webkit-linear-gradient(top, #efefef 0%,#eee 100%);
- background: -o-linear-gradient(top, #efefef 0%,#eee 100%);
- background: -ms-linear-gradient(top, #efefef 0%,#eee 100%);
- background: linear-gradient(top, #efefef 0%,#eee 100%);
+
+/* Official buttons */
+.sd-social-official .sd-content ul, .sd-social-official .sd-content ul li {
+ line-height: 25px !important;
}
-div.sharedaddy a.sd-button:active {
- background-color: #efefef;
- box-shadow: inset 0 -1px 0 #fff;
- border-color: #ddd;
+.sd-social-official .sd-content>ul>li>a.sd-button span {
+ line-height: 1;
}
-a.sd-button > span {
- padding: 4px 8px;
+.sd-social-official .sd-content ul:after {
+ content: ".";
display: block;
- opacity: .8;
- line-height: 1.5em;
- text-shadow: none;
+ height: 0;
+ clear: both;
+ visibility: hidden;
}
-a.sd-button:hover span {
- opacity: 1;
+.sd-social-official .sd-content li.share-press-this a {
+ margin: 0 0 5px 0;
}
-.sd-button span.share-count {
- font-size: 90%;
- color: #666;
- margin-left: 5px;
- line-height: 1;
+.sd-social-official .sd-content ul>li {
+ display: block;
+ float: left;
+ margin: 0 10px 5px 0 !important;
+ height: 25px;
}
-/* @noflip */
-.rtl .sd-button span.share-count {
- margin-right: 5px;
+.sd-social-official .fb-share-button > span {
+ vertical-align: top !important;
}
-/* Button Style Options */
-
-.sd-social-icon-text a.sd-button > span,
-a.sd-button > span {
- padding: 1px 5px 1px 23px;
- background-position: 2px center;
- background-repeat: no-repeat;
+.sd-social-official .sd-content .pocket_button iframe {
+ width: 98px;
}
-.sd-social-icon a.sd-button > span {
- padding: 3px;
- width: 16px;
- height: 16px;
- text-indent: -9999px;
- background-position: center center;
- background-repeat: no-repeat;
+.sd-social-official .sd-content .twitter_button iframe {
+ width: 96px;
}
-.sd-social-text a.sd-button > span {
- background: none !important;
- padding-left: 5px
+
+/* Individual official buttons */
+.stumbleupon_button iframe, .reddit_button iframe {
+ margin-top: 1px;
}
-.sd-social-official li {
- height: 21px;
+.pocket_button iframe, .googleplus1_button iframe, .pinterest_button, .twitter_button, .linkedin_button>span {
+ margin: 0 !important;
}
-div.sharedaddy .no-text {
- width: 21px;
- height: 21px;
+body .sd-social-official li.share-print ,
+body .sd-social-official li.share-email a,
+body .sd-social-official li.share-custom a,
+body .sd-social-official li a.share-more,
+body .sd-social-official li.share-digg a,
+body .sd-social-official li.share-press-this a
+{
+ position: relative;
+ top: 0;
}
-div.sharedaddy .no-text a {
- text-decoration: none;
+
+/* Custom icons */
+body .sd-social-icon .sd-content li.share-custom>a {
+ padding: 2px 3px 0 3px;
+ position: relative;
+ top: 4px;
}
-div.sharedaddy .no-icon a span, div.sharedaddy li.no-icon div a span {
- padding-left: 5px;
- background-image: none;
+body .sd-social-icon .sd-content li.share-custom a span,
+body .sd-social-icon-text .sd-content li.share-custom a span,
+body .sd-social-text .sd-content li.share-custom a span,
+body .sd-social-official .sd-content li.share-custom a span,
+body .sd-content ul li.share-custom a.share-icon span
+{
+ background-size: 16px 16px;
+ background-repeat: no-repeat;
+ margin-left: 0;
+ padding: 0 0 0 19px;
+ display: inline-block;
+ height: 16px;
+ line-height: 16px;
}
-/* @noflip */
-.rtl .sd-social-icon-text a.sd-button > span,
-.rtl a.sd-button > span {
- padding: 3px 23px 3px 5px;
- background-position: 98% center;
+body .sd-social-icon .sd-content li.share-custom a span {
+ width: 0;
}
-/* @noflip */
-.rtl .sd-social-text a.sd-button > span {
- padding-left: 0;
- padding-right: 5px
+body .sd-content li.share-custom a:hover span {
}
-/* @noflip */
-.rtl div.sharedaddy .no-icon a span, .rtl div.sharedaddy li.no-icon div a span {
- padding-left: 0;
- padding-right: 5px
+body .sd-social-icon .sd-content li.share-custom a span {
+ padding-left: 16px !important;
}
-/* Icons */
-li.share-facebook a.sd-button > span {
- background-image: url('images/facebook.png');
+/* Overflow Sharing dialog */
+.sharing-hidden .inner {
+ position: absolute;
+ z-index: 2;
+ border: 1px solid #ccc;
+ padding: 10px;
+ background: #fff;
+ box-shadow: 0px 5px 20px rgba(0,0,0,.2);
+ -webkit-border-radius: 2px;
+ -moz-border-radius: 2px;
+ border-radius: 2px;
+ margin-top: 5px;
+ max-width: 400px;
}
-li.share-tumblr a.sd-button > span {
- background-image: url('images/tumblr.png');
+.sharing-hidden .inner ul{
+ margin: 0 !important;
}
-li.share-twitter a.sd-button > span {
- background-image: url('images/twitter.png?1');
+.sd-social-official .sd-content .sharing-hidden ul>li.share-end {
+ clear: both;
+ margin: 0;
+ height: 0;
}
-li.share-google-plus-1 a.sd-button > span {
- background-image: url('images/googleplus1.png?1');
+.sharing-hidden .inner:before, .sharing-hidden .inner:after {
+ position: absolute;
+ z-index: 1;
+ top: -8px;
+ left: 20px;
+ width: 0;
+ height: 0;
+ border-left: 6px solid transparent;
+ border-right: 6px solid transparent;
+ border-bottom: 8px solid #ccc;
+ content: "";
+ display: block;
}
-li.share-linkedin a.sd-button > span {
- background-image: url('images/linkedin.png');
+.sharing-hidden .inner:after {
+ z-index: 2;
+ top: -7px;
+ border-left: 6px solid transparent;
+ border-right: 6px solid transparent;
+ border-bottom: 8px solid #fff;
}
-li.share-press-this a.sd-button > span {
- background-image: url('images/wordpress.png');
+.sharing-hidden ul {
+ margin: 0;
}
-li.share-digg a.sd-button > span {
- background-image: url('images/digg.png');
-}
-li.share-stumbleupon a.sd-button > span {
- background-image: url('images/stumbleupon.png');
-}
+/**
+ * Special colorful look for "Icon Only" option
+ */
-li.share-reddit a.sd-button > span {
- background-image: url('images/reddit.png');
+.sd-social-icon .sd-content ul li[class*='share-'] a,
+.sd-social-icon .sd-content ul li[class*='share-'] a:hover,
+.sd-social-icon .sd-content ul li[class*='share-'] div.option a {
+ border-radius: 50%;
+ -webkit-border-radius: 50%;
+ border: 0;
+ box-shadow: none;
+ padding: 8px;
+ position: relative;
+ top: -2px;
+ line-height: 1;
+ width: auto;
+ height: auto;
+ margin-bottom: 0;
}
-li.share-pinterest a.sd-button > span {
- background-image: url('images/pinterest.png');
+.sd-social-icon .sd-content ul li[class*='share-'] a.sd-button>span,
+.sd-social-icon .sd-content ul li[class*='share-'] div.option a span {
+ line-height: 1;
}
-li.share-pocket a.sd-button > span {
- background-image: url('images/pocket.png');
+.sd-social-icon .sd-content ul li[class*='share-'] a:hover,
+.sd-social-icon .sd-content ul li[class*='share-'] div.option a:hover {
+ border: none;
+ opacity: .6;
}
-li.share-kindle a.sd-button > span {
- background-image: url('images/kindle.png');
+.sd-social-icon .sd-content ul li[class*='share-'] a.sd-button:before {
+ top: 0;
}
-li.share-email a.sd-button > span {
- background-image: url('images/email.png');
+.sd-social-icon .sd-content ul li[class*='share-'] a.sd-button.share-custom {
+ padding: 8px 8px 6px 8px;
+ top: 5px;
}
-li.share-print a.sd-button > span {
- background-image: url('images/print.png');
+.sd-social-icon .sd-content ul li a.sd-button.share-more {
+ margin-left: 10px;
}
-a.sd-button.share-more span {
- background-image: url('images/more.png');
+.sd-social-icon .sd-content ul li:first-child a.sd-button.share-more {
+ margin-left: 0;
}
-@media only screen and (-moz-min-device-pixel-ratio: 1.5), only screen and (-o-min-device-pixel-ratio: 3/2), only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-device-pixel-ratio: 1.5), only screen and (min-resolution: 120dpi) {
- li.share-facebook a.sd-button > span {
- background-image: url('images/facebook@2x.png');
- background-size: 16px 16px;
- }
+.sd-social-icon .sd-button span.share-count {
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ border-radius: 0;
+ background: #555;
+ font-size: 9px;
+}
- li.share-tumblr a.sd-button > span {
- background-image: url('images/tumblr@2x.png');
- background-size: 16px 16px;
- }
+/* Special look colors */
+.sd-social-icon .sd-content ul li[class*='share-'] a.sd-button {
+ background: #e9e9e9;
+ margin-top: 2px;
+ text-indent: 0;
+}
- li.share-twitter a.sd-button > span {
- background-image: url('images/twitter@2x.png?1');
- background-size: 16px 16px;
- }
+.sd-social-icon .sd-content ul li[class*='share-'].share-tumblr a.sd-button {
+ background: #2c4762;
+ color: #fff !important;
+}
- li.share-google-plus-1 a.sd-button > span {
- background-image: url('images/googleplus1@2x.png');
- background-size: 16px 16px;
- }
+.sd-social-icon .sd-content ul li[class*='share-'].share-facebook a.sd-button {
+ background: #3b5998;
+ color: #fff !important;
+}
- li.share-linkedin a.sd-button > span {
- background-image: url('images/linkedin@2x.png');
- background-size: 16px 16px;
- }
+.sd-social-icon .sd-content ul li[class*='share-'].share-stumbleupon a.sd-button {
+ background: #ea4b24;
+ color: #fff !important;
+}
- li.share-press-this a.sd-button > span {
- background-image: url('images/wordpress@2x.png');
- background-size: 16px 16px;
- }
+.sd-social-icon .sd-content ul li[class*='share-'].share-twitter a.sd-button {
+ background: #00acee;
+ color: #fff !important;
+}
- li.share-digg a.sd-button > span {
- background-image: url('images/digg@2x.png?1');
- background-size: 16px 16px;
- }
+.sd-social-icon .sd-content ul li[class*='share-'].share-pinterest a.sd-button {
+ background: #ca1f27;
+ color: #fff !important;
+}
- li.share-stumbleupon a.sd-button > span {
- background-image: url('images/stumbleupon@2x.png');
- background-size: 16px 16px;
- }
+.sd-social-icon .sd-content ul li[class*='share-'].share-digg a.sd-button {
+ color: #555555 !important;
+}
- li.share-reddit a.sd-button > span {
- background-image: url('images/reddit@2x.png');
- background-size: 16px 16px;
- }
+.sd-social-icon .sd-content ul li[class*='share-'].share-press-this a.sd-button {
+ background: #1e8cbe;
+ color: #fff !important;
+}
- li.share-pinterest a.sd-button > span {
- background-image: url('images/pinterest@2x.png');
- background-size: 16px 16px;
- }
+.sd-social-icon .sd-content ul li[class*='share-'].share-linkedin a.sd-button {
+ background: #0077b5;
+ color: #fff !important;
+}
- li.share-pocket a.sd-button > span {
- background-image: url('images/pocket@2x.png');
- background-size: 16px 16px;
- }
+.sd-social-icon .sd-content ul li[class*='share-'].share-google-plus-1 a.sd-button {
+ background: #dd4b39;
+ color: #fff !important;
+}
- li.share-kindle a.sd-button > span {
- background-image: url('images/kindle@2x.png');
- background-size: 16px 16px;
- }
+.sd-social-icon .sd-content ul li[class*='share-'].share-pocket a.sd-button {
+ background: #ee4056;
+ color: #fff !important;
+}
- li.share-email a.sd-button > span {
- background-image: url('images/email@2x.png?1');
- background-size: 16px 16px;
- }
+.sd-social-icon .sd-content ul li[class*='share-'].share-reddit a.sd-button {
+ background: #cee3f8;
+ color: #555555 !important;
+}
- li.share-print a.sd-button > span {
- background-image: url('images/print@2x.png');
- background-size: 16px 16px;
- }
- a.sd-button.share-more span {
- background-image: url('images/more@2x.png?1');
- background-size: 16px 16px;
- }
+/**
+ * Screen Reader Text for "Icon Only" option
+ */
+.sharing-screen-reader-text {
+ clip: rect(1px, 1px, 1px, 1px);
+ position: absolute !important;
+ height: 1px;
+ width: 1px;
+ overflow: hidden;
}
-/* More pannel */
-
-div.sharedaddy .sharing-hidden .inner {
- max-width: 250px;
- padding: 15px 15px 10px;
- position: absolute;
- margin-left: -100px;
- z-index: 1001;
- background-color: #fff;
- border: 1px solid #ccc;
- -moz-border-radius: 3px !important;
- -webkit-border-radius: 3px !important;
- border-radius: 3px !important;
- -moz-box-shadow: 0px 2px 8px #ccc;
- -webkit-box-shadow: 0px 2px 8px #ccc;
- box-shadow: 0px 2px 8px #ccc;
- -webkit-box-shadow: 0px 2px 8px rgba(0, 0, 0, .2);
- -moz-box-shadow: 0px 2px 8px rgba(0, 0, 0, .2);
- box-shadow: 0px 2px 8px rgba(0, 0, 0, .2);
-}
-
-/* @noflip */
-.rtl div.sharedaddy .sharing-hidden .inner {
- margin-left: 0;
- margin-right: -100px;
+.sharing-screen-reader-text:hover,
+.sharing-screen-reader-text:active,
+.sharing-screen-reader-text:focus {
+ background-color: #f1f1f1;
+ border-radius: 3px;
+ box-shadow: 0 0 2px 2px rgba(0, 0, 0, 0.6);
+ clip: auto !important;
+ color: #21759b;
+ display: block;
+ font-size: 14px;
+ font-weight: bold;
+ height: auto;
+ left: 5px;
+ line-height: normal;
+ padding: 15px 23px 14px;
+ text-decoration: none;
+ top: 5px;
+ width: auto;
+ z-index: 100000; /* Above WP toolbar */
}
-div.sharedaddy.sharedaddy-dark .sharing-hidden .inner {
- border-color: #222;
-}
-/* =Sharing: Email Dialog
--------------------------------------------------------------- */
+/**
+ * Sharing Email Dialog
+ */
#sharing_email {
- width: 312px;
- padding: 15px;
+ width: 342px;
position: absolute;
- margin-left: -120px;
z-index: 1001;
- background-color: #fff;
border: 1px solid #ccc;
- -moz-border-radius: 3px;
- -webkit-border-radius: 3px;
- border-radius: 3px;
- -moz-box-shadow: 0px 2px 8px #ccc;
- -webkit-box-shadow: 0px 2px 8px #ccc;
- box-shadow: 0px 2px 8px #ccc;
- -webkit-box-shadow: 0px 2px 8px rgba(0, 0, 0, .2);
- -moz-box-shadow: 0px 2px 8px rgba(0, 0, 0, .2);
- box-shadow: 0px 2px 8px rgba(0, 0, 0, .2);
+ padding: 15px;
+ background: #fff;
+ box-shadow: 0px 5px 20px rgba(0,0,0,.2);
text-align: left;
}
@@ -470,14 +627,14 @@ div.sharedaddy.sharedaddy-dark #sharing_email {
#sharing_email .errors {
color: #fff;
background-color: #771a09;
- font-size: 11px;
+ font-size: 12px;
padding: 5px 8px;
- line-height: 11px;
+ line-height: 1;
margin: 10px 0 0 0;
}
#sharing_email label {
- font-size: 11px;
+ font-size: 12px;
color: #333;
font-weight: bold;
display: block;
@@ -486,51 +643,38 @@ div.sharedaddy.sharedaddy-dark #sharing_email {
text-shadow: none;
}
-#sharing_email input[type="text"] {
- width: 98.5%;
- margin-bottom: 12px;
+#sharing_email form {
+ margin: 0;
+}
+
+#sharing_email input[type="text"], #sharing_email input[type="email"] {
+ width: 100%;
+ box-sizing: border-box;
+ -moz-box-sizing:border-box;
+ -webkit-box-sizing:border-box;
border: 1px solid #ccc;
+ margin-bottom: 1em;
background: #fff;
+ font-size: 12px;
color: #333;
+ max-width: none;
+ padding: 1px 3px;
+}
+#jetpack-source_f_name {
+ display: none!important;
+ position: absolute !important;
+ left: -9000px;
}
#sharing_email .sharing_cancel {
- padding: 0 0 0 10px;
- font-size: 11px;
+ padding: 0 0 0 1em;
+ font-size: 12px;
text-shadow: none;
}
#sharing_email .recaptcha {
width: 312px;
height: 123px;
- margin: 10px 0 14px 0;
+ margin: 0 0 1em 0;
}
-/* =RTL
--------------------------------------------------------------- */
-/* @noflip */
-body.rtl .sharing ul {
- float: right;
-}
-
-/* @noflip */
-body.rtl .sharing li {
- margin: 0 0 0 10px !important;
-}
-
-/* @noflip */
-.rtl #sharing_email {
- margin-left: -0px;
- margin-right: -120px;
- text-align: right
-}
-
-/* @noflip */
-.rtl #sharing_email label {
- text-align: right
-}
-
-/* @noflip */
-.rtl #sharing_email .sharing_cancel {
- padding: 0 10px 0 0;
-}
diff --git a/plugins/jetpack/modules/sharedaddy/sharing.js b/plugins/jetpack/modules/sharedaddy/sharing.js
index c996bb6f..daa92da1 100644
--- a/plugins/jetpack/modules/sharedaddy/sharing.js
+++ b/plugins/jetpack/modules/sharedaddy/sharing.js
@@ -1,70 +1,205 @@
-var WPCOMSharing = {
- done_urls : [],
- get_counts : function( url ) {
- if ( 'undefined' != typeof WPCOMSharing.done_urls[ WPCOM_sharing_counts[ url ] ] )
- return;
-
- if ( jQuery( '#sharing-facebook-' + WPCOM_sharing_counts[ url ] ).length )
- jQuery.getScript( 'https://api.facebook.com/method/fql.query?query=' + encodeURIComponent( "SELECT total_count, url FROM link_stat WHERE url='" + url + "'" ) + '&format=json&callback=WPCOMSharing.update_facebook_count' );
- if ( jQuery( '#sharing-twitter-' + WPCOM_sharing_counts[ url ] ).length )
- jQuery.getScript( window.location.protocol + '//cdn.api.twitter.com/1/urls/count.json?callback=WPCOMSharing.update_twitter_count&url=' + encodeURIComponent( url ) );
- if ( jQuery( '#sharing-linkedin-' + WPCOM_sharing_counts[ url ] ).length )
- jQuery.getScript( window.location.protocol + '//www.linkedin.com/countserv/count/share?format=jsonp&callback=WPCOMSharing.update_linkedin_count&url=' + encodeURIComponent( url ) );
-
- WPCOMSharing.done_urls[ WPCOM_sharing_counts[ url ] ] = true;
- },
- update_facebook_count : function( data ) {
- if ( 'undefined' != typeof data[0].total_count && ( data[0].total_count * 1 ) > 0 ) {
- WPCOMSharing.inject_share_count( 'sharing-facebook-' + WPCOM_sharing_counts[ data[0].url ], data[0].total_count );
- }
- },
- update_twitter_count : function( data ) {
- if ( 'undefined' != typeof data.count && ( data.count * 1 ) > 0 ) {
- WPCOMSharing.inject_share_count( 'sharing-twitter-' + WPCOM_sharing_counts[ data.url ], data.count );
- }
- },
- update_linkedin_count : function( data ) {
- if ( 'undefined' != typeof data.count && ( data.count * 1 ) > 0 ) {
- WPCOMSharing.inject_share_count( 'sharing-linkedin-' + WPCOM_sharing_counts[ data.url ], data.count );
+/* global WPCOM_sharing_counts, Recaptcha */
+var sharing_js_options;
+if ( sharing_js_options && sharing_js_options.counts ) {
+ var WPCOMSharing = {
+ done_urls : [],
+ twitter_count : {},
+ get_counts : function( url ) {
+ var https_url, http_url, urls, id, service, service_url;
+
+ id = WPCOM_sharing_counts[ url ];
+
+ if ( 'undefined' !== typeof WPCOMSharing.done_urls[ id ] ) {
+ return;
+ }
+
+ // get both the http and https version of these URLs
+ https_url = encodeURIComponent( url.replace( /^http:\/\//i, 'https://' ) );
+ http_url = encodeURIComponent( url.replace( /^https:\/\//i, 'http://' ) );
+
+ urls = {
+ facebook: [
+ 'https://graph.facebook.com/?ids=' +
+ http_url +
+ ',' +
+ https_url +
+ '&format=json&callback=WPCOMSharing.update_facebook_count'
+ ],
+ twitter: [
+ 'https://cdn.api.twitter.com/1/urls/count.json?callback=WPCOMSharing.update_twitter_count&url=' +
+ http_url,
+ 'https://cdn.api.twitter.com/1/urls/count.json?callback=WPCOMSharing.update_twitter_count&url=' +
+ https_url
+ ],
+ // LinkedIn actually gets the share count for both the http and https version automatically -- so we don't need to do extra magic
+ linkedin: [
+ window.location.protocol +
+ '//www.linkedin.com/countserv/count/share?format=jsonp&callback=WPCOMSharing.update_linkedin_count&url=' +
+ encodeURIComponent( url )
+ ],
+ // Pinterest, like LinkedIn, handles share counts for both http and https
+ pinterest: [
+ window.location.protocol +
+ '//api.pinterest.com/v1/urls/count.json?callback=WPCOMSharing.update_pinterest_count&url=' +
+ encodeURIComponent( url )
+ ]
+ };
+
+ if ( ! WPCOMSharing.showFacebookCount() ) {
+ delete urls.facebook;
+ }
+
+ for ( service in urls ) {
+ if ( ! jQuery( 'a[data-shared=sharing-' + service + '-' + id + ']' ).length ) {
+ continue;
+ }
+
+ while ( ( service_url = urls[ service ].pop() ) ) {
+ jQuery.getScript( service_url );
+ }
+ }
+ WPCOMSharing.done_urls[ id ] = true;
+ },
+
+ // All Facebook-enabled apps will be automaticaly upgraded to API v2.0 on April 30, 2015.
+ // endpoints will also require auth, so the below call will no logner work. a solution is being worked on
+ // but for Jetpacks that have not updated yet, we don't want the call to fail.
+ showFacebookCount: function() {
+ var day = new Date();
+
+ // if someone is running this version way past when they should be
+ if ( 2015 !== day.getFullYear() ) {
+ return false;
+ }
+
+ // after april
+ if ( 3 < day.getMonth() ) {
+ return false;
+ }
+
+ // 29th or 30th of april
+ if ( 3 === day.getMonth() ) {
+ if ( 29 <= day.getDate() ) {
+ return false;
+ }
+ }
+
+ return true;
+ },
+
+ // get the version of the url that was stored in the dom (sharing-$service-URL)
+ get_permalink: function( url ) {
+ if ( 'https:' === window.location.protocol ) {
+ url = url.replace( /^http:\/\//i, 'https://' );
+ } else {
+ url = url.replace( /^https:\/\//i, 'http://' );
+ }
+
+ // Some services (e.g. Twitter) canonicalize the URL with a trailing
+ // slash. We can account for this by checking whether either format
+ // exists as a known URL
+ if ( ! ( url in WPCOM_sharing_counts ) ) {
+ var rxTrailingSlash = /\/$/,
+ formattedSlashUrl = rxTrailingSlash.test( url ) ? url.replace( rxTrailingSlash, '' ) : url + '/';
+
+ if ( formattedSlashUrl in WPCOM_sharing_counts ) {
+ url = formattedSlashUrl;
+ }
+ }
+
+ return url;
+ },
+ update_facebook_count : function( data ) {
+ var shareCount = 0;
+ if ( 'undefined' !== typeof data && 'undefined' !== typeof Object.keys(data) && Object.keys(data).length > 0 ) {
+ if ( 'undefined' !== typeof data[Object.keys(data)[0]].shares ) {
+ shareCount += data[Object.keys(data)[0]].shares;
+ }
+
+ if ( 'undefined' !== typeof data[Object.keys(data)[1]].shares ) {
+ shareCount += data[Object.keys(data)[1]].shares;
+ }
+
+ if ( shareCount > 0 ) {
+ WPCOMSharing.inject_share_count( 'sharing-facebook-' + WPCOM_sharing_counts[ WPCOMSharing.get_permalink( Object.keys(data)[0] ) ], shareCount );
+ }
+ }
+ },
+ update_twitter_count : function( data ) {
+ if ( 'number' === typeof data.count ) {
+ var permalink = WPCOMSharing.get_permalink( data.url );
+
+ if ( ! WPCOMSharing.twitter_count[ permalink ] ) {
+ WPCOMSharing.twitter_count[ permalink ] = 0;
+ }
+
+ WPCOMSharing.twitter_count[ permalink ] += data.count;
+
+ if ( WPCOMSharing.twitter_count[ permalink ] > 0 ) {
+ WPCOMSharing.inject_share_count( 'sharing-twitter-' + WPCOM_sharing_counts[ permalink ], WPCOMSharing.twitter_count[ permalink ] );
+ }
+ }
+ },
+ update_linkedin_count : function( data ) {
+ if ( 'undefined' !== typeof data.count && ( data.count * 1 ) > 0 ) {
+ WPCOMSharing.inject_share_count( 'sharing-linkedin-' + WPCOM_sharing_counts[ data.url ], data.count );
+ }
+ },
+ update_pinterest_count : function( data ) {
+ if ( 'undefined' !== typeof data.count && ( data.count * 1 ) > 0 ) {
+ WPCOMSharing.inject_share_count( 'sharing-pinterest-' + WPCOM_sharing_counts[ data.url ], data.count );
+ }
+ },
+ inject_share_count : function( id, count ) {
+ var $share = jQuery( 'a[data-shared=' + id + '] > span');
+ $share.find( '.share-count' ).remove();
+ $share.append( '<span class="share-count">' + WPCOMSharing.format_count( count ) + '</span>' );
+ },
+ format_count : function( count ) {
+ if ( count < 1000 ) {
+ return count;
+ }
+ if ( count >= 1000 && count < 10000 ) {
+ return String( count ).substring( 0, 1 ) + 'K+';
+ }
+ return '10K+';
}
- },
- inject_share_count : function( dom_id, count ) {
- jQuery( '#' + dom_id + ' span' ).append( '<span class="share-count">' + WPCOMSharing.format_count( count ) + '</span>' );
- },
- format_count : function( count ) {
- if ( count < 1000 )
- return count;
- if ( count >= 1000 && count < 10000 )
- return String( count ).substring( 0, 1 ) + 'K+';
- return '10K+';
- }
-};
+ };
+}
(function($){
+ var $body, $sharing_email;
+
$.fn.extend( {
- share_is_email: function( value ) {
+ share_is_email: function() {
return /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test( this.val() );
}
} );
- $( document ).on( 'ready', WPCOMSharing_do );
- $( document.body ).on( 'post-load', WPCOMSharing_do );
+ $body = $( document.body ).on( 'post-load', WPCOMSharing_do );
+ $( document ).on( 'ready', function() {
+ $sharing_email = $( '#sharing_email' );
+ $body.append( $sharing_email );
+ WPCOMSharing_do();
+ } );
function WPCOMSharing_do() {
- if ( 'undefined' != typeof WPCOM_sharing_counts ) {
- for ( var url in WPCOM_sharing_counts ) {
+ var url, $more_sharing_buttons;
+ if ( 'undefined' !== typeof WPCOM_sharing_counts ) {
+ for ( url in WPCOM_sharing_counts ) {
WPCOMSharing.get_counts( url );
}
}
- var $more_sharing_buttons = $( '.sharedaddy a.sharing-anchor' );
+ $more_sharing_buttons = $( '.sharedaddy a.sharing-anchor' );
$more_sharing_buttons.click( function() {
return false;
} );
$( '.sharedaddy a' ).each( function() {
- if ( $( this ).attr( 'href' ) && $( this ).attr( 'href' ).indexOf( 'share=' ) != -1 )
+ if ( $( this ).attr( 'href' ) && $( this ).attr( 'href' ).indexOf( 'share=' ) !== -1 ) {
$( this ).attr( 'href', $( this ).attr( 'href' ) + '&nb=1' );
+ }
} );
// Show hidden buttons
@@ -73,7 +208,7 @@ var WPCOMSharing = {
// Non-touchscreen device: use click if not already appearing due to a hover event
$more_sharing_buttons.on( 'click', function() {
var $more_sharing_button = $( this ),
- $more_sharing_pane = $more_sharing_button.parents( 'div:first' ).find( '.inner' );
+ $more_sharing_pane = $more_sharing_button.parents( 'div:first' ).find( '.inner' );
if ( $more_sharing_pane.is( ':animated' ) ) {
// We're in the middle of some other event's animation
@@ -85,7 +220,7 @@ var WPCOMSharing = {
return;
}
- $( '#sharing_email' ).slideUp( 200 );
+ $sharing_email.slideUp( 200 );
$more_sharing_pane.css( {
left: $more_sharing_button.position().left + 'px',
@@ -97,12 +232,15 @@ var WPCOMSharing = {
// Non-touchscreen device: use hover/mouseout with delay
$more_sharing_buttons.hover( function() {
var $more_sharing_button = $( this ),
- $more_sharing_pane = $more_sharing_button.parents( 'div:first' ).find( '.inner' );
+ $more_sharing_pane = $more_sharing_button.parents( 'div:first' ).find( '.inner' ),
+ timer;
- if ( !$more_sharing_pane.is( ':animated' ) ) {
+ if ( ! $more_sharing_pane.is( ':animated' ) ) {
// Create a timer to make the area appear if the mouse hovers for a period
- var timer = setTimeout( function() {
- $( '#sharing_email' ).slideUp( 200 );
+ timer = setTimeout( function() {
+ var handler_item_leave, handler_item_enter, handler_original_leave, handler_original_enter, close_it;
+
+ $sharing_email.slideUp( 200 );
$more_sharing_pane.data( 'justSlid', true );
$more_sharing_pane.css( {
@@ -126,7 +264,7 @@ var WPCOMSharing = {
} );
// The following handlers take care of the mouseenter/mouseleave for the share button and the share area - if both are left then we close the share area
- var handler_item_leave = function() {
+ handler_item_leave = function() {
$more_sharing_button.data( 'hasitem', false );
if ( $more_sharing_button.data( 'hasoriginal' ) === false ) {
@@ -135,12 +273,12 @@ var WPCOMSharing = {
}
};
- var handler_item_enter = function() {
+ handler_item_enter = function() {
$more_sharing_button.data( 'hasitem', true );
clearTimeout( $more_sharing_button.data( 'timer2' ) );
- }
+ };
- var handler_original_leave = function() {
+ handler_original_leave = function() {
$more_sharing_button.data( 'hasoriginal', false );
if ( $more_sharing_button.data( 'hasitem' ) === false ) {
@@ -149,12 +287,12 @@ var WPCOMSharing = {
}
};
- var handler_original_enter = function() {
+ handler_original_enter = function() {
$more_sharing_button.data( 'hasoriginal', true );
clearTimeout( $more_sharing_button.data( 'timer2' ) );
};
- var close_it = function() {
+ close_it = function() {
$more_sharing_pane.data( 'justSlid', true );
$more_sharing_pane.slideUp( 200, function() {
setTimeout( function() {
@@ -181,58 +319,75 @@ var WPCOMSharing = {
} );
}
+ $( document ).click(function() {
+
+ // Click outside
+ // remove any timer
+ $more_sharing_buttons.each( function() {
+ clearTimeout( $( this ).data( 'timer' ) );
+ } );
+ $more_sharing_buttons.data( 'timer', false );
+
+ // slide down forcibly
+ $( '.sharedaddy .inner' ).slideUp();
+
+ });
+
// Add click functionality
- $( '.sharedaddy ul' ).each( function( item ) {
+ $( '.sharedaddy ul' ).each( function() {
- if ( 'yep' == $( this ).data( 'has-click-events' ) )
+ if ( 'yep' === $( this ).data( 'has-click-events' ) ) {
return;
+ }
$( this ).data( 'has-click-events', 'yep' );
- printUrl = function ( uniqueId, urlToPrint ) {
- $( 'body:first' ).append( '<iframe style="position:fixed;top:100;left:100;height:1px;width:1px;border:none;" id="printFrame-' + uniqueId + '" name="printFrame-' + uniqueId + '" src="' + urlToPrint + '" onload="frames[\'printFrame-' + uniqueId + '\'].focus();frames[\'printFrame-' + uniqueId + '\'].print();"></iframe>' )
+ var printUrl = function ( uniqueId, urlToPrint ) {
+ $( 'body:first' ).append( '<iframe style="position:fixed;top:100;left:100;height:1px;width:1px;border:none;" id="printFrame-' + uniqueId + '" name="printFrame-' + uniqueId + '" src="' + urlToPrint + '" onload="frames[\'printFrame-' + uniqueId + '\'].focus();frames[\'printFrame-' + uniqueId + '\'].print();"></iframe>' );
};
// Print button
$( this ).find( 'a.share-print' ).click( function() {
- ref = $( this ).attr( 'href' );
-
- var do_print = function() {
- if ( ref.indexOf( '#print' ) == -1 ) {
- uid = new Date().getTime();
- printUrl( uid , ref );
- }
- else
- print();
- }
+ var ref = $( this ).attr( 'href' ),
+ do_print = function() {
+ if ( ref.indexOf( '#print' ) === -1 ) {
+ var uid = new Date().getTime();
+ printUrl( uid , ref );
+ } else {
+ print();
+ }
+ };
// Is the button in a dropdown?
if ( $( this ).parents( '.sharing-hidden' ).length > 0 ) {
$( this ).parents( '.inner' ).slideUp( 0, function() {
do_print();
} );
- }
- else
+ } else {
do_print();
+ }
return false;
} );
// Press This button
$( this ).find( 'a.share-press-this' ).click( function() {
- var s = '';
-
- if ( window.getSelection )
- s = window.getSelection();
- else if( document.getSelection )
- s = document.getSelection();
- else if( document.selection )
- s = document.selection.createRange().text;
+ var s = '';
+
+ if ( window.getSelection ) {
+ s = window.getSelection();
+ } else if( document.getSelection ) {
+ s = document.getSelection();
+ } else if( document.selection ) {
+ s = document.selection.createRange().text;
+ }
- if ( s )
+ if ( s ) {
$( this ).attr( 'href', $( this ).attr( 'href' ) + '&sel=' + encodeURI( s ) );
+ }
- if ( !window.open( $( this ).attr( 'href' ), 't', 'toolbar=0,resizable=1,scrollbars=1,status=1,width=720,height=570' ) )
+ if ( !window.open( $( this ).attr( 'href' ), 't', 'toolbar=0,resizable=1,scrollbars=1,status=1,width=720,height=570' ) ) {
document.location.href = $( this ).attr( 'href' );
+ }
return false;
} );
@@ -241,9 +396,9 @@ var WPCOMSharing = {
$( 'a.share-email', this ).on( 'click', function() {
var url = $( this ).attr( 'href' ), key;
- if ( $( '#sharing_email' ).is( ':visible' ) )
- $( '#sharing_email' ).slideUp( 200 );
- else {
+ if ( $sharing_email.is( ':visible' ) ) {
+ $sharing_email.slideUp( 200 );
+ } else {
$( '.sharedaddy .inner' ).slideUp();
$( '#sharing_email .response' ).remove();
@@ -252,14 +407,15 @@ var WPCOMSharing = {
$( '#sharing_email form a.sharing_cancel' ).show();
key = '';
- if ( $( '#recaptcha_public_key' ).length > 0 )
+ if ( $( '#recaptcha_public_key' ).length > 0 ) {
key = $( '#recaptcha_public_key' ).val();
+ }
// Update the recaptcha
- Recaptcha.create( key, 'sharing_recaptcha', { lang : recaptcha_options.lang } );
+ Recaptcha.create( key, 'sharing_recaptcha', { lang : sharing_js_options.lang } );
// Show dialog
- $( '#sharing_email' ).css( {
+ $sharing_email.css( {
left: $( this ).offset().left + 'px',
top: $( this ).offset().top + $( this ).height() + 'px'
} ).slideDown( 200 );
@@ -267,7 +423,7 @@ var WPCOMSharing = {
// Hook up other buttons
$( '#sharing_email a.sharing_cancel' ).unbind( 'click' ).click( function() {
$( '#sharing_email .errors' ).hide();
- $( '#sharing_email' ).slideUp( 200 );
+ $sharing_email.slideUp( 200 );
$( '#sharing_background' ).fadeOut();
return false;
} );
@@ -284,13 +440,15 @@ var WPCOMSharing = {
$( '#sharing_email .errors' ).hide();
$( '#sharing_email .error' ).removeClass( 'error' );
- if ( $( '#sharing_email input[name=source_email]' ).share_is_email() == false )
+ if ( ! $( '#sharing_email input[name=source_email]' ).share_is_email() ) {
$( '#sharing_email input[name=source_email]' ).addClass( 'error' );
+ }
- if ( $( '#sharing_email input[name=target_email]' ).share_is_email() == false )
+ if ( ! $( '#sharing_email input[name=target_email]' ).share_is_email() ) {
$( '#sharing_email input[name=target_email]' ).addClass( 'error' );
+ }
- if ( $( '#sharing_email .error' ).length == 0 ) {
+ if ( $( '#sharing_email .error' ).length === 0 ) {
// AJAX send the form
$.ajax( {
url: url,
@@ -299,7 +457,7 @@ var WPCOMSharing = {
success: function( response ) {
form.find( 'img.loading' ).hide();
- if ( response == '1' || response == '2' || response == '3' ) {
+ if ( response === '1' || response === '2' || response === '3' ) {
$( '#sharing_email .errors-' + response ).show();
form.find( 'input[type=submit]' ).removeAttr( 'disabled' );
form.find( 'a.sharing_cancel' ).show();
@@ -307,9 +465,9 @@ var WPCOMSharing = {
}
else {
$( '#sharing_email form' ).hide();
- $( '#sharing_email' ).append( response );
+ $sharing_email.append( response );
$( '#sharing_email a.sharing_cancel' ).click( function() {
- $( '#sharing_email' ).slideUp( 200 );
+ $sharing_email.slideUp( 200 );
$( '#sharing_background' ).fadeOut();
return false;
} );
@@ -338,6 +496,7 @@ var WPCOMSharing = {
})( jQuery );
// Recaptcha code
+/* jshint ignore:start */
var RecaptchaTemplates={};RecaptchaTemplates.VertHtml='<table id="recaptcha_table" class="recaptchatable" > <tr> <td colspan="6" class=\'recaptcha_r1_c1\'></td> </tr> <tr> <td class=\'recaptcha_r2_c1\'></td> <td colspan="4" class=\'recaptcha_image_cell\'><div id="recaptcha_image"></div></td> <td class=\'recaptcha_r2_c2\'></td> </tr> <tr> <td rowspan="6" class=\'recaptcha_r3_c1\'></td> <td colspan="4" class=\'recaptcha_r3_c2\'></td> <td rowspan="6" class=\'recaptcha_r3_c3\'></td> </tr> <tr> <td rowspan="3" class=\'recaptcha_r4_c1\' height="49"> <div class="recaptcha_input_area"> <label for="recaptcha_response_field" class="recaptcha_input_area_text"><span id="recaptcha_instructions_image" class="recaptcha_only_if_image recaptcha_only_if_no_incorrect_sol"></span><span id="recaptcha_instructions_audio" class="recaptcha_only_if_no_incorrect_sol recaptcha_only_if_audio"></span><span id="recaptcha_instructions_error" class="recaptcha_only_if_incorrect_sol"></span></label><br/> <input name="recaptcha_response_field" id="recaptcha_response_field" type="text" /> </div> </td> <td rowspan="4" class=\'recaptcha_r4_c2\'></td> <td><a id=\'recaptcha_reload_btn\'><img id=\'recaptcha_reload\' width="25" height="17" /></a></td> <td rowspan="4" class=\'recaptcha_r4_c4\'></td> </tr> <tr> <td><a id=\'recaptcha_switch_audio_btn\' class="recaptcha_only_if_image"><img id=\'recaptcha_switch_audio\' width="25" height="16" alt="" /></a><a id=\'recaptcha_switch_img_btn\' class="recaptcha_only_if_audio"><img id=\'recaptcha_switch_img\' width="25" height="16" alt=""/></a></td> </tr> <tr> <td><a id=\'recaptcha_whatsthis_btn\'><img id=\'recaptcha_whatsthis\' width="25" height="16" /></a></td> </tr> <tr> <td class=\'recaptcha_r7_c1\'></td> <td class=\'recaptcha_r8_c1\'></td> </tr> </table> ';RecaptchaTemplates.CleanCss=".recaptchatable td img{display:block}.recaptchatable .recaptcha_image_cell center img{height:57px}.recaptchatable .recaptcha_image_cell center{height:57px}.recaptchatable .recaptcha_image_cell{background-color:white;height:57px;padding:7px!important}.recaptchatable,#recaptcha_area tr,#recaptcha_area td,#recaptcha_area th{margin:0!important;border:0!important;border-collapse:collapse!important;vertical-align:middle!important}.recaptchatable *{margin:0;padding:0;border:0;color:black;position:static;top:auto;left:auto;right:auto;bottom:auto;text-align:left!important}.recaptchatable #recaptcha_image{margin:auto;border:1px solid #dfdfdf!important}.recaptchatable a img{border:0}.recaptchatable a,.recaptchatable a:hover{-moz-outline:none;border:0!important;padding:0!important;text-decoration:none;color:blue;background:none!important;font-weight:normal}.recaptcha_input_area{position:relative!important;background:none!important}.recaptchatable label.recaptcha_input_area_text{border:1px solid #dfdfdf!important;margin:0!important;padding:0!important;position:static!important;top:auto!important;left:auto!important;right:auto!important;bottom:auto!important}.recaptcha_theme_red label.recaptcha_input_area_text,.recaptcha_theme_white label.recaptcha_input_area_text{color:black!important}.recaptcha_theme_blackglass label.recaptcha_input_area_text{color:white!important}.recaptchatable #recaptcha_response_field{font-size:11pt}.recaptcha_theme_blackglass #recaptcha_response_field,.recaptcha_theme_white #recaptcha_response_field{border:1px solid gray}.recaptcha_theme_red #recaptcha_response_field{border:1px solid #cca940}.recaptcha_audio_cant_hear_link{font-size:7pt;color:black}.recaptchatable{line-height:1em;border:1px solid #dfdfdf!important}.recaptcha_error_text{color:red}";RecaptchaTemplates.CleanHtml='<table id="recaptcha_table" class="recaptchatable"> <tr height="73"> <td class=\'recaptcha_image_cell\' width="302"><center><div id="recaptcha_image"></div></center></td> <td style="padding: 10px 7px 7px 7px;"> <a id=\'recaptcha_reload_btn\'><img id=\'recaptcha_reload\' width="25" height="18" alt="" /></a> <a id=\'recaptcha_switch_audio_btn\' class="recaptcha_only_if_image"><img id=\'recaptcha_switch_audio\' width="25" height="15" alt="" /></a><a id=\'recaptcha_switch_img_btn\' class="recaptcha_only_if_audio"><img id=\'recaptcha_switch_img\' width="25" height="15" alt=""/></a> <a id=\'recaptcha_whatsthis_btn\'><img id=\'recaptcha_whatsthis\' width="25" height="16" /></a> </td> <td style="padding: 18px 7px 18px 7px;"> <img id=\'recaptcha_logo\' alt="" width="71" height="36" /> </td> </tr> <tr> <td style="padding-left: 7px;"> <div class="recaptcha_input_area" style="padding-top: 2px; padding-bottom: 7px;"> <input style="border: 1px solid #3c3c3c; width: 302px;" name="recaptcha_response_field" id="recaptcha_response_field" type="text" /> </div> </td> <td></td> <td style="padding: 4px 7px 12px 7px;"> <img id="recaptcha_tagline" width="71" height="17" /> </td> </tr> </table> ';RecaptchaTemplates.ContextHtml='<table id="recaptcha_table" class="recaptchatable"> <tr> <td colspan="6" class=\'recaptcha_r1_c1\'></td> </tr> <tr> <td class=\'recaptcha_r2_c1\'></td> <td colspan="4" class=\'recaptcha_image_cell\'><div id="recaptcha_image"></div></td> <td class=\'recaptcha_r2_c2\'></td> </tr> <tr> <td rowspan="6" class=\'recaptcha_r3_c1\'></td> <td colspan="4" class=\'recaptcha_r3_c2\'></td> <td rowspan="6" class=\'recaptcha_r3_c3\'></td> </tr> <tr> <td rowspan="3" class=\'recaptcha_r4_c1\' height="49"> <div class="recaptcha_input_area"> <label for="recaptcha_response_field" class="recaptcha_input_area_text"><span id="recaptcha_instructions_context" class="recaptcha_only_if_image recaptcha_only_if_no_incorrect_sol"></span><span id="recaptcha_instructions_audio" class="recaptcha_only_if_no_incorrect_sol recaptcha_only_if_audio"></span><span id="recaptcha_instructions_error" class="recaptcha_only_if_incorrect_sol"></span></label><br/> <input name="recaptcha_response_field" id="recaptcha_response_field" type="text" /> </div> </td> <td rowspan="4" class=\'recaptcha_r4_c2\'></td> <td><a id=\'recaptcha_reload_btn\'><img id=\'recaptcha_reload\' width="25" height="17" /></a></td> <td rowspan="4" class=\'recaptcha_r4_c4\'></td> </tr> <tr> <td><a id=\'recaptcha_switch_audio_btn\' class="recaptcha_only_if_image"><img id=\'recaptcha_switch_audio\' width="25" height="16" alt="" /></a><a id=\'recaptcha_switch_img_btn\' class="recaptcha_only_if_audio"><img id=\'recaptcha_switch_img\' width="25" height="16" alt=""/></a></td> </tr> <tr> <td><a id=\'recaptcha_whatsthis_btn\'><img id=\'recaptcha_whatsthis\' width="25" height="16" /></a></td> </tr> <tr> <td class=\'recaptcha_r7_c1\'></td> <td class=\'recaptcha_r8_c1\'></td> </tr> </table> ';RecaptchaTemplates.VertCss=".recaptchatable td img{display:block}.recaptchatable .recaptcha_r1_c1{background:url(IMGROOT/sprite.png) 0 -63px no-repeat;width:318px;height:9px}.recaptchatable .recaptcha_r2_c1{background:url(IMGROOT/sprite.png) -18px 0 no-repeat;width:9px;height:57px}.recaptchatable .recaptcha_r2_c2{background:url(IMGROOT/sprite.png) -27px 0 no-repeat;width:9px;height:57px}.recaptchatable .recaptcha_r3_c1{background:url(IMGROOT/sprite.png) 0 0 no-repeat;width:9px;height:63px}.recaptchatable .recaptcha_r3_c2{background:url(IMGROOT/sprite.png) -18px -57px no-repeat;width:300px;height:6px}.recaptchatable .recaptcha_r3_c3{background:url(IMGROOT/sprite.png) -9px 0 no-repeat;width:9px;height:63px}.recaptchatable .recaptcha_r4_c1{background:url(IMGROOT/sprite.png) -43px 0 no-repeat;width:171px;height:49px}.recaptchatable .recaptcha_r4_c2{background:url(IMGROOT/sprite.png) -36px 0 no-repeat;width:7px;height:57px}.recaptchatable .recaptcha_r4_c4{background:url(IMGROOT/sprite.png) -214px 0 no-repeat;width:97px;height:57px}.recaptchatable .recaptcha_r7_c1{background:url(IMGROOT/sprite.png) -43px -49px no-repeat;width:171px;height:8px}.recaptchatable .recaptcha_r8_c1{background:url(IMGROOT/sprite.png) -43px -49px no-repeat;width:25px;height:8px}.recaptchatable .recaptcha_image_cell center img{height:57px}.recaptchatable .recaptcha_image_cell center{height:57px}.recaptchatable .recaptcha_image_cell{background-color:white;height:57px}#recaptcha_area,#recaptcha_table{width:318px!important}.recaptchatable,#recaptcha_area tr,#recaptcha_area td,#recaptcha_area th{margin:0!important;border:0!important;padding:0!important;border-collapse:collapse!important;vertical-align:middle!important}.recaptchatable *{margin:0;padding:0;border:0;font-family:helvetica,sans-serif;font-size:8pt;color:black;position:static;top:auto;left:auto;right:auto;bottom:auto;text-align:left!important}.recaptchatable #recaptcha_image{margin:auto}.recaptchatable img{border:0!important;margin:0!important;padding:0!important}.recaptchatable a,.recaptchatable a:hover{-moz-outline:none;border:0!important;padding:0!important;text-decoration:none;color:blue;background:none!important;font-weight:normal}.recaptcha_input_area{position:relative!important;width:146px!important;height:45px!important;margin-left:20px!important;margin-right:5px!important;margin-top:4px!important;background:none!important}.recaptchatable label.recaptcha_input_area_text{margin:0!important;padding:0!important;position:static!important;top:auto!important;left:auto!important;right:auto!important;bottom:auto!important;background:none!important;height:auto!important;width:auto!important}.recaptcha_theme_red label.recaptcha_input_area_text,.recaptcha_theme_white label.recaptcha_input_area_text{color:black!important}.recaptcha_theme_blackglass label.recaptcha_input_area_text{color:white!important}.recaptchatable #recaptcha_response_field{width:145px!important;position:absolute!important;bottom:7px!important;padding:0!important;margin:0!important;font-size:10pt}.recaptcha_theme_blackglass #recaptcha_response_field,.recaptcha_theme_white #recaptcha_response_field{border:1px solid gray}.recaptcha_theme_red #recaptcha_response_field{border:1px solid #cca940}.recaptcha_audio_cant_hear_link{font-size:7pt;color:black}.recaptchatable{line-height:1em}#recaptcha_instructions_error{color:red!important}";var RecaptchaStr_en={visual_challenge:"Get a visual challenge",audio_challenge:"Get an audio challenge",refresh_btn:"Get a new challenge",instructions_visual:"Type the two words:",instructions_context:"Type the words in the boxes:",instructions_audio:"Type what you hear:",help_btn:"Help",play_again:"Play sound again",cant_hear_this:"Download sound as MP3",incorrect_try_again:"Incorrect. Try again."},RecaptchaStr_de={visual_challenge:"Visuelle Aufgabe generieren",audio_challenge:"Audio-Aufgabe generieren",
refresh_btn:"Neue Aufgabe generieren",instructions_visual:"Gib die 2 W\u00f6rter ein:",instructions_context:"",instructions_audio:"Gib die 8 Ziffern ein:",help_btn:"Hilfe",incorrect_try_again:"Falsch. Nochmals versuchen!"},RecaptchaStr_es={visual_challenge:"Obt\u00e9n un reto visual",audio_challenge:"Obt\u00e9n un reto audible",refresh_btn:"Obt\u00e9n un nuevo reto",instructions_visual:"Escribe las 2 palabras:",instructions_context:"",instructions_audio:"Escribe los 8 n\u00fameros:",help_btn:"Ayuda",
incorrect_try_again:"Incorrecto. Otro intento."},RecaptchaStr_fr={visual_challenge:"D\u00e9fi visuel",audio_challenge:"D\u00e9fi audio",refresh_btn:"Nouveau d\u00e9fi",instructions_visual:"Entrez les deux mots:",instructions_context:"",instructions_audio:"Entrez les huit chiffres:",help_btn:"Aide",incorrect_try_again:"Incorrect."},RecaptchaStr_nl={visual_challenge:"Test me via een afbeelding",audio_challenge:"Test me via een geluidsfragment",refresh_btn:"Nieuwe uitdaging",instructions_visual:"Type de twee woorden:",
@@ -367,3 +526,4 @@ if(!d)d=document.body;var e=d.className;e=e.replace(RegExp("(^|\\s+)"+a+"(\\s+|$
c=(Recaptcha.checkFlashVer()?'<br/><a class="recaptcha_audio_cant_hear_link" href="#" onclick="Recaptcha.playAgain(); return false;">'+RecaptchaStr.play_again+"</a>":"")+'<br/><a class="recaptcha_audio_cant_hear_link" target="_blank" href="'+c+'">'+RecaptchaStr.cant_hear_this+"</a>";return a+c},gethttpwavurl:function(){var a=RecaptchaState;if(Recaptcha.type=="audio"){a=a.server+"image?c="+a.challenge;if(a.indexOf("https://")==0)a="http://"+a.substring(8);return a}return""},checkFlashVer:function(){var a=
navigator.appVersion.indexOf("MSIE")!=-1?true:false,b=navigator.appVersion.toLowerCase().indexOf("win")!=-1?true:false,c=navigator.userAgent.indexOf("Opera")!=-1?true:false,d=-1;if(navigator.plugins!=null&&navigator.plugins.length>0){if(navigator.plugins["Shockwave Flash 2.0"]||navigator.plugins["Shockwave Flash"]){a=navigator.plugins["Shockwave Flash 2.0"]?" 2.0":"";a=navigator.plugins["Shockwave Flash"+a].description;a=a.split(" ");a=a[2].split(".");d=a[0]}}else if(a&&b&&!c)try{var e=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"),
f=e.GetVariable("$version");d=f.split(" ")[1].split(",")[0]}catch(g){}return d>=9},getlang:function(){return RecaptchaOptions.lang}};
+/* jshint ignore:end */
diff --git a/plugins/jetpack/modules/sharedaddy/sharing.php b/plugins/jetpack/modules/sharedaddy/sharing.php
index 24a1e91f..7ddd2ac9 100644
--- a/plugins/jetpack/modules/sharedaddy/sharing.php
+++ b/plugins/jetpack/modules/sharedaddy/sharing.php
@@ -24,9 +24,18 @@ class Sharing_Admin {
public function sharing_head() {
wp_enqueue_script( 'sharing-js', WP_SHARING_PLUGIN_URL.'admin-sharing.js', array( 'jquery-ui-draggable', 'jquery-ui-droppable', 'jquery-ui-sortable', 'jquery-form' ), 2 );
- wp_enqueue_style( 'sharing-admin', WP_SHARING_PLUGIN_URL.'admin-sharing.css', false, JETPACK__VERSION );
- wp_enqueue_style( 'sharing', WP_SHARING_PLUGIN_URL.'sharing.css', false, JETPACK__VERSION );
- wp_enqueue_script( 'sharing-js-fe', WP_SHARING_PLUGIN_URL . 'sharing.js', array( ), 3 );
+
+ // @todo: Remove this opt-out filter in the future
+ if ( ( ! defined( 'IS_WPCOM' ) ) || ( ! IS_WPCOM ) || apply_filters( 'wpl_sharing_2014_1', true ) ) {
+ wp_enqueue_style( 'sharing-admin', WP_SHARING_PLUGIN_URL.'admin-sharing.css', false, JETPACK__VERSION );
+ wp_enqueue_style( 'sharing', WP_SHARING_PLUGIN_URL.'sharing.css', false, JETPACK__VERSION );
+ wp_enqueue_style( 'genericons' );
+ } else {
+ wp_enqueue_style( 'sharing-admin', WP_SHARING_PLUGIN_URL.'admin-sharing-legacy.css', false, JETPACK__VERSION );
+ wp_enqueue_style( 'sharing', WP_SHARING_PLUGIN_URL.'sharing-legacy.css', false, JETPACK__VERSION );
+ }
+
+ wp_enqueue_script( 'sharing-js-fe', WP_SHARING_PLUGIN_URL . 'sharing.js', array( ), 4 );
add_thickbox();
}
@@ -40,6 +49,11 @@ class Sharing_Admin {
if ( isset( $_POST['_wpnonce'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'sharing-options' ) ) {
$sharer = new Sharing_Service();
$sharer->set_global_options( $_POST );
+ /**
+ * Fires when updating sharing settings.
+ *
+ * @since 1.1.0
+ */
do_action( 'sharing_admin_update' );
wp_safe_redirect( admin_url( 'options-general.php?page=sharing&update=saved' ) );
@@ -121,13 +135,13 @@ class Sharing_Admin {
}
echo '<li class="'.implode( ' ', $klasses ).'">';
- echo $service->display_preview();
+ $service->display_preview();
echo '</li>';
}
public function output_service( $id, $service, $show_dropdown = false ) {
?>
- <li class="service advanced share-<?php echo $service->get_class(); ?>" id="<?php echo $service->get_id(); ?>">
+ <li class="service advanced share-<?php echo $service->get_class(); ?>" id="<?php echo $service->get_id(); ?>" tabindex="0">
<span class="options-left"><?php echo esc_html( $service->get_name() ); ?></span>
<?php if ( 0 === strpos( $service->get_id(), 'custom-' ) || $service->has_advanced_options() ) : ?>
<span class="close"><a href="#" class="remove">&times;</a></span>
@@ -156,57 +170,68 @@ class Sharing_Admin {
if ( isset( $_GET['update'] ) && $_GET['update'] == 'saved' )
echo '<div class="updated"><p>'.__( 'Settings have been saved', 'jetpack' ).'</p></div>';
+
+ if( ! isset( $global['sharing_label'] ) ) {
+ $global['sharing_label'] = __( 'Share this:', 'jetpack' );
+ }
?>
<div class="wrap">
- <div class="icon32" id="icon-options-general"><br /></div>
- <h2><?php _e( 'Sharing Settings', 'jetpack' ); ?></h2>
-
- <?php do_action( 'pre_admin_screen_sharing' ) ?>
+ <div class="icon32" id="icon-options-general"><br /></div>
+ <h2><?php _e( 'Sharing Settings', 'jetpack' ); ?></h2>
+
+ <?php
+ /**
+ * Fires at the top of the admin sharing settings screen.
+ *
+ * @since 1.6.0
+ */
+ do_action( 'pre_admin_screen_sharing' );
+ ?>
<?php if ( current_user_can( 'manage_options' ) ) : ?>
<div class="share_manage_options">
- <h3><?php _e( 'Sharing Buttons', 'jetpack' ) ?></h3>
- <p><?php _e( 'Add sharing buttons to your blog and allow your visitors to share posts with their friends.', 'jetpack' ) ?></p>
+ <h3><?php _e( 'Sharing Buttons', 'jetpack' ) ?></h3>
+ <p><?php _e( 'Add sharing buttons to your blog and allow your visitors to share posts with their friends.', 'jetpack' ) ?></p>
- <div id="services-config">
- <table id="available-services">
+ <div id="services-config">
+ <table id="available-services">
<tr>
- <td class="description">
- <h3><?php _e( 'Available Services', 'jetpack' ); ?></h3>
- <p><?php _e( "Drag and drop the services you'd like to enable into the box below.", 'jetpack' ); ?></p>
- <p><a href="#TB_inline?height=395&amp;width=600&amp;inlineId=new-service" title="<?php echo esc_attr( __( 'Add a new service', 'jetpack' ) ); ?>" class="thickbox" id="add-a-new-service"><?php _e( 'Add a new service', 'jetpack' ); ?></a></p>
- </td>
- <td class="services">
- <ul class="services-available" style="height: 100px;">
- <?php foreach ( $sharer->get_all_services_blog() AS $id => $service ) : ?>
- <?php
- if ( !isset( $enabled['all'][$id] ) )
+ <td class="description">
+ <h3><?php _e( 'Available Services', 'jetpack' ); ?></h3>
+ <p><?php _e( "Drag and drop the services you'd like to enable into the box below.", 'jetpack' ); ?></p>
+ <p><a href="#TB_inline?height=395&amp;width=600&amp;inlineId=new-service" class="thickbox" id="add-a-new-service"><?php _e( 'Add a new service', 'jetpack' ); ?></a></p>
+ </td>
+ <td class="services">
+ <ul class="services-available" style="height: 100px;">
+ <?php foreach ( $sharer->get_all_services_blog() AS $id => $service ) : ?>
+ <?php
+ if ( !isset( $enabled['all'][$id] ) )
$this->output_service( $id, $service );
?>
- <?php endforeach; ?>
- </ul>
+ <?php endforeach; ?>
+ </ul>
<?php
- if ( -1 == get_option( 'blog_public' ) )
+ if ( -1 == get_option( 'blog_public' ) )
echo '<p><strong>'.__( 'Please note that your services have been restricted because your site is private.', 'jetpack' ).'</strong></p>';
- ?>
- <br class="clearing" />
- </td>
+ ?>
+ <br class="clearing" />
+ </td>
</tr>
- </table>
+ </table>
- <table id="enabled-services">
- <tr>
- <td class="description">
+ <table id="enabled-services">
+ <tr>
+ <td class="description">
<h3>
<?php _e( 'Enabled Services', 'jetpack' ); ?>
<img src="<?php echo admin_url( 'images/loading.gif' ); ?>" width="16" height="16" alt="loading" style="vertical-align: middle; display: none" />
</h3>
<p><?php _e( 'Services dragged here will appear individually.', 'jetpack' ); ?></p>
- </td>
- <td class="services" id="share-drop-target">
- <h2 id="drag-instructions" <?php if ( count( $enabled['visible'] ) > 0 ) echo ' style="display: none"'; ?>><?php _e( 'Drag and drop available services here.', 'jetpack' ); ?></h2>
+ </td>
+ <td class="services" id="share-drop-target">
+ <h2 id="drag-instructions" <?php if ( count( $enabled['visible'] ) > 0 ) echo ' style="display: none"'; ?>><?php _e( 'Drag and drop available services here.', 'jetpack' ); ?></h2>
<ul class="services-enabled">
<?php foreach ( $enabled['visible'] as $id => $service ) : ?>
@@ -217,14 +242,14 @@ class Sharing_Admin {
</ul>
</td>
<td id="hidden-drop-target" class="services">
- <p><?php _e( 'Services dragged here will be hidden behind a share button.', 'jetpack' ); ?></p>
+ <p><?php _e( 'Services dragged here will be hidden behind a share button.', 'jetpack' ); ?></p>
- <ul class="services-hidden">
+ <ul class="services-hidden">
<?php foreach ( $enabled['hidden'] as $id => $service ) : ?>
<?php $this->output_service( $id, $service, true ); ?>
<?php endforeach; ?>
<li class="end-fix"></li>
- </ul>
+ </ul>
</td>
</tr>
</table>
@@ -242,16 +267,16 @@ class Sharing_Admin {
<?php endif; ?>
<div class="sd-content">
<ul class="preview">
- <?php foreach ( $enabled['visible'] as $id => $service ) : ?>
+ <?php foreach ( $enabled['visible'] as $id => $service ) : ?>
<?php $this->output_preview( $service ); ?>
<?php endforeach; ?>
<?php if ( count( $enabled['hidden'] ) > 0 ) : ?>
- <li class="advanced"><a href="#" class="sharing-anchor sd-button share-more"><span><?php _e( 'More', 'jetpack' ); ?></span></a></li>
- <?php endif; ?>
- </ul>
+ <li class="advanced"><a href="#" class="sharing-anchor sd-button share-more"><span><?php _e( 'More', 'jetpack' ); ?></span></a></li>
+ <?php endif; ?>
+ </ul>
- <?php if ( count( $enabled['hidden'] ) > 0 ) : ?>
+ <?php if ( count( $enabled['hidden'] ) > 0 ) : ?>
<div class="sharing-hidden">
<div class="inner" style="display: none; <?php echo count( $enabled['hidden'] ) == 1 ? 'width:150px;' : ''; ?>">
<?php if ( count( $enabled['hidden'] ) == 1 ) : ?>
@@ -295,40 +320,40 @@ class Sharing_Admin {
<input type="hidden" name="hidden" value="<?php echo implode( ',', array_keys( $enabled['hidden'] ) ); ?>" />
<input type="hidden" name="_wpnonce" value="<?php echo wp_create_nonce( 'sharing-options' );?>" />
</form>
- </div>
-
- <form method="post" action="">
- <table class="form-table">
- <tbody>
- <tr valign="top">
- <th scope="row"><label><?php _e( 'Button style', 'jetpack' ); ?></label></th>
- <td>
- <select name="button_style" id="button_style">
- <option<?php if ( $global['button_style'] == 'icon-text' ) echo ' selected="selected"';?> value="icon-text"><?php _e( 'Icon + text', 'jetpack' ); ?></option>
- <option<?php if ( $global['button_style'] == 'icon' ) echo ' selected="selected"';?> value="icon"><?php _e( 'Icon only', 'jetpack' ); ?></option>
- <option<?php if ( $global['button_style'] == 'text' ) echo ' selected="selected"';?> value="text"><?php _e( 'Text only', 'jetpack' ); ?></option>
- <option<?php if ( $global['button_style'] == 'official' ) echo ' selected="selected"';?> value="official"><?php _e( 'Official buttons', 'jetpack' ); ?></option>
- </select>
- </td>
- </tr>
- <tr valign="top">
- <th scope="row"><label><?php _e( 'Sharing label', 'jetpack' ); ?></label></th>
- <td>
- <input type="text" name="sharing_label" value="<?php echo esc_attr( $global['sharing_label'] ); ?>" />
- </td>
- </tr>
- <tr valign="top">
- <th scope="row"><label><?php _e( 'Open links in', 'jetpack' ); ?></label></th>
- <td>
- <select name="open_links">
- <option<?php if ( $global['open_links'] == 'new' ) echo ' selected="selected"';?> value="new"><?php _e( 'New window', 'jetpack' ); ?></option>
- <option<?php if ( $global['open_links'] == 'same' ) echo ' selected="selected"';?> value="same"><?php _e( 'Same window', 'jetpack' ); ?></option>
- </select>
- </td>
- </tr>
- <?php echo apply_filters( 'sharing_show_buttons_on_row_start', '<tr valign="top">' ); ?>
- <th scope="row"><label><?php _e( 'Show buttons on', 'jetpack' ); ?></label></th>
- <td>
+ </div>
+
+ <form method="post" action="">
+ <table class="form-table">
+ <tbody>
+ <tr valign="top">
+ <th scope="row"><label><?php _e( 'Button style', 'jetpack' ); ?></label></th>
+ <td>
+ <select name="button_style" id="button_style">
+ <option<?php if ( $global['button_style'] == 'icon-text' ) echo ' selected="selected"';?> value="icon-text"><?php _e( 'Icon + text', 'jetpack' ); ?></option>
+ <option<?php if ( $global['button_style'] == 'icon' ) echo ' selected="selected"';?> value="icon"><?php _e( 'Icon only', 'jetpack' ); ?></option>
+ <option<?php if ( $global['button_style'] == 'text' ) echo ' selected="selected"';?> value="text"><?php _e( 'Text only', 'jetpack' ); ?></option>
+ <option<?php if ( $global['button_style'] == 'official' ) echo ' selected="selected"';?> value="official"><?php _e( 'Official buttons', 'jetpack' ); ?></option>
+ </select>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row"><label><?php _e( 'Sharing label', 'jetpack' ); ?></label></th>
+ <td>
+ <input type="text" name="sharing_label" value="<?php echo esc_attr( $global['sharing_label'] ); ?>" />
+ </td>
+ </tr>
+ <?php
+ /**
+ * Filters the HTML at the beginning of the "Show button on" row.
+ *
+ * @since 2.1.0
+ *
+ * @param string $var Opening HTML tag at the beginning of the "Show button on" row.
+ */
+ echo apply_filters( 'sharing_show_buttons_on_row_start', '<tr valign="top">' );
+ ?>
+ <th scope="row"><label><?php _e( 'Show buttons on', 'jetpack' ); ?></label></th>
+ <td>
<?php
$br = false;
foreach ( $shows as $show ) :
@@ -341,71 +366,101 @@ class Sharing_Admin {
?>
<?php if ( $br ) echo '<br />'; ?><label><input type="checkbox"<?php checked( in_array( $show, $global['show'] ) ); ?> name="show[]" value="<?php echo esc_attr( $show ); ?>" /> <?php echo esc_html( $label ); ?></label>
<?php $br = true; endforeach; ?>
- </td>
- <?php echo apply_filters( 'sharing_show_buttons_on_row_end', '</tr>' ); ?>
-
- <?php do_action( 'sharing_global_options' ); ?>
- </tbody>
- </table>
+ </td>
+ <?php
+ /**
+ * Filters the HTML at the end of the "Show button on" row.
+ *
+ * @since 2.1.0
+ *
+ * @param string $var Closing HTML tag at the end of the "Show button on" row.
+ */
+ echo apply_filters( 'sharing_show_buttons_on_row_end', '</tr>' );
+ ?>
+
+ <?php
+ /**
+ * Fires at the end of the sharing global options settings table.
+ *
+ * @since 1.1.0
+ */
+ do_action( 'sharing_global_options' );
+ ?>
+ </tbody>
+ </table>
- <p class="submit">
+ <p class="submit">
<input type="submit" name="submit" class="button-primary" value="<?php _e( 'Save Changes', 'jetpack' ); ?>" />
- </p>
+ </p>
<input type="hidden" name="_wpnonce" value="<?php echo wp_create_nonce( 'sharing-options' );?>" />
- </form>
-
- <div id="new-service" style="display: none">
- <form method="post" action="<?php echo admin_url( 'admin-ajax.php' ); ?>" id="new-service-form">
- <table class="form-table">
- <tbody>
- <tr valign="top">
- <th scope="row" width="100"><label><?php _e( 'Service name', 'jetpack' ); ?></label></th>
- <td>
- <input type="text" name="sharing_name" id="new_sharing_name" size="40" />
- </td>
- </tr>
- <tr valign="top">
- <th scope="row" width="100"><label><?php _e( 'Sharing URL', 'jetpack' ); ?></label></th>
- <td>
- <input type="text" name="sharing_url" id="new_sharing_url" size="40" />
-
- <p><?php _e( 'You can add the following variables to your service sharing URL:', 'jetpack' ); ?><br/>
- <code>%post_title%</code>, <code>%post_url%</code>, <code>%post_full_url%</code>, <code>%post_excerpt%</code>, <code>%post_tags%</code></p>
- </td>
- </tr>
- <tr valign="top">
- <th scope="row" width="100"><label><?php _e( 'Icon URL', 'jetpack' ); ?></label></th>
- <td>
- <input type="text" name="sharing_icon" id="new_sharing_icon" size="40" />
- <p><?php _e( 'Enter the URL of a 16x16px icon you want to use for this service.', 'jetpack' ); ?></p>
- </td>
- </tr>
- <tr valign="top" width="100">
- <th scope="row"></th>
- <td>
+ </form>
+
+ <div id="new-service" style="display: none">
+ <form method="post" action="<?php echo admin_url( 'admin-ajax.php' ); ?>" id="new-service-form">
+ <table class="form-table">
+ <tbody>
+ <tr valign="top">
+ <th scope="row" width="100"><label><?php _e( 'Service name', 'jetpack' ); ?></label></th>
+ <td>
+ <input type="text" name="sharing_name" id="new_sharing_name" size="40" />
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" width="100"><label><?php _e( 'Sharing URL', 'jetpack' ); ?></label></th>
+ <td>
+ <input type="text" name="sharing_url" id="new_sharing_url" size="40" />
+
+ <p><?php _e( 'You can add the following variables to your service sharing URL:', 'jetpack' ); ?><br/>
+ <code>%post_title%</code>, <code>%post_url%</code>, <code>%post_full_url%</code>, <code>%post_excerpt%</code>, <code>%post_tags%</code></p>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" width="100"><label><?php _e( 'Icon URL', 'jetpack' ); ?></label></th>
+ <td>
+ <input type="text" name="sharing_icon" id="new_sharing_icon" size="40" />
+ <p><?php _e( 'Enter the URL of a 16x16px icon you want to use for this service.', 'jetpack' ); ?></p>
+ </td>
+ </tr>
+ <tr valign="top" width="100">
+ <th scope="row"></th>
+ <td>
<input type="submit" class="button-primary" value="<?php _e( 'Create Share Button', 'jetpack' ); ?>" />
- <img src="<?php echo admin_url( 'images/loading.gif' ); ?>" width="16" height="16" alt="loading" style="vertical-align: middle; display: none" />
- </td>
- </tr>
+ <img src="<?php echo admin_url( 'images/loading.gif' ); ?>" width="16" height="16" alt="loading" style="vertical-align: middle; display: none" />
+ </td>
+ </tr>
- <?php do_action( 'sharing_new_service_form' ); ?>
- </tbody>
- </table>
+ <?php
+ /**
+ * Fires after the custom sharing service form
+ *
+ * @since 1.1.0
+ */
+ do_action( 'sharing_new_service_form' );
+ ?>
+ </tbody>
+ </table>
- <?php do_action( 'post_admin_screen_sharing' ) ?>
+ <?php
+ /**
+ * Fires at the bottom of the admin sharing settings screen.
+ *
+ * @since 1.6.0
+ */
+ do_action( 'post_admin_screen_sharing' );
+ ?>
<div class="inerror" style="display: none; margin-top: 15px">
<p><?php _e( 'An error occurred creating your new sharing service - please check you gave valid details.', 'jetpack' ); ?></p>
</div>
- <input type="hidden" name="action" value="sharing_new_service" />
+ <input type="hidden" name="action" value="sharing_new_service" />
<input type="hidden" name="_wpnonce" value="<?php echo wp_create_nonce( 'sharing-new_service' );?>" />
- </form>
- </div>
- </div>
+ </form>
+ </div>
+ </div>
- <?php endif; ?>
+ <?php endif; ?>
</div>
diff --git a/plugins/jetpack/modules/shortcodes.php b/plugins/jetpack/modules/shortcodes.php
index e9362aff..4852cf25 100644
--- a/plugins/jetpack/modules/shortcodes.php
+++ b/plugins/jetpack/modules/shortcodes.php
@@ -2,12 +2,13 @@
/**
* Module Name: Shortcode Embeds
- * Module Description: Easily embed videos and more from sites like YouTube, Vimeo, and SlideShare.
- * Sort Order: 11
+ * Module Description: Embed content from YouTube, Vimeo, SlideShare, and more, no coding necessary.
+ * Sort Order: 3
* First Introduced: 1.1
* Major Changes In: 1.2
* Requires Connection: No
* Auto Activate: Yes
+ * Module Tags: Photos and Videos, Social, Writing, Appearance
*/
/**
@@ -45,11 +46,19 @@ function jetpack_load_shortcodes() {
$shortcode_includes[] = $file;
}
+/**
+ * This filter allows other plugins to override which shortcodes Jetpack loads.
+ *
+ * @since 2.2.1
+ *
+ * @param array $shortcode_includes An array of which shortcodes to include.
+ */
$shortcode_includes = apply_filters( 'jetpack_shortcodes_to_include', $shortcode_includes );
foreach ( $shortcode_includes as $include ) {
- if ( version_compare( $wp_version, '3.6-z', '>=' ) && stristr( $include, 'audio.php' ) )
+ if ( version_compare( $wp_version, '3.6-z', '>=' ) && stristr( $include, 'audio.php' ) ) {
continue;
+ }
include $include;
}
@@ -66,6 +75,22 @@ if ( version_compare( $wp_version, '3.6-z', '>=' ) ) {
return $out;
}
+
+ function jetpack_shortcode_get_audio_id( $atts ) {
+ if ( isset( $atts[ 0 ] ) )
+ return $atts[ 0 ];
+ else
+ return 0;
+ }
+}
+
+if ( ! function_exists( 'jetpack_shortcode_get_wpvideo_id' ) ) {
+ function jetpack_shortcode_get_wpvideo_id( $atts ) {
+ if ( isset( $atts[ 0 ] ) )
+ return $atts[ 0 ];
+ else
+ return 0;
+ }
}
jetpack_load_shortcodes();
diff --git a/plugins/jetpack/modules/shortcodes/archives.php b/plugins/jetpack/modules/shortcodes/archives.php
index c407978f..28a0ad52 100644
--- a/plugins/jetpack/modules/shortcodes/archives.php
+++ b/plugins/jetpack/modules/shortcodes/archives.php
@@ -23,23 +23,37 @@ function archives_shortcode( $attr ) {
'after' => '',
'order' => 'desc',
);
- extract( shortcode_atts( $default_atts, $attr ) );
+ extract( shortcode_atts( $default_atts, $attr, 'archives' ) );
- if ( !in_array( $type, array( 'yearly', 'monthly', 'daily', 'weekly', 'postbypost' ) ) )
+ if ( ! in_array( $type, array( 'yearly', 'monthly', 'daily', 'weekly', 'postbypost' ) ) )
$type = 'postbypost';
- if ( !in_array( $format, array( 'html', 'option', 'custom' ) ) )
- $format = 'html';
+ if ( ! in_array( $format, array( 'html', 'option', 'custom' ) ) )
+ $format = 'html';
- if ( '' != $limit )
- $limit = (int)$limit;
+ if ( '' != $limit ) {
+ $limit = ( int ) $limit;
+ // A Limit of 0 makes no sense so revert back to the default.
+ if ( 0 == $limit ) {
+ $limit = '';
+ }
+ }
- $showcount = (bool)$showcount;
+
+ $showcount = ( bool ) $showcount;
$before = wp_kses( $before, $allowedposttags );
$after = wp_kses( $after, $allowedposttags );
// Get the archives
- $archives = wp_get_archives( 'type=' . $type . '&limit=' . $limit . '&format=' . $format . '&echo=0&show_post_count=' . $showcount . '&before=' . $before . '&after=' . $after );
+ $archives = wp_get_archives( array(
+ 'type' => $type,
+ 'limit' => $limit,
+ 'format' => $format,
+ 'echo' => false,
+ 'show_post_count' => $showcount,
+ 'before' => $before,
+ 'after' => $after
+ ) );
if ( 'asc' == $order )
$archives = implode( "\n", array_reverse( explode( "\n", $archives ) ) );
diff --git a/plugins/jetpack/modules/shortcodes/audio.php b/plugins/jetpack/modules/shortcodes/audio.php
index 744cf49c..60b82b9f 100644
--- a/plugins/jetpack/modules/shortcodes/audio.php
+++ b/plugins/jetpack/modules/shortcodes/audio.php
@@ -36,6 +36,7 @@ class AudioShortcode {
function audio_shortcode( $atts ) {
global $ap_playerID;
global $post;
+
if ( ! is_array( $atts ) ) {
return '<!-- Audio shortcode passed invalid attributes -->';
}
@@ -49,6 +50,11 @@ class AudioShortcode {
}
}
+ $post_id = 0;
+ if ( isset( $post ) ) {
+ $post_id = $post->ID;
+ }
+
// add the special .js
wp_enqueue_script(
'audio-shortcode',
@@ -61,6 +67,28 @@ class AudioShortcode {
self::$add_script = true;
$atts[0] = strip_tags( join( ' ', $atts ) );
$src = ltrim( $atts[0], '=' );
+
+ /**
+ * Set the audio player default colors.
+ *
+ * @since 1.4.0
+ *
+ * @param array $ap_options {
+ * The default colors for the audio player in hexidecimal format (e.g. 0x#F8F8F8).
+ *
+ * @type string $bg Background color.
+ * @type string $leftbg Left background color.
+ * @type string $lefticon Left icon color.
+ * @type string $rightbg Right background color.
+ * @type string $rightbghover Right background hover color.
+ * @type string $righticon Right icon color.
+ * @type string $righticonhover Right icon hover color.
+ * @type string $text Text color.
+ * @type string $slider Slider color.
+ * @type string $track Track color.
+ * @type string $border Border color.
+ * @type string $loader Loader color.
+ */
$ap_options = apply_filters(
'audio_player_default_colors',
array(
@@ -227,9 +255,9 @@ class AudioShortcode {
if ( 0 == $i ) { // only need one player
$html5_audio .= <<<AUDIO
- <span id="wp-as-{$post->ID}_{$ap_playerID}-container">
- <audio id='wp-as-{$post->ID}_{$ap_playerID}' controls preload='none' $loop style='background-color:$bgcolor;width:{$width}px;'>
- <span id="wp-as-{$post->ID}_{$ap_playerID}-nope">$not_supported</span>
+ <span id="wp-as-{$post_id}_{$ap_playerID}-container">
+ <audio id='wp-as-{$post_id}_{$ap_playerID}' controls preload='none' $loop style='background-color:$bgcolor;width:{$width}px;'>
+ <span id="wp-as-{$post_id}_{$ap_playerID}-nope">$not_supported</span>
</audio>
</span>
<br />
@@ -241,27 +269,31 @@ AUDIO;
// player controls, if needed
if ( 1 < $num_files ) {
$html5_audio .= <<<CONTROLS
- <span id='wp-as-{$post->ID}_{$ap_playerID}-controls' style='display:none;'>
- <a id='wp-as-{$post->ID}_{$ap_playerID}-prev'
- href='javascript:audioshortcode.prev_track( "{$post->ID}_{$ap_playerID}" );'
+ <span id='wp-as-{$post_id}_{$ap_playerID}-controls' style='display:none;'>
+ <a id='wp-as-{$post_id}_{$ap_playerID}-prev'
+ href='javascript:audioshortcode.prev_track( "{$post_id}_{$ap_playerID}" );'
style='font-size:1.5em;'>&laquo;</a>
|
- <a id='wp-as-{$post->ID}_{$ap_playerID}-next'
- href='javascript:audioshortcode.next_track( "{$post->ID}_{$ap_playerID}", true, $script_loop );'
+ <a id='wp-as-{$post_id}_{$ap_playerID}-next'
+ href='javascript:audioshortcode.next_track( "{$post_id}_{$ap_playerID}", true, $script_loop );'
style='font-size:1.5em;'>&raquo;</a>
</span>
CONTROLS;
}
- $html5_audio .= "<span id='wp-as-{$post->ID}_{$ap_playerID}-playing'></span>";
-
- if ( is_ssl() )
- $protocol = 'https';
- else
- $protocol = 'http';
-
+ $html5_audio .= "<span id='wp-as-{$post_id}_{$ap_playerID}-playing'></span>";
+
+ /**
+ * Sets external resource URL.
+ *
+ * @since 1.4.0
+ *
+ * @param string $args URL of external resource.
+ *
+ */
$swfurl = apply_filters(
'jetpack_static_url',
- "$protocol://en.wordpress.com/wp-content/plugins/audio-player/player.swf" );
+ set_url_scheme( "http://en.wordpress.com/wp-content/plugins/audio-player/player.swf" )
+ );
// all the fancy javascript is causing Google Reader to break, just include flash in GReader
// override html5 audio code w/ just not supported code
@@ -272,7 +304,7 @@ CONTROLS;
if ( $all_mp3 ) {
// process regular flash player, inserting HTML5 tags into object as fallback
$audio_tags = <<<FLASH
- <object id='wp-as-{$post->ID}_{$ap_playerID}-flash' type='application/x-shockwave-flash' data='$swfurl' width='$width' height='24'>
+ <object id='wp-as-{$post_id}_{$ap_playerID}-flash' type='application/x-shockwave-flash' data='$swfurl' width='$width' height='24'>
<param name='movie' value='$swfurl' />
<param name='FlashVars' value='{$flash_vars}' />
<param name='quality' value='high' />
@@ -296,8 +328,9 @@ FLASH;
// mashup the artist/titles for the script
$script_titles = array();
for ( $i = 0; $i < $num_files; $i++ ) {
- $script_titles[] = $file_artists[$i] . $file_titles[$i];
-
+ if ( isset( $file_artists[ $i ] ) && isset( $file_titles[ $i ] ) ) {
+ $script_titles[] = $file_artists[ $i ] . $file_titles[ $i ];
+ }
}
// javacript to control audio
@@ -310,7 +343,7 @@ FLASH;
var prep = function() {
if ( 'undefined' === typeof window.audioshortcode ) { return; }
audioshortcode.prep(
- '{$post->ID}_{$ap_playerID}',
+ '{$post_id}_{$ap_playerID}',
$script_files,
$script_titles,
$volume,
diff --git a/plugins/jetpack/modules/shortcodes/bandcamp.php b/plugins/jetpack/modules/shortcodes/bandcamp.php
index cfaedb9c..95553633 100644
--- a/plugins/jetpack/modules/shortcodes/bandcamp.php
+++ b/plugins/jetpack/modules/shortcodes/bandcamp.php
@@ -12,6 +12,7 @@ function shortcode_handler_bandcamp( $atts ) {
$attributes = shortcode_atts( array(
'album' => null, // integer album id
'track' => null, // integer track id
+ 'video' => null, // integer track id for video player
'size' => 'venti', // one of the supported sizes
'bgcol' => 'FFFFFF', // hex, no '#' prefix
'linkcol' => null, // hex, no '#' prefix
@@ -19,11 +20,13 @@ function shortcode_handler_bandcamp( $atts ) {
'width' => null, // integer with optional "%"
'height' => null, // integer with optional "%"
'notracklist' => null, // may be string "true" (defaults false)
- 'artwork' => null, // may be string "false" (defaults true)
+ 'tracklist' => null, // may be string "false" (defaults true)
+ 'artwork' => null, // may be string "false" (alternately: "none") or "small" (default is large)
+ 'minimal' => null, // may be string "true" (defaults false)
'theme' => null, // may be theme identifier string ("light"|"dark" so far)
'package' => null, // integer package id
't' => null // integer track number
- ), $atts );
+ ), $atts, 'bandcamp' );
$sizes = array(
'venti' => array( 'width' => 400, 'height' => 100 ),
@@ -43,29 +46,40 @@ function shortcode_handler_bandcamp( $atts ) {
$height = null;
$width = null;
- // Build iframe url. Args are appended as
+ $isVideo = false;
+
+ // Build iframe url. For audio players, args are appended as
// extra path segments for historical reasons having to
// do with an IE-only flash bug which required this URL
- // to contain no querystring
+ // to contain no querystring. Delay the actual joining
+ // of args into a string until after we decide if it's
+ // a video player or an audio player
+ $argparts = array();
+
+ if ( !isset( $attributes['album'] ) && !isset( $attributes['track'] ) && !isset( $attributes['video'] ) ) {
+ return "[bandcamp: shortcode must include 'track', 'album', or 'video' param]";
+ }
- $url = "http://bandcamp.com/EmbeddedPlayer/v=2/";
if ( isset( $attributes['track'] ) ) {
$track = (int) $attributes['track'];
- $url .= "track={$track}";
-
- if ( $sizekey == 'tall' ) {
- $sizekey .= '_track';
- }
- } elseif ( isset( $attributes['album'] ) ) {
+ array_push( $argparts, "track={$track}" );
+ } elseif ( isset( $attributes['video'] ) ) {
+ $track = (int) $attributes['video']; // videos are referenced by track id
+ $urlbase = "//bandcamp.com/EmbeddedPlayer/v=2";
+ $isVideo = true;
+ array_push( $argparts, "track={$track}" );
+ }
+ if ( isset( $attributes['album'] ) ) {
$album = (int) $attributes['album'];
- $url .= "album={$album}";
- $type = 'album';
+ array_push( $argparts, "album={$album}" );
+ }
- if ( $sizekey == 'tall' ) {
+ if ( $sizekey == 'tall' ) {
+ if ( isset( $attributes['album'] ) ) {
$sizekey .= '_album';
+ } else {
+ $sizekey .= '_track';
}
- } else {
- return "[bandcamp: shortcode must include track or album id]";
}
// if size specified that we don't recognize, fall back on venti
@@ -101,42 +115,65 @@ function shortcode_handler_bandcamp( $atts ) {
}
if ( isset( $attributes['layout'] ) ) {
- $url .= "/layout={$attributes['layout']}";
+ array_push( $argparts, "layout={$attributes['layout']}" );
} elseif ( isset( $attributes['size'] ) && preg_match( "|^[a-zA-Z0-9]+$|", $attributes['size'] ) ) {
- $url .= "/size={$attributes['size']}";
+ array_push( $argparts, "size={$attributes['size']}" );
}
if ( isset( $attributes['bgcol'] ) && preg_match( "|^[0-9A-Fa-f]+$|", $attributes['bgcol'] ) ) {
- $url .= "/bgcol={$attributes['bgcol']}";
+ array_push( $argparts, "bgcol={$attributes['bgcol']}" );
}
if ( isset( $attributes['linkcol'] ) && preg_match( "|^[0-9A-Fa-f]+$|", $attributes['linkcol'] ) ) {
- $url .= "/linkcol={$attributes['linkcol']}";
+ array_push( $argparts, "linkcol={$attributes['linkcol']}" );
}
if ( isset( $attributes['package'] ) && preg_match( "|^[0-9]+$|", $attributes['package'] ) ) {
- $url .= "/package={$attributes['package']}";
+ array_push( $argparts, "package={$attributes['package']}" );
}
if ( isset( $attributes['t'] ) && preg_match( "|^[0-9]+$|", $attributes['t'] ) ) {
- $url .= "/t={$attributes['t']}";
+ array_push( $argparts, "t={$attributes['t']}" );
}
if ( $attributes['notracklist'] == "true" ) {
- $url .= "/notracklist=true";
+ array_push( $argparts, "notracklist=true" );
+ }
+
+ // 'tracklist' arg deprecates 'notracklist=true' to be less weird. note, behavior
+ // if both are specified is undefined
+ switch ( $attributes['tracklist'] ) {
+ case "false":
+ case "none":
+ array_push( $argparts, "tracklist=false" );
+ break;
}
- if ( $attributes['artwork'] == "false" ) {
- $url .= "/artwork=false";
+ switch ( $attributes['artwork'] ) {
+ case "false":
+ case "none":
+ case "small":
+ array_push( $argparts, "artwork=" . $attributes['artwork'] );
+ break;
+ }
+
+ if ( $attributes['minimal'] == "true" ) {
+ array_push( $argparts, "minimal=true" );
}
if ( isset( $attributes['theme'] ) && preg_match( "|^[a-zA-Z_]+$|", $attributes['theme'] ) ) {
- $url .= "/theme={$attributes['theme']}";
+ array_push( $argparts, "theme={$attributes['theme']}" );
}
- $url .= '/';
+ if ( $isVideo ) {
+ $url = "//bandcamp.com/VideoEmbed?" . join( '&', $argparts );
+ $extraAttrs = " mozallowfullscreen='1' webkitallowfullscreen='1' allowfullscreen='1'";
+ } else {
+ $url = "//bandcamp.com/EmbeddedPlayer/v=2/" . join( '/', $argparts ) . '/';
+ $extraAttrs = '';
+ }
- return "<iframe width='" . esc_attr( $width ) . "' height='" . esc_attr( $height ) . "' style='position: relative; display: block; width: " . esc_attr( $csswidth ) . "; height: " . esc_attr( $cssheight ) . ";' src='" . esc_url( $url ) . "' allowtransparency='true' frameborder='0'></iframe>";
+ return "<iframe width='" . esc_attr( $width ) . "' height='" . esc_attr( $height ) . "' style='position: relative; display: block; width: " . esc_attr( $csswidth ) . "; height: " . esc_attr( $cssheight ) . ";' src='" . esc_url( $url ) . "' allowtransparency='true' frameborder='0'" . $extraAttrs . "></iframe>";
}
add_shortcode( 'bandcamp', 'shortcode_handler_bandcamp' );
diff --git a/plugins/jetpack/modules/shortcodes/cartodb.php b/plugins/jetpack/modules/shortcodes/cartodb.php
new file mode 100644
index 00000000..74292830
--- /dev/null
+++ b/plugins/jetpack/modules/shortcodes/cartodb.php
@@ -0,0 +1,18 @@
+<?php
+
+
+/*
+ * CartoDB
+ *
+ * example URL: http://osm2.cartodb.com/viz/08aef918-94da-11e4-ad83-0e0c41326911/public_map
+ *
+ * possible patterns:
+ * [username].cartodb.com/viz/[map-id]/public_map
+ * [username].cartodb.com/viz/[map-id]/embed_map
+ * [username].cartodb.com/viz/[map-id]/map
+ * [organization].cartodb.com/u/[username]/viz/[map-id]/public_map
+ * [organization].cartodb.com/u/[username]/viz/[map-id]/embed_map
+ * [organization].cartodb.com/u/[username]/viz/[map-id]/map
+*/
+
+wp_oembed_add_provider( '#https?://(?:www\.)?[^/^\.]+\.cartodb\.com/\S+#i', 'https://services.cartodb.com/oembed', true ); \ No newline at end of file
diff --git a/plugins/jetpack/modules/shortcodes/css/recipes-print.css b/plugins/jetpack/modules/shortcodes/css/recipes-print.css
new file mode 100644
index 00000000..b3e76af1
--- /dev/null
+++ b/plugins/jetpack/modules/shortcodes/css/recipes-print.css
@@ -0,0 +1,3 @@
+.jetpack-recipe-meta li.jetpack-recipe-print {
+ display: none;
+}
diff --git a/plugins/jetpack/modules/shortcodes/css/recipes.css b/plugins/jetpack/modules/shortcodes/css/recipes.css
new file mode 100644
index 00000000..08b9b00c
--- /dev/null
+++ b/plugins/jetpack/modules/shortcodes/css/recipes.css
@@ -0,0 +1,33 @@
+.jetpack-recipe {
+ border: 1px solid #f2f2f2;
+ border-radius: 1px;
+ clear: both;
+ margin: 1.5em 1%;
+ padding: 1% 2%;
+}
+.jetpack-recipe-title {
+ border-bottom: 1px solid #ccc;
+ margin: .25em 0;
+ padding: .25em 0;
+}
+.jetpack-recipe .jetpack-recipe-meta {
+ display: block;
+ font-size: .9em;
+ list-style-type: none;
+ margin-right: 0;
+ margin-left: 0;
+ padding: 0;
+ overflow: hidden;
+ width: 100%;
+}
+.jetpack-recipe .jetpack-recipe-meta li {
+ float: left;
+ list-style-type: none;
+ margin: 0;
+ padding: 0 5% 0 0;
+}
+.jetpack-recipe-meta li.jetpack-recipe-print {
+ float: right;
+ padding-right: 0;
+ text-align: right;
+}
diff --git a/plugins/jetpack/modules/shortcodes/css/rtl/recipes-rtl.css b/plugins/jetpack/modules/shortcodes/css/rtl/recipes-rtl.css
new file mode 100644
index 00000000..26da7d16
--- /dev/null
+++ b/plugins/jetpack/modules/shortcodes/css/rtl/recipes-rtl.css
@@ -0,0 +1,35 @@
+/* This file was automatically generated on Feb 24 2014 16:44:25 */
+
+.jetpack-recipe {
+ border: 1px solid #f2f2f2;
+ border-radius: 1px;
+ clear: both;
+ margin: 1.5em 1%;
+ padding: 1% 2%;
+}
+.jetpack-recipe-title {
+ border-bottom: 1px solid #ccc;
+ margin: .25em 0;
+ padding: .25em 0;
+}
+.jetpack-recipe .jetpack-recipe-meta {
+ display: block;
+ font-size: .9em;
+ list-style-type: none;
+ margin-left: 0;
+ margin-right: 0;
+ padding: 0;
+ overflow: hidden;
+ width: 100%;
+}
+.jetpack-recipe .jetpack-recipe-meta li {
+ float: right;
+ list-style-type: none;
+ margin: 0;
+ padding: 0 0 0 5%;
+}
+.jetpack-recipe-meta li.jetpack-recipe-print {
+ float: left;
+ padding-left: 0;
+ text-align: left;
+}
diff --git a/plugins/jetpack/modules/shortcodes/css/rtl/slideshow-shortcode-rtl.css b/plugins/jetpack/modules/shortcodes/css/rtl/slideshow-shortcode-rtl.css
index fdfa6aea..5d51694f 100644
--- a/plugins/jetpack/modules/shortcodes/css/rtl/slideshow-shortcode-rtl.css
+++ b/plugins/jetpack/modules/shortcodes/css/rtl/slideshow-shortcode-rtl.css
@@ -1,4 +1,4 @@
-/* This file was automatically generated on Aug 22 2013 17:45:44 */
+/* This file was automatically generated on Oct 06 2014 18:02:19 */
.slideshow-window {
background-color: #222;
@@ -9,6 +9,12 @@
-khtml-border-radius: 11px;
margin-bottom: 20px;
height: 410px;
+ z-index: 1;
+}
+
+.slideshow-window.slideshow-white {
+ background-color: #fff;
+ border-color: #fff;
}
.slideshow-window, .slideshow-window * {
@@ -24,14 +30,14 @@
}
body div.slideshow-window * img {
- /* Override any styles that might be present in the page stylesheet */
- border-width: 0 !important;
- margin-left: auto !important;
- margin-right: auto !important;
- padding: 0 !important;
- background-color: transparent !important;
- background-image: none !important;
- max-width: 100%;
+ /* Override any styles that might be present in the page stylesheet */
+ border-width: 0 !important;
+ margin-left: auto !important;
+ margin-right: auto !important;
+ padding: 0 !important;
+ background-color: transparent !important;
+ background-image: none !important;
+ max-width: 100%;
}
.slideshow-loading img {
@@ -51,7 +57,7 @@ body div.slideshow-window * img {
}
.slideshow-line-height-hack {
- overflow: hide;
+ overflow: hidden;
width: 0px;
font-size: 0px;
}
@@ -74,12 +80,13 @@ body div.slideshow-window * img {
/* @noflip */
.slideshow-controls {
z-index: 1000;
- position: absolute;
- bottom: 30px;
- margin: auto;
+ position: absolute;
+ bottom: 30px;
+ margin: auto;
text-align: center;
width: 100%;
- display: none;
+ -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
+ opacity: 0.5;
direction:ltr;
}
diff --git a/plugins/jetpack/modules/shortcodes/css/slideshow-shortcode.css b/plugins/jetpack/modules/shortcodes/css/slideshow-shortcode.css
index fb3ec530..2dc3a649 100644
--- a/plugins/jetpack/modules/shortcodes/css/slideshow-shortcode.css
+++ b/plugins/jetpack/modules/shortcodes/css/slideshow-shortcode.css
@@ -7,6 +7,12 @@
-khtml-border-radius: 11px;
margin-bottom: 20px;
height: 410px;
+ z-index: 1;
+}
+
+.slideshow-window.slideshow-white {
+ background-color: #fff;
+ border-color: #fff;
}
.slideshow-window, .slideshow-window * {
@@ -22,14 +28,14 @@
}
body div.slideshow-window * img {
- /* Override any styles that might be present in the page stylesheet */
- border-width: 0 !important;
- margin-right: auto !important;
- margin-left: auto !important;
- padding: 0 !important;
- background-color: transparent !important;
- background-image: none !important;
- max-width: 100%;
+ /* Override any styles that might be present in the page stylesheet */
+ border-width: 0 !important;
+ margin-right: auto !important;
+ margin-left: auto !important;
+ padding: 0 !important;
+ background-color: transparent !important;
+ background-image: none !important;
+ max-width: 100%;
}
.slideshow-loading img {
@@ -49,7 +55,7 @@ body div.slideshow-window * img {
}
.slideshow-line-height-hack {
- overflow: hide;
+ overflow: hidden;
width: 0px;
font-size: 0px;
}
@@ -72,12 +78,13 @@ body div.slideshow-window * img {
/* @noflip */
.slideshow-controls {
z-index: 1000;
- position: absolute;
- bottom: 30px;
- margin: auto;
+ position: absolute;
+ bottom: 30px;
+ margin: auto;
text-align: center;
width: 100%;
- display: none;
+ -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
+ opacity: 0;
direction:ltr;
}
diff --git a/plugins/jetpack/modules/shortcodes/css/style.css b/plugins/jetpack/modules/shortcodes/css/style.css
index 137663a3..5ef78159 100644
--- a/plugins/jetpack/modules/shortcodes/css/style.css
+++ b/plugins/jetpack/modules/shortcodes/css/style.css
@@ -46,6 +46,7 @@ body.presentation-wrapper-fullscreen-parent {
margin: 20px auto;
border: 1px solid #e5e5e5;
overflow: hidden;
+ line-height: normal;
}
.presentation {
@@ -184,4 +185,4 @@ body.presentation-wrapper-fullscreen-parent {
-ms-transition : opacity .5s;
-o-transition : opacity .5s;
transition : opacity .5s;
-} \ No newline at end of file
+}
diff --git a/plugins/jetpack/modules/shortcodes/dailymotion.php b/plugins/jetpack/modules/shortcodes/dailymotion.php
index fe2e6ab6..a366eac6 100644
--- a/plugins/jetpack/modules/shortcodes/dailymotion.php
+++ b/plugins/jetpack/modules/shortcodes/dailymotion.php
@@ -16,34 +16,43 @@
* Code as of 01.01.11:
* <object width="560" height="421"><param name="movie" value="http://www.dailymotion.com/swf/video/xaose5?width=560&theme=denim&foreground=%2392ADE0&highlight=%23A2ACBF&background=%23202226&start=&animatedTitle=&iframe=0&additionalInfos=0&autoPlay=0&hideInfos=0"></param><param name="allowFullScreen" value="true"></param><param name="allowScriptAccess" value="always"></param><embed type="application/x-shockwave-flash" src="http://www.dailymotion.com/swf/video/xaose5?width=560&theme=denim&foreground=%2392ADE0&highlight=%23A2ACBF&background=%23202226&start=&animatedTitle=&iframe=0&additionalInfos=0&autoPlay=0&hideInfos=0" width="560" height="421" allowfullscreen="true" allowscriptaccess="always"></embed></object><br /><b><a href="http://www.dailymotion.com/video/xaose5_sexy-surprise_na">Sexy Surprise</a></b><br /><i>Uploaded by <a href="http://www.dailymotion.com/GilLavie">GilLavie</a>. - <a target="_self" href="http://www.dailymotion.com/channel/sexy/featured/1">Find more steamy, sexy videos.</a></i>
* movie param enforces anti-xss protection
+ *
+ * Scroll down for the new <iframe> embed code handler.
*/
function dailymotion_embed_to_shortcode( $content ) {
- if ( false === stripos( $content, 'www.dailymotion.com/swf/' ) )
+ if ( false === stripos( $content, 'www.dailymotion.com/swf/' ) ) {
return $content;
+ }
- $regexp = '!<object.*>\s*(<param.*></param>\s*)*<embed((?:\s+\w+="[^"]*")*)\s+src="http(?:\:|&#0*58;)//(www\.dailymotion\.com/swf/[^"]*)"((?:\s+\w+="[^"]*")*)\s*(?:/>|>\s*</embed>)\s*</object><br /><b><a .*>.*</a></b><br /><i>.*</i>!';
+ $regexp = '!<object.*>\s*(<param.*></param>\s*)*<embed((?:\s+\w+="[^"]*")*)\s+src="http(?:\:|&#0*58;)//(www\.dailymotion\.com/swf/[^"]*)"((?:\s+\w+="[^"]*")*)\s*(?:/>|>\s*</embed>)\s*</object><br /><b><a .*>.*</a></b><br /><i>.*</i>!';
$regexp_ent = str_replace( '&amp;#0*58;', '&amp;#0*58;|&#0*58;', htmlspecialchars( $regexp, ENT_NOQUOTES ) );
foreach ( array( 'regexp', 'regexp_ent' ) as $reg ) {
- if ( ! preg_match_all( $$reg, $content, $matches, PREG_SET_ORDER ) )
+ if ( ! preg_match_all( $$reg, $content, $matches, PREG_SET_ORDER ) ) {
continue;
+ }
foreach ( $matches as $match ) {
- $src = html_entity_decode( $match[3] );
+ $src = html_entity_decode( $match[3] );
$params = $match[2] . $match[4];
+
if ( 'regexp_ent' == $reg ) {
- $src = html_entity_decode( $src );
+ $src = html_entity_decode( $src );
$params = html_entity_decode( $params );
}
+
$params = wp_kses_hair( $params, array( 'http' ) );
- if ( !isset( $params['type'] ) || 'application/x-shockwave-flash' != $params['type']['value'] )
+
+ if ( ! isset( $params['type'] ) || 'application/x-shockwave-flash' != $params['type']['value'] ) {
continue;
+ }
$id = basename( substr( $src, strlen( 'www.dailymotion.com/swf' ) ) );
$id = preg_replace( '/[^a-z0-9].*$/i', '', $id );
$content = str_replace( $match[0], "[dailymotion id=$id]", $content );
+ /** This action is documented in modules/shortcodes/youtube.php */
do_action( 'jetpack_embed_to_shortcode', 'dailymotion', $id );
}
}
@@ -66,6 +75,7 @@ add_filter( 'pre_kses', 'dailymotion_embed_to_shortcode' );
*
* The new style is now:
* [dailymotion id=x8oma9 title=2 user=3 video=4]
+ * @todo: Update code to sniff for iframe embeds and convert those to shortcodes.
*
* @param array $atts
* @return string html
@@ -78,39 +88,92 @@ function dailymotion_shortcode( $atts ) {
if ( isset( $atts[0] ) ) {
$id = ltrim( $atts[0], '=' );
$atts['id'] = $id;
+
} else {
$params = shortcode_new_to_old_params( $atts );
- parse_str( $params, $atts );
+ parse_str( $params, $atts_new );
+
+ foreach( $atts_new as $k => $v ) {
+ $atts[ $k ] = $v;
+ }
}
- if ( isset( $atts['id'] ) )
+ if ( isset( $atts['id'] ) ) {
$id = $atts['id'];
- else
+ } else {
return '<!--Dailymotion error: bad or missing ID-->';
+ }
- if ( !empty( $content_width ) )
+ if ( ! empty( $content_width ) ) {
$width = min( 425, intval( $content_width ) );
- else
+ } else {
$width = 425;
+ }
$height = ( 425 == $width ) ? 334 : ( $width / 425 ) * 334;
- $id = urlencode( $id );
+ $id = urlencode( $id );
- $output = '<object width="' . $width . '" height="' . $height . '"><param name="movie" value="http://www.dailymotion.com/swf/';
- $after = '';
- if ( preg_match( '/^[a-z0-9]+$/', $id ) ) {
- $output .= $id;
+ if ( preg_match( '/^[A-Za-z0-9]+$/', $id ) ) {
+ $output = '<iframe width="' . $width . '" height="' . $height . '" src="' . esc_url( '//www.dailymotion.com/embed/video/' . $id ) . '" frameborder="0"></iframe>';
+ $after = '';
- if ( array_key_exists( 'video', $atts ) && $video = preg_replace( '/[^-a-z0-9_]/i', '', $atts['video'] ) && array_key_exists( 'title', $atts ) && $title = wp_kses( $atts['title'], array() ) )
- $after .= '<br /><strong><a href="http://www.dailymotion.com/video/' . $video . '">' . $title . '</a></strong>';
+ if ( array_key_exists( 'video', $atts ) && $video = preg_replace( '/[^-a-z0-9_]/i', '', $atts['video'] ) && array_key_exists( 'title', $atts ) && $title = wp_kses( $atts['title'], array() ) ) {
+ $after .= '<br /><strong><a href="' . esc_url( 'http://www.dailymotion.com/video/' . $video ) . '">' . esc_html( $title ) . '</a></strong>';
+ }
- if ( array_key_exists( 'user', $atts ) && $user = preg_replace( '/[^-a-z0-9_]/i', '', $atts['user'] ) )
- $after .= '<br /><em>Uploaded by <a href="http://www.dailymotion.com/' . $user . '">' . $user . '</a></em>';
+ if ( array_key_exists( 'user', $atts ) && $user = preg_replace( '/[^-a-z0-9_]/i', '', $atts['user'] ) ) {
+ $after .= '<br /><em>Uploaded by <a href="' . esc_url( 'http://www.dailymotion.com/' . $user ) . '">' . esc_html( $user ) . '</a></em>';
+ }
}
- $output .= '"></param><param name="allowfullscreen" value="true"></param><param name="wmode" value="opaque"></param><embed src="http://www.dailymotion.com/swf/' . $id . '" width="' . $width . '" height="' . $height . '" allowfullscreen="true" wmode="opaque"></embed></object>';
-
return $output . $after;
}
add_shortcode( 'dailymotion', 'dailymotion_shortcode' );
+
+/**
+ * Dailymotion Embed Reversal (with new iframe code as of 17.09.2014)
+ *
+ * Converts a generic HTML embed code from Dailymotion into an
+ * oEmbeddable URL.
+ */
+
+function jetpack_dailymotion_embed_reversal( $content ) {
+ if ( false === stripos( $content, 'dailymotion.com/embed' ) ) {
+ return $content;
+ }
+
+ /* Sample embed code as of Sep 17th 2014:
+
+ <iframe frameborder="0" width="480" height="270" src="//www.dailymotion.com/embed/video/x25x71x" allowfullscreen></iframe><br /><a href="http://www.dailymotion.com/video/x25x71x_dog-with-legs-in-casts-learns-how-to-enter-the-front-door_animals" target="_blank">Dog with legs in casts learns how to enter the...</a> <i>by <a href="http://www.dailymotion.com/videobash" target="_blank">videobash</a></i>
+ */
+ $regexes = array();
+
+ // I'm Konstantin and I love regex.
+ $regexes[] = '#<iframe[^>]+?src=" (?:https?:)?//(?:www\.)?dailymotion\.com/embed/video/([^"\'/]++) "[^>]*+>\s*+</iframe>\s*+(?:<br\s*+/>)?\s*+
+ (?: <a[^>]+?href=" (?:https?:)?//(?:www\.)?dailymotion\.com/[^"\']++ "[^>]*+>.+?</a>\s*+ )?
+ (?: <i>.*?<a[^>]+?href=" (?:https?:)?//(?:www\.)?dailymotion\.com/[^"\']++ "[^>]*+>.+?</a>\s*+</i> )?#ix';
+
+ $regexes[] = '#&lt;iframe(?:[^&]|&(?!gt;))+?src=" (?:https?:)?//(?:www\.)?dailymotion\.com/embed/video/([^"\'/]++) "(?:[^&]|&(?!gt;))*+&gt;\s*+&lt;/iframe&gt;\s*+(?:&lt;br\s*+/&gt;)?\s*+
+ (?: &lt;a(?:[^&]|&(?!gt;))+?href=" (?:https?:)?//(?:www\.)?dailymotion\.com/[^"\']++ "(?:[^&]|&(?!gt;))*+&gt;.+?&lt;/a&gt;\s*+ )?
+ (?: &lt;i&gt;.*?&lt;a(?:[^&]|&(?!gt;))+?href=" (?:https?:)?//(?:www\.)?dailymotion\.com/[^"\']++ "(?:[^&]|&(?!gt;))*+&gt;.+?&lt;/a&gt;\s*+&lt;/i&gt; )?#ix';
+
+ foreach ( $regexes as $regex ) {
+ if ( ! preg_match_all( $regex, $content, $matches, PREG_SET_ORDER ) ) {
+ continue;
+ }
+
+ foreach ( $matches as $match ) {
+ $url = esc_url( sprintf( 'https://dailymotion.com/video/%s', $match[1] ) );
+ $replace_regex = sprintf( '#\s*%s\s*#', preg_quote( $match[0], '#' ) );
+ $content = preg_replace( $replace_regex, sprintf( "\n\n%s\n\n", $url ), $content );
+
+ /** This action is documented in modules/shortcodes/youtube.php */
+ do_action( 'jetpack_embed_to_shortcode', 'dailymotion', $url );
+ }
+ }
+
+ return $content;
+}
+
+add_filter( 'pre_kses', 'jetpack_dailymotion_embed_reversal' );
diff --git a/plugins/jetpack/modules/shortcodes/diggthis.php b/plugins/jetpack/modules/shortcodes/diggthis.php
index 0077a468..0287218c 100644
--- a/plugins/jetpack/modules/shortcodes/diggthis.php
+++ b/plugins/jetpack/modules/shortcodes/diggthis.php
@@ -1,40 +1,11 @@
<?php
/**
- * Digg changed their button API.
- *
- * The old style button was something like this:
- * [digg=http://digg.com/some-digg-permalink] - uses digg permalink as id.
- *
- * The new style is:
- * [digg class="wide"] # The class options are: 'wide', 'medium', 'compact', 'icon'
- * and uses get_permalink() as id.
- *
- * @author Veselin Nikolov
+ * Digg's API is no more and support has been removed
*/
-function digg_shortcode_js() {
- echo '
-<script type="text/javascript">
-(function(){var s=document.createElement("SCRIPT"),s1=document.getElementsByTagName("SCRIPT")[0];s.type="text/javascript";s.async=true;s.src="http://widgets.digg.com/buttons.js";s1.parentNode.insertBefore(s,s1);})();
-</script>
-';
-}
-
function digg_shortcode( $atts ) {
- static $printed_digg_code = false;
-
- if ( ! $printed_digg_code ) {
- add_action( 'wp_footer', 'digg_shortcode_js' );
- $printed_digg_code = true;
- }
-
- if ( isset( $atts['class']) && in_array( $atts['class'], array( 'wide', 'medium', 'compact', 'icon' ) ) )
- $class = ucfirst( $atts['class'] );
- else
- $class = 'Medium';
-
- return '<a class="DiggThisButton Digg' . $class . '" href="http://digg.com/submit?url=' . urlencode( get_permalink() ) . '&amp;title=' . urlencode( get_the_title() ) . '"></a>';
+ return '';
}
add_shortcode( 'digg', 'digg_shortcode' );
diff --git a/plugins/jetpack/modules/shortcodes/facebook.php b/plugins/jetpack/modules/shortcodes/facebook.php
index 39152a2c..239253d6 100644
--- a/plugins/jetpack/modules/shortcodes/facebook.php
+++ b/plugins/jetpack/modules/shortcodes/facebook.php
@@ -1,26 +1,50 @@
<?php
-
/**
* Facebook embeds
*/
-define( 'JETPACK_FACEBOOK_EMBED_REGEX', '#^https?://(www.)?facebook\.com/([^/]+)/posts/([^/]+)?#' );
+define( 'JETPACK_FACEBOOK_EMBED_REGEX', '#^https?://(www.)?facebook\.com/([^/]+)/(posts|photos)/([^/]+)?#' );
+define( 'JETPACK_FACEBOOK_ALTERNATE_EMBED_REGEX', '#^https?://(www.)?facebook\.com/permalink.php\?([^\s]+)#' );
define( 'JETPACK_FACEBOOK_PHOTO_EMBED_REGEX', '#^https?://(www.)?facebook\.com/photo.php\?([^\s]+)#' );
+define( 'JETPACK_FACEBOOK_PHOTO_ALTERNATE_EMBED_REGEX', '#^https?://(www.)?facebook\.com/([^/]+)/photos/([^/]+)?#' );
+
+define( 'JETPACK_FACEBOOK_VIDEO_EMBED_REGEX', '#^https?://(www.)?facebook\.com/video.php\?([^\s]+)#' );
-// Example URL: https://www.facebook.com/VenusWilliams/posts/10151647007373076
+// Example URL: https://www.facebook.com/VenusWilliams/posts/10151647007373076
wp_embed_register_handler( 'facebook', JETPACK_FACEBOOK_EMBED_REGEX, 'jetpack_facebook_embed_handler' );
-// Photos are handled on a different endpoint; e.g. https://www.facebook.com/photo.php?fbid=10151609960150073&set=a.398410140072.163165.106666030072&type=1
+
+// Example URL: https://www.facebook.com/permalink.php?id=222622504529111&story_fbid=559431180743788
+wp_embed_register_handler( 'facebook-alternate', JETPACK_FACEBOOK_ALTERNATE_EMBED_REGEX, 'jetpack_facebook_embed_handler' );
+
+// Photos are handled on a different endpoint; e.g. https://www.facebook.com/photo.php?fbid=10151609960150073&set=a.398410140072.163165.106666030072&type=1
wp_embed_register_handler( 'facebook-photo', JETPACK_FACEBOOK_PHOTO_EMBED_REGEX, 'jetpack_facebook_embed_handler' );
+// Photos (from pages for example) can be at
+wp_embed_register_handler( 'facebook-alternate-photo', JETPACK_FACEBOOK_PHOTO_ALTERNATE_EMBED_REGEX, 'jetpack_facebook_embed_handler' );
+
+// Videos e.g. https://www.facebook.com/video.php?v=772471122790796
+wp_embed_register_handler( 'facebook-video', JETPACK_FACEBOOK_VIDEO_EMBED_REGEX, 'jetpack_facebook_embed_handler' );
+
function jetpack_facebook_embed_handler( $matches, $attr, $url ) {
static $did_script;
if ( ! $did_script ) {
$did_script = true;
- add_action( 'wp_footer', 'jetpack_facebook_add_script' );
+ add_action( 'wp_footer', 'jetpack_facebook_add_script' );
+ }
+
+ if ( false !== strpos( $url, 'video.php' ) ) {
+ $embed = sprintf( '<div class="fb-video" data-allowfullscreen="true" data-href="%s"></div>', esc_url( $url ) );
+ } else {
+ $embed = sprintf( '<fb:post href="%s"></fb:post>', esc_url( $url ) );
}
- return sprintf( '<fb:post href="%s"></fb:post>', esc_url( $url ) );
+ // since Facebook is a faux embed, we need to load the JS SDK in the wpview embed iframe
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX && ! empty( $_POST['action'] ) && 'parse-embed' == $_POST['action'] ) {
+ return $embed . '<script src="//connect.facebook.net/en_US/all.js#xfbml=1"></script>';
+ } else {
+ return $embed;
+ }
}
function jetpack_facebook_add_script() {
diff --git a/plugins/jetpack/modules/shortcodes/flickr.php b/plugins/jetpack/modules/shortcodes/flickr.php
index 3f1b13c5..bdc28f0e 100644
--- a/plugins/jetpack/modules/shortcodes/flickr.php
+++ b/plugins/jetpack/modules/shortcodes/flickr.php
@@ -5,11 +5,11 @@
Author: kellan
License: BSD/GPL/public domain (take your pick)
-[flickr video=http://flickr.com/photos/revdancatt/2345938910/]
-[flickr video=2345938910]
-[flickr video=2345938910 show_info=true w=400 h=300]
-[flickr video=2345938910 show_info=true w=400 h=300 secret=846d9c1be9]
-
+[flickr video=http://www.flickr.com/photos/chaddles/2402990826]
+[flickr video=2402990826]
+[flickr video=2402990826 show_info=no]
+[flickr video=2402990826 w=200 h=150]
+[flickr video=2402990826 secret=846d9c1b39]
*/
/*
@@ -73,6 +73,7 @@ function flickr_embed_to_shortcode( $content ) {
$code .= ']';
$content = str_replace( $match[0], $code, $content );
+ /** This action is documented in modules/shortcodes/youtube.php */
do_action( 'jetpack_embed_to_shortcode', 'flickr_video', $flashvars['photo_id'] );
}
}
@@ -90,48 +91,94 @@ function flickr_shortcode_handler( $atts ) {
'h' => 300,
'secret' => 0,
'size' => 0,
- ), $atts );
+ ), $atts, 'flickr' );
- if ( isset( $atts['video'] ) ) {
+ if ( ! empty( $atts['video'] ) ) {
$showing = 'video';
$src = $atts['video'];
- } elseif ( isset( $atts['photo'] ) ) {
+ } elseif ( ! empty( $atts['photo'] ) ) {
$showing = 'photo';
$src = $atts['photo'];
} else {
return '';
}
- if ( preg_match( "!photos/(([0-9a-zA-Z-_]+)|([0-9]+@N[0-9]+))/([0-9]+)/?$!", $src, $m ) )
- $atts['photo_id'] = $m[4];
- else
- $atts['photo_id'] = $atts['video'];
+ if ( is_ssl() ) {
+ $src = str_replace( 'http://', 'https://', $src );
+ }
if ( $showing == 'video' ) {
- if ( ! isset( $atts['show_info'] ) || in_array( $atts['show_info'], array('yes', 'true') ) )
+
+ if ( ! is_numeric( $src ) && ! preg_match( '~^(https?:)?//([\da-z\-]+\.)*?((static)?flickr\.com|flic\.kr)/.*~i', $src ) ) {
+ return '';
+ }
+
+ if ( preg_match( "!photos/(([0-9a-zA-Z-_]+)|([0-9]+@N[0-9]+))/([0-9]+)/?$!", $src, $m ) ) {
+ $atts['photo_id'] = $m[4];
+ } else {
+ $atts['photo_id'] = $atts['video'];
+ }
+
+ if ( ! isset( $atts['show_info'] ) || in_array( $atts['show_info'], array('yes', 'true') ) ) {
$atts['show_info'] = 'true';
- elseif ( in_array( $atts['show_info'], array( 'false', 'no' ) ) )
+ } elseif ( in_array( $atts['show_info'], array( 'false', 'no' ) ) ) {
$atts['show_info'] = 'false';
+ }
- if ( isset( $atts['secret'] ) )
- $atts['secret'] = preg_replace( '![^\w]+!i', '', $atts['secret'] );
+ if ( isset( $atts['secret'] ) ) {
+ $atts['secret'] = preg_replace( '![^\w]+!i', '', $atts['secret'] );
+ }
return flickr_shortcode_video_markup( $atts );
- } else {
- return '';
+ } elseif ( 'photo' == $showing ) {
+
+ if ( ! preg_match( '~^(https?:)?//([\da-z\-]+\.)*?((static)?flickr\.com|flic\.kr)/.*~i', $src ) ) {
+ return '';
+ }
+
+ $src = sprintf( '%s/player/', untrailingslashit( $src ) );
+
+ return sprintf( '<iframe src="%s" height="%s" width="%s" frameborder="0" allowfullscreen webkitallowfullscreen mozallowfullscreen oallowfullscreen msallowfullscreen></iframe>', esc_url( $src ), esc_attr( $atts['h'] ), esc_attr( $atts['w'] ) );
}
+
}
function flickr_shortcode_video_markup( $atts ) {
$atts = array_map( 'esc_attr', $atts );
+ $http = ( is_ssl() ) ? 'https://' : 'http://';
$photo_vars = "photo_id=$atts[photo_id]";
if ( isset( $atts['secret'] ) )
$photo_vars .= "&amp;photo_secret=$atts[secret]";
return <<<EOD
-<object type="application/x-shockwave-flash" width="$atts[w]" height="$atts[h]" data="http://www.flickr.com/apps/video/stewart.swf?v=1.161" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"> <param name="flashvars" value="$photo_vars&amp;flickr_show_info_box=$atts[show_info]"></param><param name="movie" value="http://www.flickr.com/apps/video/stewart.swf?v=1.161"></param><param name="bgcolor" value="#000000"></param><param name="allowFullScreen" value="true"></param><param name="wmode" value="opaque"></param><embed type="application/x-shockwave-flash" src="http://www.flickr.com/apps/video/stewart.swf?v=1.161" bgcolor="#000000" allowfullscreen="true" flashvars="$photo_vars&amp;flickr_show_info_box=$atts[show_info]" wmode="opaque" height="$atts[h]" width="$atts[w]"></embed></object>
+<object type="application/x-shockwave-flash" width="$atts[w]" height="$atts[h]" data="{$http}www.flickr.com/apps/video/stewart.swf?v=1.161" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"> <param name="flashvars" value="$photo_vars&amp;flickr_show_info_box=$atts[show_info]"></param><param name="movie" value="{$http}www.flickr.com/apps/video/stewart.swf?v=1.161"></param><param name="bgcolor" value="#000000"></param><param name="allowFullScreen" value="true"></param><param name="wmode" value="opaque"></param><embed type="application/x-shockwave-flash" src="{$http}www.flickr.com/apps/video/stewart.swf?v=1.161" bgcolor="#000000" allowfullscreen="true" flashvars="$photo_vars&amp;flickr_show_info_box=$atts[show_info]" wmode="opaque" height="$atts[h]" width="$atts[w]"></embed></object>
EOD;
}
add_shortcode( 'flickr', 'flickr_shortcode_handler' );
+
+// Override core's Flickr support because Flickr oEmbed doesn't support web embeds
+wp_embed_register_handler( 'flickr', '#https?://(www\.)?flickr\.com/.*#i', 'jetpack_flickr_oembed_handler' );
+
+function jetpack_flickr_oembed_handler( $matches, $attr, $url ) {
+ // Legacy slideshow embeds end with /show/
+ // e.g. http://www.flickr.com/photos/yarnaholic/sets/72157615194738969/show/
+ if ( '/show/' !== substr( $url, -strlen( '/show/' ) ) ) {
+ // These lookups need cached, as they don't use WP_Embed (which caches)
+ $cache_key = md5( $url . serialize( $attr ) );
+ $cache_group = 'oembed_flickr';
+
+ $html = wp_cache_get( $cache_key, $cache_group );
+
+ if ( false === $html ) {
+ $html = _wp_oembed_get_object()->get_html( $url, $attr );
+
+ wp_cache_set( $cache_key, $html, $cache_group, 60 * MINUTE_IN_SECONDS );
+ }
+
+ return $html;
+ }
+
+ return flickr_shortcode_handler( array( 'photo' => $url ) );
+}
diff --git a/plugins/jetpack/modules/shortcodes/gist.php b/plugins/jetpack/modules/shortcodes/gist.php
new file mode 100644
index 00000000..9a8f63db
--- /dev/null
+++ b/plugins/jetpack/modules/shortcodes/gist.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * GitHub's Gist site supports oEmbed but their oembed provider only
+ * returns raw HTML (no styling) and the first little bit of the code.
+ *
+ * Their Javascript-based embed method is a lot better, so that's what we're using.
+ */
+wp_embed_register_handler( 'github-gist', '#https?://gist\.github\.com/([a-zA-Z0-9]+)#', 'github_gist_embed_handler' );
+add_shortcode( 'gist', 'github_gist_shortcode' );
+
+function github_gist_embed_handler( $matches, $attr, $url, $rawattr ) {
+ // Let the shortcode callback do all the work
+ return github_gist_shortcode( $attr, $url );
+}
+
+function github_gist_shortcode( $atts, $content = '' ) {
+
+ if ( empty( $atts[0] ) && empty( $content ) )
+ return '<!-- Missing Gist ID -->';
+
+ $id = ( ! empty( $content ) ) ? $content : $atts[0];
+
+ // Parse a URL
+ if ( ! is_numeric( $id ) )
+ $id = preg_replace( '#https?://gist.github.com/([a-zA-Z0-9]+)#', '$1', $id );
+
+ if ( ! $id )
+ return '<!-- Invalid Gist ID -->';
+
+ $embed_url = "https://gist.github.com/{$id}.js";
+
+ if ( ! empty( $atts['file'] ) )
+ $embed_url = add_query_arg( 'file', urlencode( $atts['file'] ), $embed_url );
+ // inline style to prevent the bottom margin to the embed that themes like TwentyTen, et al., add to tables
+ return '<style>.gist table { margin-bottom: 0; }</style>' . '<script src="' . esc_url( $embed_url ) . '"></script>';
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/shortcodes/googlemaps.php b/plugins/jetpack/modules/shortcodes/googlemaps.php
index 224654fa..404e0659 100644
--- a/plugins/jetpack/modules/shortcodes/googlemaps.php
+++ b/plugins/jetpack/modules/shortcodes/googlemaps.php
@@ -6,38 +6,43 @@
* into the [googlemaps http://...] shortcode format
*/
function jetpack_googlemaps_embed_to_short_code( $content ) {
- if ( false === strpos( $content, 'maps.google.' ) && false === strpos( $content, 'google.com/maps' ) )
+
+ if ( false === strpos( $content, 'maps.google.' ) && 1 !== preg_match( '@google\.[^/]+/maps?@', $content ) )
return $content;
// IE and TinyMCE format things differently
// &lt;iframe width="425" height="350" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="<a href="https://maps.google.co.uk/maps/ms?msa=0&amp;amp;msid=206216869547772496318.0004bf5f0ff25aea47bd9&amp;amp;hl=en&amp;amp;ie=UTF8&amp;amp;t=m&amp;amp;ll=50.91917,-1.398808&amp;amp;spn=0.013225,0.011794&amp;amp;output=embed&quot;&gt;&lt;/iframe&gt;&lt;br">https://maps.google.co.uk/maps/ms?msa=0&amp;amp;msid=206216869547772496318.0004bf5f0ff25aea47bd9&amp;amp;hl=en&amp;amp;ie=UTF8&amp;amp;t=m&amp;amp;ll=50.91917,-1.398808&amp;amp;spn=0.013225,0.011794&amp;amp;output=embed"&gt;&lt;/iframe&gt;&lt;br</a> /&gt;&lt;small&gt;View &lt;a href="<a href="https://maps.google.co.uk/maps/ms?msa=0&amp;amp;msid=206216869547772496318.0004bf5f0ff25aea47bd9&amp;amp;hl=en&amp;amp;ie=UTF8&amp;amp;t=m&amp;amp;ll=50.91917,-1.398808&amp;amp;spn=0.013225,0.011794&amp;amp;source=embed">https://maps.google.co.uk/maps/ms?msa=0&amp;amp;msid=206216869547772496318.0004bf5f0ff25aea47bd9&amp;amp;hl=en&amp;amp;ie=UTF8&amp;amp;t=m&amp;amp;ll=50.91917,-1.398808&amp;amp;spn=0.013225,0.011794&amp;amp;source=embed</a>" style="color:#0000FF;text-align:left"&gt;OARA Membership Discount Map&lt;/a&gt; in a larger map&lt;/small&gt;
if ( strpos( $content, 'src="<a href="' ) !== false ) {
- $content = preg_replace_callback( '#&lt;iframe\s[^&]*?(?:&(?!gt;)[^&]*?)*?src="<a href="https?://.*?\.google\.(.*?)/(.*?)\?(.+?)&quot;[^&]*?(?:&(?!gt;)[^&]*?)*?&gt;\s*&lt;/iframe&gt;&lt;br">[^"]*?"&gt;\s*&lt;/iframe&gt;&lt;br</a>\s*/&gt;\s*&lt;small&gt;.*?&lt;/small&gt;#i', 'jetpack_googlemaps_embed_to_short_code_callback', $content );
+ $content = preg_replace_callback( '#&lt;iframe\s[^&]*?(?:&(?!gt;)[^&]*?)*?src="<a href="https?://(.*)?\.google\.(.*?)/(.*?)\?(.+?)&quot;[^&]*?(?:&(?!gt;)[^&]*?)*?&gt;\s*&lt;/iframe&gt;&lt;br">[^"]*?"&gt;\s*&lt;/iframe&gt;(?:&lt;br</a>\s*/&gt;\s*&lt;small&gt;.*?&lt;/small&gt;)?#i', 'jetpack_googlemaps_embed_to_short_code_callback', $content );
return $content;
}
- $content = preg_replace_callback( '!\<iframe\s[^>]*?src="https?://.*?\.google\.(.*?)/(.*?)\?(.+?)"[^>]*?\>\s*\</iframe\>\s*(?:\<br\s*/?\>)?\s*\<small\>.*?\</small\>!i', 'jetpack_googlemaps_embed_to_short_code_callback', $content );
+ $content = preg_replace_callback( '!\<iframe\s[^>]*?src="https?://(.*)?\.google\.(.*?)/(.*?)\?(.+?)"[^>]*?\>\s*\</iframe\>(?:\s*(?:\<br\s*/?\>)?\s*\<small\>.*?\</small\>)?!i', 'jetpack_googlemaps_embed_to_short_code_callback', $content );
- $content = preg_replace_callback( '#&lt;iframe\s[^&]*?(?:&(?!gt;)[^&]*?)*?src="https?://.*?\.google\.(.*?)/(.*?)\?(.+?)"[^&]*?(?:&(?!gt;)[^&]*?)*?&gt;\s*&lt;/iframe&gt;\s*(?:&lt;br\s*/?&gt;)?\s*&lt;small&gt;.*?&lt;/small&gt;#i', 'jetpack_googlemaps_embed_to_short_code_callback', $content );
+ $content = preg_replace_callback( '#&lt;iframe\s[^&]*?(?:&(?!gt;)[^&]*?)*?src="https?://(.*)?\.google\.(.*?)/(.*?)\?(.+?)"[^&]*?(?:&(?!gt;)[^&]*?)*?&gt;\s*&lt;/iframe&gt;(?:\s*(?:&lt;br\s*/?&gt;)?\s*&lt;small&gt;.*?&lt;/small&gt;)?#i', 'jetpack_googlemaps_embed_to_short_code_callback', $content );
return $content;
}
function jetpack_googlemaps_embed_to_short_code_callback( $match ) {
- if ( preg_match( '/\bwidth=[\'"](\d+)/', $match[0], $width ) ) {
- $width = (int) $width[1];
+
+ if ( preg_match( '/\bwidth=[\'"](\d+)(%)?/', $match[0], $width ) ) {
+ $percent = ! empty( $width[2] ) ? '%' : '';
+ $width = absint( $width[1] ) . $percent;
} else {
$width = 425;
}
- if ( preg_match( '/\bheight=[\'"](\d+)/', $match[0], $height ) ) {
- $height = (int) $height[1];
+ if ( preg_match( '/\bheight=[\'"](\d+)(%)?/', $match[0], $height ) ) {
+ $percent = ! empty( $height[2] ) ? '%' : '';
+ $height = absint( $height[1] ) . $percent;
} else {
$height = 350;
}
- $url = "https://maps.google.{$match[1]}/{$match[2]}?{$match[3]}&amp;w={$width}&amp;h={$height}";
+ $url = "https://{$match[1]}.google.{$match[2]}/{$match[3]}?{$match[4]}&amp;w={$width}&amp;h={$height}";
+ /** This action is documented in modules/shortcodes/youtube.php */
do_action( 'jetpack_embed_to_shortcode', 'googlemaps', $url );
return "[googlemaps $url]";
@@ -45,8 +50,15 @@ function jetpack_googlemaps_embed_to_short_code_callback( $match ) {
add_filter( 'pre_kses', 'jetpack_googlemaps_embed_to_short_code' );
+/**
+ * [googlemaps] shortcode
+ *
+ * Example usage:
+ * [googlemaps http://maps.google.com/maps?f=q&hl=en&geocode=&q=San+Francisco,+CA&sll=43.469466,-83.998504&sspn=0.01115,0.025942&g=San+Francisco,+CA&ie=UTF8&z=12&iwloc=addr&ll=37.808156,-122.402458&output=embed&s=AARTsJp56EajYksz3JXgNCwT3LJnGsqqAQ&w=425&h=350]
+ * [googlemaps https://mapsengine.google.com/map/embed?mid=zbBhkou4wwtE.kUmp8K6QJ7SA&w=640&h=480]
+ */
function jetpack_googlemaps_shortcode( $atts ) {
- if ( !isset($atts[0]) || apply_filters( 'jetpack_bail_on_shortcode', false, 'googlemaps' ) )
+ if ( !isset($atts[0]) )
return '';
$params = ltrim( $atts[0], '=' );
@@ -54,7 +66,7 @@ function jetpack_googlemaps_shortcode( $atts ) {
$width = 425;
$height = 350;
- if ( preg_match( '!^https?://maps\.google(\.co|\.com)?(\.[a-z]+)?/.*?(\?.+)!i', $params, $match ) ) {
+ if ( preg_match( '!^https?://(www|maps|mapsengine)\.google(\.co|\.com)?(\.[a-z]+)?/.*?(\?.+)!i', $params, $match ) ) {
$params = str_replace( '&amp;amp;', '&amp;', $params );
$params = str_replace( '&amp;', '&', $params );
parse_str( $params, $arg );
@@ -79,9 +91,21 @@ function jetpack_googlemaps_shortcode( $atts ) {
if( is_ssl() )
$url = str_replace( 'http://', 'https://', $url );
- $link_url = preg_replace( '!output=embed!', 'source=embed', $url );
+ $css_class = 'googlemaps';
+
+ if ( ! empty( $atts['align'] ) && in_array( strtolower( $atts['align'] ), array( 'left', 'center', 'right' ), true ) ) {
+ $atts['align'] = strtolower( $atts['align'] );
+
+ if ( $atts['align'] === 'left' ) {
+ $css_class .= ' alignleft';
+ } elseif ( $atts['align'] === 'center' ) {
+ $css_class .= ' aligncenter';
+ } elseif ( $atts['align'] === 'right' ) {
+ $css_class .= ' alignright';
+ }
+ }
- return '<div class="googlemaps"><iframe width="' . $width . '" height="' . $height . '" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="' . $url . '"></iframe><br /><small><a href="' . $link_url . '" style="text-align:left">View Larger Map</a></small></div>';
+ return '<div class="' . esc_attr( $css_class ) . '"><iframe width="' . $width . '" height="' . $height . '" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="' . $url . '"></iframe></div>';
}
}
add_shortcode( 'googlemaps', 'jetpack_googlemaps_shortcode' );
diff --git a/plugins/jetpack/modules/shortcodes/googleplus.php b/plugins/jetpack/modules/shortcodes/googleplus.php
index 95d8b813..759d9b62 100644
--- a/plugins/jetpack/modules/shortcodes/googleplus.php
+++ b/plugins/jetpack/modules/shortcodes/googleplus.php
@@ -4,9 +4,10 @@
* Google+ embeds
*/
-define( 'JETPACK_GOOGLEPLUS_EMBED_REGEX', '#^https?://plus\.(sandbox\.)?google\.com/([^/]+)/posts/([^/]+)$#' );
+define( 'JETPACK_GOOGLEPLUS_EMBED_REGEX', '#^https?://plus\.(sandbox\.)?google\.com/(u/\d+/)?([^/]+)/posts/([^/]+)$#' );
-// Example URL: https://plus.google.com/114986219448604314131/posts/LgHkesWCmJo
+// Example URL: https://plus.google.com/114986219448604314131/posts/LgHkesWCmJo
+// Alternate example: https://plus.google.com/u/0/100004581596612508203/posts/2UKwN67MBQs (note the /u/0/)
wp_embed_register_handler( 'googleplus', JETPACK_GOOGLEPLUS_EMBED_REGEX, 'jetpack_googleplus_embed_handler' );
function jetpack_googleplus_embed_handler( $matches, $attr, $url ) {
@@ -14,7 +15,7 @@ function jetpack_googleplus_embed_handler( $matches, $attr, $url ) {
if ( ! $did_script ) {
$did_script = true;
- add_action( 'wp_footer', 'jetpack_googleplus_add_script' );
+ add_action( 'wp_footer', 'jetpack_googleplus_add_script' );
}
return sprintf( '<div class="g-post" data-href="%s"></div>', esc_url( $url ) );
@@ -34,7 +35,7 @@ function jetpack_googleplus_shortcode_handler( $atts ) {
if ( empty( $atts['url'] ) )
return;
- if ( ! preg_match( JETPACK_GOOGLEPLUS_EMBED_REGEX, $atts['url'] ) )
+ if ( ! preg_match( JETPACK_GOOGLEPLUS_EMBED_REGEX, $atts['url'] ) )
return;
return $wp_embed->shortcode( $atts, $atts['url'] );
diff --git a/plugins/jetpack/modules/shortcodes/images/collapse.png b/plugins/jetpack/modules/shortcodes/images/collapse.png
index 6cdf84fd..921057f1 100644
--- a/plugins/jetpack/modules/shortcodes/images/collapse.png
+++ b/plugins/jetpack/modules/shortcodes/images/collapse.png
Binary files differ
diff --git a/plugins/jetpack/modules/shortcodes/images/expand.png b/plugins/jetpack/modules/shortcodes/images/expand.png
index ddf11ea2..b1e0c56f 100644
--- a/plugins/jetpack/modules/shortcodes/images/expand.png
+++ b/plugins/jetpack/modules/shortcodes/images/expand.png
Binary files differ
diff --git a/plugins/jetpack/modules/shortcodes/images/slide-nav.png b/plugins/jetpack/modules/shortcodes/images/slide-nav.png
index da6b74aa..7fa82c4f 100644
--- a/plugins/jetpack/modules/shortcodes/images/slide-nav.png
+++ b/plugins/jetpack/modules/shortcodes/images/slide-nav.png
Binary files differ
diff --git a/plugins/jetpack/modules/shortcodes/instagram.php b/plugins/jetpack/modules/shortcodes/instagram.php
new file mode 100644
index 00000000..52f83747
--- /dev/null
+++ b/plugins/jetpack/modules/shortcodes/instagram.php
@@ -0,0 +1,178 @@
+<?php
+
+
+/**
+ * Embed Reversal for Instagram
+ *
+ * Hooked to pre_kses, converts an embed code from Instagram.com to an oEmbeddable URL.
+ * @return (string) the filtered or the original content
+ **/
+function jetpack_instagram_embed_reversal( $content ) {
+ if ( false === stripos( $content, 'instagram.com' ) )
+ return $content;
+
+ /* Sample embed code:
+ <blockquote class="instagram-media" data-instgrm-captioned data-instgrm-version="2" style=" background:#FFF; border:0; border-radius:3px; box-shadow:0 0 1px 0 rgba(0,0,0,0.5),0 1px 10px 0 rgba(0,0,0,0.15); margin: 1px; max-width:658px; padding:0; width:99.375%; width:-webkit-calc(100% - 2px); width:calc(100% - 2px);"><div style="padding:8px;"><div style=" background:#F8F8F8; line-height:0; margin-top:40px; padding-bottom:55%; padding-top:45%; text-align:center; width:100%;"><div style="position:relative;"><div style=" -webkit-animation:dkaXkpbBxI 1s ease-out infinite; animation:dkaXkpbBxI 1s ease-out infinite; background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAMAAAApWqozAAAAGFBMVEUiIiI9PT0eHh4gIB4hIBkcHBwcHBwcHBydr+JQAAAACHRSTlMABA4YHyQsM5jtaMwAAADfSURBVDjL7ZVBEgMhCAQBAf//42xcNbpAqakcM0ftUmFAAIBE81IqBJdS3lS6zs3bIpB9WED3YYXFPmHRfT8sgyrCP1x8uEUxLMzNWElFOYCV6mHWWwMzdPEKHlhLw7NWJqkHc4uIZphavDzA2JPzUDsBZziNae2S6owH8xPmX8G7zzgKEOPUoYHvGz1TBCxMkd3kwNVbU0gKHkx+iZILf77IofhrY1nYFnB/lQPb79drWOyJVa/DAvg9B/rLB4cC+Nqgdz/TvBbBnr6GBReqn/nRmDgaQEej7WhonozjF+Y2I/fZou/qAAAAAElFTkSuQmCC); display:block; height:44px; margin:0 auto -44px; position:relative; top:-44px; width:44px;"></div><span style=" color:#c9c8cd; font-family:Arial,sans-serif; font-size:12px; font-style:normal; font-weight:bold; position:relative; top:15px;">Loading</span></div></div><p style=" font-family:Arial,sans-serif; font-size:14px; line-height:17px; margin:8px 0 0 0; padding:0 4px; word-wrap:break-word;"> Balloons</p><p style=" line-height:32px; margin-bottom:0; margin-top:8px; padding:0; text-align:center;"> <a href="https://instagram.com/p/r9vfPrmjeB/" style=" color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:normal; text-decoration:none;" target="_top"> View on Instagram</a></p></div><style>@-webkit-keyframes"dkaXkpbBxI"{ 0%{opacity:0.5;} 50%{opacity:1;} 100%{opacity:0.5;} } @keyframes"dkaXkpbBxI"{ 0%{opacity:0.5;} 50%{opacity:1;} 100%{opacity:0.5;} }</style></blockquote>
+ <script async defer src="https://platform.instagram.com/en_US/embeds.js"></script>
+ */
+
+ $regexes = array();
+
+ // new style js
+ $regexes[] = '#<blockquote[^>]+?class="instagram-media"[^>](.+?)>(.+?)</blockquote><script[^>]+?src="(https?:)?//platform\.instagram\.com/(.+?)/embeds\.js"></script>#ix';
+
+ // Let's play nice with the visual editor too.
+ $regexes[] = '#&lt;blockquote(?:[^&]|&(?!gt;))+?class="instagram-media"(?:[^&]|&(?!gt;))(.+?)&gt;(.+?)&lt;/blockquote&gt;&lt;script(?:[^&]|&(?!gt;))+?src="(https?:)?//platform\.instagram\.com/(.+?)/embeds\.js"(?:[^&]|&(?!gt;))*+&gt;&lt;/script&gt;#ix';
+
+ // old style iframe
+ $regexes[] = '#<iframe[^>]+?src="(?:https?:)?//instagram\.com/p/([^"\'/]++)[^"\']*?"[^>]*+>\s*?</iframe>#i';
+
+ // Let's play nice with the visual editor too.
+ $regexes[] = '#&lt;iframe(?:[^&]|&(?!gt;))+?src="(?:https?:)?//instagram\.com/p/([^"\'/]++)[^"\']*?"(?:[^&]|&(?!gt;))*+&gt;\s*?&lt;/iframe&gt;#i';
+
+ foreach ( $regexes as $regex ) {
+ if ( ! preg_match_all( $regex, $content, $matches, PREG_SET_ORDER ) )
+ continue;
+
+ foreach ( $matches as $match ) {
+ if ( ! preg_match( '#(https?:)?//instagr(\.am|am\.com)/p/([^/]*)#i', $match[2], $url_matches ) )
+ continue;
+
+ // Since we support Instagram via oEmbed, we simply leave a link on a line by itself.
+ $replace_regex = sprintf( '#\s*%s\s*#', preg_quote( $match[0], '#' ) );
+ $url = esc_url( $url_matches[0] );
+
+ $content = preg_replace( $replace_regex, sprintf( "\n\n%s\n\n", $url ), $content );
+ /** This action is documented in modules/shortcodes/youtube.php */
+ do_action( 'jetpack_embed_to_shortcode', 'instagram', $url );
+ }
+ }
+
+ return $content;
+}
+add_filter( 'pre_kses', 'jetpack_instagram_embed_reversal' );
+
+
+/**
+ * Instagram
+ */
+wp_oembed_remove_provider( '#http://instagr(\.am|am\.com)/p/.*#i' ); // remove core's oEmbed support so we can override
+wp_embed_register_handler( 'jetpack_instagram', '#http(s?)://instagr(\.am|am\.com)/p/([^/]*)#i', 'jetpack_instagram_handler' );
+
+function jetpack_instagram_handler( $matches, $atts, $url ) {
+ global $content_width;
+ static $did_script;
+
+ // keep a copy of the passed-in URL since it's modified below
+ $passed_url = $url;
+
+ $max_width = 698;
+ $min_width = 320;
+
+ if ( is_feed() ) {
+ $media_url = sprintf( 'http://instagr.am/p/%s/media/?size=l', $matches[2] );
+ return sprintf( '<a href="%s" title="%s"><img src="%s" alt="Instagram Photo" /></a>', esc_url( $url ), esc_attr__( 'View on Instagram', 'jetpack' ), esc_url( $media_url ) );
+ }
+
+ $atts = shortcode_atts( array(
+ 'width' => isset( $content_width ) ? $content_width : $max_width,
+ 'hidecaption' => false,
+ ), $atts );
+
+ $atts['width'] = absint( $atts['width'] );
+ if ( $atts['width'] > $max_width || $min_width > $atts['width'] )
+ $atts['width'] = $max_width;
+
+
+ // remove the modal param from the URL
+ $url = remove_query_arg( 'modal', $url );
+
+ // force .com instead of .am for https support
+ $url = str_replace( 'instagr.am', 'instagram.com', $url );
+
+ // The oembed endpoint expects HTTP, but HTTP requests 301 to HTTPS
+ $instagram_http_url = str_replace( 'https://', 'http://', $url );
+ $instagram_https_url = str_replace( 'http://', 'https://', $url );
+
+ $url_args = array(
+ 'url' => $instagram_http_url,
+ 'maxwidth' => $atts['width'],
+ );
+
+ if ( $atts['hidecaption'] ) {
+ $url_args['hidecaption'] = 'true';
+ }
+
+ $url = esc_url_raw( add_query_arg( $url_args, 'https://api.instagram.com/oembed/' ) );
+
+ /**
+ * Filter Object Caching for response from Instagram.
+ *
+ * Allow enabling of object caching for the response sent by Instagram when querying for Instagram image HTML.
+ *
+ * @since 3.3.0
+ *
+ * @param bool false Object caching is off by default.
+ * @param array $matches Array of Instagram URLs found in the post.
+ * @param array $atts Instagram Shortcode attributes.
+ * @param string $passed_url Instagram API URL.
+ */
+ $response_body_use_cache = apply_filters( 'instagram_cache_oembed_api_response_body', false, $matches, $atts, $passed_url );
+ $response_body = false;
+ if ( $response_body_use_cache ) {
+ $cache_key = 'oembed_response_body_' . md5( $url );
+ $response_body = wp_cache_get( $cache_key, 'instagram_embeds' );
+ }
+
+ if ( ! $response_body ) {
+ // Not using cache (default case) or cache miss
+ $instagram_response = wp_remote_get( $url, array( 'redirection' => 0 ) );
+ if ( is_wp_error( $instagram_response ) || 200 != $instagram_response['response']['code'] || empty( $instagram_response['body'] ) ) {
+ return "<!-- instagram error: invalid oratv resource -->";
+ }
+
+ $response_body = json_decode( $instagram_response['body'] );
+ if ( $response_body_use_cache ) {
+ // if caching it is short-lived since this is a "Cache-Control: no-cache" resource
+ wp_cache_set( $cache_key, $response_body, 'instagram_embeds', HOUR_IN_SECONDS + mt_rand( 0, HOUR_IN_SECONDS ) );
+ }
+ }
+
+ if ( ! empty( $response_body->html ) ) {
+ if ( ! $did_script ) {
+ $did_script = true;
+ add_action( 'wp_footer', 'jetpack_instagram_add_script' );
+ }
+
+ // there's a script in the response, which we strip on purpose since it's added above
+ $ig_embed = preg_replace( '@<(script)[^>]*?>.*?</\\1>@si', '', $response_body->html );
+ } else {
+ $ig_embed = jetpack_instagram_iframe_embed( $instagram_https_url, $atts );
+ }
+ return $ig_embed;
+}
+
+function jetpack_instagram_add_script() {
+ ?>
+ <script async defer src="//platform.instagram.com/en_US/embeds.js"></script>
+ <?php
+}
+
+// [instagram url="http://instagram.com/p/PSbF9sEIGP/"]
+// [instagram url="http://instagram.com/p/PSbF9sEIGP/" width="300"]
+add_shortcode( 'instagram', 'jetpack_shortcode_instagram' );
+function jetpack_shortcode_instagram( $atts ) {
+ global $wp_embed;
+
+ if ( empty( $atts['url'] ) || ! preg_match( '#http(s?)://instagr(\.am|am\.com)/p/([^/]*)#i', $atts['url'] ) )
+ return;
+
+ return $wp_embed->shortcode( $atts, $atts['url'] );
+}
+
+function jetpack_instagram_iframe_embed( $url, $atts ) {
+ $atts['height'] = intval( $atts['width'] ) + 98; // http://www.niemanlab.org/2013/07/instagram-embeds-are-here-but-not-quite-perfect-for-publishers/
+ $url = trailingslashit( $url ) . 'embed/';
+
+ return sprintf( '<iframe class="jp-embed-instagram" src="%s" width="%s" height="%s" frameborder="0" scrolling="no" allowtransparency="true"></iframe>', esc_url( $url ), esc_attr( $atts['width'] ), esc_attr( $atts['height'] ) );
+}
diff --git a/plugins/jetpack/modules/shortcodes/js/audio-shortcode.js b/plugins/jetpack/modules/shortcodes/js/audio-shortcode.js
index 400219e4..511fd1bf 100644
--- a/plugins/jetpack/modules/shortcodes/js/audio-shortcode.js
+++ b/plugins/jetpack/modules/shortcodes/js/audio-shortcode.js
@@ -1,3 +1,8 @@
+/* jshint onevar:false */
+/* global audioshortcode */
+
+// Note: This file no longer exists on wpcom.
+
(function($) {
window.audioshortcode = {
@@ -19,7 +24,7 @@ window.audioshortcode = {
}
// if the browser removed the script, no-op
- player = $( '#wp-as-' + player_id ).get(0);
+ var player = $( '#wp-as-' + player_id ).get(0);
if ( typeof player === 'undefined' ) {
return;
}
@@ -94,7 +99,7 @@ window.audioshortcode = {
if ( 0 === this[player_id].files.length ) {
$( '#wp-as-' + player_id + '-container' ).html( $( '#wp-as-' + player_id + '-nope' ).html() );
$( '#wp-as-' + player_id + '-controls' ).html( '' );
- } else if ( 1 == this[player_id].files.length ) {
+ } else if ( 1 === this[player_id].files.length ) {
$( '#wp-as-' + player_id + '-controls' ).html( '' );
}
},
@@ -132,7 +137,7 @@ window.audioshortcode = {
next_track: function( player_id, fromClick, loop ) {
var player = $( '#wp-as-' + player_id ).get(0);
var files = this[player_id].files;
- if ( fromClick && ( player.paused || files.length-1 == this[player_id].i ) ) {
+ if ( fromClick && ( player.paused || files.length-1 === this[player_id].i ) ) {
return;
}
diff --git a/plugins/jetpack/modules/shortcodes/js/jmpress.js b/plugins/jetpack/modules/shortcodes/js/jmpress.js
index 294e1fd6..b84bd0ef 100644
--- a/plugins/jetpack/modules/shortcodes/js/jmpress.js
+++ b/plugins/jetpack/modules/shortcodes/js/jmpress.js
@@ -1607,7 +1607,7 @@
current = eventData.current,
jmpress = $(this);
- // tabindex make it focusable so that it can recieve key events
+ // tabindex make it focusable so that it can receive key events
if(!settings.fullscreen) {
jmpress.attr("tabindex", 0);
}
diff --git a/plugins/jetpack/modules/shortcodes/js/main.js b/plugins/jetpack/modules/shortcodes/js/main.js
index a6913f78..c6ed9d07 100644
--- a/plugins/jetpack/modules/shortcodes/js/main.js
+++ b/plugins/jetpack/modules/shortcodes/js/main.js
@@ -16,7 +16,7 @@
* Presentation constructor
*/
function Presentation (wrapper) {
- var _self, size, duration, new_css, ie_regex, matches;
+ var _self, duration, new_css, ie_regex, matches;
_self = this;
@@ -69,8 +69,9 @@
// Register resizing to window when fullscreen
$(window).resize(function() {
- if ( _self.fullscreen )
+ if ( _self.fullscreen ) {
_self.resizePresentation();
+ }
});
// Register the nav bars to move the slides
@@ -111,8 +112,9 @@
// Register ESC key to exit fullscreen
$(window).on('keydown', function( event ) {
- if ( event.which == 27 )
+ if ( event.which === 27 ) {
_self.setFullscreen( false );
+ }
});
// Start the presentation
@@ -176,7 +178,7 @@
$.extend(new_css, {
'-moz-transform' : scale,
'-ms-transform' : scale,
- 'transform' : scale,
+ 'transform' : scale
});
} else {
// webkit scales everything with zoom so we need to offset the right amount
@@ -228,8 +230,9 @@
setAutoplay: function ( on ) {
var _self = this, newAutoplayTime;
- if ( _self.autoPlaying == on )
+ if ( _self.autoPlaying === on ) {
return;
+ }
newAutoplayTime = (on && _self.autoplayTime > 0) ? _self.autoplayTime : 0;
_self.slideshow.jmpress('settings').duration.defaultValue = newAutoplayTime;
diff --git a/plugins/jetpack/modules/shortcodes/js/recipes-printthis.js b/plugins/jetpack/modules/shortcodes/js/recipes-printthis.js
new file mode 100644
index 00000000..a8a52555
--- /dev/null
+++ b/plugins/jetpack/modules/shortcodes/js/recipes-printthis.js
@@ -0,0 +1,170 @@
+/*
+* printThis v1.3
+* @desc Printing plug-in for jQuery
+* @author Jason Day
+*
+* Resources (based on) :
+* jPrintArea: http://plugins.jquery.com/project/jPrintArea
+* jqPrint: https://github.com/permanenttourist/jquery.jqprint
+* Ben Nadal: http://www.bennadel.com/blog/1591-Ask-Ben-Print-Part-Of-A-Web-Page-With-jQuery.htm
+*
+* Dual licensed under the MIT and GPL licenses:
+* http://www.opensource.org/licenses/mit-license.php
+* http://www.gnu.org/licenses/gpl.html
+*
+* (c) Jason Day 2013
+*
+* Usage:
+*
+* $("#mySelector").printThis({
+* debug: false, * show the iframe for debugging
+* importCSS: true, * import page CSS
+* printContainer: true, * grab outer container as well as the contents of the selector
+* loadCSS: "path/to/my.css", * path to additional css file
+* pageTitle: "", * add title to print page
+* removeInline: false, * remove all inline styles from print elements
+* printDelay: 333, * variable print delay S. Vance
+* header: null * prefix to html
+* });
+*
+* Notes:
+* - the loadCSS will load additional css (with or without @media print) into the iframe, adjusting layout
+*/
+/* jshint onevar: false, smarttabs: true, devel: true */
+;(function ($) {
+ var opt;
+ $.fn.printThis = function (options) {
+ opt = $.extend({}, $.fn.printThis.defaults, options);
+ var $element = this instanceof jQuery ? this : $(this);
+
+ var strFrameName = 'printThis-' + (new Date()).getTime();
+
+ if(window.location.hostname !== document.domain && navigator.userAgent.match(/msie/i)){
+ // Ugly IE hacks due to IE not inheriting document.domain from parent
+ // checks if document.domain is set by comparing the host name against document.domain
+ var iframeContents = '<head><script>document.domain=\\\'' + document.domain + '\\\';</script></head><body></body>';
+ var iframeSrc = 'data:text/html;charset=utf-8,' + encodeURI(iframeContents);
+ var printI= document.createElement('iframe');
+ printI.name = 'printIframe';
+ printI.id = strFrameName;
+ printI.className = 'MSIE';
+ document.body.appendChild(printI);
+ printI.src = iframeSrc;
+
+ } else {
+ // other browsers inherit document.domain, and IE works if document.domain is not explicitly set
+ var $frame = $('<iframe id="' + strFrameName +'" name="printIframe" />');
+ $frame.appendTo('body');
+ }
+
+
+ var $iframe = $('#' + strFrameName);
+
+ // show frame if in debug mode
+ if (!opt.debug) {
+ $iframe.css({
+ position: 'absolute',
+ width: '0px',
+ height: '0px',
+ left: '-600px',
+ top: '-600px'
+ });
+ }
+
+
+ // $iframe.ready() and $iframe.load were inconsistent between browsers
+ setTimeout ( function () {
+
+ var $doc = $iframe.contents();
+
+ // import page stylesheets
+ if (opt.importCSS) {
+ $('link[rel=stylesheet]').each(function () {
+ var href = $(this).attr('href');
+ if (href) {
+ var media = $(this).attr('media') || 'all';
+ $doc.find('head').append('<link type="text/css" rel="stylesheet" href="' + href + '" media="' + media + '">');
+ }
+ });
+ }
+
+ //add title of the page
+ if (opt.pageTitle) {
+ $doc.find('head').append('<title>' + opt.pageTitle + '</title>');
+ }
+
+ // import additional stylesheet
+ if (opt.loadCSS) {
+ $doc.find('head').append('<link type="text/css" rel="stylesheet" href="' + opt.loadCSS + '">');
+ }
+
+ // print header
+ if (opt.header) {
+ $doc.find('body').append(opt.header);
+ }
+
+ // grab $.selector as container
+ if (opt.printContainer) {
+ $doc.find('body').append($element.outer());
+ }
+
+ // otherwise just print interior elements of container
+ else {
+ $element.each(function () {
+ $doc.find('body').append($(this).html());
+ });
+ }
+
+ // remove inline styles
+ if (opt.removeInline) {
+ // $.removeAttr available jQuery 1.7+
+ if ($.isFunction($.removeAttr)) {
+ $doc.find('body *').removeAttr('style');
+ } else {
+ $doc.find('body *').attr('style', '');
+ }
+ }
+
+ setTimeout(function () {
+ if($iframe.hasClass('MSIE')){
+ // check if the iframe was created with the ugly hack
+ // and perform another ugly hack out of neccessity
+ window.frames.printIframe.focus();
+ $doc.find('head').append('<script> window.print(); </script>');
+ } else {
+ // proper method
+ $iframe[0].contentWindow.focus();
+ $iframe[0].contentWindow.print();
+ }
+
+ $element.trigger( 'done');
+ //remove iframe after print
+ if (!opt.debug) {
+ setTimeout(function () {
+ $iframe.remove();
+ }, 1000);
+ }
+
+ }, opt.printDelay);
+
+ }, 333 );
+
+ };
+
+ // defaults
+ $.fn.printThis.defaults = {
+ debug: false, // show the iframe for debugging
+ importCSS: false, // import parent page css
+ printContainer: true, // print outer container/$.selector
+ loadCSS: '', // load an additional css file
+ pageTitle: '', // add title to print page
+ removeInline: false, // remove all inline styles
+ printDelay: 333, // variable print delay S. Vance
+ header: null // prefix to html
+ };
+
+ // $.selector container
+ jQuery.fn.outer = function () {
+ return $($('<div></div>').html(this.clone())).html();
+ };
+})(jQuery);
diff --git a/plugins/jetpack/modules/shortcodes/js/recipes.js b/plugins/jetpack/modules/shortcodes/js/recipes.js
new file mode 100644
index 00000000..3c987acc
--- /dev/null
+++ b/plugins/jetpack/modules/shortcodes/js/recipes.js
@@ -0,0 +1,11 @@
+/* global jetpack_recipes_vars */
+( function( $ ) {
+ $( window ).load( function() {
+ $( '.jetpack-recipe-print a' ).click( function( event ) {
+ event.preventDefault();
+
+ // Print the DIV.
+ $( this ).closest( '.jetpack-recipe' ).printThis( { pageTitle: jetpack_recipes_vars.pageTitle, loadCSS: jetpack_recipes_vars.loadCSS } );
+ } );
+ } );
+} )( jQuery );
diff --git a/plugins/jetpack/modules/shortcodes/js/slideshow-shortcode.js b/plugins/jetpack/modules/shortcodes/js/slideshow-shortcode.js
index 5e132097..8bee063f 100644
--- a/plugins/jetpack/modules/shortcodes/js/slideshow-shortcode.js
+++ b/plugins/jetpack/modules/shortcodes/js/slideshow-shortcode.js
@@ -1,3 +1,6 @@
+/* jshint onevar:false, loopfunc:true */
+/* global jetpackSlideshowSettings, escape */
+
function JetpackSlideshow( element, width, height, transition ) {
this.element = element;
this.images = [];
@@ -5,8 +8,9 @@ function JetpackSlideshow( element, width, height, transition ) {
this.transition = transition || 'fade';
var currentWidth = this.element.width();
- if ( !width || width > currentWidth )
+ if ( !width || width > currentWidth ) {
width = currentWidth;
+ }
this.width = width;
this.height = height;
@@ -40,6 +44,8 @@ JetpackSlideshow.prototype.init = function() {
var imageInfo = this.images[i];
var img = document.createElement( 'img' );
img.src = imageInfo.src + '?w=' + this.width;
+ img.title = imageInfo.title;
+ img.alt = imageInfo.alt;
img.align = 'middle';
var caption = document.createElement( 'div' );
caption.className = 'slideshow-slide-caption';
@@ -49,7 +55,7 @@ JetpackSlideshow.prototype.init = function() {
container.style.lineHeight = this.height + 'px';
// Hide loading image once first image has loaded.
- if ( i == 0 ) {
+ if ( i === 0 ) {
if ( img.complete ) {
// IE, image in cache
setTimeout( function() {
@@ -90,51 +96,63 @@ JetpackSlideshow.prototype.finishInit_ = function() {
this.renderControls_();
var self = this;
- // Initialize Cycle instance.
- this.element.cycle( {
- fx: this.transition,
- prev: this.controls.prev,
- next: this.controls.next,
- slideExpr: '.slideshow-slide',
- onPrevNextEvent: function() {
- return self.onCyclePrevNextClick_.apply( self, arguments );
- }
- } );
-
- var slideshow = this.element;
- jQuery( this.controls['stop'] ).click( function() {
- var button = jQuery(this);
- if ( ! button.hasClass( 'paused' ) ) {
- slideshow.cycle( 'pause' );
- button.removeClass( 'running' );
- button.addClass( 'paused' );
- } else {
- button.addClass( 'running' );
- button.removeClass( 'paused' );
- slideshow.cycle( 'resume', true );
- }
- return false;
- } );
+ if ( this.images.length > 1 ) {
+ // Initialize Cycle instance.
+ this.element.cycle( {
+ fx: this.transition,
+ prev: this.controls.prev,
+ next: this.controls.next,
+ slideExpr: '.slideshow-slide',
+ onPrevNextEvent: function() {
+ return self.onCyclePrevNextClick_.apply( self, arguments );
+ }
+ } );
- var controls = jQuery( this.controlsDiv_ );
- slideshow.mouseenter( function() {
- controls.fadeIn();
- } );
- slideshow.mouseleave( function() {
- controls.fadeOut();
- } );
+ var slideshow = this.element;
+ jQuery( this.controls.stop ).click( function() {
+ var button = jQuery(this);
+ if ( ! button.hasClass( 'paused' ) ) {
+ slideshow.cycle( 'pause' );
+ button.removeClass( 'running' );
+ button.addClass( 'paused' );
+ } else {
+ button.addClass( 'running' );
+ button.removeClass( 'paused' );
+ slideshow.cycle( 'resume', true );
+ }
+ return false;
+ } );
+ var controls = jQuery( this.controlsDiv_ );
+ slideshow.on( 'mouseenter focusin', function() {
+ controls.stop( true, false ).fadeTo( 200, 1 );
+ } );
+ slideshow.on( 'mouseleave', function() {
+ if ( ! jQuery( document.activeElement.parentNode ).hasClass( 'slideshow-controls' ) ) {
+ controls.fadeTo( 200, 0 );
+ }
+ } );
+ slideshow.on( 'focusout', function() {
+ if ( ! slideshow.is( ':hover' ) ) {
+ controls.fadeTo( 200, 0 );
+ }
+ } );
+ } else {
+ this.element.children( ':first' ).show();
+ this.element.css( 'position', 'relative' );
+ }
this.initialized_ = true;
};
JetpackSlideshow.prototype.renderControls_ = function() {
- if ( this.controlsDiv_ )
+ if ( this.controlsDiv_ ) {
return;
+ }
var controlsDiv = document.createElement( 'div' );
controlsDiv.className = 'slideshow-controls';
- controls = [ 'prev', 'stop', 'next' ];
+ var controls = [ 'prev', 'stop', 'next' ];
for ( var i = 0; i < controls.length; i++ ) {
var controlName = controls[i];
var a = document.createElement( 'a' );
@@ -146,15 +164,16 @@ JetpackSlideshow.prototype.renderControls_ = function() {
this.controlsDiv_ = controlsDiv;
};
-JetpackSlideshow.prototype.onCyclePrevNextClick_ = function( isNext, i, slideElement ) {
+JetpackSlideshow.prototype.onCyclePrevNextClick_ = function( isNext, i/*, slideElement*/ ) {
// If blog_id not present don't track page views
- if ( ! jetpackSlideshowSettings.blog_id )
+ if ( ! jetpackSlideshowSettings.blog_id ) {
return;
+ }
var postid = this.images[i].id;
var stats = new Image();
stats.src = document.location.protocol +
- '//stats.wordpress.com/g.gif?host=' +
+ '//pixel.wp.com/g.gif?host=' +
escape( document.location.host ) +
'&rand=' + Math.random() +
'&blog=' + jetpackSlideshowSettings.blog_id +
@@ -171,8 +190,9 @@ JetpackSlideshow.prototype.onCyclePrevNextClick_ = function( isNext, i, slideEle
$( '.jetpack-slideshow' ).each( function () {
var container = $( this );
- if ( container.data( 'processed' ) )
+ if ( container.data( 'processed' ) ) {
return;
+ }
var slideshow = new JetpackSlideshow( container, container.data( 'width' ), container.data( 'height' ), container.data( 'trans' ) );
slideshow.images = container.data( 'gallery' );
@@ -184,4 +204,4 @@ JetpackSlideshow.prototype.onCyclePrevNextClick_ = function( isNext, i, slideEle
$( document ).ready( jetpack_slideshow_init );
$( 'body' ).on( 'post-load', jetpack_slideshow_init );
-} )( jQuery ); \ No newline at end of file
+} )( jQuery );
diff --git a/plugins/jetpack/modules/shortcodes/medium.php b/plugins/jetpack/modules/shortcodes/medium.php
new file mode 100644
index 00000000..6bd651df
--- /dev/null
+++ b/plugins/jetpack/modules/shortcodes/medium.php
@@ -0,0 +1,66 @@
+<?php
+
+// Embed support for Medium https://medium.com/p/3eaed64aed8a
+
+/**
+ * Faux-oembed support for Medium permalinks
+ *
+ * e.g.
+ * https://medium.com/help-center
+ * https://medium.com/@richroll
+ */
+wp_embed_register_handler( 'medium', '#^https?://medium.com/([a-zA-z0-9-_@]+)#', 'jetpack_embed_medium_oembed' );
+
+function jetpack_embed_medium_oembed( $matches, $attr, $url ) {
+ $attr = jetpack_embed_medium_args( $attr );
+ $attr['url'] = $url;
+
+ return jetpack_embed_medium_embed_html( $attr );
+}
+
+function jetpack_embed_medium_embed_html( $args ) {
+ $args = jetpack_embed_medium_args( $args );
+
+ if ( empty( $args['url'] ) ) {
+ return;
+ }
+
+ $args['type'] = jetpack_embed_medium_get_embed_type( $args['url'] );
+
+ return sprintf( '<script async src="https://static.medium.com/embed.js"></script><a class="m-%1$s" href="%2$s" data-width="%3$s" data-border="%4$s" data-collapsed="%5$s">View %1$s at Medium.com</a>', esc_attr( $args['type'] ), esc_url( $args['url'] ), esc_attr( $args['width'] ), esc_attr( $args['border'] ), esc_attr( $args['collapsed'] ) );
+}
+
+/**
+ * Shortcode support that allows passing in URL
+ *
+ * [medium url="https://medium.com/help-center" width="100%" border="false" collapsed="true"]
+ */
+add_shortcode( 'medium', 'jetpack_embed_medium_shortcode' );
+
+function jetpack_embed_medium_shortcode( $atts ) {
+ $atts = jetpack_embed_medium_args( $atts );
+
+ if ( ! empty( $atts['url'] ) ) {
+ global $wp_embed;
+ return $wp_embed->shortcode( $atts, $atts['url'] );
+ }
+}
+
+function jetpack_embed_medium_get_embed_type( $url ) {
+ $url_path = parse_url( $url, PHP_URL_PATH );
+ if ( 0 === strpos( $url_path, '/@' ) ) {
+ return 'profile';
+ } elseif ( preg_match( '#^/[^/]+/[^/]+$#', $url_path ) ) {
+ return 'story';
+ }
+ return 'collection';
+}
+
+function jetpack_embed_medium_args( $atts ) {
+ return shortcode_atts( array(
+ 'url' => '',
+ 'width' => '400',
+ 'border' => true,
+ 'collapsed' => false,
+ ), $atts, 'medium' );
+}
diff --git a/plugins/jetpack/modules/shortcodes/mixcloud.php b/plugins/jetpack/modules/shortcodes/mixcloud.php
new file mode 100644
index 00000000..a5580312
--- /dev/null
+++ b/plugins/jetpack/modules/shortcodes/mixcloud.php
@@ -0,0 +1,52 @@
+<?php
+/*
+ * Mixcloud embeds
+ *
+ * examples:
+ * [mixcloud MalibuRum/play-6-kissy-sellouts-winter-sun-house-party-mix/ /]
+ * [mixcloud MalibuRum/play-6-kissy-sellouts-winter-sun-house-party-mix/ width=640 height=480 /]
+ * [mixcloud http://www.mixcloud.com/MalibuRum/play-6-kissy-sellouts-winter-sun-house-party-mix/ /]
+ * [mixcloud http://www.mixcloud.com/MalibuRum/play-6-kissy-sellouts-winter-sun-house-party-mix/ width=640 height=480 /]
+ * [mixcloud]http://www.mixcloud.com/MalibuRum/play-6-kissy-sellouts-winter-sun-house-party-mix/[/mixcloud]
+ * [mixcloud]MalibuRum/play-6-kissy-sellouts-winter-sun-house-party-mix/[/mixcloud]
+*/
+
+// Register oEmbed provider
+// Example URL: http://www.mixcloud.com/oembed/?url=http://www.mixcloud.com/MalibuRum/play-6-kissy-sellouts-winter-sun-house-party-mix/
+wp_oembed_add_provider('#https?://(?:www\.)?mixcloud\.com/\S*#i', 'http://www.mixcloud.com/oembed', true);
+
+// Register mixcloud shortcode
+add_shortcode( 'mixcloud', 'mixcloud_shortcode' );
+function mixcloud_shortcode( $atts, $content = null ) {
+
+ if ( empty( $atts[0] ) && empty( $content ) )
+ return "<!-- mixcloud error: invalid mixcloud resource -->";
+
+ $regular_expression = "#((?<=mixcloud.com/)([A-Za-z0-9_-]+/[A-Za-z0-9_-]+))|^([A-Za-z0-9_-]+/[A-Za-z0-9_-]+)#i";
+ preg_match( $regular_expression, $content, $match );
+ if ( ! empty( $match ) ) {
+ $resource_id = trim( $match[0] );
+ } else {
+ preg_match( $regular_expression, $atts[0], $match );
+ if ( ! empty( $match ) )
+ $resource_id = trim( $match[0] );
+ }
+
+ if ( empty( $resource_id ) )
+ return "<!-- mixcloud error: invalid mixcloud resource -->";
+
+ $atts = shortcode_atts( array(
+ 'width' => 300,
+ 'height' => 300,
+ ), $atts, 'mixcloud' );
+
+
+ // Build URL
+ $url = add_query_arg( $atts, "http://api.mixcloud.com/$resource_id/embed-html/" );
+ $head = wp_remote_head( $url );
+ if ( is_wp_error( $head ) || 200 != $head['response']['code'] )
+ return "<!-- mixcloud error: invalid mixcloud resource -->";
+
+ return sprintf( '<iframe width="%d" height="%d" scrolling="no" frameborder="no" src="%s"></iframe>', $atts['width'], $atts['height'], esc_url( $url ) );
+
+}
diff --git a/plugins/jetpack/modules/shortcodes/polldaddy.php b/plugins/jetpack/modules/shortcodes/polldaddy.php
index 6b46da7f..3b20ff1d 100644
--- a/plugins/jetpack/modules/shortcodes/polldaddy.php
+++ b/plugins/jetpack/modules/shortcodes/polldaddy.php
@@ -51,7 +51,7 @@ class PolldaddyShortcode {
'visit' => 'single',
'domain' => '',
'id' => ''
- ), $atts ) );
+ ), $atts, 'polldaddy' ) );
if ( ! is_array( $atts ) ) {
return '<!-- Polldaddy shortcode passed invalid attributes -->';
@@ -84,6 +84,7 @@ class PolldaddyShortcode {
$item_id = is_page() ? '_page_'.$post->ID : '_post_'.$post->ID;
if ( empty( $title ) )
+ /** This filter is documented in core/src/wp-includes/general-template.php */
$title = apply_filters( 'wp_title', $post->post_title, '', '' );
if ( empty( $permalink ) )
@@ -383,7 +384,7 @@ SCRIPT;
// kick it all off
new PolldaddyShortcode();
-if ( !function_exists( 'polldaddy_link' ) ) {
+if ( ! function_exists( 'polldaddy_link' ) ) {
// http://polldaddy.com/poll/1562975/?view=results&msg=voted
function polldaddy_link( $content ) {
return preg_replace( '!(?:\n|\A)http://polldaddy.com/poll/([0-9]+?)/(.+)?(?:\n|\Z)!i', "\n<script type='text/javascript' language='javascript' charset='utf-8' src='http://static.polldaddy.com/p/$1.js'></script><noscript> <a href='http://polldaddy.com/poll/$1/'>View Poll</a></noscript>\n", $content );
@@ -392,7 +393,11 @@ if ( !function_exists( 'polldaddy_link' ) ) {
// higher priority because we need it before auto-link and autop get to it
add_filter( 'the_content', 'polldaddy_link', 1 );
add_filter( 'the_content_rss', 'polldaddy_link', 1 );
- add_filter( 'comment_text', 'polldaddy_link', 1 );
+
+ /** This filter is documented in modules/shortcodes/youtube.php */
+ if ( apply_filters( 'jetpack_comments_allow_oembed', get_option( 'embed_autourls' ) ) ) {
+ add_filter( 'comment_text', 'polldaddy_link', 1 );
+ }
}
}
diff --git a/plugins/jetpack/modules/shortcodes/presentations.php b/plugins/jetpack/modules/shortcodes/presentations.php
index 6fb2b674..aa4f42ee 100644
--- a/plugins/jetpack/modules/shortcodes/presentations.php
+++ b/plugins/jetpack/modules/shortcodes/presentations.php
@@ -7,19 +7,19 @@ Version: 0.2
Author: Automattic
Author URI: http://automattic.com/wordpress-plugins/
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -109,7 +109,7 @@ class Presentations {
}
foreach ( $GLOBALS['posts'] as $p ) {
- if ( false !== strpos( $p->post_content, '[presentation' ) ) {
+ if ( has_shortcode( $p->post_content, 'presentation' ) ) {
$this->scripts_and_style_included = true;
break;
}
@@ -140,31 +140,32 @@ class Presentations {
$this->presentation_initialized = true;
$atts = shortcode_atts( array(
- 'duration' => '',
- 'height' => '',
- 'width' => '',
- 'bgcolor' => '',
- 'bgimg' => '',
- 'autoplay' => '',
+ 'duration' => '',
+ 'height' => '',
+ 'width' => '',
+ 'bgcolor' => '',
+ 'bgimg' => '',
+ 'autoplay' => '',
// Settings
- 'transition' => '',
- 'scale' => '',
- 'rotate' => '',
- 'fade' => '',
- 'fadebullets'=> '',
- ), $atts );
+ 'transition' => '',
+ 'scale' => '',
+ 'rotate' => '',
+ 'fade' => '',
+ 'fadebullets' => '',
+ ), $atts, 'presentation' );
$this->presentation_settings = array(
- 'transition' => 'down',
- 'scale' => 1,
- 'rotate' => 0,
- 'fade' => 'on',
- 'last' => array(
- 'x' => 0,
- 'y' => 0,
- 'scale' => 1,
- 'rotate' => 0,
+ 'transition' => 'down',
+ 'scale' => 1,
+ 'rotate' => 0,
+ 'fade' => 'on',
+ 'fadebullets' => 0,
+ 'last' => array(
+ 'x' => 0,
+ 'y' => 0,
+ 'scale' => 1,
+ 'rotate' => 0,
),
);
@@ -244,7 +245,6 @@ class Presentations {
}
$out.= do_shortcode( $content );
- $out.= "</section>";
}
$out.= "</section>";
@@ -266,7 +266,7 @@ class Presentations {
'fadebullets'=> '',
'bgcolor' => '',
'bgimg' => '',
- ), $atts );
+ ), $atts, 'slide' );
// Determine positioning based on transition
if ( '' == trim( $atts['transition'] ) )
diff --git a/plugins/jetpack/modules/shortcodes/recipe.php b/plugins/jetpack/modules/shortcodes/recipe.php
new file mode 100644
index 00000000..ece39fd4
--- /dev/null
+++ b/plugins/jetpack/modules/shortcodes/recipe.php
@@ -0,0 +1,147 @@
+<?php
+/**
+ * Embed recipe 'cards' in post, with basic styling and print functionality
+ *
+ */
+
+class Jetpack_Recipes {
+
+ private $scripts_and_style_included = false;
+
+ function __construct() {
+ add_action( 'init', array( $this, 'action_init' ) );
+ }
+
+ function action_init() {
+ // Enqueue styles if [recipe] exists
+ add_action( 'wp_head', array( $this, 'add_scripts' ), 1 );
+
+ // Render [recipe]
+ add_shortcode( 'recipe', array( $this, 'recipe_shortcode' ) );
+ }
+
+ /**
+ * Enqueue scripts and styles
+ */
+ function add_scripts() {
+ if ( empty( $GLOBALS['posts'] ) || ! is_array( $GLOBALS['posts'] ) ) {
+ return;
+ }
+
+ foreach ( $GLOBALS['posts'] as $p ) {
+ if ( has_shortcode( $p->post_content, 'recipe' ) ) {
+ $this->scripts_and_style_included = true;
+ break;
+ }
+ }
+
+ if ( ! $this->scripts_and_style_included ) {
+ return;
+ }
+
+ if( is_rtl() ) {
+ wp_enqueue_style( 'jetpack-recipes-style', plugins_url( '/css/rtl/recipes-rtl.css', __FILE__ ), array(), '20130919' );
+ } else {
+ wp_enqueue_style( 'jetpack-recipes-style', plugins_url( '/css/recipes.css', __FILE__ ), array(), '20130919' );
+ }
+
+
+ wp_enqueue_script( 'jetpack-recipes-printthis', plugins_url( '/js/recipes-printthis.js', __FILE__ ), array( 'jquery' ), '20131230' );
+ wp_enqueue_script( 'jetpack-recipes-js', plugins_url( '/js/recipes.js', __FILE__ ), array( 'jquery', 'jetpack-recipes-printthis' ), '20131230' );
+
+ $title_var = wp_title( '|', false, 'right' );
+ $print_css_var = plugins_url( '/css/recipes-print.css', __FILE__ );
+
+ wp_localize_script( 'jetpack-recipes-js', 'jetpack_recipes_vars', array(
+ 'pageTitle' => $title_var,
+ 'loadCSS' => $print_css_var
+ ) );
+ }
+
+ /**
+ * Our [recipe] shortcode.
+ * Prints recipe data styled to look good on *any* theme.
+ *
+ * @return resume_shortcode_html
+ */
+ static function recipe_shortcode( $atts, $content = '' ) {
+ $atts = shortcode_atts( array(
+ 'title' => '', //string
+ 'servings' => '', //intval
+ 'time' => '', //string
+ 'difficulty' => '', //string
+ 'print' => '', //string
+ ), $atts, 'recipe' );
+
+ return self::recipe_shortcode_html( $atts, $content );
+ }
+
+ /**
+ * The recipe output
+ *
+ * @return Html
+ */
+ static function recipe_shortcode_html( $atts, $content = '' ) {
+ $html = false;
+
+ $html = '<div class="hrecipe jetpack-recipe" itemscope itemtype="http://schema.org/Recipe">';
+
+ // Print the recipe title if exists
+ if ( '' != $atts['title'] ) {
+ $html .= '<h3 class="jetpack-recipe-title" itemprop="name">' . esc_html( $atts['title'] ) . '</h3>';
+ }
+
+ // Print the recipe meta if exists
+ if ( '' != $atts['servings'] || '' != $atts['time'] || '' != $atts['difficulty'] || '' != $atts['print'] ) {
+ $html .= '<ul class="jetpack-recipe-meta">';
+
+ if ( '' != $atts['servings'] ) {
+ $html .= sprintf( '<li class="jetpack-recipe-servings" itemprop="recipeYield"><strong>%1s: </strong>%2s</li>',
+ __( 'Servings', 'jetpack' ),
+ esc_html( $atts['servings'] )
+ );
+ }
+
+ if ( '' != $atts['time'] ) {
+ $html .= sprintf( '<li class="jetpack-recipe-time" itemprop="totalTime"><strong>%1s: </strong>%2s</li>',
+ __( 'Time', 'jetpack' ),
+ esc_html( $atts['time'] )
+ );
+ }
+
+ if ( '' != $atts['difficulty'] ) {
+ $html .= sprintf( '<li class="jetpack-recipe-difficulty"><strong>%1s: </strong>%2s</li>',
+ __( 'Difficulty', 'jetpack' ),
+ esc_html( $atts['difficulty'] )
+ );
+ }
+
+ if ( 'false' != $atts['print'] ) {
+ $html .= sprintf( '<li class="jetpack-recipe-print"><a href="#">%1s</a></li>',
+ __( 'Print', 'jetpack' )
+ );
+ }
+
+ $html .= '</ul>';
+ }
+
+ // Print content between codes
+ $html .= '<div class="jetpack-recipe-content">' . do_shortcode( $content ) . '</div>';
+
+ // Close it up
+ $html .= '</div>';
+
+ // If there is a recipe within a recipe, remove the shortcode
+ if ( has_shortcode( $html, 'recipe' ) ) {
+ remove_shortcode( 'recipe' );
+ }
+
+ // Sanitize html
+ $html = wp_kses_post( $html );
+
+ // Return the HTML block
+ return $html;
+ }
+}
+
+new Jetpack_Recipes();
diff --git a/plugins/jetpack/modules/shortcodes/scribd.php b/plugins/jetpack/modules/shortcodes/scribd.php
index d8677c91..a334fd55 100644
--- a/plugins/jetpack/modules/shortcodes/scribd.php
+++ b/plugins/jetpack/modules/shortcodes/scribd.php
@@ -16,7 +16,7 @@ function scribd_shortcode_handler( $atts ) {
'id' => 0,
'key' => 0,
'mode' => "",
- ), $atts );
+ ), $atts, 'scribd' );
$modes = array( 'list', 'book', 'slide', 'slideshow', 'tile' );
@@ -35,11 +35,19 @@ function scribd_shortcode_handler( $atts ) {
function scribd_shortcode_markup( $atts ) {
$markup = <<<EOD
-<iframe class="scribd_iframe_embed" src="http://www.scribd.com/embeds/$atts[id]/content?start_page=1&view_mode=$atts[mode]&access_key=$atts[key]" data-auto-height="true" scrolling="no" id="scribd_$atts[id]" width="100%" height="500" frameborder="0"></iframe>
+<iframe class="scribd_iframe_embed" src="//www.scribd.com/embeds/$atts[id]/content?start_page=1&view_mode=$atts[mode]&access_key=$atts[key]" data-auto-height="true" scrolling="no" id="scribd_$atts[id]" width="100%" height="500" frameborder="0"></iframe>
<div style="font-size:10px;text-align:center;width:100%"><a href="http://www.scribd.com/doc/$atts[id]">View this document on Scribd</a></div>
EOD;
return $markup;
}
-
add_shortcode( 'scribd', 'scribd_shortcode_handler' );
+
+// Scribd supports HTTPS, so use that endpoint to get HTTPS-compatible embeds
+function scribd_https_oembed( $providers ) {
+ if ( isset( $providers['#https?://(www\.)?scribd\.com/doc/.*#i'] ) ) {
+ $providers['#https?://(www\.)?scribd\.com/doc/.*#i'][0] = 'https://www.scribd.com/services/oembed';
+ }
+ return $providers;
+}
+add_filter( 'oembed_providers', 'scribd_https_oembed' );
diff --git a/plugins/jetpack/modules/shortcodes/slideshare.php b/plugins/jetpack/modules/shortcodes/slideshare.php
index 97d9d446..f08790ae 100644
--- a/plugins/jetpack/modules/shortcodes/slideshare.php
+++ b/plugins/jetpack/modules/shortcodes/slideshare.php
@@ -10,30 +10,36 @@ function slideshare_shortcode( $atts ) {
$params = shortcode_new_to_old_params( $atts );
parse_str( $params, $arguments );
- if ( empty( $arguments ) )
- return "<!-- SlideShare error: no arguments -->";
+ if ( empty( $arguments ) ) {
+ return '<!-- SlideShare error: no arguments -->';
+ }
- extract( $arguments );
+ extract( $arguments, EXTR_SKIP );
$pattern = '/[^-_a-zA-Z0-9]/';
- if ( empty( $id ) || preg_match( $pattern, $id ) )
- return "<!-- SlideShare error: id is missing or has illegal characters -->";
+ if ( empty( $id ) || preg_match( $pattern, $id ) ) {
+ return '<!-- SlideShare error: id is missing or has illegal characters -->';
+ }
- if ( empty( $doc ) || preg_match( $pattern, $doc ) )
- return "<!-- SlideShare error: doc is missing or has illegal characters -->";
+ if ( empty( $doc ) || preg_match( $pattern, $doc ) ) {
+ return '<!-- SlideShare error: doc is missing or has illegal characters -->';
+ }
- if ( empty( $w ) && !empty( $content_width ) )
+ if ( empty( $w ) && !empty( $content_width ) ) {
$w = intval( $content_width );
- elseif ( ! ( $w = intval( $w ) ) || $w < 300 || $w > 1600 )
+ } elseif ( ! ( $w = intval( $w ) ) || $w < 300 || $w > 1600 ) {
$w = 425;
- else
+ } else {
$w = intval( $w );
+ }
$h = ceil( $w * 348 / 425 );
$player = "<object type='application/x-shockwave-flash' wmode='opaque' data='http://static.slideshare.net/swf/ssplayer2.swf?id=$id&doc=$doc' width='$w' height='$h'><param name='movie' value='http://static.slideshare.net/swf/ssplayer2.swf?id=$id&doc=$doc' /><param name='allowFullScreen' value='true' /></object>";
- if ( !empty( $type ) && $type == 'd' )
+
+ if ( !empty( $type ) && $type == 'd' ) {
$player = "<object style='margin: 0px;' width='$w' height='$h'><param name='movie' value='http://static.slidesharecdn.com/swf/ssplayerd.swf?doc=$doc' /><param name='allowFullScreen' value='true' /><param name='wmode' value='opaque' /><embed src='http://static.slidesharecdn.com/swf/ssplayerd.swf?doc=$doc' type='application/x-shockwave-flash' allowfullscreen='true' wmode='opaque' width='$w' height='$h'></embed></object>";
+ }
return $player;
}
diff --git a/plugins/jetpack/modules/shortcodes/slideshow.php b/plugins/jetpack/modules/shortcodes/slideshow.php
index f57802b1..ced00efc 100644
--- a/plugins/jetpack/modules/shortcodes/slideshow.php
+++ b/plugins/jetpack/modules/shortcodes/slideshow.php
@@ -26,6 +26,13 @@ class Jetpack_Slideshow_Shortcode {
if ( $needs_scripts )
add_action( 'wp_enqueue_scripts', array( $this, 'maybe_enqueue_scripts' ), 1 );
+
+ /**
+ * For the moment, comment out the setting for v2.8.
+ * The remainder should work as it always has.
+ * See: https://github.com/Automattic/jetpack/pull/85/files
+ */
+ // add_action( 'admin_init', array( $this, 'register_settings' ), 5 );
}
/**
@@ -59,6 +66,47 @@ class Jetpack_Slideshow_Shortcode {
return $types;
}
+ function register_settings() {
+ add_settings_section( 'slideshow_section', __( 'Image Gallery Slideshow', 'jetpack' ), '__return_empty_string', 'media' );
+
+ add_settings_field( 'jetpack_slideshow_background_color', __( 'Background color', 'jetpack' ), array( $this, 'slideshow_background_color_callback' ), 'media', 'slideshow_section' );
+
+ register_setting( 'media', 'jetpack_slideshow_background_color', array( $this, 'slideshow_background_color_sanitize' ) );
+ }
+
+ function slideshow_background_color_callback() {
+ $options = array(
+ 'black' => __( 'Black', 'jetpack' ),
+ 'white' => __( 'White', 'jetpack' ),
+ );
+ $this->settings_select( 'jetpack_slideshow_background_color', $options );
+ }
+
+ function settings_select( $name, $values, $extra_text = '' ) {
+ if ( empty( $name ) || empty( $values ) || ! is_array( $values ) ) {
+ return;
+ }
+ $option = get_option( $name );
+ ?>
+ <fieldset>
+ <select name="<?php echo esc_attr( $name ); ?>" id="<?php esc_attr( $name ); ?>">
+ <?php foreach ( $values as $key => $value ) : ?>
+ <option value="<?php echo esc_attr( $key ); ?>" <?php selected( $key, $option ); ?>>
+ <?php echo esc_html( $value ); ?>
+ </option>
+ <?php endforeach; ?>
+ </select>
+ <?php if ( ! empty( $extra_text ) ) : ?>
+ <p class="description"><?php echo esc_html( $extra_text ); ?></p>
+ <?php endif; ?>
+ </fieldset>
+ <?php
+ }
+
+ function slideshow_background_color_sanitize( $value ) {
+ return ( 'white' == $value ) ? 'white' : 'black';
+ }
+
function shortcode_callback( $attr, $content = null ) {
global $post, $content_width;
@@ -69,7 +117,7 @@ class Jetpack_Slideshow_Shortcode {
'id' => $post->ID,
'include' => '',
'exclude' => '',
- ), $attr );
+ ), $attr, 'slideshow' );
if ( 'rand' == strtolower( $attr['order'] ) )
$attr['orderby'] = 'none';
@@ -93,7 +141,7 @@ class Jetpack_Slideshow_Shortcode {
'exclude' => $attr['exclude'],
) );
- if ( count( $attachments ) < 2 )
+ if ( count( $attachments ) < 1 )
return;
$gallery_instance = sprintf( "gallery-%d-%d", $attr['id'], ++$this->instance_count );
@@ -102,11 +150,23 @@ class Jetpack_Slideshow_Shortcode {
foreach ( $attachments as $attachment ) {
$attachment_image_src = wp_get_attachment_image_src( $attachment->ID, 'full' );
$attachment_image_src = $attachment_image_src[0]; // [url, width, height]
+ $attachment_image_title = get_the_title( $attachment->ID );
+ $attachment_image_alt = get_post_meta( $attachment->ID, '_wp_attachment_image_alt', true );
+ /**
+ * Filters the Slideshow slide caption.
+ *
+ * @since 2.3.0
+ *
+ * @param string wptexturize( strip_tags( $attachment->post_excerpt ) ) Post excerpt.
+ * @param string $attachment->ID Attachment ID.
+ */
$caption = apply_filters( 'jetpack_slideshow_slide_caption', wptexturize( strip_tags( $attachment->post_excerpt ) ), $attachment->ID );
$gallery[] = (object) array(
'src' => (string) esc_url_raw( $attachment_image_src ),
'id' => (string) $attachment->ID,
+ 'title' => (string) esc_attr( $attachment_image_title ),
+ 'alt' => (string) esc_attr( $attachment_image_alt ),
'caption' => (string) $caption,
);
}
@@ -116,12 +176,15 @@ class Jetpack_Slideshow_Shortcode {
if ( intval( $content_width ) > 0 )
$max_width = min( intval( $content_width ), $max_width );
+ $color = Jetpack_Options::get_option( 'slideshow_background_color', 'black' );
+
$js_attr = array(
'gallery' => $gallery,
'selector' => $gallery_instance,
'width' => $max_width,
'height' => $max_height,
'trans' => $attr['trans'] ? $attr['trans'] : 'fade',
+ 'color' => $color,
);
// Show a link to the gallery in feeds.
@@ -157,8 +220,41 @@ class Jetpack_Slideshow_Shortcode {
$output = '';
+ if ( defined( 'JSON_HEX_AMP' ) ) {
+ // This is nice to have, but not strictly necessary since we use _wp_specialchars() below
+ $gallery = json_encode( $attr['gallery'], JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT );
+ } else {
+ $gallery = json_encode( $attr['gallery'] );
+ }
+
$output .= '<p class="jetpack-slideshow-noscript robots-nocontent">' . esc_html__( 'This slideshow requires JavaScript.', 'jetpack' ) . '</p>';
- $output .= '<div id="' . esc_attr( $attr['selector'] . '-slideshow' ) . '" class="slideshow-window jetpack-slideshow" data-width="' . esc_attr( $attr['width'] ) . '" data-height="' . esc_attr( $attr['height'] ) . '" data-trans="' . esc_attr( $attr['trans'] ) . '" data-gallery="' . esc_attr( json_encode( $attr['gallery'] ) ) . '"></div>';
+ $output .= sprintf( '<div id="%s" class="slideshow-window jetpack-slideshow slideshow-%s" data-width="%s" data-height="%s" data-trans="%s" data-gallery="%s"></div>',
+ esc_attr( $attr['selector'] . '-slideshow' ),
+ esc_attr( $attr['color'] ),
+ esc_attr( $attr['width'] ),
+ esc_attr( $attr['height'] ),
+ esc_attr( $attr['trans'] ),
+ /*
+ * The input to json_encode() above can contain '&quot;'.
+ *
+ * For calls to json_encode() lacking the JSON_HEX_AMP option,
+ * that '&quot;' is left unaltered. Running '&quot;' through esc_attr()
+ * also leaves it unaltered since esc_attr() does not double-encode.
+ *
+ * This means we end up with an attribute like
+ * `data-gallery="{&quot;foo&quot;:&quot;&quot;&quot;}"`,
+ * which is interpreted by the browser as `{"foo":"""}`,
+ * which cannot be JSON decoded.
+ *
+ * The preferred workaround is to include the JSON_HEX_AMP (and friends)
+ * options, but these are not available until 5.3.0.
+ * Alternatively, we can use _wp_specialchars( , , , true ) instead of
+ * esc_attr(), which will double-encode.
+ *
+ * Since we can't rely on JSON_HEX_AMP, we do both.
+ */
+ _wp_specialchars( wp_check_invalid_utf8( $gallery ), ENT_QUOTES, false, true )
+ );
$output .= "
<style>
@@ -192,8 +288,20 @@ class Jetpack_Slideshow_Shortcode {
wp_enqueue_script( 'jquery-cycle', plugins_url( '/js/jquery.cycle.js', __FILE__ ) , array( 'jquery' ), '2.9999.8', true );
wp_enqueue_script( 'jetpack-slideshow', plugins_url( '/js/slideshow-shortcode.js', __FILE__ ), array( 'jquery-cycle' ), '20121214.1', true );
- wp_enqueue_style( 'jetpack-slideshow', plugins_url( '/css/slideshow-shortcode.css', __FILE__ ) );
+ if( is_rtl() ) {
+ wp_enqueue_style( 'jetpack-slideshow', plugins_url( '/css/rtl/slideshow-shortcode-rtl.css', __FILE__ ) );
+ } else {
+ wp_enqueue_style( 'jetpack-slideshow', plugins_url( '/css/slideshow-shortcode.css', __FILE__ ) );
+ }
+ /**
+ * Filters the slideshow Javascript spinner.
+ *
+ * @since 2.1.0
+ *
+ * @param array $args
+ * - string - spinner - URL of the spinner image.
+ */
wp_localize_script( 'jetpack-slideshow', 'jetpackSlideshowSettings', apply_filters( 'jetpack_js_slideshow_settings', array(
'spinner' => plugins_url( '/img/slideshow-loader.gif', __FILE__ ),
) ) );
diff --git a/plugins/jetpack/modules/shortcodes/soundcloud.php b/plugins/jetpack/modules/shortcodes/soundcloud.php
index a7486115..fe98c334 100644
--- a/plugins/jetpack/modules/shortcodes/soundcloud.php
+++ b/plugins/jetpack/modules/shortcodes/soundcloud.php
@@ -23,14 +23,16 @@ so it's eqsy to see what differs from the standard DOTORG version.
All custom modifs are annoted with "A8C" keyword in comment.
*/
-/* Register oEmbed provider
- -------------------------------------------------------------------------- */
+/**
+ * Register oEmbed provider
+ */
wp_oembed_add_provider('#https?://(?:api\.)?soundcloud\.com/.*#i', 'http://soundcloud.com/oembed', true);
-/* Register SoundCloud shortcode
- -------------------------------------------------------------------------- */
+/**
+ * Register SoundCloud shortcode
+ */
add_shortcode("soundcloud", "soundcloud_shortcode");
@@ -42,73 +44,87 @@ add_shortcode("soundcloud", "soundcloud_shortcode");
* @param {string} $content The content between non-self closing [soundcloud]…[/soundcloud] tags.
* @return {string} Widget embed code HTML
*/
-function soundcloud_shortcode($atts, $content = null) {
-
- // Custom shortcode options
- $shortcode_options = array_merge(array('url' => trim($content)), is_array($atts) ? $atts : array());
-
- // Turn shortcode option "param" (param=value&param2=value) into array
- $shortcode_params = array();
- if (isset($shortcode_options['params'])) {
- parse_str(html_entity_decode($shortcode_options['params']), $shortcode_params);
- }
- $shortcode_options['params'] = $shortcode_params;
-
- // User preference options
- $plugin_options = array_filter(array(
- 'iframe' => soundcloud_get_option('player_iframe', true),
- 'width' => soundcloud_get_option('player_width'),
- 'height' => soundcloud_url_has_tracklist($shortcode_options['url']) ? soundcloud_get_option('player_height_multi') : soundcloud_get_option('player_height'),
- 'params' => array_filter(array(
- 'auto_play' => soundcloud_get_option('auto_play'),
- 'show_comments' => soundcloud_get_option('show_comments'),
- 'color' => soundcloud_get_option('color'),
- 'theme_color' => soundcloud_get_option('theme_color'),
- )),
- ));
- // Needs to be an array
- if (!isset($plugin_options['params'])) { $plugin_options['params'] = array(); }
-
- // plugin options < shortcode options
- $options = array_merge(
- $plugin_options,
- $shortcode_options
- );
-
- // plugin params < shortcode params
- $options['params'] = array_merge(
- $plugin_options['params'],
- $shortcode_options['params']
- );
-
- // The "url" option is required
- if (!isset($options['url'])) {
- return '';
- } else {
- $options['url'] = trim($options['url']);
- }
-
- // Both "width" and "height" need to be integers
- if (isset($options['width']) && !preg_match('/^\d+$/', $options['width'])) {
- // set to 0 so oEmbed will use the default 100% and WordPress themes will leave it alone
- $options['width'] = 0;
- }
- if (isset($options['height']) && !preg_match('/^\d+$/', $options['height'])) { unset($options['height']); }
-
- // The "iframe" option must be true to load the iframe widget
- $iframe = soundcloud_booleanize($options['iframe'])
- // Default to flash widget for permalink urls (e.g. http://soundcloud.com/{username})
- // because HTML5 widget doesn’t support those yet
- ? preg_match('/api.soundcloud.com/i', $options['url'])
- : false;
-
- // Return html embed code
- if ($iframe) {
- return soundcloud_iframe_widget($options);
- } else {
- return soundcloud_flash_widget($options);
- }
-
+function soundcloud_shortcode( $atts, $content = null ) {
+
+ // Custom shortcode options
+ $shortcode_options = array_merge( array('url' => trim( $content ) ), is_array( $atts ) ? $atts : array() );
+
+ // Turn shortcode option "param" (param=value&param2=value) into array
+ $shortcode_params = array();
+ if ( isset( $shortcode_options['params'] ) ) {
+ parse_str( html_entity_decode( $shortcode_options['params'] ), $shortcode_params );
+ }
+ $shortcode_options['params'] = $shortcode_params;
+
+ $player_type = soundcloud_get_option( 'player_type', 'visual' );
+ $isIframe = $player_type !== 'flash';
+ $isVisual = !$player_type || $player_type === 'visual';
+
+ // User preference options
+ $plugin_options = array_filter(array(
+ 'iframe' => $isIframe,
+ 'width' => soundcloud_get_option( 'player_width' ),
+ 'height' => soundcloud_url_has_tracklist( $shortcode_options['url'] ) ? soundcloud_get_option( 'player_height_multi' ) : soundcloud_get_option( 'player_height' ),
+ 'params' => array_filter( array(
+ 'auto_play' => soundcloud_get_option( 'auto_play' ),
+ 'show_comments' => soundcloud_get_option( 'show_comments' ),
+ 'color' => soundcloud_get_option( 'color' ),
+ 'visual' => ( $isVisual ? 'true' : 'false' )
+ )),
+ ));
+
+ // Needs to be an array
+ if ( ! isset( $plugin_options['params'] ) ) {
+ $plugin_options['params'] = array();
+ }
+
+ // plugin options < shortcode options
+ $options = array_merge(
+ $plugin_options,
+ $shortcode_options
+ );
+
+ // plugin params < shortcode params
+ $options['params'] = array_merge(
+ $plugin_options['params'],
+ $shortcode_options['params']
+ );
+
+ // The "url" option is required
+ if ( ! isset( $options['url'] ) ) {
+ return '';
+ } else {
+ $options['url'] = trim( $options['url'] );
+ }
+
+ // Both "width" and "height" need to be integers
+ if (isset( $options['width'] ) && ! preg_match( '/^\d+$/', $options['width'] ) ) {
+ // set to 0 so oEmbed will use the default 100% and WordPress themes will leave it alone
+ $options['width'] = 0;
+ }
+ if ( isset( $options['height'] ) && ! preg_match( '/^\d+$/', $options['height'] ) ) {
+ unset( $options['height'] );
+ }
+
+ // The "iframe" option must be true to load the iframe widget
+ $iframe = soundcloud_booleanize( $options['iframe'] );
+
+ // Remove visual parameter from Flash widget, when it's false because that's the default, or when displaying the smallest player
+ if ( $options['params']['visual'] && ( ! $iframe || ! soundcloud_booleanize( $options['params']['visual'] ) || ( isset( $options['height'] ) && '20' == $options['height'] ) ) ) {
+ unset( $options['params']['visual'] );
+ }
+
+ // Merge in "url" value
+ $options['params'] = array_merge( array(
+ 'url' => $options['url']
+ ), $options['params'] );
+
+ // Return html embed code
+ if ( $iframe ) {
+ return soundcloud_iframe_widget( $options );
+ } else {
+ return soundcloud_flash_widget( $options );
+ }
}
/**
@@ -117,9 +133,9 @@ function soundcloud_shortcode($atts, $content = null) {
* @param {mixed} $default Default value
* @return {mixed} Option value
*/
-function soundcloud_get_option($option, $default = false) {
- $value = get_option('soundcloud_' . $option);
- return $value === '' ? $default : $value;
+function soundcloud_get_option( $option, $default = false ) {
+ $value = get_option( 'soundcloud_' . $option );
+ return $value === '' ? $default : $value;
}
/**
@@ -127,8 +143,8 @@ function soundcloud_get_option($option, $default = false) {
* @param {boolean|string} $value
* @return {boolean}
*/
-function soundcloud_booleanize($value) {
- return is_bool($value) ? $value : $value === 'true' ? true : false;
+function soundcloud_booleanize( $value ) {
+ return is_bool( $value ) ? $value : $value === 'true' ? true : false;
}
/**
@@ -136,8 +152,8 @@ function soundcloud_booleanize($value) {
* @param {string} $url
* @return {boolean}
*/
-function soundcloud_url_has_tracklist($url) {
- return preg_match('/^(.+?)\/(sets|groups|playlists)\/(.+?)$/', $url);
+function soundcloud_url_has_tracklist( $url ) {
+ return preg_match( '/^(.+?)\/(sets|groups|playlists)\/(.+?)$/', $url );
}
/**
@@ -145,17 +161,17 @@ function soundcloud_url_has_tracklist($url) {
* @param {array} $match Matched regex
* @return {string} Parameterized url
*/
-function soundcloud_oembed_params_callback($match) {
- global $soundcloud_oembed_params;
+function soundcloud_oembed_params_callback( $match ) {
+ global $soundcloud_oembed_params;
- // Convert URL to array
- $url = parse_url(urldecode($match[1]));
- // Convert URL query to array
- parse_str($url['query'], $query_array);
- // Build new query string
- $query = http_build_query(array_merge($query_array, $soundcloud_oembed_params));
+ // Convert URL to array
+ $url = parse_url( urldecode( $match[1] ) );
+ // Convert URL query to array
+ parse_str( $url['query'], $query_array );
+ // Build new query string
+ $query = http_build_query( array_merge( $query_array, $soundcloud_oembed_params ) );
- return 'src="' . $url['scheme'] . '://' . $url['host'] . $url['path'] . '?' . $query;
+ return 'src="' . $url['scheme'] . '://' . $url['host'] . $url['path'] . '?' . $query;
}
/**
@@ -163,21 +179,18 @@ function soundcloud_oembed_params_callback($match) {
* @param {array} $options Parameters
* @return {string} Iframe embed code
*/
-function soundcloud_iframe_widget($options) {
-
- // Merge in "url" value
- $options['params'] = array_merge(array(
- 'url' => $options['url']
- ), $options['params']);
-
- // Build URL
- $url = 'http://w.soundcloud.com/player?' . http_build_query($options['params']);
- // Set default width if not defined
- $width = isset($options['width']) && $options['width'] !== 0 ? $options['width'] : '100%';
- // Set default height if not defined
- $height = isset($options['height']) && $options['height'] !== 0 ? $options['height'] : (soundcloud_url_has_tracklist($options['url']) ? '450' : '166');
-
- return sprintf('<iframe width="%s" height="%s" scrolling="no" frameborder="no" src="%s"></iframe>', $width, $height, $url);
+function soundcloud_iframe_widget( $options ) {
+
+ // Build URL
+ $url = set_url_scheme( 'https://w.soundcloud.com/player/?' . http_build_query( $options['params'] ) );
+ // Set default width if not defined
+ $width = isset($options['width']) && $options['width'] !== 0 ? $options['width'] : '100%';
+ // Set default height if not defined
+ $height = isset($options['height']) && $options['height'] !== 0
+ ? $options['height']
+ : ( soundcloud_url_has_tracklist( $options['url']) || ( isset( $options['params']['visual'] ) && soundcloud_booleanize( $options['params']['visual'] ) ) ? '450' : '166');
+
+ return sprintf( '<iframe width="%s" height="%s" scrolling="no" frameborder="no" src="%s"></iframe>', $width, $height, $url );
}
/**
@@ -185,30 +198,64 @@ function soundcloud_iframe_widget($options) {
* @param {array} $options Parameters
* @return {string} Flash embed code
*/
-function soundcloud_flash_widget($options) {
-
- // Merge in "url" value
- $options['params'] = array_merge(array(
- 'url' => $options['url']
- ), $options['params']);
-
- // Build URL
- $url = 'http://player.soundcloud.com/player.swf?' . http_build_query($options['params']);
- // Set default width if not defined
- $width = isset($options['width']) && $options['width'] !== 0 ? $options['width'] : '100%';
- // Set default height if not defined
- $height = isset($options['height']) && $options['height'] !== 0 ? $options['height'] : (soundcloud_url_has_tracklist($options['url']) ? '255' : '81');
-
- return preg_replace('/\s\s+/', "", sprintf('<object width="%s" height="%s">
- <param name="movie" value="%s"></param>
- <param name="allowscriptaccess" value="always"></param>
- <embed width="%s" height="%s" src="%s" allowscriptaccess="always" type="application/x-shockwave-flash"></embed>
- </object>', $width, $height, $url, $width, $height, $url));
+function soundcloud_flash_widget( $options ) {
+
+ // Build URL
+ $url = set_url_scheme( 'https://player.soundcloud.com/player.swf?' . http_build_query($options['params']) );
+ // Set default width if not defined
+ $width = isset( $options['width'] ) && $options['width'] !== 0 ? $options['width'] : '100%';
+ // Set default height if not defined
+ $height = isset( $options['height'] ) && $options['height'] !== 0 ? $options['height'] : ( soundcloud_url_has_tracklist( $options['url'] ) ? '255' : '81');
+
+ return preg_replace( '/\s\s+/', "", sprintf( '<object width="%s" height="%s">
+ <param name="movie" value="%s"></param>
+ <param name="allowscriptaccess" value="always"></param>
+ <embed width="%s" height="%s" src="%s" allowscriptaccess="always" type="application/x-shockwave-flash"></embed>
+ </object>', $width, $height, $url, $width, $height, $url ) );
}
+/**
+ * SoundCloud Embed Reversal
+ *
+ * Converts a generic HTML embed code from SoundClound into a
+ * WordPress.com-compatibly shortcode.
+ */
+function jetpack_soundcloud_embed_reversal( $content ) {
+ if ( false === stripos( $content, 'w.soundcloud.com/player' ) )
+ return $content;
+
+ /* Sample embed code:
+
+ <iframe width="100%" height="450" scrolling="no" frameborder="no" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/150745932&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;visual=true"></iframe>
+ */
+
+ $regexes = array();
+
+ $regexes[] = '#<iframe[^>]+?src="((?:https?:)?//w\.soundcloud\.com/player/[^"\']++)"[^>]*+>\s*?</iframe>#i';
+ $regexes[] = '#&lt;iframe(?:[^&]|&(?!gt;))+?src="((?:https?:)?//w\.soundcloud\.com/player/[^"\']++)"(?:[^&]|&(?!gt;))*+&gt;\s*?&lt;/iframe&gt;#i';
+
+ foreach ( $regexes as $regex ) {
+ if ( ! preg_match_all( $regex, $content, $matches, PREG_SET_ORDER ) )
+ continue;
+
+ foreach ( $matches as $match ) {
+ $args = parse_url( html_entity_decode( $match[1] ), PHP_URL_QUERY );
+ $args = wp_parse_args( $args );
+
+ if ( ! preg_match( '#^(?:https?:)?//api\.soundcloud\.com/.+$#i', $args['url'], $url_matches ) )
+ continue;
+
+ $shortcode = sprintf( '[soundcloud url="%s"]', esc_url( $url_matches[0] ) );
+ $replace_regex = sprintf( '#\s*%s\s*#', preg_quote( $match[0], '#' ) );
+ $content = preg_replace( $replace_regex, sprintf( "\n\n%s\n\n", $shortcode ), $content );
+ /** This action is documented in modules/shortcodes/youtube.php */
+ do_action( 'jetpack_embed_to_shortcode', 'soundcloud', $url_matches[0] );
+ }
+ }
+
+ return $content;
+}
-/* Settings
- -------------------------------------------------------------------------- */
-/* A8C: no user-defined options, KISS */
+add_filter( 'pre_kses', 'jetpack_soundcloud_embed_reversal' );
diff --git a/plugins/jetpack/modules/shortcodes/ted.php b/plugins/jetpack/modules/shortcodes/ted.php
index 4edc2882..f49184ef 100644
--- a/plugins/jetpack/modules/shortcodes/ted.php
+++ b/plugins/jetpack/modules/shortcodes/ted.php
@@ -5,8 +5,8 @@
*
* http://www.ted.com/talks/view/id/210
* http://www.ted.com/talks/marc_goodman_a_vision_of_crimes_in_the_future.html
- * [ted id="210" lang="eng"]
- * [ted id="http://www.ted.com/talks/view/id/210" lang="eng"]
+ * [ted id="210" lang="en"]
+ * [ted id="http://www.ted.com/talks/view/id/210" lang="en"]
* [ted id=1539 lang=fr width=560 height=315]
*/
@@ -25,9 +25,9 @@ function shortcode_ted( $atts, $content = '' ) {
'id' => '',
'width' => '',
'height' => '',
- 'lang' => 'eng',
+ 'lang' => 'en',
);
- $atts = shortcode_atts( $defaults, $atts );
+ $atts = shortcode_atts( $defaults, $atts, 'ted' );
if ( empty( $atts['id'] ) )
return '<!-- Missing TED ID -->';
diff --git a/plugins/jetpack/modules/shortcodes/twitter-timeline.php b/plugins/jetpack/modules/shortcodes/twitter-timeline.php
index 8931592b..4f12d067 100644
--- a/plugins/jetpack/modules/shortcodes/twitter-timeline.php
+++ b/plugins/jetpack/modules/shortcodes/twitter-timeline.php
@@ -11,7 +11,7 @@ function twitter_timeline_shortcode( $attr ) {
);
- $attr = shortcode_atts( $default_atts, $attr );
+ $attr = shortcode_atts( $default_atts, $attr, 'twitter-timeline' );
if ( $attr['username'] != preg_replace( '/[^A-Za-z0-9_]+/', '', $attr['username'] ) )
return '<!--' . __( 'Invalid username', 'jetpack' ) . '-->';
@@ -20,7 +20,7 @@ function twitter_timeline_shortcode( $attr ) {
return '<!--' . __( 'Invalid id', 'jetpack' ) . '-->';
$tweets_by = sprintf( __( 'Tweets by @%s', 'jetpack' ), $attr['username'] );
- $output = '<a class="twitter-timeline" width="' . (int)$attr['width'] . '" height="' . (int)$attr['width'] . '" href="' . esc_url( 'https://twitter.com/'. $attr['username'] ) . '" data-widget-id="' . (int)$attr['id'] . '">' . esc_html( $tweets_by ) . '</a>';
+ $output = '<a class="twitter-timeline" width="' . (int)$attr['width'] . '" height="' . (int)$attr['height'] . '" href="' . esc_url( 'https://twitter.com/'. $attr['username'] ) . '" data-widget-id="' . esc_attr( $attr['id'] ) . '">' . esc_html( $tweets_by ) . '</a>';
add_action( 'wp_footer', 'twitter_timeline_js' );
return $output;
diff --git a/plugins/jetpack/modules/shortcodes/vimeo.php b/plugins/jetpack/modules/shortcodes/vimeo.php
index 188c8e2f..f8637704 100644
--- a/plugins/jetpack/modules/shortcodes/vimeo.php
+++ b/plugins/jetpack/modules/shortcodes/vimeo.php
@@ -12,6 +12,7 @@
function jetpack_shortcode_get_vimeo_id( $atts ) {
if ( isset( $atts[0] ) ) {
$atts[0] = trim( $atts[0] , '=' );
+ $id = false;
if ( is_numeric( $atts[0] ) )
$id = (int) $atts[0];
elseif ( preg_match( '|vimeo\.com/(\d+)/?$|i', $atts[0], $match ) )
@@ -33,13 +34,16 @@ function vimeo_shortcode( $atts ) {
global $content_width;
extract( array_map( 'intval', shortcode_atts( array(
- 'id' => 0,
- 'width' => 400,
- 'height' => 300
- ), $atts ) ) );
+ 'id' => 0,
+ 'width' => 400,
+ 'height' => 300,
+ 'autoplay' => 0,
+ 'loop' => 0,
+ ), $atts, 'vimeo' ) ) );
- if ( isset( $atts[0] ) )
+ if ( isset( $atts[0] ) ) {
$id = jetpack_shortcode_get_vimeo_id( $atts );
+ }
if ( ! $id ) return "<!-- vimeo error: not a vimeo video -->";
@@ -66,14 +70,56 @@ function vimeo_shortcode( $atts ) {
}
}
- if ( ! $width )
+ if ( ! $width ) {
$width = absint( $content_width );
+ }
- if ( ! $height )
+ if ( ! $height ) {
$height = round( ( $width / 640 ) * 360 );
+ }
+
+ /**
+ * Filter the Vimeo player width.
+ *
+ * @since 3.4.0
+ *
+ * @param int $width Width of the Vimeo player in pixels.
+ */
+ $width = (int) apply_filters( 'vimeo_width', $width );
+
+ /**
+ * Filter the Vimeo player height.
+ *
+ * @since 3.4.0
+ *
+ * @param int $height Height of the Vimeo player in pixels.
+ */
+ $height = (int) apply_filters( 'vimeo_height', $height );
+
+ $url = esc_url( set_url_scheme( "http://player.vimeo.com/video/$id" ) );
+
+ // $args['autoplay'] is parsed from the embedded url.
+ // $autoplay is parsed from shortcode arguments.
+ // in_array( 'autoplay', $atts ) catches the argument passed without a value.
+ if ( ! empty( $args['autoplay'] ) || ! empty( $autoplay ) || in_array( 'autoplay', $atts ) ) {
+ $url = add_query_arg( 'autoplay', 1, $url );
+ }
+
+ if ( ! empty( $args['loop'] ) || ! empty( $loop ) || in_array( 'loop', $atts ) ) {
+ $url = add_query_arg( 'loop', 1, $url );
+ }
- $html = "<div class='embed-vimeo' style='text-align:center;'><iframe src='http://player.vimeo.com/video/$id' width='$width' height='$height' frameborder='0'></iframe></div>";
+ $html = sprintf( '<div class="embed-vimeo" style="text-align:center;"><iframe src="%1$s" width="%2$u" height="%3$u" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>', esc_url( $url ), $width, $height );
+
+ /**
+ * Filter the Vimeo player HTML.
+ *
+ * @since 1.2.3
+ *
+ * @param string $html Embedded Vimeo player HTML.
+ */
$html = apply_filters( 'video_embed_html', $html );
+
return $html;
}
@@ -83,7 +129,7 @@ function vimeo_embed_to_shortcode( $content ) {
if ( false === stripos( $content, 'player.vimeo.com/video/' ) )
return $content;
- $regexp = '!<iframe\s+src=[\'"]http://player\.vimeo\.com/video/(\d+)[\'"]((?:\s+\w+=[\'"][^\'"]*[\'"])*)></iframe>!i';
+ $regexp = '!<iframe\s+src=[\'"](https?:)?//player\.vimeo\.com/video/(\d+)[\w=&;?]*[\'"]((?:\s+\w+=[\'"][^\'"]*[\'"])*)((?:[\s\w]*))></iframe>!i';
$regexp_ent = str_replace( '&amp;#0*58;', '&amp;#0*58;|&#0*58;', htmlspecialchars( $regexp, ENT_NOQUOTES ) );
foreach ( array( 'regexp', 'regexp_ent' ) as $reg ) {
@@ -91,9 +137,9 @@ function vimeo_embed_to_shortcode( $content ) {
continue;
foreach ( $matches as $match ) {
- $id = (int) $match[1];
+ $id = (int) $match[2];
- $params = $match[2];
+ $params = $match[3];
if ( 'regexp_ent' == $reg )
$params = html_entity_decode( $params );
diff --git a/plugins/jetpack/modules/shortcodes/vine.php b/plugins/jetpack/modules/shortcodes/vine.php
index 184d005e..0c233c0f 100644
--- a/plugins/jetpack/modules/shortcodes/vine.php
+++ b/plugins/jetpack/modules/shortcodes/vine.php
@@ -40,7 +40,7 @@ function vine_embed_video( $matches, $attr, $url, $rawattr ) {
}
$url = 'https://vine.co/v/' . $matches[1] . '/embed/' . $type;
- $vine_html = sprintf( '<iframe class="vine-embed" src="%s" width="%s" height="%s" frameborder="0"></iframe>', esc_url( $url ), (int) $vine_size, (int) $vine_size );
+ $vine_html = sprintf( '<span class="embed-vine" style="display: block;"><iframe class="vine-embed" src="%s" width="%s" height="%s" frameborder="0"></iframe></span>', esc_url( $url ), (int) $vine_size, (int) $vine_size );
if ( $vine_flag_embedded_script !== true ) {
$vine_html .= '<script async src="//platform.vine.co/static/scripts/embed.js" charset="utf-8"></script>';
diff --git a/plugins/jetpack/modules/shortcodes/youtube.php b/plugins/jetpack/modules/shortcodes/youtube.php
index df50af14..0eeed506 100644
--- a/plugins/jetpack/modules/shortcodes/youtube.php
+++ b/plugins/jetpack/modules/shortcodes/youtube.php
@@ -38,14 +38,9 @@ function youtube_embed_to_short_code( $content ) {
$old_regexp_ent = str_replace( '&amp;#0*58;', '&amp;#0*58;|&#0*58;', htmlspecialchars( $old_regexp, ENT_NOQUOTES ) );
//new code
- $ifr_regexp = '!<iframe((?:\s+\w+="[^"]*")*?)\s+src="https?://(?:www\.)*youtube.com/embed/([^"]+)".*?</iframe>!i';
+ $ifr_regexp = '!<iframe((?:\s+\w+="[^"]*")*?)\s+src="(https?:)?//(?:www\.)*youtube.com/embed/([^"]+)".*?</iframe>!i';
$ifr_regexp_ent = str_replace( '&amp;#0*58;', '&amp;#0*58;|&#0*58;', htmlspecialchars( $ifr_regexp, ENT_NOQUOTES ) );
- if ( is_ssl() )
- $protocol = 'https';
- else
- $protocol = 'http';
-
foreach ( array( 'regexp', 'regexp_ent', 'old_regexp', 'old_regexp_ent', 'ifr_regexp', 'ifr_regexp_ent' ) as $reg ) {
if ( ! preg_match_all( $$reg, $content, $matches, PREG_SET_ORDER ) )
continue;
@@ -74,15 +69,23 @@ function youtube_embed_to_short_code( $content ) {
if ( $width && $height )
$wh = "&w=$width&h=$height";
- $url = esc_url_raw( "$protocol://www.youtube.com/watch?v={$match[2]}{$wh}" );
+ $url = esc_url_raw( set_url_scheme( "http://www.youtube.com/watch?v={$match[3]}{$wh}" ) );
} else {
$match[1] = str_replace( '?', '&', $match[1] );
- $url = esc_url_raw( "$protocol://www.youtube.com/watch?v=" . html_entity_decode( $match[1] ) );
+ $url = esc_url_raw( set_url_scheme( "http://www.youtube.com/watch?v=" . html_entity_decode( $match[1] ) ) );
}
$content = str_replace( $match[0], "[youtube $url]", $content );
+ /**
+ * Fires before the YouTube embed is transformed into a shortcode.
+ *
+ * @since 1.2.0
+ *
+ * @param string youtube Shortcode name.
+ * @param string $url YouTube video URL.
+ */
do_action( 'jetpack_embed_to_shortcode', 'youtube', $url );
}
}
@@ -90,7 +93,7 @@ function youtube_embed_to_short_code( $content ) {
return $content;
}
-add_filter('pre_kses', 'youtube_embed_to_short_code');
+add_filter( 'pre_kses', 'youtube_embed_to_short_code' );
/**
* Replaces plain-text links to YouTube videos with YouTube embeds.
@@ -116,6 +119,7 @@ function youtube_link_callback( $matches ) {
* @param string $url
* @return string The normalized URL
*/
+if ( ! function_exists( 'youtube_sanitize_url' ) ) :
function youtube_sanitize_url( $url ) {
$url = trim( $url, ' "' );
$url = trim( $url );
@@ -130,6 +134,7 @@ function youtube_sanitize_url( $url ) {
return $url;
}
+endif;
/*
* url can be:
@@ -143,51 +148,10 @@ function youtube_sanitize_url( $url ) {
*/
/**
- * Same as get_youtube_id(), but with the prefix that function should've had.
- */
-function jetpack_shortcode_get_youtube_id( $url ) {
- return get_youtube_id( $url );
-}
-
-/**
- * @param $url Can be just the $url or the whole $atts array
- * @return bool|mixed The Youtube video ID
- */
-function get_youtube_id( $url ) {
-
- // Do we have an $atts array? Get first att
- if ( is_array( $url ) )
- $url = $url[0];
-
- $url = youtube_sanitize_url( $url );
- $url = parse_url( $url );
- $id = false;
-
- if ( ! isset( $url['query'] ) )
- return false;
-
- parse_str( $url['query'], $qargs );
-
- if ( ! isset( $qargs['v'] ) && ! isset( $qargs['list'] ) )
- return false;
-
- if ( isset( $qargs['list'] ) )
- $id = preg_replace( '|[^_a-z0-9-]|i', '', $qargs['list'] );
-
- if ( empty( $id ) )
- $id = preg_replace( '|[^_a-z0-9-]|i', '', $qargs['v'] );
-
- return $id;
-}
-
-/**
* Converts a YouTube URL into an embedded YouTube video.
*/
function youtube_id( $url ) {
- if ( apply_filters( 'jetpack_bail_on_shortcode', false, 'youtube' ) )
- return '';
-
- if ( ! $id = get_youtube_id( $url ) )
+ if ( ! $id = jetpack_get_youtube_id( $url ) )
return '<!--YouTube Error: bad URL entered-->';
$url = youtube_sanitize_url( $url );
@@ -196,7 +160,14 @@ function youtube_id( $url ) {
if ( ! isset( $url['query'] ) )
return false;
- parse_str( $url['query'], $qargs );
+ if ( isset( $url['fragment'] ) ) {
+ wp_parse_str( $url['fragment'], $fargs );
+ } else {
+ $fargs = array();
+ }
+ wp_parse_str( $url['query'], $qargs );
+
+ $qargs = array_merge( $fargs, $qargs );
// calculate the width and height, taking content_width into consideration
global $content_width;
@@ -236,7 +207,22 @@ function youtube_id( $url ) {
}
}
+ /**
+ * Filter the YouTube player width.
+ *
+ * @since 1.1
+ *
+ * @param int $w Width of the YouTube player in pixels.
+ */
$w = (int) apply_filters( 'youtube_width', $w );
+
+ /**
+ * Filter the YouTube player height.
+ *
+ * @since 1.1
+ *
+ * @param int $h Height of the YouTube player in pixels.
+ */
$h = (int) apply_filters( 'youtube_height', $h );
$rel = ( isset( $qargs['rel'] ) && 0 == $qargs['rel'] ) ? 0 : 1;
@@ -245,13 +231,50 @@ function youtube_id( $url ) {
$iv = ( isset( $qargs['iv_load_policy'] ) && 3 == $qargs['iv_load_policy'] ) ? 3 : 1;
$fmt = ( isset( $qargs['fmt'] ) && intval( $qargs['fmt'] ) ) ? '&fmt=' . (int) $qargs['fmt'] : '';
- $start = ( isset( $qargs['start'] ) && intval( $qargs['start'] ) ) ? '&start=' . (int) $qargs['start'] : '';
- $end = ( isset( $qargs['end'] ) && intval( $qargs['end'] ) ) ? '&end=' . (int) $qargs['end'] : '';
+
+ $start = 0;
+ if ( isset( $qargs['start'] ) ) {
+ $start = intval( $qargs['start'] );
+ } else if ( isset( $qargs['t'] ) ) {
+ $time_pieces = preg_split( '/(?<=\D)(?=\d+)/', $qargs['t'] );
+
+ foreach ( $time_pieces as $time_piece ) {
+ $int = (int) $time_piece;
+ switch ( substr( $time_piece, -1 ) ) {
+ case 'h' :
+ $start += $int * 3600;
+ break;
+ case 'm' :
+ $start += $int * 60;
+ break;
+ case 's' :
+ $start += $int;
+ break;
+ }
+ }
+ }
+
+ $start = $start ? '&start=' . $start : '';
+ $end = ( isset( $qargs['end'] ) && intval( $qargs['end'] ) ) ? '&end=' . (int) $qargs['end'] : '';
$hd = ( isset( $qargs['hd'] ) && intval( $qargs['hd'] ) ) ? '&hd=' . (int) $qargs['hd'] : '';
+ $vq = ( isset( $qargs['vq'] ) && in_array( $qargs['vq'], array('hd720','hd1080') ) ) ? '&vq=' . $qargs['vq'] : '';
+
+ $cc = ( isset( $qargs['cc_load_policy'] ) ) ? '&cc_load_policy=1' : '';
+ $cc_lang = ( isset( $qargs['cc_lang_pref'] ) ) ? '&cc_lang_pref=' . preg_replace( '/[^_a-z0-9-]/i', '', $qargs['cc_lang_pref'] ) : '';
+
$wmode = ( isset( $qargs['wmode'] ) && in_array( strtolower( $qargs['wmode'] ), array( 'opaque', 'window', 'transparent' ) ) ) ? $qargs['wmode'] : 'transparent';
+ $theme = ( isset( $qargs['theme'] ) && in_array( strtolower( $qargs['theme'] ), array( 'dark', 'light' ) ) ) ? '&theme=' . $qargs['theme'] : '';
+
$autoplay = '';
+ /**
+ * Allow YouTube videos to start playing automatically.
+ *
+ * @since 2.2.2
+ *
+ * @param bool false Enable autoplay for YouTube videos.
+ */
if ( apply_filters( 'jetpack_youtube_allow_autoplay', false ) && isset( $qargs['autoplay'] ) )
$autoplay = '&autoplay=' . (int)$qargs['autoplay'];
@@ -267,17 +290,19 @@ function youtube_id( $url ) {
}
}
- if ( is_ssl() )
- $protocol = 'https';
- else
- $protocol = 'http';
-
if ( ( isset( $url['path'] ) && '/videoseries' == $url['path'] ) || isset( $qargs['list'] ) ) {
- $html = "<span class='embed-youtube' style='$alignmentcss display: block;'><iframe class='youtube-player' type='text/html' width='$w' height='$h' src='" . esc_url( "$protocol://www.youtube.com/embed/videoseries?list=$id&hl=en_US" ) . "' frameborder='0'></iframe></span>";
+ $html = "<span class='embed-youtube' style='$alignmentcss display: block;'><iframe class='youtube-player' type='text/html' width='$w' height='$h' src='" . esc_url( set_url_scheme( "http://www.youtube.com/embed/videoseries?list=$id&hl=en_US" ) ) . "' frameborder='0' allowfullscreen='true'></iframe></span>";
} else {
- $html = "<span class='embed-youtube' style='$alignmentcss display: block;'><iframe class='youtube-player' type='text/html' width='$w' height='$h' src='" . esc_url( "$protocol://www.youtube.com/embed/$id?version=3&rel=$rel&fs=1$fmt&showsearch=$search&showinfo=$info&iv_load_policy=$iv$start$end$hd&wmode=$wmode$autoplay" ) . "' frameborder='0'></iframe></span>";
+ $html = "<span class='embed-youtube' style='$alignmentcss display: block;'><iframe class='youtube-player' type='text/html' width='$w' height='$h' src='" . esc_url( set_url_scheme( "http://www.youtube.com/embed/$id?version=3&rel=$rel&fs=1$fmt&showsearch=$search&showinfo=$info&iv_load_policy=$iv$start$end$hd&wmode=$wmode$theme$autoplay{$cc}{$cc_lang}" ) ) . "' frameborder='0' allowfullscreen='true'></iframe></span>";
}
+ /**
+ * Filter the YouTube video HTML output.
+ *
+ * @since 1.2.3
+ *
+ * @param string $html YouTube video HTML output.
+ */
$html = apply_filters( 'video_embed_html', $html );
return $html;
@@ -303,7 +328,17 @@ function wpcom_youtube_embed_crazy_url_init() {
add_action( 'init', 'wpcom_youtube_embed_crazy_url_init' );
-// higher priority because we need it before auto-link and autop get to it
-if ( get_option('embed_autourls') ) {
- add_filter( 'comment_text', 'youtube_link', 1 );
+/**
+ * Allow oEmbeds in Jetpack's Comment form.
+ *
+ * @since 2.8
+ *
+ * @param int get_option('embed_autourls') Option to automatically embed all plain text URLs.
+ */
+if ( apply_filters( 'jetpack_comments_allow_oembed', get_option('embed_autourls') ) ) {
+ // We attach wp_kses_post to comment_text in default-filters.php with priority of 10 anyway, so the iframe gets filtered out.
+ if ( ! is_admin() ) {
+ // Higher priority because we need it before auto-link and autop get to it
+ add_filter( 'comment_text', 'youtube_link', 1 );
+ }
}
diff --git a/plugins/jetpack/modules/shortlinks.php b/plugins/jetpack/modules/shortlinks.php
index e530941f..98c4856f 100644
--- a/plugins/jetpack/modules/shortlinks.php
+++ b/plugins/jetpack/modules/shortlinks.php
@@ -1,11 +1,12 @@
<?php
/**
* Module Name: WP.me Shortlinks
- * Module Description: Enable WP.me-powered shortlinks for all of your Posts and Pages for easier sharing.
- * Sort Order: 10
+ * Module Description: Enable WP.me-powered shortlinks for all posts and pages.
+ * Sort Order: 8
* First Introduced: 1.1
* Requires Connection: Yes
* Auto Activate: Yes
+ * Module Tags: Social
*/
add_filter( 'get_shortlink', 'wpme_get_shortlink_handler', 1, 4 );
@@ -49,7 +50,9 @@ function wpme_get_shortlink( $id = 0, $context = 'post', $allow_slugs = true ) {
if ( 'blog' == $context ) {
if ( empty( $id ) )
$id = $blog_id;
- return 'http://wp.me/' . wpme_dec2sixtwo( $id );
+
+ $wpme_url = 'http://wp.me/' . wpme_dec2sixtwo( $id );
+ return set_url_scheme( $wpme_url );
}
$post = get_post( $id );
@@ -68,8 +71,8 @@ function wpme_get_shortlink( $id = 0, $context = 'post', $allow_slugs = true ) {
$id = wpme_dec2sixtwo( $post_id );
if ( 'page' == $post->post_type )
$type = 'P';
- elseif ( 'post' == $post->post_type )
- $type = 'p';
+ elseif ( 'post' == $post->post_type || post_type_supports( $post->post_type, 'shortlinks' ) )
+ $type= 'p';
elseif ( 'attachment' == $post->post_type )
$type = 'a';
}
@@ -77,7 +80,8 @@ function wpme_get_shortlink( $id = 0, $context = 'post', $allow_slugs = true ) {
if ( empty( $type ) )
return '';
- return 'http://wp.me/' . $type . wpme_dec2sixtwo( $blog_id ) . '-' . $id;
+ $url = 'http://wp.me/' . $type . wpme_dec2sixtwo( $blog_id ) . '-' . $id;
+ return set_url_scheme( $url );
}
function wpme_get_shortlink_handler( $shortlink, $id, $context, $allow_slugs ) {
diff --git a/plugins/jetpack/modules/site-icon.php b/plugins/jetpack/modules/site-icon.php
new file mode 100644
index 00000000..37f0ba2f
--- /dev/null
+++ b/plugins/jetpack/modules/site-icon.php
@@ -0,0 +1,16 @@
+<?php
+
+/**
+ * Module Name: Site Icon
+ * Module Description: Add a site icon to your site.
+ * Sort Order: 22
+ * First Introduced: 3.2
+ * Requires Connection: No
+ * Auto Activate: No
+ * Module Tags: Other
+ */
+
+include dirname( __FILE__ ) . '/site-icon/jetpack-site-icon.php';
+include dirname( __FILE__ ) . '/site-icon/site-icon-functions.php';
+
+Jetpack_Sync::sync_options( __FILE__, 'jetpack_site_icon_url' ); \ No newline at end of file
diff --git a/plugins/jetpack/modules/site-icon/browser.png b/plugins/jetpack/modules/site-icon/browser.png
new file mode 100644
index 00000000..6bcb07ac
--- /dev/null
+++ b/plugins/jetpack/modules/site-icon/browser.png
Binary files differ
diff --git a/plugins/jetpack/modules/site-icon/css/site-icon-admin.css b/plugins/jetpack/modules/site-icon/css/site-icon-admin.css
new file mode 100644
index 00000000..7480873d
--- /dev/null
+++ b/plugins/jetpack/modules/site-icon/css/site-icon-admin.css
@@ -0,0 +1,57 @@
+/**
+ * Blavatar Module for Jetpack
+ */
+
+.site-icon-image {
+ margin: 0 20px 0 0;
+ float: left;
+}
+.site-icon-content {
+ padding: 10px;
+ position: relative;
+ overflow: hidden;
+}
+.site-icon-crop-shell {
+ max-width: 720px;
+}
+.site-icon-crop-preview-shell {
+ float: right;
+ width: 172px;
+ overflow: hidden;
+}
+.site-icon-crop-preview-shell h3 {
+ margin-top: 0;
+}
+.site-icon-crop-favicon-preview-shell {
+ position: relative;
+ margin-bottom: 20px;
+}
+.site-icon-crop-preview-favicon {
+ width:16px;
+ height:16px;
+ overflow:hidden;
+ position: absolute;
+ top:23px;
+ left:102px;
+}
+.site-icon-browser-title {
+ position: absolute;
+ top:23px;
+ left:128px;
+ width:100px;
+ overflow: hidden;
+ height:16px;
+}
+.site-icon-crop-preview-homeicon {
+ width:64px;
+ height:64px;
+ overflow:hidden;
+ border-radius: 16px;
+}
+.site-icon-title .small {
+ color:#999;
+ font-size: 16px;
+}
+.wp-core-ui .site-icon-submit-form .button {
+ vertical-align: middle;
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/site-icon/jetpack-site-icon.php b/plugins/jetpack/modules/site-icon/jetpack-site-icon.php
new file mode 100644
index 00000000..26fec236
--- /dev/null
+++ b/plugins/jetpack/modules/site-icon/jetpack-site-icon.php
@@ -0,0 +1,813 @@
+<?php
+
+/*
+Plugin Name: Site Icon
+Plugin URL: http://wordpress.com/
+Description: Add a site icon for your website.
+Version: 0.1
+Author: Automattic
+
+Released under the GPL v.2 license.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+*/
+
+class Jetpack_Site_Icon {
+
+ public $module = 'site-icon';
+ public static $version = 1;
+ public static $assets_version = 2;
+
+ public static $min_size = 512; // the minimum size of the blavatar, 512 is the same as wp.com can be overwritten by SITE_ICON_MIN_SIZE
+ public static $page_crop = 512; // the size to which to crop the image so that we can display it in the UI nicely
+
+ public static $accepted_file_types = array(
+ 'image/jpg',
+ 'image/jpeg',
+ 'image/gif',
+ 'image/png'
+ );
+
+ public static $site_icon_sizes = array(
+ 256,
+ 128,
+ 80,
+ 64,
+ 32,
+ 16,
+ );
+
+ static $instance = false;
+
+ /**
+ * Singleton
+ */
+ public static function init() {
+ if ( ! self::$instance ){
+ self::$instance = new Jetpack_Site_Icon;
+ self::$instance->register_hooks();
+ }
+
+ return self::$instance;
+ }
+
+ private function __construct() {
+ self::$min_size = ( defined( 'SITE_ICON_MIN_SIZE' ) && is_int( SITE_ICON_MIN_SIZE ) ) ? SITE_ICON_MIN_SIZE : self::$min_size;
+ }
+
+ /**
+ * Register our actions and filters
+ * @return null
+ */
+ public function register_hooks(){
+ add_action( 'jetpack_modules_loaded', array( $this, 'jetpack_modules_loaded' ) );
+ add_action( 'admin_menu', array( $this, 'admin_menu_upload_site_icon' ) );
+ add_filter( 'display_media_states', array( $this, 'add_media_state' ) );
+ add_action( 'admin_init', array( $this, 'admin_init' ) );
+ add_action( 'admin_init', array( $this, 'delete_site_icon_hook' ) );
+ add_action( 'atom_head', array( $this, 'atom_icon' ) );
+ add_action( 'rss2_head', array( $this, 'rss2_icon' ) );
+
+ add_action( 'admin_print_styles-options-general.php', array( $this, 'add_general_options_styles' ) );
+
+ // Add the favicon to the front end and backend
+ add_action( 'wp_head', array( $this, 'site_icon_add_meta' ) );
+ add_action( 'admin_head', array( $this, 'site_icon_add_meta' ) );
+
+ add_action( 'delete_option', array( 'Jetpack_Site_Icon', 'delete_temp_data' ), 10, 1); // used to clean up after itself.
+ add_action( 'delete_attachment', array( 'Jetpack_Site_Icon', 'delete_attachment_data' ), 10, 1); // in case user deletes the attachment via
+ add_filter( 'get_post_metadata', array( 'Jetpack_Site_Icon', 'delete_attachment_images' ), 10, 4 );
+ }
+
+ /**
+ * After all modules have been loaded.
+ */
+ public function jetpack_modules_loaded() {
+ Jetpack::enable_module_configurable( $this->module );
+ Jetpack::module_configuration_load( $this->module, array( $this, 'jetpack_configuration_load' ) );
+ }
+
+ /**
+ * Add meta elements to a blog header to light up Blavatar icons recognized by user agents.
+ * @link http://www.whatwg.org/specs/web-apps/current-work/multipage/links.html#rel-icon HTML5 specification link icon
+ *
+ */
+ public function site_icon_add_meta() {
+ /**
+ * Toggles the Favicon meta elements from being loaded.
+ *
+ * @since 3.2.0
+ *
+ * @param bool Output Site Icon Meta Elements.
+ */
+ if ( apply_filters( 'site_icon_has_favicon', false ) ) {
+ return;
+ }
+
+ $url_114 = jetpack_site_icon_url( null, 114 );
+ $url_72 = jetpack_site_icon_url( null, 72 );
+ $url_32 = jetpack_site_icon_url( null, 32 );
+ if( $url_32 ) {
+ echo '<link rel="icon" href="'.esc_url( $url_32 ) .'" sizes="32x32" />' . "\n";
+ echo '<link rel="apple-touch-icon-precomposed" href="'. esc_url( $url_114 ) .'">' . "\n";
+ // windows tiles
+ echo '<meta name="msapplication-TileImage" content="' . esc_url( $url_114 ) . '"/>' . "\n";
+ }
+
+ }
+ /**
+ * Display icons in RSS2.
+ */
+ public function rss2_icon() {
+ /** This filter is documented in modules/site-icon/jetpack-site-icon.php */
+ if ( apply_filters( 'site_icon_has_favicon', false ) ) {
+ return;
+ }
+
+ $rss_title = get_wp_title_rss();
+ if ( empty( $rss_title ) ) {
+ $rss_title = get_bloginfo_rss( 'name' );
+ }
+
+ $icon = jetpack_site_icon_url( null, 32 );
+ if( $icon ) {
+ echo '
+ <image>
+ <url>' . convert_chars( $icon ) . '</url>
+ <title>' . $rss_title . '</title>
+ <link>' . get_bloginfo_rss( 'url' ) . '</link>
+ <width>32</width>
+ <height>32</height>
+ </image> '."\n";
+ }
+ }
+
+ /**
+ * Display icons in atom feeds.
+ *
+ */
+ public function atom_icon() {
+ /** This filter is documented in modules/site-icon/jetpack-site-icon.php */
+ if ( apply_filters( 'site_icon_has_favicon', false ) ) {
+ return;
+ }
+
+ $url = jetpack_site_icon_url( null, 32 );
+ if( $url ) {
+ echo '
+ <icon>' . $url . '</icon> '."\n";
+ }
+ }
+
+ /**
+ * Add a hidden upload page from people
+ */
+ public function admin_menu_upload_site_icon() {
+ $page_hook = add_submenu_page(
+ null,
+ __( 'Site Icon Upload', 'jetpack' ),
+ '',
+ 'manage_options',
+ 'jetpack-site_icon-upload',
+ array( $this, 'upload_site_icon_page' )
+ );
+
+ add_action( "admin_head-$page_hook", array( $this, 'upload_balavatar_head' ) );
+ }
+
+
+ /**
+ * Add styles to the General Settings Screen
+ */
+ public function add_general_options_styles() {
+ wp_enqueue_style( 'site-icon-admin' );
+ }
+ /**
+ * Add Styles to the Upload UI Page
+ *
+ */
+ public function upload_balavatar_head() {
+
+ wp_register_script( 'site-icon-crop', plugin_dir_url( __FILE__ ). "js/site-icon-crop.js" , array( 'jquery', 'jcrop' ) , self::$assets_version, false);
+ if ( isset( $_REQUEST['step'] ) && $_REQUEST['step'] == 2 ) {
+ wp_enqueue_script( 'site-icon-crop' );
+ wp_enqueue_style( 'jcrop' );
+ }
+ wp_enqueue_style( 'site-icon-admin' );
+ }
+
+ public function add_media_state( $media_states ) {
+
+ if ( jetpack_has_site_icon() ) {
+ global $post;
+
+ if( $post->ID == Jetpack_Options::get_option( 'site_icon_id' ) ) {
+ $media_states[] = __( 'Site Icon', 'jetpack' );
+ }
+
+ }
+ return $media_states;
+ }
+
+ /**
+ * Direct the user to the Settings -> General
+ */
+ public static function jetpack_configuration_load() {
+ wp_safe_redirect( admin_url( 'options-general.php#site-icon' ) );
+ exit;
+ }
+
+ /**
+ * Load on when the admin is initialized
+ */
+ public function admin_init() {
+ /* register the styles and scripts */
+ wp_register_style( 'site-icon-admin' , plugin_dir_url( __FILE__ ). "css/site-icon-admin.css", array(), self::$assets_version );
+ // register the settings
+ add_settings_section(
+ $this->module,
+ '',
+ array( $this, 'site_icon_settings' ),
+ 'general'
+ );
+
+ // We didn't have site_icon_url in 3.2 // this could potentially be removed in a year
+ if( get_option( 'site_icon_id' ) && ! Jetpack_Options::get_option( 'site_icon_url' ) ) {
+ Jetpack_Options::update_option( 'site_icon_id', get_option( 'site_icon_id' ) );
+ Jetpack_Options::update_option( 'site_icon_url', jetpack_site_icon_url( get_current_blog_id(), 512 ) );
+ delete_option( 'site_icon_id' );
+ }
+ }
+
+ /**
+ * Checks for permission to delete the site_icon
+ */
+ public function delete_site_icon_hook() {
+ // Delete the site_icon
+ if ( isset( $GLOBALS['plugin_page'] ) && 'jetpack-site_icon-upload' == $GLOBALS['plugin_page'] ) {
+ if ( isset( $_GET['action'] )
+ && 'remove' == $_GET['action']
+ && isset( $_GET['nonce'] )
+ && wp_verify_nonce( $_GET['nonce'], 'remove_site_icon' ) ) {
+
+ $site_icon_id = Jetpack_Options::get_option( 'site_icon_id' );
+ // Delete the previous Blavatar
+ self::delete_site_icon( $site_icon_id, true );
+ wp_safe_redirect( admin_url( 'options-general.php#site-icon' ) );
+ }
+ }
+ }
+
+ /**
+ * Add HTML to the General Settings
+ */
+ public function site_icon_settings() {
+ $upload_blavatar_url = admin_url( 'options-general.php?page=jetpack-site_icon-upload' );
+
+ // lets delete the temp data that we might he holding on to
+ self::delete_temporay_data();
+
+ ?>
+ <div id="site-icon" class="site-icon-shell">
+ <h3><?php echo esc_html_e( 'Site Icon', 'jetpack' ); ?></h3>
+ <div class="site-icon-content postbox">
+ <div class="site-icon-image">
+ <?php if( jetpack_has_site_icon() ) {
+ echo jetpack_get_site_icon( null, 128 );
+ } ?>
+ </div>
+ <div class="site-icon-meta">
+
+ <?php if ( jetpack_has_site_icon() ) {
+ $remove_blavatar_url = admin_url( 'options-general.php?page=jetpack-site_icon-upload' )."&action=remove&nonce=".wp_create_nonce( 'remove_site_icon' ); // this could be an ajax url
+ ?>
+ <p><a href="<?php echo esc_url( $upload_blavatar_url ); ?>" id="site-icon-update" class="button"><?php echo esc_html_e( 'Update Site Icon', 'jetpack' ); ?></a>
+ <a href="<?php echo esc_url( $remove_blavatar_url ); ?>" id="site-icon-remove" ><?php echo esc_html_e( 'Remove Icon', 'jetpack' ); ?></a> </p>
+
+ <?php } else { ?>
+
+ <a href="<?php echo esc_url( $upload_blavatar_url ); ?>" id="site-icon-update" class="button"><?php echo esc_html_e( 'Add a Site Icon', 'jetpack' ); ?></a>
+
+ <?php } ?>
+
+ <div class="site-icon-info">
+ <p><?php echo esc_html_e( 'Site Icon creates a favicon for your site and more.', 'jetpack' ); ?></p>
+ </div>
+
+ </div>
+ </div>
+ </div>
+ <?php
+ }
+
+ /**
+ * Hidden Upload Blavatar page for people that don't like modals
+ */
+ public function upload_site_icon_page() { ?>
+ <div class="wrap">
+ <?php require_once( dirname( __FILE__ ) . '/upload-site-icon.php' ); ?>
+ </div>
+ <?php
+ }
+
+ /**
+ * Select a file admin view
+ */
+ public static function select_page() {
+ // Display the site_icon form to upload the image
+ ?>
+ <form action="<?php echo esc_url( admin_url( 'options-general.php?page=jetpack-site_icon-upload' ) ); ?>" method="post" enctype="multipart/form-data">
+
+ <h2 class="site-icon-title">
+ <?php if( jetpack_has_site_icon() ) {
+ esc_html_e( 'Update Site Icon', 'jetpack' );
+ } else {
+ esc_html_e( 'Add Site Icon', 'jetpack' );
+ } ?> <span class="small"><?php esc_html_e( 'select a file', 'jetpack' ); ?></span></h2>
+ <p><?php esc_html_e( 'Upload a image that you want to use as your site icon. You will be asked to crop it in the next step.', 'jetpack' ); ?></p>
+
+
+ <p><input name="site-iconfile" id="site-iconfile" type="file" /></p>
+ <p><?php esc_html_e( 'The image needs to be at least', 'jetpack' ); ?> <strong><?php echo self::$min_size; ?>px</strong> <?php esc_html_e( 'in both width and height.', 'jetpack' ); ?></p>
+ <p class="submit site-icon-submit-form">
+ <input name="submit" value="<?php esc_attr_e( 'Upload Image' , 'jetpack' ); ?>" type="submit" class="button button-primary button-large" /><?php printf( __( ' or <a href="%s">Cancel</a> and go back to the settings.' , 'jetpack' ), esc_url( admin_url( 'options-general.php' ) ) ); ?>
+ <input name="step" value="2" type="hidden" />
+
+ <?php wp_nonce_field( 'update-site_icon-2', '_nonce' ); ?>
+ </p>
+ </form>
+ <?php
+ }
+
+ /**
+ * Crop a the image admin view
+ */
+ public static function crop_page() {
+ // handle the uploaded image
+ $image = self::handle_file_upload( $_FILES['site-iconfile'] );
+
+ // display the image image croppping funcunality
+ if( is_wp_error( $image ) ) { ?>
+ <div id="message" class="updated error below-h2"><p><?php echo esc_html( $image->get_error_message() ); ?></p></div>
+ <?php
+ // back to step one
+ $_POST = array();
+ self::delete_temporay_data();
+ self::select_page();
+ return;
+ }
+
+ $crop_data = get_option( 'site_icon_temp_data' );
+ $crop_ration = $crop_data['large_image_data'][0] / $crop_data['resized_image_data'][0]; // always bigger then 1
+
+ // lets make sure that the Javascript ia also loaded
+ wp_localize_script( 'site-icon-crop', 'Site_Icon_Crop_Data', self::initial_crop_data( $crop_data['large_image_data'][0] , $crop_data['large_image_data'][1], $crop_data['resized_image_data'][0], $crop_data['resized_image_data'][1] ) );
+ ?>
+
+ <h2 class="site-icon-title"><?php esc_html_e( 'Site Icon', 'jetpack' ); ?> <span class="small"><?php esc_html_e( 'crop the image', 'jetpack' ); ?></span></h2>
+ <div class="site-icon-crop-shell">
+ <form action="" method="post" enctype="multipart/form-data">
+ <p class="site-icon-submit-form"><input name="submit" value="<?php esc_attr_e( 'Crop Image', 'jetpack' ); ?>" type="submit" class="button button-primary button-large" /><?php printf( __( ' or <a href="%s">Cancel</a> and go back to the settings.' , 'jetpack' ), esc_url( admin_url( 'options-general.php' ) ) ); ?></p>
+ <div class="site-icon-crop-preview-shell">
+
+ <h3><?php esc_html_e( 'Preview', 'jetpack' ); ?></h3>
+
+ <strong><?php esc_html_e( 'As your favicon', 'jetpack' ); ?></strong>
+ <div class="site-icon-crop-favicon-preview-shell">
+ <img src="<?php echo esc_url( plugin_dir_url( __FILE__ ). "browser.png" ); ?>" class="site-icon-browser-preview" width="172" height="79" alt="<?php esc_attr_e( 'Browser Chrome' , 'jetpack' ); ?>" />
+ <div class="site-icon-crop-preview-favicon">
+ <img src="<?php echo esc_url( $image[0] ); ?>" id="preview-favicon" alt="<?php esc_attr_e( 'Preview Favicon' , 'jetpack' ); ?>" />
+ </div>
+ <span class="site-icon-browser-title"><?php echo esc_html( get_bloginfo( 'name' ) ); ?></span>
+ </div>
+
+ <strong><?php esc_html_e( 'As a mobile icon', 'jetpack' ); ?></strong>
+ <div class="site-icon-crop-preview-homeicon">
+ <img src="<?php echo esc_url( $image[0] ); ?>" id="preview-homeicon" alt="<?php esc_attr_e( 'Preview Home Icon' , 'jetpack' ); ?>" />
+ </div>
+ </div>
+ <img src="<?php echo esc_url( $image[0] ); ?>" id="crop-image" class="site-icon-crop-image"
+ width="<?php echo esc_attr( $crop_data['resized_image_data'][0] ); ?>"
+ height="<?php echo esc_attr( $crop_data['resized_image_data'][1] ); ?>"
+ alt="<?php esc_attr_e( 'Image to be cropped', 'jetpack' ); ?>" />
+
+ <input name="step" value="3" type="hidden" />
+ <input type="hidden" id="crop-x" name="crop-x" />
+ <input type="hidden" id="crop-y" name="crop-y" />
+ <input type="hidden" id="crop-width" name="crop-w" />
+ <input type="hidden" id="crop-height" name="crop-h" />
+
+ <?php wp_nonce_field( 'update-site_icon-3', '_nonce' ); ?>
+
+ </form>
+ </div>
+ <?php
+ }
+ /**
+ * All done page admin view
+ *
+ */
+ public static function all_done_page() {
+
+ $temp_image_data = get_option( 'site_icon_temp_data' );
+ if( ! $temp_image_data ) {
+ // start again
+ self::select_page();
+ return;
+ }
+ $crop_ration = $temp_image_data['large_image_data'][0] / $temp_image_data['resized_image_data'][0]; // always bigger then 1
+
+ $crop_data = self::convert_coodiantes_from_resized_to_full( $_POST['crop-x'], $_POST['crop-y'], $_POST['crop-w'], $_POST['crop-h'], $crop_ration );
+
+ $image_edit = wp_get_image_editor( _load_image_to_edit_path( $temp_image_data['large_image_attachment_id'] ) );
+
+ if ( is_wp_error( $image_edit ) ) {
+ return $image_edit;
+ }
+
+ // Delete the previous site_icon
+ $previous_site_icon_id = Jetpack_Options::get_option( 'site_icon_id' );
+ self::delete_site_icon( $previous_site_icon_id );
+
+ // crop the image
+ $image_edit->crop( $crop_data['crop_x'], $crop_data['crop_y'],$crop_data['crop_width'], $crop_data['crop_height'], self::$min_size, self::$min_size );
+
+ $dir = wp_upload_dir();
+
+ $site_icon_filename = $image_edit->generate_filename( dechex ( time() ) . 'v' . self::$version . '_site_icon', null, 'png' );
+
+ // If the attachment is a URL, then change it to a local file name to allow us to save and then upload the cropped image
+ $check_url = parse_url( $site_icon_filename );
+ if ( isset( $check_url['host'] ) ) {
+ $upload_dir = wp_upload_dir();
+ $site_icon_filename = $upload_dir['path'] . '/' . basename( $site_icon_filename );
+ }
+
+ $image_edit->save( $site_icon_filename );
+
+ add_filter( 'intermediate_image_sizes_advanced', array( 'Jetpack_Site_Icon', 'additional_sizes' ) );
+
+ $site_icon_id = self::save_attachment(
+ __( 'Large Blog Image', 'jetpack' ) ,
+ $site_icon_filename,
+ 'image/png'
+ );
+
+ remove_filter( 'intermediate_image_sizes_advanced', array( 'Jetpack_Site_Icon', 'additional_sizes' ) );
+
+ // Save the site_icon data into option
+ Jetpack_Options::update_option( 'site_icon_id', $site_icon_id );
+
+ //Get the site icon URL ready to sync
+ Jetpack_Options::update_option( 'site_icon_url', jetpack_site_icon_url( get_current_blog_id(), 512 ) );
+
+ ?>
+ <h2 class="site-icon-title"><?php esc_html_e( 'Site Icon', 'jetpack' ); ?> <span class="small"><?php esc_html_e( 'All Done', 'jetpack' ); ?></span></h2>
+ <div id="message" class="updated below-h2"><p><?php esc_html_e( 'Your site icon has been uploaded!', 'jetpack' ); ?> <a href="<?php echo esc_url( admin_url( 'options-general.php' ) ); ?>" ><?php esc_html_e( 'Back to General Settings' , 'jetpack' ); ?></a></p></div>
+ <?php echo jetpack_get_site_icon( null, $size = '128' ); ?>
+ <?php echo jetpack_get_site_icon( null, $size = '48' ); ?>
+ <?php echo jetpack_get_site_icon( null, $size = '16' ); ?>
+
+ <?php
+ }
+
+ /**
+ * This function is used to pass data to the localize script
+ * so that we can center the cropper and also set the minimum
+ * cropper if we still want to show the
+ *
+ * @param int $large_width
+ * @param int $large_height
+ * @param int $resized_width
+ * @param int $resized_height
+ * @return array
+ */
+ public static function initial_crop_data( $large_width, $large_height, $resized_width, $resized_height ) {
+ $init_x = 0;
+ $init_y = 0;
+
+ $ration = $large_width / $resized_width;
+ $min_crop_size = ( self::$min_size / $ration );
+
+ // Landscape format ( width > height )
+ if( $resized_width > $resized_height ) {
+ $init_x = ( self::$page_crop - $resized_height ) / 2;
+ $init_size = $resized_height;
+ }
+
+ // Portrait format ( height > width )
+ if( $resized_width < $resized_height ) {
+ $init_y = ( self::$page_crop - $resized_width ) / 2;
+ $init_size = $resized_height;
+ }
+
+ // Square height == width
+ if( $resized_width = $resized_height ) {
+ $init_size = $resized_height;
+ }
+
+ return array(
+ 'init_x' => $init_x,
+ 'init_y' => $init_y,
+ 'init_size' => $init_size,
+ 'min_size' => $min_crop_size
+ );
+ }
+
+ /**
+ * Delete the temporary created data and attachments
+ *
+ * @return null
+ */
+ public static function delete_temporay_data() {
+ // This should autimatically delete the temporary files as well
+ delete_option( 'site_icon_temp_data' );
+ }
+
+ /**
+ * Function gets fired when delete_option( 'site_icon_temp_data' ) is run.
+ *
+ * @param $option string
+ * @return null
+ */
+ public static function delete_temp_data( $option ) {
+ if( 'site_icon_temp_data' == $option ) {
+ $temp_image_data = get_option( 'site_icon_temp_data' );
+
+ remove_action( 'delete_attachment', array( 'Jetpack_Site_Icon', 'delete_attachment_data' ), 10, 1);
+
+ wp_delete_attachment( $temp_image_data['large_image_attachment_id'] , true );
+ wp_delete_attachment( $temp_image_data['resized_image_attacment_id'] , true );
+ }
+ return null;
+ }
+
+ /**
+ * @param $post_id
+ */
+ public static function delete_attachment_data( $post_id ) {
+ // The user could be deleting the site_icon image
+ $site_icon_id = Jetpack_Options::get_option( 'site_icon_id' );
+ if( $site_icon_id && $post_id == $site_icon_id ) {
+ Jetpack_Options::delete_option( 'site_icon_id' );
+ Jetpack_Options::delete_option( 'site_icon_url' );
+ }
+ // The user could be deleting the temporary images
+ }
+
+ /**
+ * @param $check
+ * @param $post_id
+ * @param $meta_key
+ * @param $single
+ *
+ * @return mixed
+ */
+ public static function delete_attachment_images( $check, $post_id, $meta_key, $single ) {
+ $site_icon_id = Jetpack_Options::get_option( 'site_icon_id' );
+ if( $post_id == $site_icon_id && '_wp_attachment_backup_sizes' == $meta_key && true == $single )
+ add_filter( 'intermediate_image_sizes', array( 'Jetpack_Site_Icon', 'intermediate_image_sizes' ) );
+ return $check;
+ }
+
+ /**
+ * Delete the blavatar and all the attached data
+ *
+ * @param $id
+ *
+ * @return mixed
+ */
+ public static function delete_site_icon( $id ) {
+ // We add the filter to make sure that we also delete all the added images
+ add_filter( 'intermediate_image_sizes', array( 'Jetpack_Site_Icon', 'intermediate_image_sizes' ) );
+ wp_delete_attachment( $id , true );
+ remove_filter( 'intermediate_image_sizes', array( 'Jetpack_Site_Icon', 'intermediate_image_sizes' ) );
+ // for good measure also
+ self::delete_temporay_data();
+
+ // Delete the URL from the Jetpack Options array
+ Jetpack_Options::delete_option( 'site_icon_url' );
+
+ return Jetpack_Options::delete_option( 'site_icon_id' );
+ }
+
+ /**
+ * @param $crop_x
+ * @param $crop_y
+ * @param $crop_width
+ * @param $crop_height
+ * @param $ratio
+ *
+ * @return array
+ */
+ public static function convert_coodiantes_from_resized_to_full( $crop_x, $crop_y, $crop_width, $crop_height, $ratio ) {
+ return array(
+ 'crop_x' => floor( $crop_x * $ratio ),
+ 'crop_y' => floor( $crop_y * $ratio ),
+ 'crop_width' => floor( $crop_width * $ratio ),
+ 'crop_height' => floor( $crop_height * $ratio ),
+ );
+ }
+
+ /**
+ * Handle the uploaded image
+ *
+ * @param $uploaded_file
+ *
+ * @return mixed
+ */
+ public static function handle_file_upload( $uploaded_file ) {
+
+ // check that the image accuallt is a file with size
+ if( !isset( $uploaded_file ) || ($uploaded_file['size'] <= 0 ) ) {
+ return new WP_Error( 'broke', __( 'Please upload a file.', 'jetpack' ) );
+ }
+
+ $arr_file_type = wp_check_filetype( basename( $uploaded_file['name'] ) );
+ $uploaded_file_type = $arr_file_type['type'];
+ if( ! in_array( $uploaded_file_type, self::$accepted_file_types ) ) {
+ // Create a temp file which should be deleted at when the scipt stops
+ return new WP_Error( 'broke', __( 'The file that you uploaded is not an accepted file type. Please try again.', 'jetpack' ) );
+ }
+
+ $image = wp_handle_upload( $uploaded_file, array( 'test_form' => false ) );
+
+ if( is_wp_error( $image ) ) {
+ // this should contain the error message returned from wp_handle_upload
+ unlink( $image['file'] ); // Lets delete the file since we are not going to be using it
+ return $image;
+ }
+
+ // Lets try to crop the image into smaller files.
+ // We will be doing this later so it is better if it fails now.
+ $image_edit = wp_get_image_editor( $image['file'] );
+ if ( is_wp_error( $image_edit ) ) {
+ // this should contain the error message from WP_Image_Editor
+ unlink( $image['file'] ); // lets delete the file since we are not going to be using it
+ return $image_edit;
+ }
+
+ $image_size = getimagesize( $image['file'] );
+
+ if( $image_size[0] < self::$min_size || $image_size[1] < self::$min_size ) {
+
+ if( $image_size[0] < self::$min_size ) {
+ return new WP_Error( 'broke', sprintf( __( 'The image that you uploaded is smaller than %upx in width.', 'jetpack' ), self::$min_size ) );
+ }
+
+ if( $image_size[1] < self::$min_size ) {
+ return new WP_Error( 'broke', sprintf( __( 'The image that you uploaded is smaller than %upx in height.', 'jetpack' ), self::$min_size ) );
+ }
+ }
+
+ // Save the image as an attachment for later use.
+ $large_attachment_id = self::save_attachment(
+ __( 'Temporary Large Image for Blog Image', 'jetpack' ) ,
+ $image['file'],
+ $uploaded_file_type,
+ false
+ );
+
+ // Let's resize the image so that the user can easier crop a image that in the admin view
+ $image_edit->resize( self::$page_crop, self::$page_crop, false );
+ $dir = wp_upload_dir();
+
+ $resized_filename = $image_edit->generate_filename( 'temp', null, null );
+ $image_edit->save( $resized_filename );
+
+ $resized_attach_id = self::save_attachment(
+ __( 'Temporary Resized Image for Blog Image', 'jetpack' ),
+ $resized_filename,
+ $uploaded_file_type,
+ false
+ );
+
+ $resized_image_size = getimagesize( $resized_filename );
+ // Save all of this into the the database for that we can work with it later.
+ update_option( 'site_icon_temp_data', array(
+ 'large_image_attachment_id' => $large_attachment_id,
+ 'large_image_data' => $image_size,
+ 'resized_image_attacment_id' => $resized_attach_id,
+ 'resized_image_data' => $resized_image_size
+ ) );
+
+ return wp_get_attachment_image_src( $resized_attach_id, 'full' );
+ }
+
+ /**
+ * Save Blavatar files to Media Library
+ *
+ * @param string $title
+ * @param string $filename
+ * @param string $file_type
+ * @param boolean $generate_meta
+ * @return int $attactment_id
+ */
+ public static function save_attachment( $title, $file, $file_type, $generate_meta = true ) {
+
+ $filename = _wp_relative_upload_path( $file );
+
+ $wp_upload_dir = wp_upload_dir();
+ $attachment = array(
+ 'guid' => $wp_upload_dir['url'] . '/' . basename( $filename ),
+ 'post_mime_type' => $file_type,
+ 'post_title' => $title,
+ 'post_content' => '',
+ 'post_status' => 'inherit'
+ );
+ $attachment_id = wp_insert_attachment( $attachment, $filename );
+
+ if( ! function_exists( 'wp_generate_attachment_metadata' ) ) {
+ // Make sure that this file is included, as wp_generate_attachment_metadata() depends on it.
+ require_once( ABSPATH . 'wp-admin/includes/image.php' );
+ }
+ if( !$generate_meta )
+ add_filter( 'intermediate_image_sizes_advanced', array( 'Jetpack_Site_Icon', 'only_thumbnail_size' ) );
+
+ // Generate the metadata for the attachment, and update the database record.
+ $attach_data = wp_generate_attachment_metadata( $attachment_id, $file );
+ wp_update_attachment_metadata( $attachment_id, $attach_data );
+
+ if( !$generate_meta ) {
+ remove_filter( 'intermediate_image_sizes_advanced', array( 'Jetpack_Site_Icon', 'only_thumbnail_size' ) );
+ }
+
+ return $attachment_id;
+ }
+
+ /**
+ * Add additional sizes to be made when creating the site_icon images
+ *
+ * @param array $sizes
+ * @return array
+ */
+ public static function additional_sizes( $sizes ) {
+ /**
+ * Filter the different dimensions that a site icon is saved in.
+ *
+ * @since 3.2.0
+ *
+ * @param array $site_icon_sizes Sizes available for the Site Icon. Default is array(256, 128, 80, 64, 32, 16).
+ */
+ self::$site_icon_sizes = apply_filters( 'site_icon_image_sizes', self::$site_icon_sizes );
+ // use a natural sort of numbers
+ natsort( self::$site_icon_sizes );
+ self::$site_icon_sizes = array_reverse ( self::$site_icon_sizes );
+
+ // ensure that we only resize the image into
+ foreach( $sizes as $name => $size_array ) {
+ if( $size_array['crop'] ){
+ $only_crop_sizes[ $name ] = $size_array;
+ }
+ }
+
+ foreach( self::$site_icon_sizes as $size ) {
+ if( $size < self::$min_size ) {
+
+ $only_crop_sizes['site_icon-'.$size] = array(
+ "width" => $size,
+ "height"=> $size,
+ "crop" => true,
+ );
+ }
+ }
+
+ return $only_crop_sizes;
+ }
+
+ /**
+ * Helps us delete site_icon images that
+ *
+ * @param [type] $sizes [description]
+ *
+ * @return array
+ */
+ public static function intermediate_image_sizes( $sizes ) {
+ /** This filter is documented in modules/site-icon/jetpack-site-icon.php */
+ self::$site_icon_sizes = apply_filters( 'site_icon_image_sizes', self::$site_icon_sizes );
+ foreach( self::$site_icon_sizes as $size ) {
+ $sizes[] = 'site_icon-'.$size;
+ }
+ return $sizes;
+ }
+ /**
+ * Only resize the image to thumbnail so we can use
+ * Use when resizing temporary images. This way we can see the temp image in Media Gallery.
+ *
+ * @param array $sizes
+ * @return array
+ */
+ public static function only_thumbnail_size( $sizes ){
+ foreach( $sizes as $name => $size_array ) {
+ if( 'thumbnail' == $name ) {
+ $only_thumb['thumbnail'] = $size_array;
+ }
+ }
+ return $only_thumb;
+ }
+}
+
+Jetpack_Site_Icon::init();
diff --git a/plugins/jetpack/modules/custom-post-types/testimonials.php b/plugins/jetpack/modules/site-icon/js/site-icon-admin.js
index e69de29b..e69de29b 100644
--- a/plugins/jetpack/modules/custom-post-types/testimonials.php
+++ b/plugins/jetpack/modules/site-icon/js/site-icon-admin.js
diff --git a/plugins/jetpack/modules/site-icon/js/site-icon-crop.js b/plugins/jetpack/modules/site-icon/js/site-icon-crop.js
new file mode 100644
index 00000000..989b1e1f
--- /dev/null
+++ b/plugins/jetpack/modules/site-icon/js/site-icon-crop.js
@@ -0,0 +1,55 @@
+/* global Site_Icon_Crop_Data, jQuery */
+(function($) {
+ var jcrop_api, Site_Icon_Crop;
+ jcrop_api = {};
+ Site_Icon_Crop = {
+
+ updateCoords : function ( coords ) {
+
+ $('#crop-x').val( coords.x );
+ $('#crop-y').val( coords.y );
+ $('#crop-width').val( coords.w );
+ $('#crop-height').val( coords.h );
+
+ Site_Icon_Crop.showPreview( coords );
+ },
+
+ showPreview : function( coords ){
+ var rx, ry, crop_image, home_icon, preview_rx, preview_ry, favicon;
+ rx = 64 / coords.w;
+ ry = 64 / coords.h;
+ crop_image = $('#crop-image');
+ home_icon = $('#preview-homeicon');
+ home_icon.css({
+ width: Math.round(rx * crop_image.attr( 'width' ) ) + 'px',
+ height: Math.round(ry * crop_image.attr( 'height' ) ) + 'px',
+ marginLeft: '-' + Math.round(rx * coords.x) + 'px',
+ marginTop: '-' + Math.round(ry * coords.y) + 'px'
+ });
+ preview_rx = 16 / coords.w;
+ preview_ry = 16 / coords.h;
+ favicon = $('#preview-favicon');
+ favicon.css({
+ width: Math.round( preview_rx * crop_image.attr( 'width' ) ) + 'px',
+ height: Math.round( preview_ry * crop_image.attr( 'height' ) ) + 'px',
+ marginLeft: '-' + Math.round( preview_rx * coords.x ) + 'px',
+ marginTop: '-' + Math.floor( preview_ry* coords.y ) + 'px'
+ });
+ },
+
+ ready: function() {
+ jcrop_api = $.Jcrop('#crop-image');
+ jcrop_api.setOptions({
+ aspectRatio: 1,
+ onSelect: Site_Icon_Crop.updateCoords,
+ onChange: Site_Icon_Crop.updateCoords,
+ minSize: [ Site_Icon_Crop_Data.min_size, Site_Icon_Crop_Data.min_size ]
+ });
+ jcrop_api.animateTo([Site_Icon_Crop_Data.init_x, Site_Icon_Crop_Data.init_y, Site_Icon_Crop_Data.init_size, Site_Icon_Crop_Data.init_size]);
+ }
+
+ };
+
+ Site_Icon_Crop.ready();
+
+})(jQuery); \ No newline at end of file
diff --git a/plugins/jetpack/modules/site-icon/site-icon-functions.php b/plugins/jetpack/modules/site-icon/site-icon-functions.php
new file mode 100644
index 00000000..e20e2f86
--- /dev/null
+++ b/plugins/jetpack/modules/site-icon/site-icon-functions.php
@@ -0,0 +1,73 @@
+<?php
+
+
+if( ! function_exists( 'jetpack_has_site_icon' ) ) :
+function jetpack_has_site_icon( $blog_id = null ) {
+
+ if( ! is_int( $blog_id ) )
+ $blog_id = get_current_blog_id();
+
+ if( jetpack_site_icon_url( $blog_id, 512, '' ) ) {
+ return true;
+ }
+
+ return false;
+}
+endif;
+
+if( ! function_exists( 'jetpack_get_site_icon' ) ) :
+function jetpack_get_site_icon( $blog_id = null, $size = '512', $default = '', $alt = false ) {
+
+ if( ! is_int( $blog_id ) )
+ $blog_id = get_current_blog_id();
+
+ $size = esc_attr( $size );
+ $class = "avatar avatar-$size";
+ $alt = ( $alt ? esc_attr( $alt ) : __( 'Site Icon', 'jetpack' ) );
+ $src = esc_url( jetpack_site_icon_url( $blog_id, $size, $default ) );
+ $avatar = "<img alt='{$alt}' src='{$src}' class='$class' height='{$size}' width='{$size}' />";
+ /**
+ * Filters the display options for the Site Icon.
+ *
+ * @since 3.2.0
+ *
+ * @param string $avatar The Site Icon in an html image tag.
+ * @param int $blog_id The local site Blog ID.
+ * @param string $size The size of the Site Icon, default is 512.
+ * @param string $default The default URL for the Site Icon.
+ * @param string $alt The alt tag for the avatar.
+ */
+ return apply_filters( 'jetpack-get_site_icon', $avatar, $blog_id, $size, $default, $alt );
+}
+endif;
+
+if( ! function_exists( 'jetpack_site_icon_url' ) ) :
+function jetpack_site_icon_url( $blog_id = null, $size = '512', $default = false ) {
+ $url = '';
+ if( ! is_int( $blog_id ) )
+ $blog_id = get_current_blog_id();
+
+ if( function_exists( 'get_blog_option' ) ) {
+ $site_icon_id = get_blog_option( $blog_id, 'jetpack_site_icon_id' );
+ } else {
+ $site_icon_id = Jetpack_Options::get_option( 'site_icon_id' );
+ }
+
+ if( ! $site_icon_id ) {
+ if( $default === false && defined( 'SITE_ICON_DEFAULT_URL' ) )
+ $url = SITE_ICON_DEFAULT_URL;
+ else
+ $url = $default;
+ } else {
+ if( $size >= 512 ) {
+ $size_data = 'full';
+ } else {
+ $size_data = array( $size, $size );
+ }
+ $url_data = wp_get_attachment_image_src( $site_icon_id, $size_data );
+ $url = $url_data[0];
+ }
+
+ return $url;
+}
+endif;
diff --git a/plugins/jetpack/modules/site-icon/upload-site-icon.php b/plugins/jetpack/modules/site-icon/upload-site-icon.php
new file mode 100644
index 00000000..4d889309
--- /dev/null
+++ b/plugins/jetpack/modules/site-icon/upload-site-icon.php
@@ -0,0 +1,31 @@
+<?php
+
+
+/**
+ * Uploading a site_icon is a 3 step process
+ *
+ * 1. Select the file to upload
+ * 2. Crop the file
+ * 3. Confirmation page
+ */
+$step = ( isset( $_REQUEST['step'] ) ? $_REQUEST['step'] : 1 );
+$nonce = ( isset( $_REQUEST[ '_nonce' ] ) ? $_REQUEST[ '_nonce' ] : false );
+
+if( ! wp_verify_nonce( $nonce , 'update-site_icon-' . $step ) && $step > 1 ) {
+
+ echo esc_html__( 'You are not suppoed to be here!', 'jetpack' );
+ return;
+}
+switch( $step ){
+ case '1':
+ Jetpack_Site_Icon::select_page();
+ break;
+
+ case '2':
+ Jetpack_Site_Icon::crop_page();
+ break;
+
+ case '3':
+ Jetpack_Site_Icon::all_done_page();
+ break;
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/social-links.php b/plugins/jetpack/modules/social-links.php
index f87b9f82..88c13090 100644
--- a/plugins/jetpack/modules/social-links.php
+++ b/plugins/jetpack/modules/social-links.php
@@ -1,10 +1,6 @@
<?php
/**
- * Themes must declare that they support this module by adding
- * add_theme_support( 'social-links' ); on 'after_setup_theme'.
+ * Deprecated. No longer needed.
+ *
+ * @package Jetpack
*/
-function jetpack_load_additional_modules() {
- if ( current_theme_supports( 'social-links' ) )
- require_once 'social-links/social-links.php';
-}
-add_action( 'init', 'jetpack_load_additional_modules' );
diff --git a/plugins/jetpack/modules/sso.php b/plugins/jetpack/modules/sso.php
new file mode 100644
index 00000000..25203512
--- /dev/null
+++ b/plugins/jetpack/modules/sso.php
@@ -0,0 +1,978 @@
+<?php
+
+/**
+ * Module Name: Jetpack Single Sign On
+ * Module Description: Allow your users to log in using their WordPress.com accounts.
+ * Jumpstart Description: lets you login to all your Jetpack-enabled sites with one click using your WordPress.com account.
+ * Sort Order: 30
+ * Recommendation Order: 5
+ * First Introduced: 2.6
+ * Requires Connection: Yes
+ * Auto Activate: No
+ * Module Tags: Developers
+ * Feature: Jumpstart
+ */
+
+class Jetpack_SSO {
+ static $instance = null;
+
+ private function __construct() {
+
+ self::$instance = $this;
+
+ add_action( 'admin_init', array( $this, 'admin_init' ) );
+ add_action( 'admin_init', array( $this, 'register_settings' ) );
+ add_action( 'login_init', array( $this, 'login_init' ) );
+ add_action( 'delete_user', array( $this, 'delete_connection_for_user' ) );
+ add_filter( 'jetpack_xmlrpc_methods', array( $this, 'xmlrpc_methods' ) );
+ add_action( 'init', array( $this, 'maybe_logout_user' ), 5 );
+ add_action( 'jetpack_modules_loaded', array( $this, 'module_configure_button' ) );
+
+ // Adding this action so that on login_init, the action won't be sanitized out of the $action global.
+ add_action( 'login_form_jetpack-sso', '__return_true' );
+
+ if ( $this->should_hide_login_form() && apply_filters( 'jetpack_sso_display_disclaimer', true ) ) {
+ add_action( 'login_message', array( $this, 'msg_login_by_jetpack' ) );
+ }
+ }
+
+ /**
+ * Returns the single instance of the Jetpack_SSO object
+ *
+ * @since 2.8
+ * @return Jetpack_SSO
+ **/
+ public static function get_instance() {
+ if( !is_null( self::$instance ) )
+ return self::$instance;
+
+ return self::$instance = new Jetpack_SSO;
+ }
+
+ /**
+ * Add configure button and functionality to the module card on the Jetpack screen
+ **/
+ public static function module_configure_button() {
+ Jetpack::enable_module_configurable( __FILE__ );
+ Jetpack::module_configuration_load( __FILE__, array( __CLASS__, 'module_configuration_load' ) );
+ Jetpack::module_configuration_head( __FILE__, array( __CLASS__, 'module_configuration_head' ) );
+ Jetpack::module_configuration_screen( __FILE__, array( __CLASS__, 'module_configuration_screen' ) );
+ }
+
+ public static function module_configuration_load() {
+ // wp_safe_redirect( admin_url( 'options-general.php#configure-sso' ) );
+ // exit;
+ }
+
+ public static function module_configuration_head() {}
+
+ public static function module_configuration_screen() {
+ ?>
+ <form method="post" action="options.php">
+ <?php settings_fields( 'jetpack-sso' ); ?>
+ <?php do_settings_sections( 'jetpack-sso' ); ?>
+ <?php submit_button(); ?>
+ </form>
+ <?php
+ }
+
+ /**
+ * If jetpack_force_logout == 1 in current user meta the user will be forced
+ * to logout and reauthenticate with the site.
+ **/
+ public function maybe_logout_user() {
+ global $current_user;
+
+ if( 1 == $current_user->jetpack_force_logout ) {
+ delete_user_meta( $current_user->ID, 'jetpack_force_logout' );
+ self::delete_connection_for_user( $current_user->ID );
+ wp_logout();
+ wp_safe_redirect( wp_login_url() );
+ }
+ }
+
+
+ /**
+ * Adds additional methods the WordPress xmlrpc API for handling SSO specific features
+ *
+ * @param array $methods
+ * @return array
+ **/
+ public function xmlrpc_methods( $methods ) {
+ $methods['jetpack.userDisconnect'] = array( $this, 'xmlrpc_user_disconnect' );
+ return $methods;
+ }
+
+ /**
+ * Marks a user's profile for disconnect from WordPress.com and forces a logout
+ * the next time the user visits the site.
+ **/
+ public function xmlrpc_user_disconnect( $user_id ) {
+ $user_query = new WP_User_Query(
+ array(
+ 'meta_key' => 'wpcom_user_id',
+ 'meta_value' => $user_id
+ )
+ );
+ $user = $user_query->get_results();
+ $user = $user[0];
+
+
+ if( $user instanceof WP_User ) {
+ $user = wp_set_current_user( $user->ID );
+ update_user_meta( $user->ID, 'jetpack_force_logout', '1' );
+ self::delete_connection_for_user( $user->ID );
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Adds settings fields to Settings > General > Single Sign On that allows users to
+ * turn off the login form on wp-login.php
+ *
+ * @since 2.7
+ **/
+ public function register_settings() {
+
+ add_settings_section(
+ 'jetpack_sso_settings',
+ __( 'Jetpack Single Sign On' , 'jetpack' ),
+ '__return_false',
+ 'jetpack-sso'
+ );
+
+ /*
+ * Settings > General > Jetpack Single Sign On
+ * Checkbox for Remove default login form
+ */
+ /* Hide in 2.9
+ register_setting(
+ 'general',
+ 'jetpack_sso_remove_login_form',
+ array( $this, 'validate_settings_remove_login_form_checkbox' )
+ );
+
+ add_settings_field(
+ 'jetpack_sso_remove_login_form',
+ __( 'Remove default login form?' , 'jetpack' ),
+ array( $this, 'render_remove_login_form_checkbox' ),
+ 'general',
+ 'jetpack_sso_settings'
+ );
+ */
+
+ /*
+ * Settings > General > Jetpack Single Sign On
+ * Require two step authentication
+ */
+ register_setting(
+ 'jetpack-sso',
+ 'jetpack_sso_require_two_step',
+ array( $this, 'validate_jetpack_sso_require_two_step' )
+ );
+
+ add_settings_field(
+ 'jetpack_sso_require_two_step',
+ '', // __( 'Require Two-Step Authentication' , 'jetpack' ),
+ array( $this, 'render_require_two_step' ),
+ 'jetpack-sso',
+ 'jetpack_sso_settings'
+ );
+
+
+ /*
+ * Settings > General > Jetpack Single Sign On
+ */
+ register_setting(
+ 'jetpack-sso',
+ 'jetpack_sso_match_by_email',
+ array( $this, 'validate_jetpack_sso_match_by_email' )
+ );
+
+ add_settings_field(
+ 'jetpack_sso_match_by_email',
+ '', // __( 'Match by Email' , 'jetpack' ),
+ array( $this, 'render_match_by_email' ),
+ 'jetpack-sso',
+ 'jetpack_sso_settings'
+ );
+ }
+
+ /**
+ * Builds the display for the checkbox allowing user to require two step
+ * auth be enabled on WordPress.com accounts before login. Displays in Settings > General
+ *
+ * @since 2.7
+ **/
+ public function render_require_two_step() {
+ echo '<label>';
+ echo '<input type="checkbox" name="jetpack_sso_require_two_step" ' . checked( 1 == get_option( 'jetpack_sso_require_two_step' ), true, false ) . '> ';
+ esc_html_e( 'Require Two-Step Authentication' , 'jetpack' );
+ echo '</label>';
+ }
+
+ /**
+ * Validate the require two step checkbox in Settings > General
+ *
+ * @since 2.7
+ * @return boolean
+ **/
+ public function validate_jetpack_sso_require_two_step( $input ) {
+ return ( ! empty( $input ) ) ? 1 : 0;
+ }
+
+ /**
+ * Builds the display for the checkbox allowing the user to allow matching logins by email
+ * Displays in Settings > General
+ *
+ * @since 2.9
+ **/
+ public function render_match_by_email() {
+ echo '<label>';
+ echo '<input type="checkbox" name="jetpack_sso_match_by_email"' . checked( 1 == get_option( 'jetpack_sso_match_by_email' ), true, false) . '> ';
+ esc_html_e( 'Match by Email', 'jetpack' );
+ echo '</label>';
+ }
+
+ /**
+ * Validate the match by email check in Settings > General
+ *
+ * @since 2.9
+ * @return boolean
+ **/
+ public function validate_jetpack_sso_match_by_email( $input ) {
+ return ( ! empty( $input ) ) ? 1 : 0;
+ }
+
+ /**
+ * Builds the display for the checkbox allowing users to remove the default
+ * WordPress login form from wp-login.php. Displays in Settings > General
+ *
+ * @since 2.7
+ **/
+ public function render_remove_login_form_checkbox() {
+ if( $this->is_user_connected( get_current_user_id() ) ) {
+ echo '<a name="configure-sso"></a>';
+ echo '<input type="checkbox" name="jetpack_sso_remove_login_form[remove_login_form]" ' . checked( 1 == get_option( 'jetpack_sso_remove_login_form' ), true, false ) . '>';
+ echo '<p class="description">Removes default login form and disallows login via POST</p>';
+ } else {
+ echo 'Your account must be connected to WordPress.com before disabling the login form.';
+ echo '<br/>' . $this->button();
+ }
+ }
+
+ /**
+ * Validate settings input from Settings > General
+ *
+ * @since 2.7
+ * @return boolean
+ **/
+ public function validate_settings_remove_login_form_checkbox( $input ) {
+ return ( isset( $input['remove_login_form'] ) )? 1: 0;
+ }
+
+ /**
+ * Removes 'Lost your password?' text from the login form if user
+ * does not want to show the login form
+ *
+ * @since 2.7
+ * @return string
+ **/
+ public function remove_lost_password_text( $text ) {
+ if( 'Lost your password?' == $text )
+ $text = '';
+ return $text;
+ }
+
+ /**
+ * Checks to determine if the user wants to login on wp-login
+ *
+ * This function mostly exists to cover the exceptions to login
+ * that may exist as other parameters to $_GET[action] as $_GET[action]
+ * does not have to exist. By default WordPress assumes login if an action
+ * is not set, however this may not be true, as in the case of logout
+ * where $_GET[loggedout] is instead set
+ *
+ * @return boolean
+ **/
+ private function wants_to_login() {
+ $wants_to_login = false;
+
+ // Cover default WordPress behavior
+ $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : 'login';
+
+ // And now the exceptions
+ $action = isset( $_GET['loggedout'] ) ? 'loggedout' : $action;
+
+ if( 'login' == $action ) {
+ $wants_to_login = true;
+ }
+
+ return $wants_to_login;
+ }
+
+ private function bypass_login_forward_wpcom() {
+ return apply_filters( 'jetpack_sso_bypass_login_forward_wpcom', false );
+ }
+
+ function login_init() {
+ global $action;
+
+ /**
+ * If the user is attempting to logout AND the auto-forward to WordPress.com
+ * login is set then we need to ensure we do not auto-forward the user and get
+ * them stuck in an infinite logout loop.
+ */
+ if( isset( $_GET['loggedout'] ) && $this->bypass_login_forward_wpcom() ) {
+ add_filter( 'jetpack_remove_login_form', '__return_true' );
+ add_filter( 'gettext', array( $this, 'remove_lost_password_text' ) );
+ }
+
+ /**
+ * Check to see if the site admin wants to automagically forward the user
+ * to the WordPress.com login page AND that the request to wp-login.php
+ * is not something other than login (Like logout!)
+ */
+ if (
+ $this->wants_to_login()
+ && $this->bypass_login_forward_wpcom()
+ ) {
+ add_filter( 'allowed_redirect_hosts', array( $this, 'allowed_redirect_hosts' ) );
+ wp_safe_redirect( $this->build_sso_url() );
+ }
+
+ if ( 'login' === $action ) {
+ wp_enqueue_script( 'jquery' );
+ wp_enqueue_style( 'genericons' );
+ add_action( 'login_footer', array( $this, 'login_form' ) );
+ add_action( 'login_footer', array( $this, 'login_footer' ) );
+/*
+ if ( get_option( 'jetpack_sso_remove_login_form' ) ) {
+ // Check to see if the user is attempting to login via the default login form.
+ // If so we need to deny it and forward elsewhere.
+ if( isset( $_REQUEST['wp-submit'] ) && 'Log In' == $_REQUEST['wp-submit'] ) {
+ wp_die( 'Login not permitted by this method. ');
+ }
+ add_filter( 'gettext', array( $this, 'remove_lost_password_text' ) );
+ }
+*/
+ } elseif ( 'jetpack-sso' === $action ) {
+ if ( isset( $_GET['result'], $_GET['user_id'], $_GET['sso_nonce'] ) && 'success' == $_GET['result'] ) {
+ $this->handle_login();
+ } else {
+ if ( Jetpack::check_identity_crisis() ) {
+ wp_die( __( "Error: This site's Jetpack connection is currently experiencing problems.", 'jetpack' ) );
+ } else {
+ $this->maybe_save_cookie_redirect();
+ // Is it wiser to just use wp_redirect than do this runaround to wp_safe_redirect?
+ add_filter( 'allowed_redirect_hosts', array( $this, 'allowed_redirect_hosts' ) );
+ wp_safe_redirect( $this->build_sso_url() );
+ }
+ }
+ }
+ }
+
+ /**
+ * Conditionally save the redirect_to url as a cookie.
+ */
+ public static function maybe_save_cookie_redirect() {
+ if ( headers_sent() ) {
+ return new WP_Error( 'headers_sent', __( 'Cannot deal with cookie redirects, as headers are already sent.', 'jetpack' ) );
+ }
+
+ // If we have something to redirect to
+ if ( ! empty( $_GET['redirect_to'] ) ) {
+ $url = esc_url_raw( $_GET['redirect_to'] );
+ setcookie( 'jetpack_sso_redirect_to', $url, time() + HOUR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN, false, true );
+ // Otherwise, if it's already set
+ } elseif ( ! empty( $_COOKIE['jetpack_sso_redirect_to'] ) ) {
+ // Purge it.
+ setcookie( 'jetpack_sso_redirect_to', ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
+ }
+
+ if ( ! empty( $_GET['rememberme'] ) ) {
+ setcookie( 'jetpack_sso_remember_me', '1', time() + HOUR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN, false, true );
+ } elseif ( ! empty( $_COOKIE['jetpack_sso_remember_me'] ) ) {
+ setcookie( 'jetpack_sso_remember_me', ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
+ }
+ }
+
+ /**
+ * Determine if the login form should be hidden or not
+ *
+ * Method is private only because it is only used in this class so far.
+ * Feel free to change it later
+ *
+ * @return bool
+ **/
+ private function should_hide_login_form() {
+ return apply_filters( 'jetpack_remove_login_form', get_option( 'jetpack_sso_remove_login_form', false ) );
+ }
+
+ function login_form() {
+ $classes = '';
+
+ if( $this->should_hide_login_form() ) {
+ $classes .= ' forced-sso';
+ }
+ echo '<div class="jetpack-sso-wrap' . $classes . '">' . $this->button() . '</div>';
+ }
+
+ function login_footer() {
+ $hide_login_form = $this->should_hide_login_form();
+ ?>
+ <style>
+ #loginform {
+ overflow: hidden;
+ padding-bottom: 26px;
+ }
+ .jetpack-sso-wrap {
+ <?php if ( $hide_login_form ) : ?>
+ text-align: center;
+ <?php else : ?>
+ float: right;
+ <?php endif; ?>
+ margin: 1em 0 0;
+ clear: right;
+ display: block;
+ }
+
+ <?php if ( $hide_login_form ) : ?>
+ .forced-sso .jetpack-sso.button {
+ font-size: 16px;
+ line-height: 27px;
+ height: 37px;
+ padding: 5px 12px 6px 47px;
+ }
+ .forced-sso .jetpack-sso.button:before {
+ font-size: 28px !important;
+ height: 37px;
+ padding: 5px 5px 4px;
+ width: 37px;
+ }
+ <?php endif; ?>
+ </style>
+ <script>
+ jQuery(document).ready(function($){
+ <?php if ( $hide_login_form ) : ?>
+ $( '#loginform' ).empty();
+ <?php endif; ?>
+ $( '#loginform' ).append( $( '.jetpack-sso-wrap' ) );
+
+ var $rememberme = $( '#rememberme' ),
+ $ssoButton = $( 'a.jetpack-sso.button' );
+
+ $rememberme.on( 'change', function() {
+ var url = $ssoButton.prop( 'href' ),
+ isChecked = $rememberme.prop( 'checked' ) ? 1 : 0;
+
+ if ( url.match( /&rememberme=\d/ ) ) {
+ url = url.replace( /&rememberme=\d/, '&rememberme=' + isChecked );
+ } else {
+ url += '&rememberme=' + isChecked;
+ }
+
+ $ssoButton.prop( 'href', url );
+ } ).change();
+
+ });
+ </script>
+ <?php
+ }
+
+ static function delete_connection_for_user( $user_id ) {
+ if ( ! $wpcom_user_id = get_user_meta( $user_id, 'wpcom_user_id', true ) ) {
+ return;
+ }
+ Jetpack::load_xml_rpc_client();
+ $xml = new Jetpack_IXR_Client( array(
+ 'user_id' => $user_id
+ ) );
+ $xml->query( 'jetpack.sso.removeUser', $wpcom_user_id );
+
+ if ( $xml->isError() ) {
+ return false;
+ }
+
+ return $xml->getResponse();
+ }
+
+ static function request_initial_nonce() {
+ Jetpack::load_xml_rpc_client();
+ $xml = new Jetpack_IXR_Client( array(
+ 'user_id' => get_current_user_id()
+ ) );
+ $xml->query( 'jetpack.sso.requestNonce' );
+
+ if ( $xml->isError() ) {
+ wp_die( sprintf( '%s: %s', $xml->getErrorCode(), $xml->getErrorMessage() ) );
+ }
+
+ return $xml->getResponse();
+ }
+
+ /**
+ * The function that actually handles the login!
+ */
+ function handle_login() {
+ $wpcom_nonce = sanitize_key( $_GET['sso_nonce'] );
+ $wpcom_user_id = (int) $_GET['user_id'];
+ $result = sanitize_key( $_GET['result'] );
+
+ Jetpack::load_xml_rpc_client();
+ $xml = new Jetpack_IXR_Client( array(
+ 'user_id' => get_current_user_id()
+ ) );
+ $xml->query( 'jetpack.sso.validateResult', $wpcom_nonce, $wpcom_user_id );
+
+ if ( $xml->isError() ) {
+ wp_die( sprintf( '%s: %s', $xml->getErrorCode(), $xml->getErrorMessage() ) );
+ }
+
+ $user_data = $xml->getResponse();
+
+ if ( empty( $user_data ) ) {
+ wp_die( __( 'Error, invalid response data.', 'jetpack' ) );
+ }
+
+ $user_data = (object) $user_data;
+ $user = null;
+ do_action( 'jetpack_sso_pre_handle_login', $user_data );
+
+ // Check to see if having two step enable on wpcom is a requirement to login here
+ $require_two_step = apply_filters( 'jetpack_sso_require_two_step', get_option( 'jetpack_sso_require_two_step' ) );
+ if( $require_two_step && 0 == (int) $user_data->two_step_enabled ) {
+ $this->user_data = $user_data;
+ do_action( 'wp_login_failed', $user_data->login );
+ add_action( 'login_message', array( $this, 'error_msg_enable_two_step' ) );
+ return;
+ }
+
+ if ( isset( $_GET['state'] ) && ( 0 < strpos( $_GET['state'], '|' ) ) ) {
+ list( $state, $nonce ) = explode( '|', $_GET['state'] );
+
+ if ( wp_verify_nonce( $nonce, $state ) ) {
+ if ( 'sso-link-user' == $state ) {
+ $user = wp_get_current_user();
+ update_user_meta( $user->ID, 'wpcom_user_id', $user_data->ID );
+ add_filter( 'login_redirect', array( __CLASS__, 'profile_page_url' ) );
+ }
+ } else wp_nonce_ays();
+ }
+
+ if ( empty( $user ) ) {
+ $user = $this->get_user_by_wpcom_id( $user_data->ID );
+ }
+
+ // If we don't have one by wpcom_user_id, try by the email?
+ if ( empty( $user ) && self::match_by_email() ) {
+ $user = get_user_by( 'email', $user_data->email );
+ if ( $user ) {
+ update_user_meta( $user->ID, 'wpcom_user_id', $user_data->ID );
+ }
+ }
+
+ // If we've still got nothing, create the user.
+ if ( empty( $user ) && ( get_option( 'users_can_register' ) || self::new_user_override() ) ) {
+ // If not matching by email we still need to verify the email does not exist
+ // or this blows up
+ /**
+ * If match_by_email is true, we know the email doesn't exist, as it would have
+ * been found in the first pass. If get_user_by( 'email' ) doesn't find the
+ * user, then we know that email is unused, so it's safe to add.
+ */
+ if ( self::match_by_email() || ! get_user_by( 'email', $user_data->email ) ) {
+ $username = $user_data->login;
+
+ if ( username_exists( $username ) ) {
+ $username = $user_data->login . '_' . $user_data->ID;
+ }
+
+ $tries = 0;
+ while ( username_exists( $username ) ) {
+ $username = $user_data->login . '_' . $user_data->ID . '_' . mt_rand();
+ if ( $tries++ >= 5 ) {
+ wp_die( __( "Error: Couldn't create suitable username.", 'jetpack' ) );
+ }
+ }
+
+ $password = wp_generate_password( 20 );
+ $user_id = wp_create_user( $username, $password, $user_data->email );
+ $user = get_userdata( $user_id );
+
+ $user->display_name = $user_data->display_name;
+ $user->first_name = $user_data->first_name;
+ $user->last_name = $user_data->last_name;
+ $user->url = $user_data->url;
+ $user->description = $user_data->description;
+ wp_update_user( $user );
+
+ update_user_meta( $user->ID, 'wpcom_user_id', $user_data->ID );
+ } else {
+ $this->user_data = $user_data;
+ // do_action( 'wp_login_failed', $user_data->login );
+ add_action( 'login_message', array( $this, 'error_msg_email_already_exists' ) );
+ return;
+ }
+ }
+
+ do_action( 'jetpack_sso_handle_login', $user, $user_data );
+
+ if ( $user ) {
+ // Cache the user's details, so we can present it back to them on their user screen.
+ update_user_meta( $user->ID, 'wpcom_user_data', $user_data );
+
+ $remember = false;
+ if ( ! empty( $_COOKIE['jetpack_sso_remember_me'] ) ) {
+ $remember = true;
+ // And then purge it
+ setcookie( 'jetpack_sso_remember_me', ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
+ }
+ // Set remember me value
+ $remember = apply_filters( 'jetpack_remember_login', $remember );
+ wp_set_auth_cookie( $user->ID, $remember );
+
+ // Run the WP core login action
+ do_action( 'wp_login', $user->user_login, $user );
+
+ $_request_redirect_to = isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
+ $redirect_to = user_can( $user, 'edit_posts' ) ? admin_url() : self::profile_page_url();
+
+ // If we have a saved redirect to request in a cookie
+ if ( ! empty( $_COOKIE['jetpack_sso_redirect_to'] ) ) {
+ // Set that as the requested redirect to
+ $redirect_to = $_request_redirect_to = esc_url_raw( $_COOKIE['jetpack_sso_redirect_to'] );
+ // And then purge it
+ setcookie( 'jetpack_sso_redirect_to', ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
+ }
+
+ wp_safe_redirect( apply_filters( 'login_redirect', $redirect_to, $_request_redirect_to, $user ) );
+ exit;
+ }
+
+ $this->user_data = $user_data;
+ do_action( 'wp_login_failed', $user_data->login );
+ add_action( 'login_message', array( $this, 'cant_find_user' ) );
+ }
+
+ static function profile_page_url() {
+ return admin_url( 'profile.php' );
+ }
+
+ static function match_by_email() {
+ $match_by_email = ( 1 == get_option( 'jetpack_sso_match_by_email', true ) ) ? true: false;
+ $match_by_email = defined( 'WPCC_MATCH_BY_EMAIL' ) ? WPCC_MATCH_BY_EMAIL : $match_by_email;
+
+ return apply_filters( 'jetpack_sso_match_by_email', $match_by_email );
+ }
+
+ static function new_user_override() {
+ $new_user_override = defined( 'WPCC_NEW_USER_OVERRIDE' ) ? WPCC_NEW_USER_OVERRIDE : false;
+ return apply_filters( 'jetpack_sso_new_user_override', $new_user_override );
+ }
+
+ function allowed_redirect_hosts( $hosts ) {
+ if ( empty( $hosts ) ) {
+ $hosts = array();
+ }
+ $hosts[] = 'wordpress.com';
+
+ return array_unique( $hosts );
+ }
+
+ function button( $args = array() ) {
+ $defaults = array(
+ 'action' => 'jetpack-sso',
+ );
+
+ $args = wp_parse_args( $args, $defaults );
+
+ if ( ! empty( $_GET['redirect_to'] ) ) {
+ $args['redirect_to'] = esc_url_raw( $_GET['redirect_to'] );
+ }
+
+ $url = add_query_arg( $args, wp_login_url() );
+
+ $css = "<style>
+ .jetpack-sso.button {
+ position: relative;
+ padding-left: 37px;
+ }
+ .jetpack-sso.button:before {
+ display: block;
+ box-sizing: border-box;
+ padding: 7px 0 0;
+ text-align: center;
+ position: absolute;
+ top: -1px;
+ left: -1px;
+ border-radius: 2px 0 0 2px;
+ content: '\\f205';
+ background: #0074a2;
+ color: #fff;
+ -webkit-font-smoothing: antialiased;
+ width: 30px;
+ height: 107%;
+ height: calc( 100% + 2px );
+ font: normal 22px/1 Genericons !important;
+ text-shadow: none;
+ }
+ @media screen and (min-width: 783px) {
+ .jetpack-sso.button:before {
+ padding-top: 3px;
+ }
+ }
+ .jetpack-sso.button:hover {
+ border: 1px solid #aaa;
+ }";
+
+ if ( version_compare( $GLOBALS['wp_version'], '3.8-alpha', '<' ) ) {
+ $css .= "
+ .jetpack-sso.button:before {
+ width: 25px;
+ font-size: 18px !important;
+ }
+ ";
+ }
+
+ $css .= "</style>";
+
+ $button = sprintf( '<a href="%1$s" class="jetpack-sso button">%2$s</a>', esc_url( $url ), esc_html__( 'Log in with WordPress.com', 'jetpack' ) );
+ return $button . $css;
+ }
+
+ function build_sso_url( $args = array() ) {
+ $defaults = array(
+ 'action' => 'jetpack-sso',
+ 'site_id' => Jetpack_Options::get_option( 'id' ),
+ 'sso_nonce' => self::request_initial_nonce(),
+ );
+
+ if ( isset( $_GET['state'] ) && check_admin_referer( $_GET['state'] ) ) {
+ $defaults['state'] = rawurlencode( $_GET['state'] . '|' . $_GET['_wpnonce'] );
+ }
+
+ $args = wp_parse_args( $args, $defaults );
+ $url = add_query_arg( $args, 'https://wordpress.com/wp-login.php' );
+
+ return $url;
+ }
+
+ function get_user_by_wpcom_id( $wpcom_user_id ) {
+ $user_query = new WP_User_Query( array(
+ 'meta_key' => 'wpcom_user_id',
+ 'meta_value' => intval( $wpcom_user_id ),
+ 'number' => 1,
+ ) );
+
+ $users = $user_query->get_results();
+ return $users ? array_shift( $users ) : null;
+ }
+
+ /**
+ * Error message displayed on the login form when two step is required and
+ * the user's account on WordPress.com does not have two step enabled.
+ *
+ * @since 2.7
+ * @param string $message
+ * @return string
+ **/
+ public function error_msg_enable_two_step( $message ) {
+ $err = __( sprintf( 'This site requires two step authentication be enabled for your user account on WordPress.com. Please visit the <a href="%1$s"> Security Settings</a> page to enable two step', 'https://wordpress.com/settings/security/' ) , 'jetpack' );
+
+ $message .= sprintf( '<p class="message" id="login_error">%s</p>', $err );
+
+ return $message;
+ }
+
+ /**
+ * Error message displayed when the user tries to SSO, but match by email
+ * is off and they already have an account with their email address on
+ * this site.
+ *
+ * @param string $message
+ * @return string
+ */
+ public function error_msg_email_already_exists( $message ) {
+ $err = __( sprintf( 'You already have an account on this site. Please visit your <a href="%1$s">profile page</a> page to link your account to WordPress.com!', admin_url( 'profile.php' ) ) , 'jetpack' );
+
+ $message .= sprintf( '<p class="message" id="login_error">%s</p>', $err );
+
+ return $message;
+ }
+
+ /**
+ * Message displayed when the site admin has disabled the default WordPress
+ * login form in Settings > General > Single Sign On
+ *
+ * @since 2.7
+ * @param string $message
+ * @return string
+ **/
+ public function msg_login_by_jetpack( $message ) {
+
+ $msg = __( sprintf( 'Jetpack authenticates through WordPress.com — to log in, enter your WordPress.com username and password, or <a href="%1$s">visit WordPress.com</a> to create a free account now.', 'http://wordpress.com/signup' ) , 'jetpack' );
+
+ $msg = apply_filters( 'jetpack_sso_disclaimer_message', $msg );
+
+ $message .= sprintf( '<p class="message">%s</p>', $msg );
+ return $message;
+ }
+
+ /**
+ * Error message displayed on the login form when the user attempts
+ * to post to the login form and it is disabled.
+ *
+ * @since 2.8
+ * @param string $message
+ * @param string
+ **/
+ public function error_msg_login_method_not_allowed( $message ) {
+ $err = __( 'Login method not allowed' , 'jetpack' );
+ $message .= sprintf( '<p class="message" id="login_error">%s</p>', $err );
+
+ return $message;
+ }
+ function cant_find_user( $message ) {
+ if ( self::match_by_email() ) {
+ $err_format = __( 'We couldn\'t find an account with the email <strong><code>%1$s</code></strong> to log you in with. If you already have an account on <strong>%2$s</strong>, please make sure that <strong><code>%1$s</code></strong> is configured as the email address, or that you have connected to WordPress.com on your profile page.', 'jetpack' );
+ } else {
+ $err_format = __( 'We couldn\'t find any account on <strong>%2$s</strong> that is linked to your WordPress.com account to log you in with. If you already have an account on <strong>%2$s</strong>, please make sure that you have connected to WordPress.com on your profile page.', 'jetpack' );
+ }
+ $err = sprintf( $err_format, $this->user_data->email, get_bloginfo( 'name' ) );
+ $message .= sprintf( '<p class="message" id="login_error">%s</p>', $err );
+ return $message;
+ }
+
+ /**
+ * Deal with user connections...
+ */
+ function admin_init() {
+ add_action( 'show_user_profile', array( $this, 'edit_profile_fields' ) ); // For their own profile
+ add_action( 'edit_user_profile', array( $this, 'edit_profile_fields' ) ); // For folks editing others profiles
+
+ if ( isset( $_GET['jetpack_sso'] ) && 'purge' == $_GET['jetpack_sso'] && check_admin_referer( 'jetpack_sso_purge' ) ) {
+ $user = wp_get_current_user();
+ // Remove the connection on the wpcom end.
+ self::delete_connection_for_user( $user->ID );
+ // Clear it locally.
+ delete_user_meta( $user->ID, 'wpcom_user_id' );
+ delete_user_meta( $user->ID, 'wpcom_user_data' );
+ // Forward back to the profile page.
+ wp_safe_redirect( remove_query_arg( array( 'jetpack_sso', '_wpnonce' ) ) );
+ }
+ }
+
+ /**
+ * Determines if a local user is connected to WordPress.com
+ *
+ * @since 2.8
+ * @param integer $user_id - Local user id
+ * @return boolean
+ **/
+ public function is_user_connected( $user_id ) {
+ return $this->get_user_data( $user_id ) ;
+ }
+
+ /**
+ * Retrieves a user's WordPress.com data
+ *
+ * @since 2.8
+ * @param integer $user_id - Local user id
+ * @return mixed null or stdClass
+ **/
+ public function get_user_data( $user_id ) {
+ return get_user_meta( $user_id, 'wpcom_user_data', true );
+ }
+
+ function edit_profile_fields( $user ) {
+ wp_enqueue_style( 'genericons' );
+ ?>
+
+ <h3><?php _e( 'WordPress.com Single Sign On', 'jetpack' ); ?></h3>
+ <p><?php _e( 'Connecting with WordPress.com SSO enables you to log in via your WordPress.com account.', 'jetpack' ); ?></p>
+
+ <?php if ( $this->is_user_connected( $user->ID ) ) : /* If the user is currently connected... */ ?>
+ <?php $user_data = $this->get_user_data( $user->ID ); ?>
+ <table class="form-table jetpack-sso-form-table">
+ <tbody>
+ <tr>
+ <td>
+ <div class="profile-card">
+ <?php echo get_avatar( $user_data->email ); ?>
+ <p class="connected"><strong><?php _e( 'Connected', 'jetpack' ); ?></strong></p>
+ <p><?php echo esc_html( $user_data->login ); ?></p>
+ <span class="two_step">
+ <?php
+ if( $user_data->two_step_enabled ) {
+ ?> <p class="enabled"><a href="https://wordpress.com/settings/security/"><?php _e( 'Two step Enabled', 'jetpack' ); ?></a></p> <?php
+ } else {
+ ?> <p class="disabled"><a href="https://wordpress.com/settings/security/"><?php _e( 'Two step Disabled', 'jetpack' ); ?></a></p> <?php
+ }
+ ?>
+ </span>
+
+ </div>
+ <p><a class="button button-secondary" href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'jetpack_sso', 'purge' ), 'jetpack_sso_purge' ) ); ?>"><?php _e( 'Unlink This Account', 'jetpack' ); ?></a></p>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+ <style>
+ .jetpack-sso-form-table td {
+ padding-left: 0;
+ }
+
+ .jetpack-sso-form-table .profile-card {
+ padding: 10px;
+ background: #fff;
+ overflow: hidden;
+ max-width: 400px;
+ box-shadow: 0 1px 2px rgba( 0, 0, 0, 0.1 );
+ margin-bottom: 1em;
+ }
+
+ .jetpack-sso-form-table .profile-card img {
+ float: left;
+ margin-right: 1em;
+ width: 48px;
+ height: 48px;
+ }
+
+ .jetpack-sso-form-table .profile-card .connected {
+ float: right;
+ margin-right: 0.5em;
+ color: #0a0;
+ }
+
+ .jetpack-sso-form-table .profile-card p {
+ margin-top: 0.7em;
+ font-size: 1.2em;
+ }
+
+ .jetpack-sso-form-table .profile-card .two_step .enabled a {
+ float: right;
+ color: #0a0;
+ }
+
+ .jetpack-sso-form-table .profile-card .two_step .disabled a {
+ float: right;
+ color: red;
+ }
+ </style>
+
+ <?php elseif ( get_current_user_id() == $user->ID ) : ?>
+
+ <?php echo $this->button( 'state=sso-link-user&_wpnonce=' . wp_create_nonce('sso-link-user') ); // update ?>
+
+ <?php else : ?>
+
+ <p><?php _e( 'This profile is not currently linked to a WordPress.com Profile.', 'jetpack' ); ?></p>
+
+ <?php endif;
+ }
+}
+
+Jetpack_SSO::get_instance();
diff --git a/plugins/jetpack/modules/stats.php b/plugins/jetpack/modules/stats.php
index 90fd34ff..f156017f 100644
--- a/plugins/jetpack/modules/stats.php
+++ b/plugins/jetpack/modules/stats.php
@@ -1,11 +1,14 @@
<?php
/**
* Module Name: WordPress.com Stats
- * Module Description: Simple, concise site stats with no additional load on your server.
+ * Module Description: Monitor your stats with clear, concise reports and no additional load on your server.
* Sort Order: 1
+ * Recommendation Order: 2
* First Introduced: 1.1
* Requires Connection: Yes
* Auto Activate: Yes
+ * Module Tags: WordPress.com Stats, Recommended
+ * Feature: Recommended
*/
if ( defined( 'STATS_VERSION' ) ) {
@@ -57,16 +60,29 @@ function stats_load() {
add_action( 'jetpack_admin_menu', 'stats_admin_menu' );
- add_action( 'wp_dashboard_setup', 'stats_register_dashboard_widget' );
+ // Map stats caps
+ add_filter( 'map_meta_cap', 'stats_map_meta_caps', 10, 4 );
+
+ if ( isset( $_GET['oldwidget'] ) ) {
+ // Old one.
+ add_action( 'wp_dashboard_setup', 'stats_register_dashboard_widget' );
+ } elseif ( current_user_can( 'view_stats' ) ) {
+ // New way.
+ add_action( 'load-index.php', 'stats_enqueue_dashboard_head' );
+ add_action( 'wp_dashboard_setup', 'stats_register_widget_control_callback' ); // hacky but works
+ add_action( 'jetpack_dashboard_widget', 'stats_jetpack_dashboard_widget' );
+ }
add_filter( 'jetpack_xmlrpc_methods', 'stats_xmlrpc_methods' );
- // Map stats caps
- add_filter( 'map_meta_cap', 'stats_map_meta_caps', 10, 4 );
add_filter( 'pre_option_db_version', 'stats_ignore_db_version' );
}
+function stats_enqueue_dashboard_head() {
+ add_action( 'admin_head', 'stats_dashboard_head' );
+}
+
/**
* Prevent sparkline img requests being redirected to upgrade.php.
* See wp-admin/admin.php where it checks $wp_db_version.
@@ -125,6 +141,8 @@ function stats_template_redirect() {
$blog = Jetpack_Options::get_option( 'id' );
$tz = get_option( 'gmt_offset' );
$v = 'ext';
+ $blog_url = parse_url( site_url() );
+ $srv = $blog_url['host'];
$j = sprintf( '%s:%s', JETPACK__API_VERSION, JETPACK__VERSION );
if ( $wp_the_query->is_single || $wp_the_query->is_page || $wp_the_query->is_posts_page ) {
// Store and reset the queried_object and queried_object_id
@@ -144,20 +162,17 @@ function stats_template_redirect() {
$post = '0';
}
- $http = is_ssl() ? 'https' : 'http';
- $week = gmdate( 'YW' );
-
- $data = stats_array( compact( 'v', 'j', 'blog', 'post', 'tz' ) );
+ $script = set_url_scheme( '//stats.wp.com/e-' . gmdate( 'YW' ) . '.js' );
+ $data = stats_array( compact( 'v', 'j', 'blog', 'post', 'tz', 'srv' ) );
$stats_footer = <<<END
+<script type='text/javascript' src='{$script}' async defer></script>
+<script type='text/javascript'>
+ _stq = window._stq || [];
+ _stq.push([ 'view', {{$data}} ]);
+ _stq.push([ 'clickTrackerInit', '{$blog}', '{$post}' ]);
+</script>
- <script src="$http://stats.wordpress.com/e-$week.js" type="text/javascript"></script>
- <script type="text/javascript">
- st_go({{$data}});
- var load_cmc = function(){linktracker_init($blog,$post,2);};
- if ( typeof addLoadEvent != 'undefined' ) addLoadEvent(load_cmc);
- else load_cmc();
- </script>
END;
}
@@ -212,7 +227,7 @@ function stats_upgrade_options( $options ) {
'count_roles' => array(),
'blog_id' => Jetpack_Options::get_option( 'id' ),
'do_not_track' => true, // @todo
- 'hide_smile' => false,
+ 'hide_smile' => true,
);
if ( isset( $options['reg_users'] ) ) {
@@ -249,7 +264,7 @@ function stats_array( $kvs ) {
* Admin Pages
*/
function stats_admin_menu() {
- global $pagenow;
+ global $pagenow;
// If we're at an old Stats URL, redirect to the new one.
// Don't even bother with caps, menu_page_url(), etc. Just do it.
@@ -273,6 +288,7 @@ function stats_admin_path() {
function stats_reports_load() {
wp_enqueue_script( 'jquery' );
wp_enqueue_script( 'postbox' );
+ wp_enqueue_script( 'underscore' );
add_action( 'admin_print_styles', 'stats_reports_css' );
@@ -338,22 +354,22 @@ function stats_reports_page() {
if ( isset( $_GET['dashboard'] ) )
return stats_dashboard_widget_content();
+ $blog_id = stats_get_option( 'blog_id' );
+
if ( !isset( $_GET['noheader'] ) && empty( $_GET['nojs'] ) && empty( $_COOKIE['stnojs'] ) ) {
$nojs_url = add_query_arg( 'nojs', '1' );
- if ( 'classic' != $color = get_user_option( 'admin_color' ) ) {
- $color = 'fresh';
- }
$http = is_ssl() ? 'https' : 'http';
// Loading message
// No JS fallback message
?>
-<style type="text/css">
-@media only screen and (-moz-min-device-pixel-ratio: 1.5), only screen and (-o-min-device-pixel-ratio: 3/2), only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-device-pixel-ratio: 1.5) {
- img.wpcom-loading-64 { width: 32px; height: 32px; }
-}
-</style>
+<div class="wrap">
+ <h2><?php esc_html_e( 'Site Stats', 'jetpack'); ?> <a style="font-size:13px;" href="<?php echo esc_url( admin_url('admin.php?page=jetpack&configure=stats') ); ?>"><?php esc_html_e( 'Configure', 'jetpack'); ?></a></h2>
+</div>
<div id="stats-loading-wrap" class="wrap">
-<p class="hide-if-no-js"><img class="wpcom-loading-64" alt="<?php esc_attr_e( 'Loading&hellip;', 'jetpack' ); ?>" src="<?php echo esc_url( "$http://" . STATS_DASHBOARD_SERVER . "/i/loading/$color-64.gif" ); ?>" /></p>
+<p class="hide-if-no-js"><img width="32" height="32" alt="<?php esc_attr_e( 'Loading&hellip;', 'jetpack' ); ?>" src="<?php
+/** This filter is documented in modules/shortcodes/audio.php */
+echo esc_url( apply_filters( 'jetpack_static_url', "{$http}://en.wordpress.com/i/loading/loading-64.gif" ) ); ?>" /></p>
+<p style="font-size: 11pt; margin: 0;"><a href="https://wordpress.com/stats/<?php echo $blog_id; ?>"><?php esc_html_e( 'View stats on WordPress.com right now', 'jetpack' ); ?></a></p>
<p class="hide-if-js"><?php esc_html_e( 'Your Site Stats work better with Javascript enabled.', 'jetpack' ); ?><br />
<a href="<?php echo esc_url( $nojs_url ); ?>"><?php esc_html_e( 'View Site Stats without Javascript', 'jetpack' ); ?></a>.</p>
</div>
@@ -361,7 +377,6 @@ function stats_reports_page() {
return;
}
- $blog_id = stats_get_option( 'blog_id' );
$day = isset( $_GET['day'] ) && preg_match( '/^\d{4}-\d{2}-\d{2}$/', $_GET['day'] ) ? $_GET['day'] : false;
$q = array(
'noheader' => 'true',
@@ -374,6 +389,9 @@ function stats_reports_page() {
'ssl' => is_ssl(),
'j' => sprintf( '%s:%s', JETPACK__API_VERSION, JETPACK__VERSION ),
);
+ if ( get_locale() !== 'en_US' ) {
+ $q['jp_lang'] = get_locale();
+ }
$args = array(
'view' => array( 'referrers', 'postviews', 'searchterms', 'clicks', 'post', 'table' ),
'numdays' => 'int',
@@ -410,11 +428,13 @@ function stats_reports_page() {
}
}
- if ( isset( $_REQUEST['chart'] ) ) {
- if ( preg_match( '/^[a-z0-9-]+$/', $_REQUEST['chart'] ) )
- $url = 'http://' . STATS_DASHBOARD_SERVER . "/wp-includes/charts/{$_GET['chart']}.php";
+ if ( isset( $_GET['chart'] ) ) {
+ if ( preg_match( '/^[a-z0-9-]+$/', $_GET['chart'] ) ) {
+ $chart = sanitize_title( $_GET['chart'] );
+ $url = 'https://' . STATS_DASHBOARD_SERVER . "/wp-includes/charts/{$chart}.php";
+ }
} else {
- $url = 'http://' . STATS_DASHBOARD_SERVER . "/wp-admin/index.php";
+ $url = 'https://' . STATS_DASHBOARD_SERVER . "/wp-admin/index.php";
}
$url = add_query_arg( $q, $url );
@@ -452,7 +472,7 @@ function stats_convert_admin_urls( $html ) {
}
function stats_convert_image_urls( $html ) {
- $url = ( is_ssl() ? 'https' : 'http' ) . '://' . STATS_DASHBOARD_SERVER;
+ $url = set_url_scheme( 'https://' . STATS_DASHBOARD_SERVER );
$html = preg_replace( '|(["\'])(/i/stats.+)\\1|', '$1' . $url . '$2$1', $html );
return $html;
}
@@ -556,7 +576,7 @@ function stats_configuration_screen() {
?>
</td></tr>
<tr valign="top"><th scope="row"><?php _e( 'Smiley' , 'jetpack' ); ?></th>
- <td><label><input type='checkbox'<?php checked( isset( $options['hide_smile'] ) && $options['hide_smile'] ); ?> name='hide_smile' id='hide_smile' /> <?php _e( 'Hide the stats smiley face image.', 'jetpack' ); ?></label><br /> <span class="description"><?php _e( 'The image helps collect stats and <strong>makes the world a better place</strong> but should still work when hidden', 'jetpack' ); ?> <img class="stats-smiley" alt="<?php esc_attr_e( 'Smiley face', 'jetpack' ); ?>" src="<?php echo esc_url( plugins_url( '_inc/images/stats-smiley.gif', dirname( __FILE__ ) ) ); ?>" width="6" height="5" /></span></td></tr>
+ <td><label><input type='checkbox'<?php checked( isset( $options['hide_smile'] ) && $options['hide_smile'] ); ?> name='hide_smile' id='hide_smile' /> <?php _e( 'Hide the stats smiley face image.', 'jetpack' ); ?></label><br /> <span class="description"><?php _e( 'The image helps collect stats and <strong>makes the world a better place</strong> but should still work when hidden', 'jetpack' ); ?> <img class="stats-smiley" alt="<?php esc_attr_e( 'Smiley face', 'jetpack' ); ?>" src="<?php echo esc_url( plugins_url( 'images/stats-smiley.gif', dirname( __FILE__ ) ) ); ?>" width="6" height="5" /></span></td></tr>
<tr valign="top"><th scope="row"><?php _e( 'Report visibility' , 'jetpack' ); ?></th>
<td>
<?php _e( 'Select the roles that will be able to view stats reports.', 'jetpack' ); ?><br/>
@@ -666,7 +686,25 @@ function stats_get_blog() {
);
$blog = array_merge( stats_get_options(), $blog );
unset( $blog['roles'], $blog['blog_id'] );
- return array_map( 'esc_html', $blog );
+ return stats_esc_html_deep( $blog );
+}
+
+/**
+ * Modified from stripslashes_deep()
+ */
+function stats_esc_html_deep( $value ) {
+ if ( is_array( $value ) ) {
+ $value = array_map( 'stats_esc_html_deep', $value );
+ } elseif ( is_object( $value ) ) {
+ $vars = get_object_vars( $value );
+ foreach ( $vars as $key => $data ) {
+ $value->{$key} = stats_esc_html_deep( $data );
+ }
+ } elseif ( is_string( $value ) ) {
+ $value = esc_html( $value );
+ }
+
+ return $value;
}
function stats_xmlrpc_methods( $methods ) {
@@ -774,28 +812,96 @@ function stats_dashboard_widget_control() {
<?php
}
+function stats_jetpack_dashboard_widget() {
+ ?>
+ <h3>
+ <span class="js-toggle-stats_dashboard_widget_control">
+ <?php esc_html_e( 'Configure', 'jetpack' ); ?>
+ </span>
+ <?php esc_html_e( 'Site Stats', 'jetpack' ); ?>
+ </h3>
+ <form id="stats_dashboard_widget_control" action="<?php esc_url( admin_url() ); ?>" method="post">
+ <?php stats_dashboard_widget_control(); ?>
+ <?php wp_nonce_field( 'edit-dashboard-widget_dashboard_stats', 'dashboard-widget-nonce' ); ?>
+ <input type="hidden" name="widget_id" value="dashboard_stats" />
+ <?php submit_button( __( 'Submit', 'jetpack' ) ); ?>
+ </form>
+ <div id="dashboard_stats">
+ <div class="inside">
+ <div style="height: 250px;"></div>
+ </div>
+ </div>
+ <script>
+ jQuery(document).ready(function($){
+ $('.js-toggle-stats_dashboard_widget_control').click(function(e){
+ e.preventDefault();
+ $(this).parent().toggleClass('controlVisible');
+ $('#stats_dashboard_widget_control').slideToggle();
+ });
+ });
+ </script>
+ <style>
+ .js-toggle-stats_dashboard_widget_control {
+ float: right;
+ font-weight: 400;
+ color: #444;
+ font-size: .8em;
+ text-decoration: underline;
+ cursor: pointer;
+ }
+ #stats_dashboard_widget_control {
+ display: none;
+ padding: 0 10px;
+ overflow: hidden;
+ }
+ #stats_dashboard_widget_control .button-primary {
+ float: right;
+ }
+ #dashboard_stats {
+ box-sizing: border-box;
+ width: 100%;
+ padding: 0 10px;
+ }
+ </style>
+ <?php
+}
+
+function stats_register_widget_control_callback() {
+ $GLOBALS['wp_dashboard_control_callbacks']['dashboard_stats'] = 'stats_dashboard_widget_control';
+}
// Javascript and CSS for dashboard widget
function stats_dashboard_head() { ?>
<script type="text/javascript">
/* <![CDATA[ */
jQuery(window).load( function() {
jQuery( function($) {
- var dashStats = $( '#dashboard_stats.postbox div.inside' );
+ resizeChart();
+ jQuery(window).resize( _.debounce( function(){
+ resizeChart();
+ }, 100) );
+ } );
- if ( dashStats.find( '.dashboard-widget-control-form' ).size() ) {
+ function resizeChart() {
+ var dashStats = jQuery( '#dashboard_stats div.inside' );
+
+ if ( dashStats.find( '.dashboard-widget-control-form' ).length ) {
return;
}
- if ( ! dashStats.size() ) {
- dashStats = $( '#dashboard_stats div.dashboard-widget-content' );
+ if ( ! dashStats.length ) {
+ dashStats = jQuery( '#dashboard_stats div.dashboard-widget-content' );
var h = parseInt( dashStats.parent().height() ) - parseInt( dashStats.prev().height() );
var args = 'width=' + dashStats.width() + '&height=' + h.toString();
} else {
- var args = 'width=' + ( dashStats.prev().width() * 2 ).toString();
+ if ( jQuery('#dashboard_stats' ).hasClass('postbox') ) {
+ var args = 'width=' + ( dashStats.prev().width() * 2 ).toString();
+ } else {
+ var args = 'width=' + ( dashStats.width() * 2 ).toString();
+ }
}
dashStats.not( '.dashboard-widget-control' ).load( 'admin.php?page=stats&noheader&dashboard&' + args );
- } );
+ }
} );
/* ]]> */
</script>
@@ -897,7 +1003,7 @@ function stats_dashboard_widget_content() {
'j' => sprintf( '%s:%s', JETPACK__API_VERSION, JETPACK__VERSION ),
);
- $url = 'http://' . STATS_DASHBOARD_SERVER . "/wp-admin/index.php";
+ $url = 'https://' . STATS_DASHBOARD_SERVER . "/wp-admin/index.php";
$url = add_query_arg( $q, $url );
$method = 'GET';
@@ -1005,9 +1111,9 @@ function stats_print_wp_remote_error( $get, $url ) {
<div class="wrap">
<p><?php printf( __( 'We were unable to get your stats just now. Please reload this page to try again. If this error persists, please <a href="%1$s">contact support</a>. In your report please include the information below.', 'jetpack' ), 'http://support.wordpress.com/contact/?jetpack=needs-service' ); ?></p>
<pre>
- User Agent: "<?php print htmlspecialchars( $_SERVER['HTTP_USER_AGENT'] ); ?>"
- Page URL: "http<?php print (is_ssl()?'s':'') . '://' . htmlspecialchars( $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ); ?>"
- API URL: "<?php print clean_url( $url ); ?>"
+ User Agent: "<?php echo esc_html( $_SERVER['HTTP_USER_AGENT'] ); ?>"
+ Page URL: "http<?php echo (is_ssl()?'s':'') . '://' . esc_html( $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ); ?>"
+ API URL: "<?php echo esc_url( $url ); ?>"
<?php
if ( is_wp_error( $get ) ) {
foreach ( $get->get_error_codes() as $code ) {
@@ -1103,6 +1209,10 @@ function stats_get_remote_csv( $url ) {
// rather than parsing the csv and its special cases, we create a new file and do fgetcsv on it.
function stats_str_getcsv( $csv ) {
+ if ( function_exists( 'str_getcsv' ) ) {
+ $lines = str_getcsv( $csv, "\n" );
+ return array_map( 'str_getcsv', $lines );
+ }
if ( !$temp = tmpfile() ) // tmpfile() automatically unlinks
return false;
@@ -1116,4 +1226,3 @@ function stats_str_getcsv( $csv ) {
return $data;
}
-
diff --git a/plugins/jetpack/modules/subscriptions.php b/plugins/jetpack/modules/subscriptions.php
index 1becb481..dacf2f4e 100644
--- a/plugins/jetpack/modules/subscriptions.php
+++ b/plugins/jetpack/modules/subscriptions.php
@@ -1,11 +1,15 @@
<?php
/**
* Module Name: Subscriptions
- * Module Description: Allow users to subscribe to your posts and comments to receive a notification via email.
- * Sort Order: 3
+ * Module Description: Allow users to subscribe to your posts and comments and receive notifications via email.
+ * Jumpstart Description: give visitors two easy subscription options — while commenting, or via a separate email subscription widget you can display.
+ * Sort Order: 9
+ * Recommendation Order: 8
* First Introduced: 1.2
* Requires Connection: Yes
* Auto Activate: Yes
+ * Module Tags: Social
+ * Feature: Jumpstart
*/
add_action( 'jetpack_modules_loaded', 'jetpack_subscriptions_load' );
@@ -248,18 +252,20 @@ class Jetpack_Subscriptions {
}
public function reading_section() {
+ echo '<p id="follower-settings">';
_e( 'These settings change emails sent from your blog to followers.', 'jetpack' );
+ echo '</p>';
}
public function setting_invitation() {
$settings = $this->get_settings();
- echo '<textarea name="subscription_options[invitation]" class="large-text" cols="50" rows="5">'.$settings['invitation'].'</textarea>';
+ echo '<textarea name="subscription_options[invitation]" class="large-text" cols="50" rows="5">' . esc_textarea( $settings['invitation'] ) . '</textarea>';
echo '<p><span class="description">'.__( 'Introduction text sent when someone follows your blog. (Site and confirmation details will be automatically added for you.)', 'jetpack' ).'</span></p>';
}
public function setting_comment_follow() {
$settings = $this->get_settings();
- echo '<textarea name="subscription_options[comment_follow]" class="large-text" cols="50" rows="5">'.$settings['comment_follow'].'</textarea>';
+ echo '<textarea name="subscription_options[comment_follow]" class="large-text" cols="50" rows="5">' . esc_textarea( $settings['comment_follow'] ) . '</textarea>';
echo '<p><span class="description">'.__( 'Introduction text sent when someone follows a post on your blog. (Site and confirmation details will be automatically added for you.)', 'jetpack' ).'</span></p>';
}
@@ -465,17 +471,19 @@ class Jetpack_Subscriptions {
$str = '';
- if ( FALSE === has_filter( 'comment_form', 'show_subscription_checkbox' ) && 1 == get_option( 'stc_enabled', 1 ) ) {
+ if ( FALSE === has_filter( 'comment_form', 'show_subscription_checkbox' ) && 1 == get_option( 'stc_enabled', 1 ) && empty( $post->post_password ) ) {
// Subscribe to comments checkbox
$str .= '<p class="comment-subscription-form"><input type="checkbox" name="subscribe_comments" id="subscribe_comments" value="subscribe" style="width: auto; -moz-appearance: checkbox; -webkit-appearance: checkbox;"' . $comments_checked . ' /> ';
- $str .= '<label class="subscribe-label" id="subscribe-label" for="subscribe_comments" style="display: inline;">' . __( 'Notify me of follow-up comments by email.', 'jetpack' ) . '</label>';
+ $comment_sub_text = __( 'Notify me of follow-up comments by email.', 'jetpack' );
+ $str .= '<label class="subscribe-label" id="subscribe-label" for="subscribe_comments">' . esc_html( apply_filters( 'jetpack_subscribe_comment_label', $comment_sub_text ) ) . '</label>';
$str .= '</p>';
}
if ( 1 == get_option( 'stb_enabled', 1 ) ) {
// Subscribe to blog checkbox
$str .= '<p class="comment-subscription-form"><input type="checkbox" name="subscribe_blog" id="subscribe_blog" value="subscribe" style="width: auto; -moz-appearance: checkbox; -webkit-appearance: checkbox;"' . $blog_checked . ' /> ';
- $str .= '<label class="subscribe-label" id="subscribe-blog-label" for="subscribe_blog" style="display: inline;">' . __( 'Notify me of new posts by email.', 'jetpack' ) . '</label>';
+ $blog_sub_text = __( 'Notify me of new posts by email.', 'jetpack' );
+ $str .= '<label class="subscribe-label" id="subscribe-blog-label" for="subscribe_blog">' . esc_html( apply_filters( 'jetpack_subscribe_blog_label', $blog_sub_text ) ) . '</label>';
$str .= '</p>';
}
@@ -559,80 +567,146 @@ class Jetpack_Subscriptions_Widget extends WP_Widget {
$this->WP_Widget( 'blog_subscription', __( 'Blog Subscriptions (Jetpack)', 'jetpack' ), $widget_ops, $control_ops );
}
+ /*
+ * Check for the option to show subscriber count.
+ *
+ * This function only serves the purpose of backwards compatibility for versions < 3.4
+ *
+ * @since 3.5
+ * @return bool Will return true only if a site still has the option to show subscriber count.
+ */
+ function has_show_subscriber_count_option() {
+ $widget_options = get_option( 'widget_blog_subscription' );
+ if ( ! empty( $widget_options ) && is_array( $widget_options ) ) {
+ foreach ( $widget_options as $k => $option ) {
+ if ( ! empty( $option['show_subscribers_total'] ) && 1 == $option['show_subscribers_total'] ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
function widget( $args, $instance ) {
- global $current_user;
+ if ( ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM )
+ && false === apply_filters( 'jetpack_auto_fill_logged_in_user', false )
+ ) {
+ $subscribe_email = '';
+ } else {
+ global $current_user;
+ if ( ! empty( $current_user->user_email ) ) {
+ $subscribe_email = esc_attr( $current_user->user_email );
+ } else {
+ $subscribe_email = '';
+ }
+ }
+
+
$source = 'widget';
$instance = wp_parse_args( (array) $instance, $this->defaults() );
- $subscribe_text = isset( $instance['subscribe_text'] ) ? stripslashes( $instance['subscribe_text'] ) : '';
- $subscribe_button = isset( $instance['subscribe_button'] ) ? stripslashes( $instance['subscribe_button'] ) : '';
- $show_subscribers_total = (bool) $instance['show_subscribers_total'];
+ $subscribe_text = isset( $instance['subscribe_text'] ) ? stripslashes( $instance['subscribe_text'] ) : '';
+ $subscribe_placeholder = isset( $instance['subscribe_placeholder'] ) ? stripslashes( $instance['subscribe_placeholder'] ) : '';
+ $subscribe_button = isset( $instance['subscribe_button'] ) ? stripslashes( $instance['subscribe_button'] ) : '';
+ $success_message = isset( $instance['success_message'] ) ? stripslashes( $instance['success_message'] ) : '';
$subscribers_total = $this->fetch_subscriber_count();
$widget_id = esc_attr( !empty( $args['widget_id'] ) ? esc_attr( $args['widget_id'] ) : mt_rand( 450, 550 ) );
- if ( ! is_array( $subscribers_total ) )
- $show_subscribers_total = FALSE;
+ $show_subscribers_total = is_array( $subscribers_total ) && $this->has_show_subscriber_count_option();
- echo $args['before_widget'];
- echo $args['before_title'] . '<label for="subscribe-field">' . esc_attr( $instance['title'] ) . '</label>' . $args['after_title'] . "\n";
+ // Give the input element a unique ID
+ $subscribe_field_id = apply_filters( 'subscribe_field_id', 'subscribe-field', $widget_id );
- $referer = ( is_ssl() ? 'https' : 'http' ) . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
+ // Enqueue the form's CSS
+ wp_register_style( 'jetpack-subscriptions', plugins_url( 'subscriptions/subscriptions.css', __FILE__ ) );
+ wp_enqueue_style( 'jetpack-subscriptions' );
- // Check for subscription confirmation.
- if ( isset( $_GET['subscribe'] ) && 'success' == $_GET['subscribe'] ) : ?>
-
- <div class="success">
- <p><?php esc_html_e( 'An email was just sent to confirm your subscription. Please find the email now and click activate to start subscribing.', 'jetpack' ); ?></p>
- </div>
+ // Display the subscription form
+ echo $args['before_widget'];
+
+ // Only show the title if there actually is a title
+ if( ! empty( $instance['title'] ) ) {
+ echo $args['before_title'] . esc_attr( $instance['title'] ) . $args['after_title'] . "\n";
+ }
- <?php endif;
+ $referer = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
// Display any errors
if ( isset( $_GET['subscribe'] ) ) :
switch ( $_GET['subscribe'] ) :
case 'invalid_email' : ?>
- <p class="error"><?php esc_html_e( 'The email you entered was invalid, please check and try again.', 'jetpack' ); ?></p>
+ <p class="error"><?php esc_html_e( 'The email you entered was invalid. Please check and try again.', 'jetpack' ); ?></p>
<?php break;
case 'already' : ?>
- <p class="error"><?php esc_html_e( 'You have already subscribed to this site, please check your inbox.', 'jetpack' ); ?></p>
+ <p class="error"><?php esc_html_e( 'You have already subscribed to this site. Please check your inbox.', 'jetpack' ); ?></p>
<?php break;
- case 'success' :
- echo wpautop( $subscribe_text );
- break;
+ case 'success' : ?>
+ <div class="success"><?php echo wpautop( str_replace( '[total-subscribers]', number_format_i18n( $subscribers_total['value'] ), $success_message ) ); ?></div>
+ <?php break;
default : ?>
- <p class="error"><?php esc_html_e( 'There was an error when subscribing, please try again.', 'jetpack' ) ?></p>
+ <p class="error"><?php esc_html_e( 'There was an error when subscribing. Please try again.', 'jetpack' ); ?></p>
<?php break;
endswitch;
endif;
- // Display a subscribe form ?>
- <form action="" method="post" accept-charset="utf-8" id="subscribe-blog-<?php echo $widget_id; ?>">
+ // Display a subscribe form
+ if ( isset( $_GET['subscribe'] ) && 'success' == $_GET['subscribe'] ) { ?>
<?php
- if ( ! isset ( $_GET['subscribe'] ) ) {
- ?><p><?php echo $subscribe_text ?></p><?php
- }
-
- if ( $show_subscribers_total && 0 < $subscribers_total['value'] ) {
- echo wpautop( sprintf( _n( 'Join %s other subscriber', 'Join %s other subscribers', $subscribers_total['value'], 'jetpack' ), number_format_i18n( $subscribers_total['value'] ) ) );
- }
- ?>
-
- <p><input type="text" name="email" style="width: 95%; padding: 1px 2px" value="<?php echo !empty( $current_user->user_email ) ? esc_attr( $current_user->user_email ) : esc_html__( 'Email Address', 'jetpack' ); ?>" id="subscribe-field" onclick="if ( this.value == '<?php esc_html_e( 'Email Address', 'jetpack' ) ?>' ) { this.value = ''; }" onblur="if ( this.value == '' ) { this.value = '<?php esc_html_e( 'Email Address', 'jetpack' ) ?>'; }" /></p>
-
- <p>
- <input type="hidden" name="action" value="subscribe" />
- <input type="hidden" name="source" value="<?php echo esc_url( $referer ); ?>" />
- <input type="hidden" name="sub-type" value="<?php echo esc_attr( $source ); ?>" />
- <input type="hidden" name="redirect_fragment" value="<?php echo $widget_id; ?>" />
+ } else { ?>
+ <form action="#" method="post" accept-charset="utf-8" id="subscribe-blog-<?php echo $widget_id; ?>">
<?php
- if ( is_user_logged_in() ) {
- wp_nonce_field( 'blogsub_subscribe_'. get_current_blog_id(), '_wpnonce', false );
+ if ( ! isset ( $_GET['subscribe'] ) ) {
+ ?><div id="subscribe-text"><?php echo wpautop( str_replace( '[total-subscribers]', number_format_i18n( $subscribers_total['value'] ), $subscribe_text ) ); ?></div><?php
+ }
+
+ if ( $show_subscribers_total && 0 < $subscribers_total['value'] ) {
+ echo wpautop( sprintf( _n( 'Join %s other subscriber', 'Join %s other subscribers', $subscribers_total['value'], 'jetpack' ), number_format_i18n( $subscribers_total['value'] ) ) );
+ }
+
+ if ( ! isset ( $_GET['subscribe'] ) ) { ?>
+ <p id="subscribe-email">
+ <label id="jetpack-subscribe-label" for="<?php echo esc_attr( $subscribe_field_id ); ?>">
+ <?php echo !empty( $subscribe_placeholder ) ? esc_html( $subscribe_placeholder ) : esc_html__( 'Email Address:', 'jetpack' ); ?>
+ </label>
+ <input type="email" name="email" required="required" class="required" value="<?php echo esc_attr( $subscribe_email ); ?>" id="<?php echo esc_attr( $subscribe_field_id ); ?>" placeholder="<?php echo esc_attr( $subscribe_placeholder ); ?>" />
+ </p>
+
+ <p id="subscribe-submit">
+ <input type="hidden" name="action" value="subscribe" />
+ <input type="hidden" name="source" value="<?php echo esc_url( $referer ); ?>" />
+ <input type="hidden" name="sub-type" value="<?php echo esc_attr( $source ); ?>" />
+ <input type="hidden" name="redirect_fragment" value="<?php echo $widget_id; ?>" />
+ <?php
+ if ( is_user_logged_in() ) {
+ wp_nonce_field( 'blogsub_subscribe_'. get_current_blog_id(), '_wpnonce', false );
+ }
+ ?>
+ <input type="submit" value="<?php echo esc_attr( $subscribe_button ); ?>" name="jetpack_subscriptions_widget" />
+ </p>
+ <?php }?>
+ </form>
+
+ <script>
+ ( function( d ) {
+ if ( ( 'placeholder' in d.createElement( 'input' ) ) ) {
+ var label = d.getElementById( 'jetpack-subscribe-label' );
+ label.style.clip = 'rect(1px, 1px, 1px, 1px)';
+ label.style.position = 'absolute';
+ label.style.height = '1px';
+ label.style.width = '1px';
+ label.style.overflow = 'hidden';
}
- ?>
- <input type="submit" value="<?php echo esc_attr( $subscribe_button ); ?>" name="jetpack_subscriptions_widget" />
- </p>
- </form>
+ } ) ( document );
+ // Special check for required email input because Safari doesn't support HTML5 "required"
+ jQuery( '#subscribe-blog-<?php echo $widget_id; ?>' ).submit( function( event ) {
+ if ( jQuery( '.required' ).val() == '' ) {
+ event.preventDefault();
+ jQuery( '.required' ).focus();
+ }
+ });
+ </script>
+ <?php } ?>
<?php
echo "\n" . $args['after_widget'];
@@ -681,8 +755,9 @@ class Jetpack_Subscriptions_Widget extends WP_Widget {
$instance['title'] = wp_kses( stripslashes( $new_instance['title'] ), array() );
$instance['subscribe_text'] = wp_filter_post_kses( stripslashes( $new_instance['subscribe_text'] ) );
- $instance['subscribe_logged_in'] = wp_filter_post_kses( stripslashes( $new_instance['subscribe_logged_in'] ) );
+ $instance['subscribe_placeholder'] = wp_kses( stripslashes( $new_instance['subscribe_placeholder'] ), array() );
$instance['subscribe_button'] = wp_kses( stripslashes( $new_instance['subscribe_button'] ), array() );
+ $instance['success_message'] = wp_kses( stripslashes( $new_instance['success_message'] ), array() );
$instance['show_subscribers_total'] = isset( $new_instance['show_subscribers_total'] ) && $new_instance['show_subscribers_total'];
return $instance;
@@ -692,9 +767,9 @@ class Jetpack_Subscriptions_Widget extends WP_Widget {
return array(
'title' => esc_html__( 'Subscribe to Blog via Email', 'jetpack' ),
'subscribe_text' => esc_html__( 'Enter your email address to subscribe to this blog and receive notifications of new posts by email.', 'jetpack' ),
+ 'subscribe_placeholder' => esc_html__( 'Email Address', 'jetpack' ),
'subscribe_button' => esc_html__( 'Subscribe', 'jetpack' ),
- 'subscribe_logged_in' => esc_html__( 'Click to subscribe to this blog and receive notifications of new posts by email.', 'jetpack' ),
- 'show_subscribers_total' => true,
+ 'success_message' => esc_html__( 'Success! An email was just sent to confirm your subscription. Please find the email now and click activate to start subscribing', 'jetpack' ),
);
}
@@ -703,16 +778,9 @@ class Jetpack_Subscriptions_Widget extends WP_Widget {
$title = stripslashes( $instance['title'] );
$subscribe_text = stripslashes( $instance['subscribe_text'] );
+ $subscribe_placeholder = stripslashes( $instance['subscribe_placeholder'] );
$subscribe_button = stripslashes( $instance['subscribe_button'] );
- $show_subscribers_total = checked( $instance['show_subscribers_total'], true, false );
-
- $subs_fetch = $this->fetch_subscriber_count();
-
- if ( 'failed' == $subs_fetch['status'] ) {
- printf( '<div class="error inline"><p>' . __( '%s: %s', 'jetpack' ) . '</p></div>', esc_html( $subs_fetch['code'] ), esc_html( $subs_fetch['message'] ) );
- }
- $subscribers_total = number_format_i18n( $subs_fetch['value'] );
-
+ $success_message = stripslashes( $instance['success_message']);
?>
<p>
<label for="<?php echo $this->get_field_id( 'title' ); ?>">
@@ -727,17 +795,26 @@ class Jetpack_Subscriptions_Widget extends WP_Widget {
</label>
</p>
<p>
+ <label for="<?php echo $this->get_field_id( 'subscribe_placeholder' ); ?>">
+ <?php esc_html_e( 'Subscribe Placeholder:', 'jetpack' ); ?>
+ <input class="widefat" id="<?php echo $this->get_field_id( 'subscribe_placeholder' ); ?>" name="<?php echo $this->get_field_name( 'subscribe_placeholder' ); ?>" type="text" value="<?php echo esc_attr( $subscribe_placeholder ); ?>" />
+ </label>
+</p>
+<p>
<label for="<?php echo $this->get_field_id( 'subscribe_button' ); ?>">
<?php _e( 'Subscribe Button:', 'jetpack' ); ?>
<input class="widefat" id="<?php echo $this->get_field_id( 'subscribe_button' ); ?>" name="<?php echo $this->get_field_name( 'subscribe_button' ); ?>" type="text" value="<?php echo esc_attr( $subscribe_button ); ?>" />
</label>
</p>
<p>
- <label for="<?php echo $this->get_field_id( 'show_subscribers_total' ); ?>">
- <input type="checkbox" id="<?php echo $this->get_field_id( 'show_subscribers_total' ); ?>" name="<?php echo $this->get_field_name( 'show_subscribers_total' ); ?>" value="1"<?php echo $show_subscribers_total; ?> />
- <?php echo esc_html( sprintf( _n( 'Show total number of subscribers? (%s subscriber)', 'Show total number of subscribers? (%s subscribers)', $subscribers_total, 'jetpack' ), $subscribers_total ) ); ?>
+ <label for="<?php echo $this->get_field_id( 'success_message' ); ?>">
+ <?php _e( 'Success Message Text:', 'jetpack' ); ?>
+ <textarea style="width: 95%" id="<?php echo $this->get_field_id( 'success_message' ); ?>" name="<?php echo $this->get_field_name( 'success_message' ); ?>" type="text"><?php echo esc_html( $success_message ); ?></textarea>
</label>
</p>
+<p>
+ <small><?php esc_html_e( 'You can use the shortcode [total-subscribers] in both the text displayed to readers and the success message to show the number of subscribers to your site.', 'jetpack' ); ?></small>
+</p>
<?php
}
}
@@ -746,7 +823,7 @@ add_shortcode( 'jetpack_subscription_form', 'jetpack_do_subscription_form' );
function jetpack_do_subscription_form( $args ) {
$args['show_subscribers_total'] = empty( $args['show_subscribers_total'] ) ? false : true;
- $args = shortcode_atts( Jetpack_Subscriptions_Widget::defaults(), $args );
+ $args = shortcode_atts( Jetpack_Subscriptions_Widget::defaults(), $args, 'jetpack_subscription_form' );
ob_start();
the_widget( 'Jetpack_Subscriptions_Widget', $args );
$output = ob_get_clean();
diff --git a/plugins/jetpack/modules/subscriptions/subscriptions.css b/plugins/jetpack/modules/subscriptions/subscriptions.css
new file mode 100644
index 00000000..c70bee05
--- /dev/null
+++ b/plugins/jetpack/modules/subscriptions/subscriptions.css
@@ -0,0 +1,8 @@
+#subscribe-email input {
+ width: 95%;
+ padding: 1px 2px;
+}
+
+.comment-subscription-form .subscribe-label {
+ display: inline !important;
+}
diff --git a/plugins/jetpack/modules/theme-tools.php b/plugins/jetpack/modules/theme-tools.php
index ab746cf9..4d377344 100644
--- a/plugins/jetpack/modules/theme-tools.php
+++ b/plugins/jetpack/modules/theme-tools.php
@@ -1,64 +1,57 @@
<?php
/*
* Load code specific to themes or theme tools
+ * This file is special, and is not an actual `module` as such.
+ * It is included by ./module-extras.php
*/
-
-/**
- * INFINITE SCROLL
- */
+
+function jetpack_load_theme_tools() {
+ if ( current_theme_supports( 'tonesque' ) ) {
+ jetpack_require_lib( 'tonesque' );
+ }
+}
+add_action( 'init', 'jetpack_load_theme_tools', 30 );
/**
- * Load theme's infinite scroll annotation file, if present in the IS plugin.
- * The `setup_theme` action is used because the annotation files should be using `after_setup_theme` to register support for IS.
+ * Load theme compat file if it exists.
*
- * As released in Jetpack 2.0, a child theme's parent wasn't checked for in the plugin's bundled support, hence the convoluted way the parent is checked for now.
+ * A theme could add its own compat files here if they like. For example:
*
- * @uses is_admin, wp_get_theme, get_theme, get_current_theme, apply_filters
- * @action setup_theme
- * @return null
+ * add_filter( 'jetpack_theme_compat_files', 'mytheme_jetpack_compat_file' );
+ * function mytheme_jetpack_compat_file( $files ) {
+ * $files['mytheme'] = locate_template( 'jetpack-compat.php' );
+ * return $files;
+ * }
*/
-function jetpack_load_infinite_scroll_annotation() {
- if ( is_admin() && isset( $_GET['page'] ) && 'jetpack' == $_GET['page'] ) {
- $theme = function_exists( 'wp_get_theme' ) ? wp_get_theme() : get_theme( get_current_theme() );
-
- if ( ! is_a( $theme, 'WP_Theme' ) && ! is_array( $theme ) )
- return;
+function jetpack_load_theme_compat() {
+ $compat_files = apply_filters( 'jetpack_theme_compat_files', array(
+ 'twentyfourteen' => JETPACK__PLUGIN_DIR . 'modules/theme-tools/compat/twentyfourteen.php',
+ 'twentyfifteen' => JETPACK__PLUGIN_DIR . 'modules/theme-tools/compat/twentyfifteen.php',
+ ) );
- $customization_file = apply_filters( 'infinite_scroll_customization_file', dirname( __FILE__ ) . "/infinite-scroll/themes/{$theme['Stylesheet']}.php", $theme['Stylesheet'] );
+ _jetpack_require_compat_file( get_stylesheet(), $compat_files );
- if ( is_readable( $customization_file ) ) {
- require_once( $customization_file );
- }
- elseif ( ! empty( $theme['Template'] ) ) {
- $customization_file = dirname( __FILE__ ) . "/infinite-scroll/themes/{$theme['Template']}.php";
-
- if ( is_readable( $customization_file ) )
- require_once( $customization_file );
- }
+ if ( is_child_theme() ) {
+ _jetpack_require_compat_file( get_template(), $compat_files );
}
}
-add_action( 'setup_theme', 'jetpack_load_infinite_scroll_annotation' );
+add_action( 'after_setup_theme', 'jetpack_load_theme_compat', -1 );
+
/**
- * Prevent IS from being activated if theme doesn't support it
+ * Requires a file once, if the passed key exists in the files array.
*
- * @param bool $can_activate
- * @filter jetpack_can_activate_infinite-scroll
- * @return bool
+ * @access private
+ * @param string $key
+ * @param array $files
+ * @return void
*/
-function jetpack_can_activate_infinite_scroll( $can_activate ) {
- return (bool) current_theme_supports( 'infinite-scroll' );
-}
-add_filter( 'jetpack_can_activate_infinite-scroll', 'jetpack_can_activate_infinite_scroll' );
-
-require_once( dirname( __FILE__ ) . '/featured-content/featured-content.php' );
-
-require_once( dirname( __FILE__ ) . '/social-links.php' );
-
-require_once( dirname( __FILE__ ) . '/tonesque.php' );
-
-// Custom Post Types - we don't want a module card for these (yet)
-require_once( dirname( __FILE__ ) . '/custom-post-types/comics.php' );
-require_once( dirname( __FILE__ ) . '/custom-post-types/testimonial.php' );
+function _jetpack_require_compat_file( $key, $files ) {
+ if ( ! is_string( $key ) ) {
+ return new WP_Error( 'key_not_string', 'The specified key is not actually a string.', compact( 'key' ) );
+ }
-require_once( dirname( __FILE__ ) . '/random-redirect.php' );
+ if ( array_key_exists( $key, $files ) && is_readable( $files[ $key ] ) ) {
+ require_once $files[ $key ];
+ }
+}
diff --git a/plugins/jetpack/modules/theme-tools/compat/twentyfifteen-rtl.css b/plugins/jetpack/modules/theme-tools/compat/twentyfifteen-rtl.css
new file mode 100644
index 00000000..5d545f5b
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/compat/twentyfifteen-rtl.css
@@ -0,0 +1,752 @@
+/**
+ * Jetpack Portfolio Shortcode
+ */
+
+.site .portfolio-entry {
+ margin-bottom: 1.6em;
+}
+
+.site .portfolio-entry-title,
+.site .portfolio-entry-meta,
+.site .portfolio-entry-content {
+ font-size: 1.2rem;
+ font-size: 12px;
+ line-height: 1.5;
+}
+
+.site .portfolio-featured-image + .portfolio-entry-title {
+ margin-top: 0.75em;
+ margin-bottom: 0.75em;
+}
+
+.site .portfolio-entry-meta {
+ font-family: "Noto Sans", sans-serif;
+}
+
+.site .portfolio-entry-content .more-link:after {
+ font-size: 16px;
+ top: 1px;
+}
+
+/**
+ * Jetpack Widgets
+ */
+
+/* Blog Subscriptions Widget */
+.jetpack_subscription_widget #subscribe-email input {
+ padding: 0.375em;
+ width: 100%;
+}
+
+.jetpack_subscription_widget form > :last-child {
+ margin-bottom: 0;
+}
+
+/* Display WordPress Posts Widget */
+.widget_jetpack_display_posts_widget .jetpack-display-remote-posts {
+ margin: 0;
+}
+
+.widget_jetpack_display_posts_widget .jetpack-display-remote-posts h4 {
+ font-size: inherit;
+ margin: 0 0 1.6em;
+}
+
+.widget_jetpack_display_posts_widget .jetpack-display-remote-posts img {
+ margin: 0 0 1.6em;
+}
+
+.widget_jetpack_display_posts_widget .jetpack-display-remote-posts p {
+ font-size: inherit;
+ line-height: 1.6 !important;
+ margin: 0 0 1.6em !important;
+}
+
+.widget_jetpack_display_posts_widget .jetpack-display-remote-posts > :last-child {
+ margin-bottom: 0 !important;
+}
+
+/* Gallery Widget */
+.widget-gallery .slideshow-window {
+ border-radius: 0;
+}
+
+/* Gravatar Profile Widget */
+.widget-area .widget-grofile .grofile-thumbnail {
+ border-radius: 50%;
+ max-width: 200px;
+}
+
+.widget-area .widget-grofile h4 {
+ margin: 1.6em 0 0;
+}
+
+.widget-area .widget-grofile .grofile-accounts {
+ margin-top: 0.8em;
+}
+
+/* Image Widget */
+.widget_image .wp-caption {
+ margin-bottom: 0;
+}
+
+.widget_image .wp-caption-text {
+ padding-bottom: 0;
+}
+
+/* RSS Links Widget */
+.widget_rss_links img {
+ position: relative;
+ top: -2px;
+}
+
+
+/* List type widgets */
+.widget_rss_links ul,
+.widget_top-posts ul ,
+.widget_upcoming_events_widget ul {
+ list-style: none;
+ margin: 0;
+}
+
+.widget_rss_links li,
+.widget_top-posts li,
+.widget_upcoming_events_widget li {
+ border-top: 1px solid #eaeaea;
+ border-top: 1px solid rgba(51, 51, 51, 0.1);
+ padding: 0.7667em 0;
+}
+
+.widget_rss_links li:first-child,
+.widget_top-posts li:first-child,
+.widget_upcoming_events_widget li:first-child {
+ border-top: 0;
+ padding-top: 0;
+}
+
+.widget_rss_links li:last-child,
+.widget_top-posts li:last-child,
+.widget_upcoming_events_widget li:last-child {
+ padding-bottom: 0;
+}
+
+
+/**
+ * Shortcodes Embeds
+ */
+
+/* Facebook */
+.fb_iframe_widget {
+ margin-bottom: 1.6em;
+ max-width: 100%;
+}
+
+.fb_iframe_widget span {
+ max-width: 100%;
+}
+
+/* Gist */
+.gist table {
+ table-layout: auto;
+}
+
+.site .gist .gist-file {
+ margin-bottom: 1.5em;
+}
+
+/* Googlemaps */
+.googlemaps {
+ margin-bottom: 1.6em;
+}
+
+.googlemaps iframe {
+ margin-bottom: 0;
+}
+
+/* Polldaddy */
+.PDS_Poll {
+ display: block !important;
+ margin-bottom: 1.6em;
+}
+
+.PDS_Poll .pds-box {
+ max-width: 100%;
+ width: auto;
+}
+
+/* Presentation */
+.site .presentation-wrapper {
+ margin: 0 auto 1.6em;
+}
+
+/* Recipes */
+.site .jetpack-recipe {
+ border: 0;
+ margin: 0 0 1.6em;
+ padding: 0;
+}
+
+.site .jetpack-recipe-title {
+ border: 0;
+ margin-top: 0;
+ padding: 0;
+}
+
+.site .jetpack-recipe .jetpack-recipe-meta {
+ font-size: inherit;
+ margin: 0;
+}
+
+/* Slideshow */
+.site .slideshow-window {
+ border-radius: 0;
+ margin-bottom: 1.6em;
+}
+
+/* Twitter-timeline */
+iframe[id*="twitter-widget-"] {
+ display: block;
+}
+
+/* Vine */
+.vine-embed {
+ display: block;
+}
+
+/* VideoPress */
+.site .video-player {
+ margin-bottom: 1.6em;
+ padding: 0;
+}
+
+.video-player object {
+ margin-bottom: 0;
+}
+
+
+/**
+ * Tiled gallery
+ */
+
+.site .tiled-gallery {
+ margin-bottom: 1.6em;
+}
+
+
+/**
+ * Responsive Videos
+ */
+
+.jetpack-video-wrapper {
+ margin-bottom: 1.6em;
+}
+
+.jetpack-video-wrapper > embed,
+.jetpack-video-wrapper > iframe,
+.jetpack-video-wrapper > object,
+.jetpack-video-wrapper > .wp-video {
+ margin-bottom: 0;
+}
+
+
+/**
+ * Jetpack Comments
+ */
+
+.comment-form iframe {
+ margin: 0;
+}
+
+.comment-form .subscribe-label {
+ font-weight: 400;
+ text-transform: none;
+}
+
+.comment-subscription-form {
+ font-size: 12px;
+ font-size: 1.2rem;
+ line-height: 1.5em;
+ margin: 2em 0 0;
+}
+
+.comment-subscription-form + .comment-subscription-form {
+ margin-top: 1em;
+}
+
+
+/**
+ * Sharing
+ */
+
+.hentry div.sharedaddy h3.sd-title,
+.hentry h3.sd-title {
+ font-family: "Noto Sans", sans-serif;
+ font-size: 12px;
+ font-size: 1.2rem;
+ line-height: 1;
+ margin: 0 0 1em 0;
+ opacity: 0.7;
+ text-transform: uppercase;
+}
+
+
+/**
+ * Related Posts
+ */
+
+.hentry #jp-relatedposts {
+ margin: 0;
+ padding-top: 0;
+}
+
+.hentry .jp-relatedposts-post-title a {
+ border-bottom: 0;
+}
+
+.hentry .jp-relatedposts-headline em:before {
+ opacity: 0.7;
+}
+
+.hentry div#jp-relatedposts h3.jp-relatedposts-headline {
+ font-family: "Noto Sans", sans-serif;
+ font-size: 12px;
+ font-size: 1.2rem;
+ opacity: 0.7;
+ text-transform: uppercase;
+}
+
+.hentry div#jp-relatedposts div.jp-relatedposts-items-visual {
+ margin-left: 0;
+}
+
+.hentry div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post {
+ margin-bottom: 1.6em;
+ opacity: 1;
+}
+
+.hentry div#jp-relatedposts div.jp-relatedposts-items-visual h4.jp-relatedposts-post-title,
+.hentry div#jp-relatedposts div.jp-relatedposts-items p {
+ font-size: 1.2rem;
+ font-size: 12px;
+ line-height: 1.5;
+}
+
+.hentry .jp-relatedposts-post-title {
+ font-weight: 700;
+}
+
+.hentry div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post .jp-relatedposts-post-title a {
+ font-weight: inherit;
+}
+
+.hentry div#jp-relatedposts div.jp-relatedposts-items div.jp-relatedposts-post:hover .jp-relatedposts-post-title a,
+.hentry div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post .jp-relatedposts-post-title a {
+ text-decoration: none;
+}
+
+.hentry div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post .jp-relatedposts-post-context,
+.hentry div#jp-relatedposts div.jp-relatedposts-items-visual div.jp-relatedposts-post-nothumbs p.jp-relatedposts-post-excerpt {
+ opacity: 0.7;
+}
+
+.hentry .jp-relatedposts-post-img {
+ margin-bottom: 0.6em;
+}
+
+
+/**
+ * Stats
+ */
+
+#wpstats {
+ display: none;
+}
+
+
+/**
+ * Media Queries
+ */
+
+@media screen and (min-width: 46.25em) {
+ .site .portfolio-entry {
+ margin-bottom: 1.6471em;
+ }
+
+ .site .portfolio-entry-title,
+ .site .portfolio-entry-meta,
+ .site .portfolio-entry-content {
+ font-size: 1.4rem;
+ font-size: 14px;
+ }
+
+ .site .portfolio-entry-content .more-link:after {
+ top: 3px;
+ }
+
+ .site .hentry .gist .gist-file {
+ margin-bottom: 1.75em;
+ }
+
+ .site .widget .gist .gist-file {
+ margin-bottom: 1.3125em;
+ }
+
+ .hentry .fb_iframe_widget,
+ .hentry .googlemaps,
+ .hentry .PDS_Poll,
+ .site .hentry .presentation-wrapper,
+ .site .hentry .jetpack-recipe,
+ .site .hentry .slideshow-window,
+ .site .hentry .video-player {
+ margin-bottom: 1.6471em;
+ }
+
+ .widget .fb_iframe_widget,
+ .widget .googlemaps,
+ .widget .PDS_Poll,
+ .site .widget .presentation-wrapper,
+ .site .widget .jetpack-recipe,
+ .site .widget .slideshow-window,
+ .site .widget .video-player {
+ margin-bottom: 1.5em;
+ }
+
+ .widget_jetpack_display_posts_widget .jetpack-display-remote-posts h4,
+ .widget_jetpack_display_posts_widget .jetpack-display-remote-posts img {
+ margin: 0 0 1.5em;
+ }
+
+ .widget_jetpack_display_posts_widget .jetpack-display-remote-posts p {
+ line-height: 1.5 !important;
+ margin: 0 0 1.5em !important;
+ }
+
+ .widget-area .widget-grofile h4 {
+ margin: 1.5em 0 0;
+ }
+
+ .widget-area .widget-grofile .grofile-accounts {
+ margin-top: 0.75em;
+ }
+
+ .jetpack_subscription_widget #subscribe-email input {
+ padding: 0.5625em;
+ }
+
+ .widget_rss_links li,
+ .widget_top-posts li,
+ .widget_upcoming_events_widget li {
+ padding: 0.9643em 0;
+ }
+
+ .site .tiled-gallery {
+ margin-bottom: 1.6471em;
+ }
+
+ .jetpack-video-wrapper {
+ margin-bottom: 1.6471em;
+ }
+
+ .comment-subscription-form {
+ font-size: 14px;
+ font-size: 1.4rem;
+ }
+
+ .hentry div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post {
+ margin-bottom: 0;
+ }
+
+ .hentry div#jp-relatedposts div.jp-relatedposts-items-visual h4.jp-relatedposts-post-title,
+ .hentry div#jp-relatedposts div.jp-relatedposts-items p {
+ font-size: 1.4rem;
+ font-size: 14px;
+ }
+
+ .jp-relatedposts-post-img {
+ margin-bottom: 0.6176em;
+ }
+}
+
+@media screen and (min-width: 55em) {
+ .site .portfolio-entry {
+ margin-bottom: 1.6842em
+ }
+
+ .site .portfolio-entry-title,
+ .site .portfolio-entry-meta,
+ .site .portfolio-entry-content {
+ font-size: 1.6rem;
+ font-size: 16px;
+ }
+
+ .site .portfolio-entry-content .more-link:after {
+ font-size: 24px;
+ top: 0;
+ }
+
+ .site .hentry .gist .gist-file {
+ margin-bottom: 2em;
+ }
+
+ .site .widget .gist .gist-file {
+ margin-bottom: 1.5em;
+ }
+
+ .hentry .fb_iframe_widget,
+ .hentry .googlemaps,
+ .hentry .PDS_Poll,
+ .site .hentry .presentation-wrapper,
+ .site .hentry .jetpack-recipe,
+ .site .hentry .slideshow-window,
+ .site .hentry .video-player {
+ margin-bottom: 1.6842em;
+ }
+
+ .site .tiled-gallery {
+ margin-bottom: 1.6842em;
+ }
+
+ .jetpack_subscription_widget #subscribe-email input {
+ padding: 0.75em;
+ }
+
+ .widget_rss_links li,
+ .widget_top-posts li,
+ .widget_upcoming_events_widget li {
+ padding: 0.7188em 0;
+ }
+
+ .jetpack-video-wrapper {
+ margin-bottom: 1.6842em;
+ }
+
+ .comment-subscription-form {
+ font-size: 16px;
+ font-size: 1.6rem;
+ }
+
+ .hentry div#jp-relatedposts div.jp-relatedposts-items-visual h4.jp-relatedposts-post-title,
+ .hentry div#jp-relatedposts div.jp-relatedposts-items p {
+ font-size: 1.6rem;
+ font-size: 16px;
+ line-height: 1.5em;
+ }
+
+ .jp-relatedposts-post-img {
+ margin-bottom: 0.6315em;
+ }
+}
+
+@media screen and (min-width: 59.6875em) {
+ .site .portfolio-entry {
+ margin-bottom: 1.6em
+ }
+
+ .site .portfolio-entry-title,
+ .site .portfolio-entry-meta,
+ .site .portfolio-entry-content {
+ font-size: 1.2rem;
+ font-size: 12px;
+ }
+
+ .site .portfolio-entry-content .more-link:after {
+ font-size: 16px;
+ top: 1px;
+ }
+
+ .site .hentry .gist .gist-file {
+ margin-bottom: 1.5em;
+ }
+
+ .site .widget .gist .gist-file {
+ margin-bottom: 1.125em;
+ }
+
+ .hentry .fb_iframe_widget,
+ .hentry .googlemaps,
+ .hentry .PDS_Poll,
+ .site .hentry .presentation-wrapper,
+ .site .hentry .jetpack-recipe,
+ .site .hentry .slideshow-window,
+ .site .hentry .video-player {
+ margin-bottom: 1.6em;
+ }
+
+ .site .tiled-gallery {
+ margin-bottom: 1.6em;
+ }
+
+ .jetpack_subscription_widget #subscribe-email input {
+ padding: 0.4583em;
+ }
+
+ .jetpack-video-wrapper {
+ margin-bottom: 1.6em;
+ }
+
+ .widget-area .widget-grofile .grofile-thumbnail {
+ max-width: 100%;
+ }
+
+ .widget_rss_links li,
+ .widget_top-posts li,
+ .widget_upcoming_events_widget li {
+ padding: 0.4583em 0;
+ }
+
+ .comment-subscription-form {
+ font-size: 12px;
+ font-size: 1.2rem;
+ }
+
+ .hentry div#jp-relatedposts div.jp-relatedposts-items-visual h4.jp-relatedposts-post-title,
+ .hentry div#jp-relatedposts div.jp-relatedposts-items p {
+ font-size: 1.2rem;
+ font-size: 12px;
+ line-height: 1.5;
+ }
+
+ .jp-relatedposts-post-img {
+ margin-bottom: 0.6em;
+ }
+}
+
+@media screen and (min-width: 68.75em) {
+ .site .portfolio-entry {
+ margin-bottom: 1.6471em
+ }
+
+ .site .portfolio-entry-title,
+ .site .portfolio-entry-meta,
+ .site .portfolio-entry-content {
+ font-size: 1.4rem;
+ font-size: 14px;
+ }
+
+ .site .portfolio-entry-content .more-link:after {
+ top: 3px;
+ }
+
+ .site .hentry .gist .gist-file {
+ margin-bottom: 1.75em;
+ }
+
+ .site .widget .gist .gist-file {
+ margin-bottom: 1.3125em;
+ }
+
+ .hentry .fb_iframe_widget,
+ .hentry .googlemaps,
+ .hentry .PDS_Poll,
+ .site .hentry .presentation-wrapper,
+ .site .hentry .jetpack-recipe,
+ .site .hentry .slideshow-window,
+ .site .hentry .video-player {
+ margin-bottom: 1.6471em;
+ }
+
+ .site .tiled-gallery {
+ margin-bottom: 1.6471em;
+ }
+
+ .jetpack_subscription_widget #subscribe-email input {
+ padding: 0.5em;
+ }
+
+ .widget_rss_links li,
+ .widget_top-posts li,
+ .widget_upcoming_events_widget li {
+ padding: 0.4643em 0;
+ }
+
+ .jetpack-video-wrapper {
+ margin-bottom: 1.6471em;
+ }
+
+ .comment-subscription-form {
+ font-size: 14px;
+ font-size: 1.4rem;
+ }
+
+ .hentry div#jp-relatedposts div.jp-relatedposts-items-visual h4.jp-relatedposts-post-title,
+ .hentry div#jp-relatedposts div.jp-relatedposts-items p {
+ font-size: 14px;
+ font-size: 1.4rem;
+ }
+
+ .jp-relatedposts-post-img {
+ margin-bottom: 0.6176em;
+ }
+}
+
+@media screen and (min-width: 77.5em) {
+ .site .portfolio-entry {
+ margin-bottom: 1.6842em
+ }
+
+ .site .portfolio-entry-title,
+ .site .portfolio-entry-meta,
+ .site .portfolio-entry-content {
+ font-size: 1.6rem;
+ font-size: 16px;
+ }
+
+ .site .portfolio-entry-content .more-link:after {
+ font-size: 24px;
+ top: 0;
+ }
+
+ .site .hentry .gist .gist-file {
+ margin-bottom: 2em;
+ }
+
+ .site .widget .gist .gist-file {
+ margin-bottom: 1.5em;
+ }
+
+ .hentry .fb_iframe_widget,
+ .hentry .googlemaps,
+ .hentry .PDS_Poll,
+ .site .hentry .presentation-wrapper,
+ .site .hentry .jetpack-recipe,
+ .site .hentry .slideshow-window,
+ .site .hentry .video-player {
+ margin-bottom: 1.6842em;
+ }
+
+ .widget_rss_links li,
+ .widget_top-posts li,
+ .widget_upcoming_events_widget li {
+ padding: 0.4688em 0;
+ }
+
+ .site .tiled-gallery {
+ margin-bottom: 1.6842em;
+ }
+
+ .jetpack-video-wrapper {
+ margin-bottom: 1.6842em;
+ }
+
+ .hentry div.sharedaddy h3.sd-title,
+ .hentry div#jp-relatedposts h3.jp-relatedposts-headline {
+ font-size: 13px;
+ font-size: 1.3rem;
+ }
+
+ .comment-subscription-form {
+ font-size: 16px;
+ font-size: 1.6rem;
+ }
+
+ .hentry div#jp-relatedposts div.jp-relatedposts-items-visual h4.jp-relatedposts-post-title,
+ .hentry div#jp-relatedposts div.jp-relatedposts-items p {
+ font-size: 16px;
+ font-size: 1.6rem;
+ line-height: 1.5em;
+ }
+
+ .jp-relatedposts-post-img {
+ margin-bottom: 0.6315em;
+ }
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/theme-tools/compat/twentyfifteen.css b/plugins/jetpack/modules/theme-tools/compat/twentyfifteen.css
new file mode 100644
index 00000000..e5c44f36
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/compat/twentyfifteen.css
@@ -0,0 +1,752 @@
+/**
+ * Jetpack Portfolio Shortcode
+ */
+
+.site .portfolio-entry {
+ margin-bottom: 1.6em;
+}
+
+.site .portfolio-entry-title,
+.site .portfolio-entry-meta,
+.site .portfolio-entry-content {
+ font-size: 1.2rem;
+ font-size: 12px;
+ line-height: 1.5;
+}
+
+.site .portfolio-featured-image + .portfolio-entry-title {
+ margin-top: 0.75em;
+ margin-bottom: 0.75em;
+}
+
+.site .portfolio-entry-meta {
+ font-family: "Noto Sans", sans-serif;
+}
+
+.site .portfolio-entry-content .more-link:after {
+ font-size: 16px;
+ top: 1px;
+}
+
+/**
+ * Jetpack Widgets
+ */
+
+/* Blog Subscriptions Widget */
+.jetpack_subscription_widget #subscribe-email input {
+ padding: 0.375em;
+ width: 100%;
+}
+
+.jetpack_subscription_widget form > :last-child {
+ margin-bottom: 0;
+}
+
+/* Display WordPress Posts Widget */
+.widget_jetpack_display_posts_widget .jetpack-display-remote-posts {
+ margin: 0;
+}
+
+.widget_jetpack_display_posts_widget .jetpack-display-remote-posts h4 {
+ font-size: inherit;
+ margin: 0 0 1.6em;
+}
+
+.widget_jetpack_display_posts_widget .jetpack-display-remote-posts img {
+ margin: 0 0 1.6em;
+}
+
+.widget_jetpack_display_posts_widget .jetpack-display-remote-posts p {
+ font-size: inherit;
+ line-height: 1.6 !important;
+ margin: 0 0 1.6em !important;
+}
+
+.widget_jetpack_display_posts_widget .jetpack-display-remote-posts > :last-child {
+ margin-bottom: 0 !important;
+}
+
+/* Gallery Widget */
+.widget-gallery .slideshow-window {
+ border-radius: 0;
+}
+
+/* Gravatar Profile Widget */
+.widget-area .widget-grofile .grofile-thumbnail {
+ border-radius: 50%;
+ max-width: 200px;
+}
+
+.widget-area .widget-grofile h4 {
+ margin: 1.6em 0 0;
+}
+
+.widget-area .widget-grofile .grofile-accounts {
+ margin-top: 0.8em;
+}
+
+/* Image Widget */
+.widget_image .wp-caption {
+ margin-bottom: 0;
+}
+
+.widget_image .wp-caption-text {
+ padding-bottom: 0;
+}
+
+/* RSS Links Widget */
+.widget_rss_links img {
+ position: relative;
+ top: -2px;
+}
+
+
+/* List type widgets */
+.widget_rss_links ul,
+.widget_top-posts ul ,
+.widget_upcoming_events_widget ul {
+ list-style: none;
+ margin: 0;
+}
+
+.widget_rss_links li,
+.widget_top-posts li,
+.widget_upcoming_events_widget li {
+ border-top: 1px solid #eaeaea;
+ border-top: 1px solid rgba(51, 51, 51, 0.1);
+ padding: 0.7667em 0;
+}
+
+.widget_rss_links li:first-child,
+.widget_top-posts li:first-child,
+.widget_upcoming_events_widget li:first-child {
+ border-top: 0;
+ padding-top: 0;
+}
+
+.widget_rss_links li:last-child,
+.widget_top-posts li:last-child,
+.widget_upcoming_events_widget li:last-child {
+ padding-bottom: 0;
+}
+
+
+/**
+ * Shortcodes Embeds
+ */
+
+/* Facebook */
+.fb_iframe_widget {
+ margin-bottom: 1.6em;
+ max-width: 100%;
+}
+
+.fb_iframe_widget span {
+ max-width: 100%;
+}
+
+/* Gist */
+.gist table {
+ table-layout: auto;
+}
+
+.site .gist .gist-file {
+ margin-bottom: 1.5em;
+}
+
+/* Googlemaps */
+.googlemaps {
+ margin-bottom: 1.6em;
+}
+
+.googlemaps iframe {
+ margin-bottom: 0;
+}
+
+/* Polldaddy */
+.PDS_Poll {
+ display: block !important;
+ margin-bottom: 1.6em;
+}
+
+.PDS_Poll .pds-box {
+ max-width: 100%;
+ width: auto;
+}
+
+/* Presentation */
+.site .presentation-wrapper {
+ margin: 0 auto 1.6em;
+}
+
+/* Recipes */
+.site .jetpack-recipe {
+ border: 0;
+ margin: 0 0 1.6em;
+ padding: 0;
+}
+
+.site .jetpack-recipe-title {
+ border: 0;
+ margin-top: 0;
+ padding: 0;
+}
+
+.site .jetpack-recipe .jetpack-recipe-meta {
+ font-size: inherit;
+ margin: 0;
+}
+
+/* Slideshow */
+.site .slideshow-window {
+ border-radius: 0;
+ margin-bottom: 1.6em;
+}
+
+/* Twitter-timeline */
+iframe[id*="twitter-widget-"] {
+ display: block;
+}
+
+/* Vine */
+.vine-embed {
+ display: block;
+}
+
+/* VideoPress */
+.site .video-player {
+ margin-bottom: 1.6em;
+ padding: 0;
+}
+
+.video-player object {
+ margin-bottom: 0;
+}
+
+
+/**
+ * Tiled gallery
+ */
+
+.site .tiled-gallery {
+ margin-bottom: 1.6em;
+}
+
+
+/**
+ * Responsive Videos
+ */
+
+.jetpack-video-wrapper {
+ margin-bottom: 1.6em;
+}
+
+.jetpack-video-wrapper > embed,
+.jetpack-video-wrapper > iframe,
+.jetpack-video-wrapper > object,
+.jetpack-video-wrapper > .wp-video {
+ margin-bottom: 0;
+}
+
+
+/**
+ * Jetpack Comments
+ */
+
+.comment-form iframe {
+ margin: 0;
+}
+
+.comment-form .subscribe-label {
+ font-weight: 400;
+ text-transform: none;
+}
+
+.comment-subscription-form {
+ font-size: 12px;
+ font-size: 1.2rem;
+ line-height: 1.5em;
+ margin: 2em 0 0;
+}
+
+.comment-subscription-form + .comment-subscription-form {
+ margin-top: 1em;
+}
+
+
+/**
+ * Sharing
+ */
+
+.hentry div.sharedaddy h3.sd-title,
+.hentry h3.sd-title {
+ font-family: "Noto Sans", sans-serif;
+ font-size: 12px;
+ font-size: 1.2rem;
+ line-height: 1;
+ margin: 0 0 1em 0;
+ opacity: 0.7;
+ text-transform: uppercase;
+}
+
+
+/**
+ * Related Posts
+ */
+
+.hentry #jp-relatedposts {
+ margin: 0;
+ padding-top: 0;
+}
+
+.hentry .jp-relatedposts-post-title a {
+ border-bottom: 0;
+}
+
+.hentry .jp-relatedposts-headline em:before {
+ opacity: 0.7;
+}
+
+.hentry div#jp-relatedposts h3.jp-relatedposts-headline {
+ font-family: "Noto Sans", sans-serif;
+ font-size: 12px;
+ font-size: 1.2rem;
+ opacity: 0.7;
+ text-transform: uppercase;
+}
+
+.hentry div#jp-relatedposts div.jp-relatedposts-items-visual {
+ margin-right: 0;
+}
+
+.hentry div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post {
+ margin-bottom: 1.6em;
+ opacity: 1;
+}
+
+.hentry div#jp-relatedposts div.jp-relatedposts-items-visual h4.jp-relatedposts-post-title,
+.hentry div#jp-relatedposts div.jp-relatedposts-items p {
+ font-size: 1.2rem;
+ font-size: 12px;
+ line-height: 1.5;
+}
+
+.hentry .jp-relatedposts-post-title {
+ font-weight: 700;
+}
+
+.hentry div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post .jp-relatedposts-post-title a {
+ font-weight: inherit;
+}
+
+.hentry div#jp-relatedposts div.jp-relatedposts-items div.jp-relatedposts-post:hover .jp-relatedposts-post-title a,
+.hentry div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post .jp-relatedposts-post-title a {
+ text-decoration: none;
+}
+
+.hentry div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post .jp-relatedposts-post-context,
+.hentry div#jp-relatedposts div.jp-relatedposts-items-visual div.jp-relatedposts-post-nothumbs p.jp-relatedposts-post-excerpt {
+ opacity: 0.7;
+}
+
+.hentry .jp-relatedposts-post-img {
+ margin-bottom: 0.6em;
+}
+
+
+/**
+ * Stats
+ */
+
+#wpstats {
+ display: none;
+}
+
+
+/**
+ * Media Queries
+ */
+
+@media screen and (min-width: 46.25em) {
+ .site .portfolio-entry {
+ margin-bottom: 1.6471em;
+ }
+
+ .site .portfolio-entry-title,
+ .site .portfolio-entry-meta,
+ .site .portfolio-entry-content {
+ font-size: 1.4rem;
+ font-size: 14px;
+ }
+
+ .site .portfolio-entry-content .more-link:after {
+ top: 3px;
+ }
+
+ .site .hentry .gist .gist-file {
+ margin-bottom: 1.75em;
+ }
+
+ .site .widget .gist .gist-file {
+ margin-bottom: 1.3125em;
+ }
+
+ .hentry .fb_iframe_widget,
+ .hentry .googlemaps,
+ .hentry .PDS_Poll,
+ .site .hentry .presentation-wrapper,
+ .site .hentry .jetpack-recipe,
+ .site .hentry .slideshow-window,
+ .site .hentry .video-player {
+ margin-bottom: 1.6471em;
+ }
+
+ .widget .fb_iframe_widget,
+ .widget .googlemaps,
+ .widget .PDS_Poll,
+ .site .widget .presentation-wrapper,
+ .site .widget .jetpack-recipe,
+ .site .widget .slideshow-window,
+ .site .widget .video-player {
+ margin-bottom: 1.5em;
+ }
+
+ .widget_jetpack_display_posts_widget .jetpack-display-remote-posts h4,
+ .widget_jetpack_display_posts_widget .jetpack-display-remote-posts img {
+ margin: 0 0 1.5em;
+ }
+
+ .widget_jetpack_display_posts_widget .jetpack-display-remote-posts p {
+ line-height: 1.5 !important;
+ margin: 0 0 1.5em !important;
+ }
+
+ .widget-area .widget-grofile h4 {
+ margin: 1.5em 0 0;
+ }
+
+ .widget-area .widget-grofile .grofile-accounts {
+ margin-top: 0.75em;
+ }
+
+ .jetpack_subscription_widget #subscribe-email input {
+ padding: 0.5625em;
+ }
+
+ .widget_rss_links li,
+ .widget_top-posts li,
+ .widget_upcoming_events_widget li {
+ padding: 0.9643em 0;
+ }
+
+ .site .tiled-gallery {
+ margin-bottom: 1.6471em;
+ }
+
+ .jetpack-video-wrapper {
+ margin-bottom: 1.6471em;
+ }
+
+ .comment-subscription-form {
+ font-size: 14px;
+ font-size: 1.4rem;
+ }
+
+ .hentry div#jp-relatedposts div.jp-relatedposts-items .jp-relatedposts-post {
+ margin-bottom: 0;
+ }
+
+ .hentry div#jp-relatedposts div.jp-relatedposts-items-visual h4.jp-relatedposts-post-title,
+ .hentry div#jp-relatedposts div.jp-relatedposts-items p {
+ font-size: 1.4rem;
+ font-size: 14px;
+ }
+
+ .jp-relatedposts-post-img {
+ margin-bottom: 0.6176em;
+ }
+}
+
+@media screen and (min-width: 55em) {
+ .site .portfolio-entry {
+ margin-bottom: 1.6842em
+ }
+
+ .site .portfolio-entry-title,
+ .site .portfolio-entry-meta,
+ .site .portfolio-entry-content {
+ font-size: 1.6rem;
+ font-size: 16px;
+ }
+
+ .site .portfolio-entry-content .more-link:after {
+ font-size: 24px;
+ top: 0;
+ }
+
+ .site .hentry .gist .gist-file {
+ margin-bottom: 2em;
+ }
+
+ .site .widget .gist .gist-file {
+ margin-bottom: 1.5em;
+ }
+
+ .hentry .fb_iframe_widget,
+ .hentry .googlemaps,
+ .hentry .PDS_Poll,
+ .site .hentry .presentation-wrapper,
+ .site .hentry .jetpack-recipe,
+ .site .hentry .slideshow-window,
+ .site .hentry .video-player {
+ margin-bottom: 1.6842em;
+ }
+
+ .site .tiled-gallery {
+ margin-bottom: 1.6842em;
+ }
+
+ .jetpack_subscription_widget #subscribe-email input {
+ padding: 0.75em;
+ }
+
+ .widget_rss_links li,
+ .widget_top-posts li,
+ .widget_upcoming_events_widget li {
+ padding: 0.7188em 0;
+ }
+
+ .jetpack-video-wrapper {
+ margin-bottom: 1.6842em;
+ }
+
+ .comment-subscription-form {
+ font-size: 16px;
+ font-size: 1.6rem;
+ }
+
+ .hentry div#jp-relatedposts div.jp-relatedposts-items-visual h4.jp-relatedposts-post-title,
+ .hentry div#jp-relatedposts div.jp-relatedposts-items p {
+ font-size: 1.6rem;
+ font-size: 16px;
+ line-height: 1.5em;
+ }
+
+ .jp-relatedposts-post-img {
+ margin-bottom: 0.6315em;
+ }
+}
+
+@media screen and (min-width: 59.6875em) {
+ .site .portfolio-entry {
+ margin-bottom: 1.6em
+ }
+
+ .site .portfolio-entry-title,
+ .site .portfolio-entry-meta,
+ .site .portfolio-entry-content {
+ font-size: 1.2rem;
+ font-size: 12px;
+ }
+
+ .site .portfolio-entry-content .more-link:after {
+ font-size: 16px;
+ top: 1px;
+ }
+
+ .site .hentry .gist .gist-file {
+ margin-bottom: 1.5em;
+ }
+
+ .site .widget .gist .gist-file {
+ margin-bottom: 1.125em;
+ }
+
+ .hentry .fb_iframe_widget,
+ .hentry .googlemaps,
+ .hentry .PDS_Poll,
+ .site .hentry .presentation-wrapper,
+ .site .hentry .jetpack-recipe,
+ .site .hentry .slideshow-window,
+ .site .hentry .video-player {
+ margin-bottom: 1.6em;
+ }
+
+ .site .tiled-gallery {
+ margin-bottom: 1.6em;
+ }
+
+ .jetpack_subscription_widget #subscribe-email input {
+ padding: 0.4583em;
+ }
+
+ .jetpack-video-wrapper {
+ margin-bottom: 1.6em;
+ }
+
+ .widget-area .widget-grofile .grofile-thumbnail {
+ max-width: 100%;
+ }
+
+ .widget_rss_links li,
+ .widget_top-posts li,
+ .widget_upcoming_events_widget li {
+ padding: 0.4583em 0;
+ }
+
+ .comment-subscription-form {
+ font-size: 12px;
+ font-size: 1.2rem;
+ }
+
+ .hentry div#jp-relatedposts div.jp-relatedposts-items-visual h4.jp-relatedposts-post-title,
+ .hentry div#jp-relatedposts div.jp-relatedposts-items p {
+ font-size: 1.2rem;
+ font-size: 12px;
+ line-height: 1.5;
+ }
+
+ .jp-relatedposts-post-img {
+ margin-bottom: 0.6em;
+ }
+}
+
+@media screen and (min-width: 68.75em) {
+ .site .portfolio-entry {
+ margin-bottom: 1.6471em
+ }
+
+ .site .portfolio-entry-title,
+ .site .portfolio-entry-meta,
+ .site .portfolio-entry-content {
+ font-size: 1.4rem;
+ font-size: 14px;
+ }
+
+ .site .portfolio-entry-content .more-link:after {
+ top: 3px;
+ }
+
+ .site .hentry .gist .gist-file {
+ margin-bottom: 1.75em;
+ }
+
+ .site .widget .gist .gist-file {
+ margin-bottom: 1.3125em;
+ }
+
+ .hentry .fb_iframe_widget,
+ .hentry .googlemaps,
+ .hentry .PDS_Poll,
+ .site .hentry .presentation-wrapper,
+ .site .hentry .jetpack-recipe,
+ .site .hentry .slideshow-window,
+ .site .hentry .video-player {
+ margin-bottom: 1.6471em;
+ }
+
+ .site .tiled-gallery {
+ margin-bottom: 1.6471em;
+ }
+
+ .jetpack_subscription_widget #subscribe-email input {
+ padding: 0.5em;
+ }
+
+ .widget_rss_links li,
+ .widget_top-posts li,
+ .widget_upcoming_events_widget li {
+ padding: 0.4643em 0;
+ }
+
+ .jetpack-video-wrapper {
+ margin-bottom: 1.6471em;
+ }
+
+ .comment-subscription-form {
+ font-size: 14px;
+ font-size: 1.4rem;
+ }
+
+ .hentry div#jp-relatedposts div.jp-relatedposts-items-visual h4.jp-relatedposts-post-title,
+ .hentry div#jp-relatedposts div.jp-relatedposts-items p {
+ font-size: 14px;
+ font-size: 1.4rem;
+ }
+
+ .jp-relatedposts-post-img {
+ margin-bottom: 0.6176em;
+ }
+}
+
+@media screen and (min-width: 77.5em) {
+ .site .portfolio-entry {
+ margin-bottom: 1.6842em
+ }
+
+ .site .portfolio-entry-title,
+ .site .portfolio-entry-meta,
+ .site .portfolio-entry-content {
+ font-size: 1.6rem;
+ font-size: 16px;
+ }
+
+ .site .portfolio-entry-content .more-link:after {
+ font-size: 24px;
+ top: 0;
+ }
+
+ .site .hentry .gist .gist-file {
+ margin-bottom: 2em;
+ }
+
+ .site .widget .gist .gist-file {
+ margin-bottom: 1.5em;
+ }
+
+ .hentry .fb_iframe_widget,
+ .hentry .googlemaps,
+ .hentry .PDS_Poll,
+ .site .hentry .presentation-wrapper,
+ .site .hentry .jetpack-recipe,
+ .site .hentry .slideshow-window,
+ .site .hentry .video-player {
+ margin-bottom: 1.6842em;
+ }
+
+ .widget_rss_links li,
+ .widget_top-posts li,
+ .widget_upcoming_events_widget li {
+ padding: 0.4688em 0;
+ }
+
+ .site .tiled-gallery {
+ margin-bottom: 1.6842em;
+ }
+
+ .jetpack-video-wrapper {
+ margin-bottom: 1.6842em;
+ }
+
+ .hentry div.sharedaddy h3.sd-title,
+ .hentry div#jp-relatedposts h3.jp-relatedposts-headline {
+ font-size: 13px;
+ font-size: 1.3rem;
+ }
+
+ .comment-subscription-form {
+ font-size: 16px;
+ font-size: 1.6rem;
+ }
+
+ .hentry div#jp-relatedposts div.jp-relatedposts-items-visual h4.jp-relatedposts-post-title,
+ .hentry div#jp-relatedposts div.jp-relatedposts-items p {
+ font-size: 16px;
+ font-size: 1.6rem;
+ line-height: 1.5em;
+ }
+
+ .jp-relatedposts-post-img {
+ margin-bottom: 0.6315em;
+ }
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/theme-tools/compat/twentyfifteen.php b/plugins/jetpack/modules/theme-tools/compat/twentyfifteen.php
new file mode 100644
index 00000000..848ce2e5
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/compat/twentyfifteen.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Jetpack Compatibility File
+ * See: http://jetpack.me/
+ */
+
+function twentyfifteen_jetpack_setup() {
+ /**
+ * Add theme support for Responsive Videos.
+ */
+ add_theme_support( 'jetpack-responsive-videos' );
+}
+add_action( 'after_setup_theme', 'twentyfifteen_jetpack_setup' );
+
+function twentyfifteen_init_jetpack() {
+ /**
+ * Add our compat CSS file for custom widget stylings and such.
+ * Set the version equal to filemtime for development builds, and the JETPACK__VERSION for production
+ * or skip it entirely for wpcom.
+ */
+ $version = false;
+ if ( method_exists( 'Jetpack', 'is_development_version' ) ) {
+ $version = Jetpack::is_development_version() ? filemtime( plugin_dir_path( __FILE__ ) . 'twentyfifteen.css' ) : JETPACK__VERSION;
+ }
+ wp_enqueue_style( 'twentyfifteen-jetpack', plugins_url( 'twentyfifteen.css', __FILE__ ), array(), $version );
+ wp_style_add_data( 'twentyfifteen-jetpack', 'rtl', 'replace' );
+}
+add_action( 'init', 'twentyfifteen_init_jetpack' );
diff --git a/plugins/jetpack/modules/theme-tools/compat/twentyfourteen-rtl.css b/plugins/jetpack/modules/theme-tools/compat/twentyfourteen-rtl.css
new file mode 100644
index 00000000..e69fb00f
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/compat/twentyfourteen-rtl.css
@@ -0,0 +1,367 @@
+/**
+ * Jetpack compat stylesheet for Twenty Fourteen.
+ */
+
+#jp-post-flair:empty {
+ display: none;
+}
+
+.site-content #jp-post-flair {
+ margin: 24px 0;
+}
+
+.widget #jp-post-flair {
+ padding-top: 0;
+}
+
+.entry-content div.jp-relatedposts {
+ margin: 0;
+}
+
+div.jp-relatedposts .jp-relatedposts-headline em:after {
+ content: ":";
+}
+
+#page .entry-content div.sharedaddy h3,
+#page .entry-summary div.sharedaddy h3,
+#page .entry-content h3.sd-title,
+#page .entry-summary h3.sd-title,
+#primary div.sharedaddy .jp-relatedposts-headline em,
+.pd-rating {
+ color: #767676;
+ font-size: 11px;
+ text-transform: uppercase;
+}
+
+.pd-rating {
+ min-height: 23px;
+ margin-bottom: 5px;
+}
+
+.wp-multiplayer,
+.PDS_Poll,
+.entry-content .slideshow-window {
+ margin-bottom: 24px;
+}
+
+.entry-content .gist table {
+ margin-bottom: 0;
+}
+
+.entry-content .slideshow-window {
+ border-radius: 0;
+}
+
+.entry-content .video-player {
+ padding: 0 0 24px;
+}
+
+.highlander-enabled #respond {
+ margin: 0;
+ padding: 0;
+}
+
+.highlander-enabled #respond h3 {
+ margin: 0 0 24px;
+}
+
+.highlander-enabled #respond h3 small a {
+ width: 24px;
+}
+
+.wpcnt {
+ margin-bottom: 15px; /* 24-9 */
+}
+
+#wpstats {
+ display: none;
+}
+
+img[id*="botd"] {
+ position: absolute;
+}
+
+
+/**
+ * Widgets
+ * -----------------------------------------------------------------------------
+ */
+
+/* About.me Widget*/
+
+.aboutme_widget #am_thumbnail {
+ margin-bottom: 18px;
+}
+
+.aboutme_widget #am_thumbnail img {
+ border: 0;
+ max-width: 100%;
+}
+
+.aboutme_widget #am_name {
+ font-weight: 900;
+ margin: 0;
+}
+
+.aboutme_widget #am_headline {
+ font-size: 14px;
+ line-height: 1.2857142857;
+ margin: 0;
+}
+
+.aboutme_widget #am_bio {
+ margin: 18px 0;
+}
+
+.aboutme_widget #am_bio p {
+ margin-bottom: 6px;
+}
+
+.aboutme_widget #am_bio:empty {
+ margin: 0;
+}
+
+.aboutme_widget #am_services {
+ margin-top: 18px;
+}
+
+/* Akismet Widget */
+
+.widget_akismet_widget a,
+.content-sidebar .widget_akismet_widget a {
+ color: rgba(255,255,255,0.5) !important;
+}
+
+.widget_akismet_widget a:hover,
+.content-sidebar .widget_akismet_widget a:hover {
+ color: rgba(255,255,255,0.7) !important;
+}
+
+/* Authors Widget */
+
+.widget_authors li {
+ margin-bottom: 9px;
+}
+
+.widget_authors li:last-child {
+ margin-bottom: 0;
+}
+
+.widget_authors img {
+ margin-left: 5px;
+}
+
+/* Contact Info Widget */
+
+.widget_contact_info > div {
+ margin-bottom: 18px;
+}
+
+.widget_contact_info > div:last-child {
+ margin-bottom: 0;
+}
+
+/* Display WordPress Posts Widget */
+
+.widget_jetpack_display_posts_widget .jetpack-display-remote-posts h4 {
+ font-size: 14px;
+ line-height: 1.2857142857;
+ margin: 0 0 9px;
+}
+
+.widget_jetpack_display_posts_widget .jetpack-display-remote-posts p {
+ font-size: 14px;
+ line-height: 1.2857142857 !important;
+}
+
+.widget_jetpack_display_posts_widget .jetpack-display-remote-posts p {
+ margin: 9px 0 18px !important;
+}
+
+/* Follow Button Widget */
+
+.widget_follow_button_widget iframe {
+ margin-bottom: 0;
+}
+
+/* Gravatar & Gravatar Profile Widget */
+
+.widget_gravatar img.avatar,
+.widget-grofile .grofile-thumbnail {
+ height: auto;
+ max-width: 100% !important;
+}
+
+.widget-area .widget-grofile h4 {
+ font-size: 12px;
+ line-height: 1.2857142857;
+ margin: 18px 0 9px;
+ text-transform: uppercase;
+}
+
+.widget-area .widget-grofile .grofile-meta h4 {
+ font-size: 18px;
+ line-height: 1;
+ text-transform: none;
+}
+
+/* Image Widget */
+
+.widget_image .wp-caption,
+.widget_image .wp-caption-text {
+ margin-bottom: 0;
+}
+
+.widget_image img {
+ height: auto;
+}
+
+/* Posts I Like Widget */
+
+.widget_jetpack_posts_i_like .widgets-list-layout li {
+ margin: 0;
+}
+
+/* Recent Comments Widget */
+
+.widget_recent_comments table,
+.widget_recent_comments td {
+ border: 0;
+}
+
+.widget_recent_comments td.recentcommentsavatartop,
+.widget_recent_comments td.recentcommentsavatarend {
+ padding: 5px 0 5px 5px;
+}
+
+.widget_recent_comments td.recentcommentstexttop,
+.widget_recent_comments td.recentcommentstextend {
+ padding: 5px 5px 5px 0;
+ vertical-align: top;
+}
+
+/* Recent Images Widget */
+
+.widget_recent_images img {
+ height: auto;
+}
+
+/* Top Posts & Pages Widget */
+
+.widget_top-posts .widgets-list-layout li {
+ margin-bottom: 0;
+}
+
+/* Twitter(old) Widget */
+
+.widget_twitter li {
+ margin-bottom: 18px;
+}
+
+.widget_twitter li:last-child {
+ margin-bottom: 0;
+}
+
+.widget_twitter iframe {
+ margin: 18px 0 0;
+}
+
+/* List type Widgets */
+
+.widget_jp_blogs_i_follow li,
+.widget_delicious li,
+.widgets-list-layout li,
+.widget_top-clicks li,
+.widget_top-posts li,
+.top_rated li,
+.widget_upcoming_events_widget .upcoming-events li {
+ border-top: 1px solid rgba(255, 255, 255, 0.2);
+ padding: 8px 0 9px;
+}
+
+.widget_jp_blogs_i_follow li:first-child,
+.widgets-list-layout li:first-child,
+.widget_top-clicks li:first-child,
+.widget_top-posts li:first-child,
+.top_rated li:first-child,
+.widget_upcoming_events_widget .upcoming-events li:first-child {
+ border-top: 0;
+}
+
+.content-sidebar .widget_jp_blogs_i_follow li,
+.content-sidebar .widgets-list-layout li,
+.content-sidebar .widget_top-clicks li,
+.content-sidebar .widget_top-posts li,
+.content-sidebar .top_rated li,
+.content-sidebar .widget_upcoming_events_widget .upcoming-events li {
+ border-color: rgba(0, 0, 0, 0.1);
+}
+
+.content-sidebar widget-area .widget-grofile h4 {
+ font-weight: 900;
+}
+
+
+/**
+ * Media Queries
+ * -----------------------------------------------------------------------------
+ */
+
+@media screen and (min-width: 1008px) {
+ .footer-sidebar .widget_jp_blogs_i_follow li,
+ .footer-sidebar .widget_jp_blogs_i_follow li,
+ .footer-sidebar .widget_top-clicks li,
+ .footer-sidebar .widget_top-posts li,
+ .footer-sidebar .top_rated li,
+ .footer-sidebar .widget_upcoming_events_widget .upcoming-events li,
+ .primary-sidebar .widget_jp_blogs_i_follow li,
+ .primary-sidebar .widget_jp_blogs_i_follow li,
+ .primary-sidebar .widget_top-clicks li,
+ .primary-sidebar .widget_top-posts li,
+ .primary-sidebar .top_rated li {
+ border-top: 0;
+ padding: 0 0 6px;
+ }
+
+ .footer-sidebar .widget_jp_blogs_i_follow li:last-child,
+ .footer-sidebar .widget_jp_blogs_i_follow li:last-child,
+ .footer-sidebar .widget_top-clicks li:last-child,
+ .footer-sidebar .widget_top-posts li:last-child,
+ .footer-sidebar .top_rated li:last-child,
+ .footer-sidebar .widget_upcoming_events_widget .upcoming-events li:last-child,
+ .primary-sidebar .widget_jp_blogs_i_follow li:last-child,
+ .primary-sidebar .widget_jp_blogs_i_follow li:last-child,
+ .primary-sidebar .widget_top-clicks li:last-child,
+ .primary-sidebar .widget_top-posts li:last-child,
+ .primary-sidebar .top_rated li:last-child {
+ padding: 0;
+ }
+
+ .primary-sidebar .widget_blog_subscription input[type="text"],
+ .footer-sidebar .widget_blog_subscription input[type="text"] {
+ padding: 3px 2px !important;
+ }
+
+ .footer-sidebar .widget_jetpack_display_posts_widget .jetpack-display-remote-posts h4,
+ .primary-sidebar .widget_jetpack_display_posts_widget .jetpack-display-remote-posts h4,
+ .footer-sidebar .widget_jetpack_display_posts_widget .jetpack-display-remote-posts p,
+ .primary-sidebar .widget_jetpack_display_posts_widget .jetpack-display-remote-posts p,
+ .footer-sidebar .widget-grofile .grofile-meta h4,
+ .primary-sidebar .widget-grofile .grofile-meta h4 {
+ font-size: 12px;
+ line-height: 1.5;
+ }
+
+ .footer-sidebar .widget_jetpack_display_posts_widget .jetpack-display-remote-posts p,
+ .primary-sidebar .widget_jetpack_display_posts_widget .jetpack-display-remote-posts p {
+ line-height: 1.5 !important;
+ }
+
+ .footer-sidebar .widget-grofile h4,
+ .primary-sidebar .widget-grofile h4,
+ .footer-sidebar .top_rated div > p:first-of-type,
+ .primary-sidebar .top_rated div > p:first-of-type {
+ font-size: 11px;
+ line-height: 1.6363636363;
+ }
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/theme-tools/compat/twentyfourteen.css b/plugins/jetpack/modules/theme-tools/compat/twentyfourteen.css
new file mode 100644
index 00000000..b4d5ea2b
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/compat/twentyfourteen.css
@@ -0,0 +1,367 @@
+/**
+ * Jetpack compat stylesheet for Twenty Fourteen.
+ */
+
+#jp-post-flair:empty {
+ display: none;
+}
+
+.site-content #jp-post-flair {
+ margin: 24px 0;
+}
+
+.widget #jp-post-flair {
+ padding-top: 0;
+}
+
+.entry-content div.jp-relatedposts {
+ margin: 0;
+}
+
+div.jp-relatedposts .jp-relatedposts-headline em:after {
+ content: ":";
+}
+
+#page .entry-content div.sharedaddy h3,
+#page .entry-summary div.sharedaddy h3,
+#page .entry-content h3.sd-title,
+#page .entry-summary h3.sd-title,
+#primary div.sharedaddy .jp-relatedposts-headline em,
+.pd-rating {
+ color: #767676;
+ font-size: 11px;
+ text-transform: uppercase;
+}
+
+.pd-rating {
+ min-height: 23px;
+ margin-bottom: 5px;
+}
+
+.wp-multiplayer,
+.PDS_Poll,
+.entry-content .slideshow-window {
+ margin-bottom: 24px;
+}
+
+.entry-content .gist table {
+ margin-bottom: 0;
+}
+
+.entry-content .slideshow-window {
+ border-radius: 0;
+}
+
+.entry-content .video-player {
+ padding: 0 0 24px;
+}
+
+.highlander-enabled #respond {
+ margin: 0;
+ padding: 0;
+}
+
+.highlander-enabled #respond h3 {
+ margin: 0 0 24px;
+}
+
+.highlander-enabled #respond h3 small a {
+ width: 24px;
+}
+
+.wpcnt {
+ margin-bottom: 15px; /* 24-9 */
+}
+
+#wpstats {
+ display: none;
+}
+
+img[id*="botd"] {
+ position: absolute;
+}
+
+
+/**
+ * Widgets
+ * -----------------------------------------------------------------------------
+ */
+
+/* About.me Widget*/
+
+.aboutme_widget #am_thumbnail {
+ margin-bottom: 18px;
+}
+
+.aboutme_widget #am_thumbnail img {
+ border: 0;
+ max-width: 100%;
+}
+
+.aboutme_widget #am_name {
+ font-weight: 900;
+ margin: 0;
+}
+
+.aboutme_widget #am_headline {
+ font-size: 14px;
+ line-height: 1.2857142857;
+ margin: 0;
+}
+
+.aboutme_widget #am_bio {
+ margin: 18px 0;
+}
+
+.aboutme_widget #am_bio p {
+ margin-bottom: 6px;
+}
+
+.aboutme_widget #am_bio:empty {
+ margin: 0;
+}
+
+.aboutme_widget #am_services {
+ margin-top: 18px;
+}
+
+/* Akismet Widget */
+
+.widget_akismet_widget a,
+.content-sidebar .widget_akismet_widget a {
+ color: rgba(255,255,255,0.5) !important;
+}
+
+.widget_akismet_widget a:hover,
+.content-sidebar .widget_akismet_widget a:hover {
+ color: rgba(255,255,255,0.7) !important;
+}
+
+/* Authors Widget */
+
+.widget_authors li {
+ margin-bottom: 9px;
+}
+
+.widget_authors li:last-child {
+ margin-bottom: 0;
+}
+
+.widget_authors img {
+ margin-right: 5px;
+}
+
+/* Contact Info Widget */
+
+.widget_contact_info > div {
+ margin-bottom: 18px;
+}
+
+.widget_contact_info > div:last-child {
+ margin-bottom: 0;
+}
+
+/* Display WordPress Posts Widget */
+
+.widget_jetpack_display_posts_widget .jetpack-display-remote-posts h4 {
+ font-size: 14px;
+ line-height: 1.2857142857;
+ margin: 0 0 9px;
+}
+
+.widget_jetpack_display_posts_widget .jetpack-display-remote-posts p {
+ font-size: 14px;
+ line-height: 1.2857142857 !important;
+}
+
+.widget_jetpack_display_posts_widget .jetpack-display-remote-posts p {
+ margin: 9px 0 18px !important;
+}
+
+/* Follow Button Widget */
+
+.widget_follow_button_widget iframe {
+ margin-bottom: 0;
+}
+
+/* Gravatar & Gravatar Profile Widget */
+
+.widget_gravatar img.avatar,
+.widget-grofile .grofile-thumbnail {
+ height: auto;
+ max-width: 100% !important;
+}
+
+.widget-area .widget-grofile h4 {
+ font-size: 12px;
+ line-height: 1.2857142857;
+ margin: 18px 0 9px;
+ text-transform: uppercase;
+}
+
+.widget-area .widget-grofile .grofile-meta h4 {
+ font-size: 18px;
+ line-height: 1;
+ text-transform: none;
+}
+
+/* Image Widget */
+
+.widget_image .wp-caption,
+.widget_image .wp-caption-text {
+ margin-bottom: 0;
+}
+
+.widget_image img {
+ height: auto;
+}
+
+/* Posts I Like Widget */
+
+.widget_jetpack_posts_i_like .widgets-list-layout li {
+ margin: 0;
+}
+
+/* Recent Comments Widget */
+
+.widget_recent_comments table,
+.widget_recent_comments td {
+ border: 0;
+}
+
+.widget_recent_comments td.recentcommentsavatartop,
+.widget_recent_comments td.recentcommentsavatarend {
+ padding: 5px 5px 5px 0;
+}
+
+.widget_recent_comments td.recentcommentstexttop,
+.widget_recent_comments td.recentcommentstextend {
+ padding: 5px 0 5px 5px;
+ vertical-align: top;
+}
+
+/* Recent Images Widget */
+
+.widget_recent_images img {
+ height: auto;
+}
+
+/* Top Posts & Pages Widget */
+
+.widget_top-posts .widgets-list-layout li {
+ margin-bottom: 0;
+}
+
+/* Twitter(old) Widget */
+
+.widget_twitter li {
+ margin-bottom: 18px;
+}
+
+.widget_twitter li:last-child {
+ margin-bottom: 0;
+}
+
+.widget_twitter iframe {
+ margin: 18px 0 0;
+}
+
+/* List type Widgets */
+
+.widget_jp_blogs_i_follow li,
+.widget_delicious li,
+.widgets-list-layout li,
+.widget_top-clicks li,
+.widget_top-posts li,
+.top_rated li,
+.widget_upcoming_events_widget .upcoming-events li {
+ border-top: 1px solid rgba(255, 255, 255, 0.2);
+ padding: 8px 0 9px;
+}
+
+.widget_jp_blogs_i_follow li:first-child,
+.widgets-list-layout li:first-child,
+.widget_top-clicks li:first-child,
+.widget_top-posts li:first-child,
+.top_rated li:first-child,
+.widget_upcoming_events_widget .upcoming-events li:first-child {
+ border-top: 0;
+}
+
+.content-sidebar .widget_jp_blogs_i_follow li,
+.content-sidebar .widgets-list-layout li,
+.content-sidebar .widget_top-clicks li,
+.content-sidebar .widget_top-posts li,
+.content-sidebar .top_rated li,
+.content-sidebar .widget_upcoming_events_widget .upcoming-events li {
+ border-color: rgba(0, 0, 0, 0.1);
+}
+
+.content-sidebar widget-area .widget-grofile h4 {
+ font-weight: 900;
+}
+
+
+/**
+ * Media Queries
+ * -----------------------------------------------------------------------------
+ */
+
+@media screen and (min-width: 1008px) {
+ .footer-sidebar .widget_jp_blogs_i_follow li,
+ .footer-sidebar .widget_jp_blogs_i_follow li,
+ .footer-sidebar .widget_top-clicks li,
+ .footer-sidebar .widget_top-posts li,
+ .footer-sidebar .top_rated li,
+ .footer-sidebar .widget_upcoming_events_widget .upcoming-events li,
+ .primary-sidebar .widget_jp_blogs_i_follow li,
+ .primary-sidebar .widget_jp_blogs_i_follow li,
+ .primary-sidebar .widget_top-clicks li,
+ .primary-sidebar .widget_top-posts li,
+ .primary-sidebar .top_rated li {
+ border-top: 0;
+ padding: 0 0 6px;
+ }
+
+ .footer-sidebar .widget_jp_blogs_i_follow li:last-child,
+ .footer-sidebar .widget_jp_blogs_i_follow li:last-child,
+ .footer-sidebar .widget_top-clicks li:last-child,
+ .footer-sidebar .widget_top-posts li:last-child,
+ .footer-sidebar .top_rated li:last-child,
+ .footer-sidebar .widget_upcoming_events_widget .upcoming-events li:last-child,
+ .primary-sidebar .widget_jp_blogs_i_follow li:last-child,
+ .primary-sidebar .widget_jp_blogs_i_follow li:last-child,
+ .primary-sidebar .widget_top-clicks li:last-child,
+ .primary-sidebar .widget_top-posts li:last-child,
+ .primary-sidebar .top_rated li:last-child {
+ padding: 0;
+ }
+
+ .primary-sidebar .widget_blog_subscription input[type="text"],
+ .footer-sidebar .widget_blog_subscription input[type="text"] {
+ padding: 3px 2px !important;
+ }
+
+ .footer-sidebar .widget_jetpack_display_posts_widget .jetpack-display-remote-posts h4,
+ .primary-sidebar .widget_jetpack_display_posts_widget .jetpack-display-remote-posts h4,
+ .footer-sidebar .widget_jetpack_display_posts_widget .jetpack-display-remote-posts p,
+ .primary-sidebar .widget_jetpack_display_posts_widget .jetpack-display-remote-posts p,
+ .footer-sidebar .widget-grofile .grofile-meta h4,
+ .primary-sidebar .widget-grofile .grofile-meta h4 {
+ font-size: 12px;
+ line-height: 1.5;
+ }
+
+ .footer-sidebar .widget_jetpack_display_posts_widget .jetpack-display-remote-posts p,
+ .primary-sidebar .widget_jetpack_display_posts_widget .jetpack-display-remote-posts p {
+ line-height: 1.5 !important;
+ }
+
+ .footer-sidebar .widget-grofile h4,
+ .primary-sidebar .widget-grofile h4,
+ .footer-sidebar .top_rated div > p:first-of-type,
+ .primary-sidebar .top_rated div > p:first-of-type {
+ font-size: 11px;
+ line-height: 1.6363636363;
+ }
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/theme-tools/compat/twentyfourteen.php b/plugins/jetpack/modules/theme-tools/compat/twentyfourteen.php
new file mode 100644
index 00000000..4ee6289f
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/compat/twentyfourteen.php
@@ -0,0 +1,71 @@
+<?php
+
+/**
+ * A last try to show posts, in case the Featured Content plugin returns no IDs.
+ *
+ * @param array $featured_ids
+ * @return array
+ */
+function twentyfourteen_featured_content_post_ids( $featured_ids ) {
+ if ( empty( $featured_ids ) ) {
+ $featured_ids = array_slice( get_option( 'sticky_posts', array() ), 0, 6 );
+ }
+
+ return $featured_ids;
+}
+add_action( 'featured_content_post_ids', 'twentyfourteen_featured_content_post_ids' );
+
+/**
+ * Set the default tag name for Featured Content.
+ *
+ * @param WP_Customize_Manager $wp_customize Theme Customizer object.
+ * @return void
+ */
+function twentyfourteen_customizer_default( $wp_customize ) {
+ $wp_customize->get_setting( 'featured-content[tag-name]' )->default = 'featured';
+}
+add_action( 'customize_register', 'twentyfourteen_customizer_default' );
+
+/**
+ * Sets a default tag of 'featured' for Featured Content.
+ *
+ * @param array $settings
+ * @return array
+ */
+function twentyfourteen_featured_content_default_settings( $settings ) {
+ $settings['tag-name'] = 'featured';
+
+ return $settings;
+}
+add_action( 'featured_content_default_settings', 'twentyfourteen_featured_content_default_settings' );
+
+/**
+ * Removes sharing markup from post content if we're not in the loop and it's a
+ * formatted post.
+ *
+ * @param bool $show Whether to show sharing options.
+ * @param WP_Post $post The post to share.
+ * @return bool
+ */
+function twentyfourteen_mute_content_filters( $show, $post ) {
+ $formats = get_theme_support( 'post-formats' );
+ if ( ! in_the_loop() && has_post_format( $formats[0], $post ) ) {
+ $show = false;
+ }
+ return $show;
+}
+add_filter( 'sharing_show', 'twentyfourteen_mute_content_filters', 10, 2 );
+
+function twentyfourteen_init_jetpack() {
+ /**
+ * Add our compat CSS file for custom widget stylings and such.
+ * Set the version equal to filemtime for development builds, and the JETPACK__VERSION for production.
+ */
+ $version = false;
+ if ( method_exists( 'Jetpack', 'is_development_version' ) ) {
+ $version = Jetpack::is_development_version() ? filemtime( plugin_dir_path( __FILE__ ) . 'twentyfourteen.css' ) : JETPACK__VERSION;
+ }
+ wp_enqueue_style( 'twentyfourteen-jetpack', plugins_url( 'twentyfourteen.css', __FILE__ ), array(), $version );
+ wp_style_add_data( 'twentyfourteen-jetpack', 'rtl', 'replace' );
+}
+add_action( 'init', 'twentyfourteen_init_jetpack' );
diff --git a/plugins/jetpack/modules/theme-tools/featured-content.php b/plugins/jetpack/modules/theme-tools/featured-content.php
new file mode 100644
index 00000000..3c3bc0be
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/featured-content.php
@@ -0,0 +1,581 @@
+<?php
+
+if ( ! class_exists( 'Featured_Content' ) && isset( $GLOBALS['pagenow'] ) && 'plugins.php' !== $GLOBALS['pagenow'] ) {
+
+/**
+ * Featured Content.
+ *
+ * This module will allow users to define a subset of posts to be displayed in a
+ * theme-designated featured content area.
+ *
+ * This feature will only be activated for themes that declare that they support
+ * it. This can be done by adding code similar to the following during the
+ * "after_setup_theme" action:
+ *
+ * add_theme_support( 'featured-content', array(
+ * 'filter' => 'mytheme_get_featured_content',
+ * 'max_posts' => 20,
+ * 'post_types' => array( 'post', 'page' ),
+ * ) );
+ *
+ * For maximum compatibility with different methods of posting users will
+ * designate a featured post tag to associate posts with. Since this tag now has
+ * special meaning beyond that of a normal tags, users will have the ability to
+ * hide it from the front-end of their site.
+ */
+class Featured_Content {
+
+ /**
+ * The maximum number of posts that a Featured Content area can contain. We
+ * define a default value here but themes can override this by defining a
+ * "max_posts" entry in the second parameter passed in the call to
+ * add_theme_support( 'featured-content' ).
+ *
+ * @see Featured_Content::init()
+ */
+ public static $max_posts = 15;
+
+ /**
+ * The registered post types supported by Featured Content. Themes can add
+ * Featured Content support for registered post types by defining a
+ * 'post_types' argument (string|array) in the call to
+ * add_theme_support( 'featured-content' ).
+ *
+ * @see Featured_Content::init()
+ */
+ public static $post_types = array( 'post' );
+
+ /**
+ * Instantiate.
+ *
+ * All custom functionality will be hooked into the "init" action.
+ */
+ public static function setup() {
+ add_action( 'init', array( __CLASS__, 'init' ), 30 );
+ }
+
+ /**
+ * Conditionally hook into WordPress.
+ *
+ * Themes must declare that they support this module by adding
+ * add_theme_support( 'featured-content' ); during after_setup_theme.
+ *
+ * If no theme support is found there is no need to hook into WordPress. We'll
+ * just return early instead.
+ *
+ * @uses Featured_Content::$max_posts
+ */
+ public static function init() {
+ $theme_support = get_theme_support( 'featured-content' );
+
+ // Return early if theme does not support featured content.
+ if ( ! $theme_support ) {
+ return;
+ }
+
+ /*
+ * An array of named arguments must be passed as the second parameter
+ * of add_theme_support().
+ */
+ if ( ! isset( $theme_support[0] ) ) {
+ return;
+ }
+
+ if ( isset( $theme_support[0]['featured_content_filter'] ) ) {
+ $theme_support[0]['filter'] = $theme_support[0]['featured_content_filter'];
+ unset( $theme_support[0]['featured_content_filter'] );
+ }
+
+ // Return early if "filter" has not been defined.
+ if ( ! isset( $theme_support[0]['filter'] ) ) {
+ return;
+ }
+
+ // Theme can override the number of max posts.
+ if ( isset( $theme_support[0]['max_posts'] ) ) {
+ self::$max_posts = absint( $theme_support[0]['max_posts'] );
+ }
+
+ add_filter( $theme_support[0]['filter'], array( __CLASS__, 'get_featured_posts' ) );
+ add_action( 'customize_register', array( __CLASS__, 'customize_register' ), 9 );
+ add_action( 'admin_init', array( __CLASS__, 'register_setting' ) );
+ add_action( 'save_post', array( __CLASS__, 'delete_transient' ) );
+ add_action( 'delete_post_tag', array( __CLASS__, 'delete_post_tag' ) );
+ add_action( 'customize_controls_enqueue_scripts', array( __CLASS__, 'enqueue_scripts' ) );
+ add_action( 'pre_get_posts', array( __CLASS__, 'pre_get_posts' ) );
+ add_action( 'switch_theme', array( __CLASS__, 'switch_theme' ) );
+ add_action( 'switch_theme', array( __CLASS__, 'delete_transient' ) );
+ add_action( 'wp_loaded', array( __CLASS__, 'wp_loaded' ) );
+
+ if ( isset( $theme_support[0]['additional_post_types'] ) ) {
+ $theme_support[0]['post_types'] = array_merge( array( 'post' ), (array) $theme_support[0]['additional_post_types'] );
+ unset( $theme_support[0]['additional_post_types'] );
+ }
+
+ // Themes can allow Featured Content pages
+ if ( isset( $theme_support[0]['post_types'] ) ) {
+ self::$post_types = array_merge( self::$post_types, (array) $theme_support[0]['post_types'] );
+
+ // register post_tag support for each post type
+ foreach ( self::$post_types as $post_type ) {
+ register_taxonomy_for_object_type( 'post_tag', $post_type );
+ }
+ }
+ }
+
+ /**
+ * Hide "featured" tag from the front-end.
+ *
+ * Has to run on wp_loaded so that the preview filters of the customizer
+ * have a chance to alter the value.
+ */
+ public static function wp_loaded() {
+ if ( self::get_setting( 'hide-tag' ) ) {
+ add_filter( 'get_terms', array( __CLASS__, 'hide_featured_term' ), 10, 3 );
+ add_filter( 'get_the_terms', array( __CLASS__, 'hide_the_featured_term' ), 10, 3 );
+ }
+ }
+
+ /**
+ * Get featured posts
+ *
+ * This method is not intended to be called directly. Theme developers should
+ * place a filter directly in their theme and then pass its name as a value of
+ * the "filter" key in the array passed as the $args parameter during the call
+ * to: add_theme_support( 'featured-content', $args ).
+ *
+ * @uses Featured_Content::get_featured_post_ids()
+ *
+ * @return array
+ */
+ public static function get_featured_posts() {
+ $post_ids = self::get_featured_post_ids();
+
+ // No need to query if there is are no featured posts.
+ if ( empty( $post_ids ) ) {
+ return array();
+ }
+
+ $featured_posts = get_posts( array(
+ 'include' => $post_ids,
+ 'posts_per_page' => count( $post_ids ),
+ 'post_type' => self::$post_types,
+ ) );
+
+ return $featured_posts;
+ }
+
+ /**
+ * Get featured post IDs
+ *
+ * This function will return the an array containing the post IDs of all
+ * featured posts.
+ *
+ * Sets the "featured_content_ids" transient.
+ *
+ * @return array Array of post IDs.
+ */
+ public static function get_featured_post_ids() {
+ // Return array of cached results if they exist.
+ $featured_ids = get_transient( 'featured_content_ids' );
+ if ( ! empty( $featured_ids ) ) {
+ return array_map( 'absint', apply_filters( 'featured_content_post_ids', (array) $featured_ids ) );
+ }
+
+ $settings = self::get_setting();
+
+ // Return empty array if no tag name is set.
+ $term = get_term_by( 'name', $settings['tag-name'], 'post_tag' );
+ if ( ! $term ) {
+ $term = get_term_by( 'id', $settings['tag-id'], 'post_tag' );
+ }
+ if ( $term ) {
+ $tag = $term->term_id;
+ } else {
+ return apply_filters( 'featured_content_post_ids', array() );
+ }
+
+ // Back compat for installs that have the quantity option still set.
+ $quantity = isset( $settings['quantity'] ) ? $settings['quantity'] : self::$max_posts;
+
+ // Query for featured posts.
+ $featured = get_posts( array(
+ 'numberposts' => $quantity,
+ 'post_type' => self::$post_types,
+ 'tax_query' => array(
+ array(
+ 'field' => 'term_id',
+ 'taxonomy' => 'post_tag',
+ 'terms' => $tag,
+ ),
+ ),
+ ) );
+
+ // Return empty array if no featured content exists.
+ if ( ! $featured )
+ return apply_filters( 'featured_content_post_ids', array() );
+
+ // Ensure correct format before save/return.
+ $featured_ids = wp_list_pluck( (array) $featured, 'ID' );
+ $featured_ids = array_map( 'absint', $featured_ids );
+
+ set_transient( 'featured_content_ids', $featured_ids );
+
+ return apply_filters( 'featured_content_post_ids', $featured_ids );
+ }
+
+ /**
+ * Delete Transient.
+ *
+ * Hooks in the "save_post" action.
+ * @see Featured_Content::validate_settings().
+ */
+ public static function delete_transient() {
+ delete_transient( 'featured_content_ids' );
+ }
+
+ /**
+ * Exclude featured posts from the blog query when the blog is the front-page,
+ * and user has not checked the "Display tag content in all listings" checkbox.
+ *
+ * Filter the home page posts, and remove any featured post ID's from it.
+ * Hooked onto the 'pre_get_posts' action, this changes the parameters of the
+ * query before it gets any posts.
+ *
+ * @uses Featured_Content::get_featured_post_ids();
+ * @uses Featured_Content::get_setting();
+ * @param WP_Query $query
+ * @return WP_Query Possibly modified WP_Query
+ */
+ public static function pre_get_posts( $query ) {
+
+ // Bail if not home or not main query.
+ if ( ! $query->is_home() || ! $query->is_main_query() ) {
+ return;
+ }
+
+ // Bail if the blog page is not the front page.
+ if ( 'posts' !== get_option( 'show_on_front' ) ) {
+ return;
+ }
+
+ $featured = self::get_featured_post_ids();
+
+ // Bail if no featured posts.
+ if ( ! $featured ) {
+ return;
+ }
+
+ $settings = self::get_setting();
+
+ // Bail if the user wants featured posts always displayed.
+ if ( true == $settings['show-all'] ) {
+ return;
+ }
+
+ // We need to respect post ids already in the blacklist.
+ $post__not_in = $query->get( 'post__not_in' );
+
+ if ( ! empty( $post__not_in ) ) {
+ $featured = array_merge( (array) $post__not_in, $featured );
+ $featured = array_unique( $featured );
+ }
+
+ $query->set( 'post__not_in', $featured );
+ }
+
+ /**
+ * Reset tag option when the saved tag is deleted.
+ *
+ * It's important to mention that the transient needs to be deleted, too.
+ * While it may not be obvious by looking at the function alone, the transient
+ * is deleted by Featured_Content::validate_settings().
+ *
+ * Hooks in the "delete_post_tag" action.
+ * @see Featured_Content::validate_settings().
+ *
+ * @param int $tag_id The term_id of the tag that has been deleted.
+ * @return void
+ */
+ public static function delete_post_tag( $tag_id ) {
+ $settings = self::get_setting();
+
+ if ( empty( $settings['tag-id'] ) || $tag_id != $settings['tag-id'] ) {
+ return;
+ }
+
+ $settings['tag-id'] = 0;
+ $settings = self::validate_settings( $settings );
+ update_option( 'featured-content', $settings );
+ }
+
+ /**
+ * Hide featured tag from displaying when global terms are queried from
+ * the front-end.
+ *
+ * Hooks into the "get_terms" filter.
+ *
+ * @uses Featured_Content::get_setting()
+ *
+ * @param array $terms A list of term objects. This is the return value of get_terms().
+ * @param array $taxonomies An array of taxonomy slugs.
+ * @return array $terms
+ */
+ public static function hide_featured_term( $terms, $taxonomies, $args ) {
+
+ // This filter is only appropriate on the front-end.
+ if ( is_admin() ) {
+ return $terms;
+ }
+
+ // We only want to hide the featured tag.
+ if ( ! in_array( 'post_tag', $taxonomies ) ) {
+ return $terms;
+ }
+
+ // Bail if no terms were returned.
+ if ( empty( $terms ) ) {
+ return $terms;
+ }
+
+ // Bail if term objects are unavailable.
+ if ( 'all' != $args['fields'] ) {
+ return $terms;
+ }
+
+ $settings = self::get_setting();
+ $tag = get_term_by( 'name', $settings['tag-name'], 'post_tag' );
+
+ if ( false !== $tag ) {
+ foreach ( $terms as $order => $term ) {
+ if ( is_object( $term ) && ( $settings['tag-id'] === $term->term_id || $settings['tag-name'] === $term->name ) ) {
+ unset( $terms[ $order ] );
+ }
+ }
+ }
+
+ return $terms;
+ }
+
+ /**
+ * Hide featured tag from displaying when terms associated with a post object
+ * are queried from the front-end.
+ *
+ * Hooks into the "get_the_terms" filter.
+ *
+ * @uses Featured_Content::get_setting()
+ *
+ * @param array $terms A list of term objects. This is the return value of get_the_terms().
+ * @param int $id The ID field for the post object that terms are associated with.
+ * @param array $taxonomy An array of taxonomy slugs.
+ * @return array $terms
+ */
+ public static function hide_the_featured_term( $terms, $id, $taxonomy ) {
+
+ // This filter is only appropriate on the front-end.
+ if ( is_admin() ) {
+ return $terms;
+ }
+
+ // Make sure we are in the correct taxonomy.
+ if ( 'post_tag' != $taxonomy ) {
+ return $terms;
+ }
+
+ // No terms? Return early!
+ if ( empty( $terms ) ) {
+ return $terms;
+ }
+
+ $settings = self::get_setting();
+ $tag = get_term_by( 'name', $settings['tag-name'], 'post_tag' );
+
+ if ( false !== $tag ) {
+ foreach ( $terms as $order => $term ) {
+ if ( $settings['tag-id'] === $term->term_id || $settings['tag-name'] === $term->name ) {
+ unset( $terms[ $order ] );
+ }
+ }
+ }
+
+ return $terms;
+ }
+
+ /**
+ * Register custom setting on the Settings -> Reading screen.
+ *
+ * @uses Featured_Content::render_form()
+ * @uses Featured_Content::validate_settings()
+ *
+ * @return void
+ */
+ public static function register_setting() {
+ add_settings_field( 'featured-content', __( 'Featured Content', 'jetpack' ), array( __class__, 'render_form' ), 'reading' );
+
+ // Register sanitization callback for the Customizer.
+ register_setting( 'featured-content', 'featured-content', array( __class__, 'validate_settings' ) );
+ }
+
+ /**
+ * Add settings to the Customizer.
+ *
+ * @param WP_Customize_Manager $wp_customize Theme Customizer object.
+ */
+ public static function customize_register( $wp_customize ) {
+ $wp_customize->add_section( 'featured_content', array(
+ 'title' => __( 'Featured Content', 'jetpack' ),
+ 'description' => sprintf( __( 'Easily feature all posts with the <a href="%1$s">"featured" tag</a> or a tag of your choice. Your theme supports up to %2$s posts in its featured content area.', 'jetpack' ), admin_url( '/edit.php?tag=featured' ), absint( self::$max_posts ) ),
+ 'priority' => 130,
+ 'theme_supports' => 'featured-content',
+ ) );
+
+ /* Add Featured Content settings.
+ *
+ * Sanitization callback registered in Featured_Content::validate_settings().
+ * See http://themeshaper.com/2013/04/29/validation-sanitization-in-customizer/comment-page-1/#comment-12374
+ */
+ $wp_customize->add_setting( 'featured-content[tag-name]', array(
+ 'type' => 'option',
+ 'sanitize_js_callback' => array( __CLASS__, 'delete_transient' ),
+ ) );
+ $wp_customize->add_setting( 'featured-content[hide-tag]', array(
+ 'default' => true,
+ 'type' => 'option',
+ 'sanitize_js_callback' => array( __CLASS__, 'delete_transient' ),
+ ) );
+ $wp_customize->add_setting( 'featured-content[show-all]', array(
+ 'default' => false,
+ 'type' => 'option',
+ 'sanitize_js_callback' => array( __CLASS__, 'delete_transient' ),
+ ) );
+
+ // Add Featured Content controls.
+ $wp_customize->add_control( 'featured-content[tag-name]', array(
+ 'label' => __( 'Tag name', 'jetpack' ),
+ 'section' => 'featured_content',
+ 'theme_supports' => 'featured-content',
+ 'priority' => 20,
+ ) );
+ $wp_customize->add_control( 'featured-content[hide-tag]', array(
+ 'label' => __( 'Hide tag from displaying in post meta and tag clouds.', 'jetpack' ),
+ 'section' => 'featured_content',
+ 'theme_supports' => 'featured-content',
+ 'type' => 'checkbox',
+ 'priority' => 30,
+ ) );
+ $wp_customize->add_control( 'featured-content[show-all]', array(
+ 'label' => __( 'Display tag content in all listings.', 'jetpack' ),
+ 'section' => 'featured_content',
+ 'theme_supports' => 'featured-content',
+ 'type' => 'checkbox',
+ 'priority' => 40,
+ ) );
+ }
+
+ /**
+ * Enqueue the tag suggestion script.
+ */
+ public static function enqueue_scripts() {
+ wp_enqueue_script( 'featured-content-suggest', plugins_url( 'js/suggest.js', __FILE__ ), array( 'suggest' ), '20131022', true );
+ }
+
+ /**
+ * Renders all form fields on the Settings -> Reading screen.
+ */
+ public static function render_form() {
+ printf( __( 'The settings for Featured Content have <a href="%s">moved to Appearance &rarr; Customize</a>.', 'jetpack' ), admin_url( 'customize.php?#accordion-section-featured_content' ) );
+ }
+
+ /**
+ * Get settings
+ *
+ * Get all settings recognized by this module. This function will return all
+ * settings whether or not they have been stored in the database yet. This
+ * ensures that all keys are available at all times.
+ *
+ * In the event that you only require one setting, you may pass its name as the
+ * first parameter to the function and only that value will be returned.
+ *
+ * @param string $key The key of a recognized setting.
+ * @return mixed Array of all settings by default. A single value if passed as first parameter.
+ */
+ public static function get_setting( $key = 'all' ) {
+ $saved = (array) get_option( 'featured-content' );
+
+ $defaults = apply_filters( 'featured_content_default_settings', array(
+ 'hide-tag' => 1,
+ 'tag-id' => 0,
+ 'tag-name' => '',
+ 'show-all' => 0,
+ ) );
+
+ $options = wp_parse_args( $saved, $defaults );
+ $options = array_intersect_key( $options, $defaults );
+
+ if ( 'all' != $key ) {
+ return isset( $options[ $key ] ) ? $options[ $key ] : false;
+ }
+
+ return $options;
+ }
+
+ /**
+ * Validate settings
+ *
+ * Make sure that all user supplied content is in an expected format before
+ * saving to the database. This function will also delete the transient set in
+ * Featured_Content::get_featured_content().
+ *
+ * @uses Featured_Content::delete_transient()
+ *
+ * @param array $input
+ * @return array $output
+ */
+ public static function validate_settings( $input ) {
+ $output = array();
+
+ if ( empty( $input['tag-name'] ) ) {
+ $output['tag-id'] = 0;
+ } else {
+ $term = get_term_by( 'name', $input['tag-name'], 'post_tag' );
+
+ if ( $term ) {
+ $output['tag-id'] = $term->term_id;
+ } else {
+ $new_tag = wp_create_tag( $input['tag-name'] );
+
+ if ( ! is_wp_error( $new_tag ) && isset( $new_tag['term_id'] ) ) {
+ $output['tag-id'] = $new_tag['term_id'];
+ }
+ }
+
+ $output['tag-name'] = $input['tag-name'];
+ }
+
+ $output['hide-tag'] = isset( $input['hide-tag'] ) && $input['hide-tag'] ? 1 : 0;
+
+ $output['show-all'] = isset( $input['show-all'] ) && $input['show-all'] ? 1 : 0;
+
+ self::delete_transient();
+
+ return $output;
+ }
+
+ /**
+ * Removes the quantity setting from the options array.
+ *
+ * @return void
+ */
+ public static function switch_theme() {
+ $option = (array) get_option( 'featured-content' );
+
+ if ( isset( $option['quantity'] ) ) {
+ unset( $option['quantity'] );
+ update_option( 'featured-content', $option );
+ }
+ }
+}
+
+Featured_Content::setup();
+
+} // end if ( ! class_exists( 'Featured_Content' ) && isset( $GLOBALS['pagenow'] ) && 'plugins.php' !== $GLOBALS['pagenow'] ) {
diff --git a/plugins/jetpack/modules/theme-tools/infinite-scroll.php b/plugins/jetpack/modules/theme-tools/infinite-scroll.php
new file mode 100644
index 00000000..70f469e6
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/infinite-scroll.php
@@ -0,0 +1,47 @@
+<?php
+/**
+* INFINITE SCROLL
+*/
+
+/**
+* Load theme's infinite scroll annotation file, if present in the IS plugin.
+* The `setup_theme` action is used because the annotation files should be using `after_setup_theme` to register support for IS.
+*
+* As released in Jetpack 2.0, a child theme's parent wasn't checked for in the plugin's bundled support, hence the convoluted way the parent is checked for now.
+*
+* @uses is_admin, wp_get_theme, get_theme, get_current_theme, apply_filters
+* @action setup_theme
+* @return null
+*/
+function jetpack_load_infinite_scroll_annotation() {
+ if ( is_admin() && isset( $_GET['page'] ) && 'jetpack' == $_GET['page'] ) {
+ $theme = function_exists( 'wp_get_theme' ) ? wp_get_theme() : get_theme( get_current_theme() );
+
+ if ( ! is_a( $theme, 'WP_Theme' ) && ! is_array( $theme ) )
+ return;
+
+ $customization_file = apply_filters( 'infinite_scroll_customization_file', dirname( __FILE__ ) . "/infinite-scroll/themes/{$theme['Stylesheet']}.php", $theme['Stylesheet'] );
+
+ if ( is_readable( $customization_file ) ) {
+ require_once( $customization_file );
+ } elseif ( ! empty( $theme['Template'] ) ) {
+ $customization_file = dirname( __FILE__ ) . "/infinite-scroll/themes/{$theme['Template']}.php";
+
+ if ( is_readable( $customization_file ) )
+ require_once( $customization_file );
+ }
+ }
+}
+add_action( 'setup_theme', 'jetpack_load_infinite_scroll_annotation' );
+
+/**
+* Prevent IS from being activated if theme doesn't support it
+*
+* @param bool $can_activate
+* @filter jetpack_can_activate_infinite-scroll
+* @return bool
+*/
+function jetpack_can_activate_infinite_scroll( $can_activate ) {
+ return (bool) current_theme_supports( 'infinite-scroll' );
+}
+add_filter( 'jetpack_can_activate_infinite-scroll', 'jetpack_can_activate_infinite_scroll' );
diff --git a/plugins/jetpack/modules/theme-tools/js/suggest.js b/plugins/jetpack/modules/theme-tools/js/suggest.js
new file mode 100644
index 00000000..6145930b
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/js/suggest.js
@@ -0,0 +1,10 @@
+/*
+ * WARNING: This file is distributed verbatim in Jetpack.
+ * There should be nothing WordPress.com specific in this file.
+ *
+ */
+
+/* global ajaxurl:true */
+jQuery( function( $ ) {
+ $( '#customize-control-featured-content-tag-name input' ).suggest( ajaxurl + '?action=ajax-tag-search&tax=post_tag', { delay: 500, minchars: 2 } );
+} );
diff --git a/plugins/jetpack/modules/theme-tools/random-redirect.php b/plugins/jetpack/modules/theme-tools/random-redirect.php
new file mode 100644
index 00000000..85984712
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/random-redirect.php
@@ -0,0 +1,69 @@
+<?php
+/*
+Plugin Name: Random Redirect
+Plugin URI: http://wordpress.org/extend/plugins/random-redirect/
+Description: Allows you to create a link to yourblog.example.com/?random which will redirect someone to a random post on your blog, in a StumbleUpon-like fashion.
+Version: 1.2-wpcom
+Author: Matt Mullenweg
+Author URI: http://photomatt.net/
+*/
+
+function jetpack_matt_random_redirect() {
+ // Verify that the Random Redirect plugin this code is from is not active
+ // See http://plugins.trac.wordpress.org/ticket/1898
+ if ( ! ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ) {
+ require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
+ if ( is_plugin_active( 'random-redirect/random-redirect.php' ) ) return;
+ }
+
+ // Set default post type.
+ $post_type = get_post_type();
+
+ // Set default category type
+ if ( is_category() ) {
+ $category = get_the_category();
+ if ( isset( $category ) && ! empty( $category ) ) {
+ $random_cat_id = $category[0]->term_id;
+ }
+ }
+
+ // Set author name if we're on an author archive.
+ if ( is_author() ) {
+ $random_author_name = get_the_author_meta( 'user_login' );
+ $random_author_query = 'AND user_login = "' . $random_author_name . '"';
+ }
+
+ // Acceptable URL formats: /[...]/?random=[post type], /?random, /&random, /&random=1
+ if ( ! isset( $_GET['random'] ) && ! in_array( strtolower( $_SERVER['REQUEST_URI'] ), array( '/&random', '/&random=1' ) ) )
+ return;
+
+ // Ignore POST requests.
+ if ( ! empty( $_POST ) )
+ return;
+
+ // Persistent AppEngine abuse. ORDER BY RAND is expensive.
+ if ( strstr( $_SERVER['HTTP_USER_AGENT'], 'AppEngine-Google' ) )
+ wp_die( 'Please <a href="http://en.support.wordpress.com/contact/">contact support</a>' );
+
+ // Set the category ID if the parameter is set.
+ if ( isset( $_GET['random_cat_id'] ) )
+ $random_cat_id = (int) $_GET['random_cat_id'];
+
+ // Change the post type if the parameter is set.
+ if ( isset( $_GET['random_post_type'] ) && post_type_exists( $_GET['random_post_type'] ) )
+ $post_type = $_GET['random_post_type'];
+
+ global $wpdb;
+
+ if ( isset( $random_cat_id ) ) {
+ $random_id = $wpdb->get_var( $wpdb->prepare( "SELECT DISTINCT ID FROM $wpdb->posts AS p INNER JOIN $wpdb->term_relationships AS tr ON (p.ID = tr.object_id AND tr.term_taxonomy_id = %s) INNER JOIN $wpdb->term_taxonomy AS tt ON(tr.term_taxonomy_id = tt.term_taxonomy_id AND taxonomy = 'category') WHERE p.post_type = %s AND post_password = '' AND post_status = 'publish' %s ORDER BY RAND() LIMIT 1", $random_cat_id, $post_type, $random_author_query ) );
+ } else {
+ $random_id = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type = %s AND post_password = '' AND post_status = 'publish' %s ORDER BY RAND() LIMIT 1", $post_type, $random_author_query ) );
+ }
+
+ $permalink = get_permalink( $random_id );
+ wp_safe_redirect( $permalink );
+ exit;
+}
+
+add_action( 'template_redirect', 'jetpack_matt_random_redirect' );
diff --git a/plugins/jetpack/modules/theme-tools/responsive-videos.php b/plugins/jetpack/modules/theme-tools/responsive-videos.php
new file mode 100644
index 00000000..5e31b66c
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/responsive-videos.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Load the Responsive videos plugin
+ */
+function jetpack_responsive_videos_init() {
+
+ /* If the doesn't theme support 'jetpack-responsive-videos', don't continue */
+ if ( ! current_theme_supports( 'jetpack-responsive-videos' ) ) {
+ return;
+ }
+
+ /* If the theme does support 'jetpack-responsive-videos', wrap the videos */
+ add_filter( 'wp_video_shortcode', 'jetpack_responsive_videos_embed_html' );
+ add_filter( 'embed_oembed_html', 'jetpack_responsive_videos_embed_html' );
+ add_filter( 'video_embed_html', 'jetpack_responsive_videos_embed_html' );
+
+ /* Wrap videos in Buddypress */
+ add_filter( 'bp_embed_oembed_html', 'jetpack_responsive_videos_embed_html' );
+
+}
+add_action( 'after_setup_theme', 'jetpack_responsive_videos_init', 99 );
+
+/**
+ * Adds a wrapper to videos and enqueue script
+ *
+ * @return string
+ */
+function jetpack_responsive_videos_embed_html( $html ) {
+ if ( empty( $html ) || ! is_string( $html ) ) {
+ return $html;
+ }
+
+ if ( defined( 'SCRIPT_DEBUG' ) && true == SCRIPT_DEBUG ) {
+ wp_enqueue_script( 'jetpack-responsive-videos-script', plugins_url( 'responsive-videos/responsive-videos.js', __FILE__ ), array( 'jquery' ), '1.1', true );
+ } else {
+ wp_enqueue_script( 'jetpack-responsive-videos-min-script', plugins_url( 'responsive-videos/responsive-videos.min.js', __FILE__ ), array( 'jquery' ), '1.1', true );
+ }
+
+ return '<div class="jetpack-video-wrapper">' . $html . '</div>';
+}
diff --git a/plugins/jetpack/modules/theme-tools/responsive-videos/responsive-videos.js b/plugins/jetpack/modules/theme-tools/responsive-videos/responsive-videos.js
new file mode 100644
index 00000000..7b099225
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/responsive-videos/responsive-videos.js
@@ -0,0 +1,93 @@
+( function( $ ) {
+
+ /**
+ * A function to help debouncing.
+ */
+ var debounce = function( func, wait ) {
+
+ var timeout, args, context, timestamp;
+
+ return function() {
+
+ context = this;
+ args = [].slice.call( arguments, 0 );
+ timestamp = new Date();
+
+ var later = function() {
+
+ var last = ( new Date() ) - timestamp;
+
+ if ( last < wait ) {
+ timeout = setTimeout( later, wait - last );
+ } else {
+ timeout = null;
+ func.apply( context, args );
+ }
+
+ };
+
+ if ( ! timeout ) {
+ timeout = setTimeout( later, wait );
+ }
+
+ };
+
+ };
+
+ /**
+ * A function to resize videos.
+ */
+ function responsive_videos() {
+
+ $( '.jetpack-video-wrapper' ).find( 'embed, iframe, object' ).each( function() {
+ var video_element, video_width, video_height, video_ratio, video_wrapper, container_width;
+
+ video_element = $( this );
+
+ if ( ! video_element.attr( 'data-ratio' ) ) {
+ video_element
+ .attr( 'data-ratio', this.height / this.width )
+ .attr( 'data-width', this.width )
+ .attr( 'data-height', this.height )
+ .css( {
+ 'display' : 'block',
+ 'margin' : 0
+ } );
+ }
+
+ video_width = video_element.attr( 'data-width' );
+ video_height = video_element.attr( 'data-height' );
+ video_ratio = video_element.attr( 'data-ratio' );
+ video_wrapper = video_element.parent();
+ container_width = video_wrapper.width();
+
+ if ( video_ratio === 'Infinity' ) {
+ video_width = '100%';
+ }
+
+ video_element
+ .removeAttr( 'height' )
+ .removeAttr( 'width' );
+
+ if ( video_width > container_width ) {
+ video_element
+ .width( container_width )
+ .height( container_width * video_ratio );
+ } else {
+ video_element
+ .width( video_width )
+ .height( video_height );
+ }
+
+ } );
+
+ }
+
+ /**
+ * Load responsive_videos().
+ * Trigger resize to make sure responsive_videos() is loaded after IS.
+ */
+ $( window ).load( responsive_videos ).resize( debounce( responsive_videos, 100 ) ).trigger( 'resize' );
+ $( document ).on( 'post-load', responsive_videos );
+
+} )( jQuery ); \ No newline at end of file
diff --git a/plugins/jetpack/modules/theme-tools/responsive-videos/responsive-videos.min.js b/plugins/jetpack/modules/theme-tools/responsive-videos/responsive-videos.min.js
new file mode 100644
index 00000000..e6873a34
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/responsive-videos/responsive-videos.min.js
@@ -0,0 +1 @@
+!function(t){function a(){t(".jetpack-video-wrapper").find("embed, iframe, object").each(function(){var a=t(this);a.attr("data-ratio")||a.attr("data-ratio",this.height/this.width).attr("data-width",this.width).attr("data-height",this.height).css({display:"block",margin:0});var i=a.attr("data-width"),e=a.attr("data-height"),r=a.attr("data-ratio"),h=a.parent(),n=h.width();"Infinity"===r&&(i="100%"),a.removeAttr("height").removeAttr("width"),i>n?a.width(n).height(n*r):a.width(i).height(e)})}var i=function(t,a){var i,e,r,h;return function(){r=this,e=[].slice.call(arguments,0),h=new Date;var n=function(){var d=new Date-h;a>d?i=setTimeout(n,a-d):(i=null,t.apply(r,e))};i||(i=setTimeout(n,a))}};t(window).load(a).resize(i(a,100)).trigger("resize"),t(document).on("post-load",a)}(jQuery); \ No newline at end of file
diff --git a/plugins/jetpack/modules/theme-tools/site-breadcrumbs.php b/plugins/jetpack/modules/theme-tools/site-breadcrumbs.php
new file mode 100644
index 00000000..0e524f7b
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-breadcrumbs.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Plugin Name: Site Breadcrumbs
+ * Plugin URI: http://wordpress.com
+ * Description: Quickly add breadcrumbs to the single view of a hierarchical post type
+ * Author: Automattic
+ * Version: 1.0
+ * Author URI: http://wordpress.com
+ * License: GPL2 or later
+ */
+
+function jetpack_breadcrumbs() {
+ if ( ! is_page() || is_front_page() ) {
+ return;
+ }
+
+ global $post;
+
+ $ancestors = array_reverse( get_post_ancestors( $post->ID ) );
+
+ $before = '<nav class="entry-breadcrumbs">';
+ $after = '</nav>';
+
+ $home = '<a href="' . esc_url( home_url( "/" ) ) . '" class="home-link" rel="home">' . __( 'Home', 'jetpack' ) . '</a>';
+
+ $breadcrumb = '';
+
+ if ( $ancestors ) {
+ foreach ( $ancestors as $ancestor ) {
+ $breadcrumb .= '<a href="' . esc_url( get_permalink( $ancestor ) ) . '">' . esc_html( get_the_title( $ancestor ) ) . '</a>';
+ }
+ }
+
+ $breadcrumb .= '<span class="current-page">' . esc_html( get_the_title( $post->ID ) ) . '</span>';
+
+ echo $before . $home . $breadcrumb . $after;
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/theme-tools/site-logo.php b/plugins/jetpack/modules/theme-tools/site-logo.php
new file mode 100644
index 00000000..cbab78e4
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo.php
@@ -0,0 +1,33 @@
+<?php
+/*
+ * Plugin Name: Site Logo
+ * Plugin URI: http://wordpress.com
+ * Description: Add a logo to your WordPress site. Set it once, and all themes that support it will display it automatically.
+ * Author: Automattic
+ * Version: 1.0
+ * Author URI: http://wordpress.com
+ * License: GPL2 or later
+ * Text Domain: site-logo
+ * Domain Path: /languages/
+ */
+
+/**
+ * Activate the Site Logo plugin.
+ *
+ * @uses current_theme_supports()
+ * @since 3.2
+ */
+function site_logo_init() {
+ // Only load our code if our theme declares support, and the standalone plugin is not activated.
+ if ( current_theme_supports( 'site-logo' ) && ! class_exists( 'Site_Logo', false ) ) {
+ // Load our class for namespacing.
+ require( dirname( __FILE__ ) . '/site-logo/inc/class-site-logo.php' );
+
+ // Load template tags.
+ require( dirname( __FILE__ ) . '/site-logo/inc/functions.php' );
+
+ // Load backwards-compatible template tags.
+ require( dirname( __FILE__ ) . '/site-logo/inc/compat.php' );
+ }
+}
+add_action( 'init', 'site_logo_init' );
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control-rtl.css b/plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control-rtl.css
new file mode 100644
index 00000000..d5441db1
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control-rtl.css
@@ -0,0 +1,12 @@
+/**
+ * RTL styles for the Site Logo control. Just swaps the button sides.
+ */
+#customize-control-site_logo .remove {
+ float: right;
+ margin-left: 3px;
+}
+
+#customize-control-site_logo .new,
+#customize-control-site_logo .change {
+ float: left;
+}
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control-rtl.min.css b/plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control-rtl.min.css
new file mode 100644
index 00000000..1893fe9c
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control-rtl.min.css
@@ -0,0 +1 @@
+#customize-control-site_logo .remove{float:right;margin-left:3px}#customize-control-site_logo .change,#customize-control-site_logo .new{float:left} \ No newline at end of file
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control.css b/plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control.css
new file mode 100644
index 00000000..b9a10fe6
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control.css
@@ -0,0 +1,49 @@
+/**
+ * Styles for the Site Logo control.
+ */
+#customize-control-site_logo .current {
+ margin-bottom: 6px;
+}
+
+#customize-control-site_logo .current span {
+ border: 1px solid #eee;
+ -webkit-border-radius: 2px;
+ border-radius: 2px;
+ color: #555;
+ display: block;
+ overflow: hidden;
+ line-height: 40px;
+ min-height: 40px;
+ padding: 0 6px;
+ text-align: center;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+#customize-control-site_logo .current img {
+ max-width: 100%;
+}
+
+#customize-control-site_logo button.new,
+#customize-control-site_logo button.change,
+#customize-control-site_logo button.remove {
+ height: auto;
+ width: 48%;
+ white-space: normal;
+}
+
+#customize-control-site_logo .remove {
+ float: left;
+ margin-right: 3px;
+}
+
+#customize-control-site_logo .new,
+#customize-control-site_logo .change {
+ float: right;
+}
+
+#customize-control-site_logo .customize-control-description {
+ display: block;
+ clear: both;
+ margin-bottom: 10px;
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control.min.css b/plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control.min.css
new file mode 100644
index 00000000..7fcee5ae
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/css/site-logo-control.min.css
@@ -0,0 +1 @@
+#customize-control-site_logo .current{margin-bottom:6px}#customize-control-site_logo .current span{border:1px solid #eee;-webkit-border-radius:2px;border-radius:2px;color:#555;display:block;overflow:hidden;line-height:40px;min-height:40px;padding:0 6px;text-align:center;text-overflow:ellipsis;white-space:nowrap}#customize-control-site_logo .current img{max-width:100%}#customize-control-site_logo button.change,#customize-control-site_logo button.new,#customize-control-site_logo button.remove{height:auto;width:48%;white-space:normal}#customize-control-site_logo .remove{float:left;margin-right:3px}#customize-control-site_logo .change,#customize-control-site_logo .new{float:right}#customize-control-site_logo .customize-control-description{display:block;clear:both;margin-bottom:10px} \ No newline at end of file
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/inc/class-site-logo-control.php b/plugins/jetpack/modules/theme-tools/site-logo/inc/class-site-logo-control.php
new file mode 100644
index 00000000..c43c0211
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/inc/class-site-logo-control.php
@@ -0,0 +1,108 @@
+<?php
+/**
+ * Custom logo uploader control for the Customizer.
+ *
+ * @package Jetpack
+ */
+class Site_Logo_Image_Control extends WP_Customize_Control {
+ /**
+ * Constructor for our custom control.
+ *
+ * @param object $wp_customize
+ * @param string $control_id
+ * @param array $args
+ * @uses Site_Logo_Image_Control::l10n()
+ */
+ public function __construct( $wp_customize, $control_id, $args = array() ) {
+ // declare these first so they can be overridden
+ $this->l10n = array(
+ 'upload' => __( 'Add logo', 'jetpack' ),
+ 'set' => __( 'Set as logo', 'jetpack' ),
+ 'choose' => __( 'Choose logo', 'jetpack' ),
+ 'change' => __( 'Change logo', 'jetpack' ),
+ 'remove' => __( 'Remove logo', 'jetpack' ),
+ 'placeholder' => __( 'No logo set', 'jetpack' ),
+ );
+
+ parent::__construct( $wp_customize, $control_id, $args );
+ }
+
+ /**
+ * This will be critical for our JS constructor.
+ */
+ public $type = 'site_logo';
+
+ /**
+ * Allows overriding of global labels by a specific control.
+ */
+ public $l10n = array();
+
+ /**
+ * The type of files that should be allowed by the media modal.
+ */
+ public $mime_type = 'image';
+
+ /**
+ * Enqueue our media manager resources, scripts, and styles.
+ *
+ * @uses wp_enqueue_media()
+ * @uses wp_enqueue_style()
+ * @uses wp_enqueue_script()
+ * @uses plugins_url()
+ */
+ public function enqueue() {
+ // Enqueues all needed media resources.
+ wp_enqueue_media();
+
+ // Enqueue our control script and styles.
+ wp_enqueue_style( 'site-logo-control', plugins_url( '../css/site-logo-control.css', __FILE__ ) );
+ wp_enqueue_script( 'site-logo-control', plugins_url( '../js/site-logo-control.js', __FILE__ ), array( 'media-views', 'customize-controls', 'underscore' ), '', true );
+ }
+
+ /**
+ * Check if we have an active site logo.
+ *
+ * @uses get_option()
+ * @return boolean
+ */
+ public function has_site_logo() {
+ $logo = get_option( 'site_logo' );
+
+ if ( empty( $logo['url'] ) ) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Display our custom control in the Customizer.
+ *
+ * @uses Site_Logo_Image_Control::l10n()
+ * @uses Site_Logo_Image_Control::mime_type()
+ * @uses Site_Logo_Image_Control::label()
+ * @uses Site_Logo_Image_Control::description()
+ * @uses esc_attr()
+ * @uses esc_html()
+ */
+ public function render_content() {
+ // We do this to allow the upload control to specify certain labels
+ $l10n = json_encode( $this->l10n );
+
+ // Control title
+ printf(
+ '<span class="customize-control-title" data-l10n="%s" data-mime="%s">%s</span>',
+ esc_attr( $l10n ),
+ esc_attr( $this->mime_type ),
+ esc_html( $this->label )
+ );
+
+ // Control description
+ if ( ! empty( $this->description ) ) : ?>
+ <span class="description customize-control-description"><?php echo $this->description; ?></span>
+ <?php endif; ?>
+
+ <div class="current"></div>
+ <div class="actions"></div>
+ <?php }
+}
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/inc/class-site-logo.php b/plugins/jetpack/modules/theme-tools/site-logo/inc/class-site-logo.php
new file mode 100644
index 00000000..a2ffae30
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/inc/class-site-logo.php
@@ -0,0 +1,354 @@
+<?php
+/**
+ * Our Site Logo class for managing a theme-agnostic logo through the Customizer.
+ *
+ * @package Jetpack
+ */
+class Site_Logo {
+ /**
+ * Stores our single instance.
+ */
+ private static $instance;
+
+ /**
+ * Stores our current logo settings.
+ */
+ public $logo;
+
+ /**
+ * Return our instance, creating a new one if necessary.
+ *
+ * @uses Site_Logo::$instance
+ * @return object Site_Logo
+ */
+ public static function instance() {
+ if ( ! isset( self::$instance ) ) {
+ self::$instance = new Site_Logo;
+ self::$instance->register_hooks();
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * Get our current logo settings stored in options.
+ *
+ * @uses get_option()
+ */
+ private function __construct() {
+ $this->logo = get_option( 'site_logo', null );
+ }
+
+ /**
+ * Register our actions and filters.
+ *
+ * @uses Site_Logo::head_text_styles()
+ * @uses Site_Logo::customize_register()
+ * @uses Site_Logo::preview_enqueue()
+ * @uses Site_Logo::body_classes()
+ * @uses Site_Logo::media_manager_image_sizes()
+ * @uses add_action
+ * @uses add_filter
+ */
+ public function register_hooks() {
+ add_action( 'wp_head', array( $this, 'head_text_styles' ) );
+ add_action( 'customize_register', array( $this, 'customize_register' ) );
+ add_action( 'customize_preview_init', array( $this, 'preview_enqueue' ) );
+ add_action( 'delete_attachment', array( $this, 'reset_on_attachment_delete' ) );
+ add_filter( 'body_class', array( $this, 'body_classes' ) );
+ add_filter( 'image_size_names_choose', array( $this, 'media_manager_image_sizes' ) );
+ add_filter( 'display_media_states', array( $this, 'add_media_state' ) );
+ }
+
+ /**
+ * Add our logo uploader to the Customizer.
+ *
+ * @param object $wp_customize Customizer object.
+ * @uses current_theme_supports()
+ * @uses current_theme_supports()
+ * @uses WP_Customize_Manager::add_setting()
+ * @uses WP_Customize_Manager::add_control()
+ * @uses Site_Logo::sanitize_checkbox()
+ */
+ public function customize_register( $wp_customize ) {
+ // Include our custom control.
+ require( dirname( __FILE__ ) . '/class-site-logo-control.php' );
+
+ //Update the Customizer section title for discoverability.
+ $wp_customize->get_section('title_tagline')->title = __( 'Site Title, Tagline, and Logo', 'jetpack' );
+
+ // Add a setting to hide header text if the theme isn't supporting the feature itself
+ if ( ! current_theme_supports( 'custom-header' ) ) {
+ $wp_customize->add_setting( 'site_logo_header_text', array(
+ 'default' => 1,
+ 'sanitize_callback' => array( $this, 'sanitize_checkbox' ),
+ 'transport' => 'postMessage',
+ ) );
+
+ $wp_customize->add_control( new WP_Customize_Control( $wp_customize, 'site_logo_header_text', array(
+ 'label' => __( 'Display Header Text', 'jetpack' ),
+ 'section' => 'title_tagline',
+ 'settings' => 'site_logo_header_text',
+ 'type' => 'checkbox',
+ ) ) );
+ }
+
+ // Add the setting for our logo value.
+ $wp_customize->add_setting( 'site_logo', array(
+ 'capability' => 'manage_options',
+ 'default' => array(
+ 'id' => 0,
+ 'sizes' => array(),
+ 'url' => false,
+ ),
+ 'sanitize_callback' => array( $this, 'sanitize_logo_setting' ),
+ 'transport' => 'postMessage',
+ 'type' => 'option',
+ ) );
+
+ // Add our image uploader.
+ $wp_customize->add_control( new Site_Logo_Image_Control( $wp_customize, 'site_logo', array(
+ 'label' => __( 'Logo', 'jetpack' ),
+ 'section' => 'title_tagline',
+ 'settings' => 'site_logo',
+ ) ) );
+ }
+
+ /**
+ * Enqueue scripts for the Customizer live preview.
+ *
+ * @uses wp_enqueue_script()
+ * @uses plugins_url()
+ * @uses current_theme_supports()
+ * @uses Site_Logo::header_text_classes()
+ * @uses wp_localize_script()
+ */
+ public function preview_enqueue() {
+ wp_enqueue_script( 'site-logo-preview', plugins_url( '../js/site-logo.js', __FILE__ ), array( 'media-views' ), '', true );
+
+ // Don't bother passing in header text classes if the theme supports custom headers.
+ if ( ! current_theme_supports( 'custom-header' ) ) {
+ $classes = jetpack_sanitize_header_text_classes( $this->header_text_classes() );
+ wp_enqueue_script( 'site-logo-header-text', plugins_url( '../js/site-logo-header-text.js', __FILE__ ), array( 'media-views' ), '', true );
+ wp_localize_script( 'site-logo-header-text', 'site_logo_header_classes', $classes );
+ }
+ }
+
+ /**
+ * Get header text classes. If not defined in add_theme_support(), defaults from Underscores will be used.
+ *
+ * @uses get_theme_support
+ * @return string String of classes to hide
+ */
+ public function header_text_classes() {
+ $args = get_theme_support( 'site-logo' );
+
+ if ( isset( $args[0][ 'header-text' ] ) ) {
+ // Use any classes defined in add_theme_support().
+ $classes = $args[0][ 'header-text' ];
+ } else {
+ // Otherwise, use these defaults, which will work with any Underscores-based theme.
+ $classes = array(
+ 'site-title',
+ 'site-description',
+ );
+ }
+
+ // If we've got an array, reduce them to a string for output
+ if ( is_array( $classes ) ) {
+ $classes = (string) '.' . implode( ', .', $classes );
+ } else {
+ $classes = (string) '.' . $classes;
+ }
+
+ return $classes;
+ }
+
+ /**
+ * Hide header text on front-end if necessary.
+ *
+ * @uses current_theme_supports()
+ * @uses get_theme_mod()
+ * @uses Site_Logo::header_text_classes()
+ * @uses esc_html()
+ */
+ public function head_text_styles() {
+ // Bail if our theme supports custom headers.
+ if ( current_theme_supports( 'custom-header' ) ) {
+ return;
+ }
+
+ // Is Display Header Text unchecked? If so, we need to hide our header text.
+ if ( ! get_theme_mod( 'site_logo_header_text', 1 ) ) {
+ $classes = $this->header_text_classes();
+ ?>
+ <!-- Site Logo: hide header text -->
+ <style type="text/css">
+ <?php echo jetpack_sanitize_header_text_classes( $classes ); ?> {
+ position: absolute;
+ clip: rect(1px, 1px, 1px, 1px);
+ }
+ </style>
+ <?php
+ }
+ }
+
+ /**
+ * Determine image size to use for the logo.
+ *
+ * @uses get_theme_support()
+ * @return string Size specified in add_theme_support declaration, or 'thumbnail' default
+ */
+ public function theme_size() {
+ $args = get_theme_support( 'site-logo' );
+ $valid_sizes = get_intermediate_image_sizes();
+
+ // Add 'full' to the list of accepted values.
+ $valid_sizes[] = 'full';
+
+ // If the size declared in add_theme_support is valid, use it; otherwise, just go with 'thumbnail'.
+ $size = ( isset( $args[0]['size'] ) && in_array( $args[0]['size'], $valid_sizes ) ) ? $args[0]['size'] : 'thumbnail';
+
+ return $size;
+ }
+
+ /**
+ * Make custom image sizes available to the media manager.
+ *
+ * @param array $sizes
+ * @uses get_intermediate_image_sizes()
+ * @return array All default and registered custom image sizes.
+ */
+ public function media_manager_image_sizes( $sizes ) {
+ // Get an array of all registered image sizes.
+ $intermediate = get_intermediate_image_sizes();
+
+ // Have we got anything fun to work with?
+ if ( is_array( $intermediate ) && ! empty( $intermediate ) ) {
+ foreach ( $intermediate as $key => $size ) {
+ // If the size isn't already in the $sizes array, add it.
+ if ( ! array_key_exists( $size, $sizes ) ) {
+ $sizes[ $size ] = $size;
+ }
+ }
+ }
+
+ return $sizes;
+ }
+
+ /**
+ * Add site logos to media states in the Media Manager.
+ *
+ * @return array The current attachment's media states.
+ */
+ public function add_media_state( $media_states ) {
+ // Only bother testing if we have a site logo set.
+ if ( $this->has_site_logo() ) {
+ global $post;
+
+ // If our attachment ID and the site logo ID match, this image is the site logo.
+ if ( $post->ID == $this->logo['id'] ) {
+ $media_states[] = __( 'Site Logo', 'jetpack' );
+ }
+ }
+
+ return $media_states;
+ }
+
+ /**
+ * Reset the site logo if the current logo is deleted in the media manager.
+ *
+ * @param int $site_id
+ * @uses Site_Logo::remove_site_logo()
+ */
+ public function reset_on_attachment_delete( $post_id ) {
+ if ( $this->logo['id'] == $post_id ) {
+ $this->remove_site_logo();
+ }
+ }
+
+ /**
+ * Determine if a site logo is assigned or not.
+ *
+ * @uses Site_Logo::$logo
+ * @return boolean True if there is an active logo, false otherwise
+ */
+ public function has_site_logo() {
+ return ( isset( $this->logo['id'] ) && 0 !== $this->logo['id'] ) ? true : false;
+ }
+
+ /**
+ * Reset the site logo option to zero (empty).
+ *
+ * @uses update_option()
+ */
+ public function remove_site_logo() {
+ update_option( 'site_logo', array(
+ 'id' => (int) 0,
+ 'sizes' => array(),
+ 'url' => '',
+ ) );
+ }
+
+ /**
+ * Adds custom classes to the array of body classes.
+ *
+ * @uses Site_Logo::has_site_logo()
+ * @return array Array of <body> classes
+ */
+ public function body_classes( $classes ) {
+ // Add a class if a Site Logo is active
+ if ( $this->has_site_logo() ) {
+ $classes[] = 'has-site-logo';
+ }
+
+ return $classes;
+ }
+
+ /**
+ * Sanitize our header text Customizer setting.
+ *
+ * @param $input
+ * @return mixed 1 if checked, empty string if not checked.
+ */
+ public function sanitize_checkbox( $input ) {
+ return ( 1 == $input ) ? 1 : '';
+ }
+
+ /**
+ * Validate and sanitize a new site logo setting.
+ *
+ * @param $input
+ * @return mixed 1 if checked, empty string if not checked.
+ */
+ public function sanitize_logo_setting( $input ) {
+ $input['id'] = absint( $input['id'] );
+ $input['url'] = esc_url_raw( $input['url'] );
+
+ // If the new setting doesn't point to a valid attachment, just reset the whole thing.
+ if ( false == wp_get_attachment_image_src( $input['id'] ) ) {
+ $input = array(
+ 'id' => (int) 0,
+ 'sizes' => array(),
+ 'url' => '',
+ );
+ }
+
+ return $input;
+ }
+}
+
+/**
+ * Allow themes and plugins to access Site_Logo methods and properties.
+ *
+ * @uses Site_Logo::instance()
+ * @return object Site_Logo
+ */
+function site_logo() {
+ return Site_Logo::instance();
+}
+
+/**
+ * One site logo, please.
+ */
+site_logo();
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/inc/compat.php b/plugins/jetpack/modules/theme-tools/site-logo/inc/compat.php
new file mode 100644
index 00000000..c51ac3aa
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/inc/compat.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ * Functions for maintaining backwards compatibility with unprefixed template tags from the original Site Logo plugin.
+ * These should never be used in themes; instead, use the template tags in functions.php.
+ * See: https://github.com/Automattic/jetpack/pull/956
+ *
+ * @package Jetpack
+ */
+
+if ( ! function_exists( 'the_site_logo' ) ) :
+/**
+ * Unprefixed, backwards-compatible function for outputting the site logo.
+ *
+ * @uses jetpack_the_site_logo()
+ */
+function the_site_logo() {
+ jetpack_the_site_logo();
+}
+endif;
+
+if ( ! function_exists( 'has_site_logo' ) ) :
+/**
+ * Unprefixed, backwards-compatible function for determining if a site logo has been set.
+ *
+ * @uses jetpack_has_site_logo()
+ * @return bool True if a site logo is set, false otherwise.
+ */
+function has_site_logo() {
+ return jetpack_has_site_logo();
+}
+endif;
+
+if ( ! function_exists( 'get_site_logo' ) ) :
+/**
+ * Unprefixed, backwards-compatible function for getting either the site logo's image URL or its ID.
+ *
+ * @param string $show Return the site logo URL or ID.
+ * @uses jetpack_get_site_logo()
+ * @return string Site logo ID or URL (the default).
+ */
+function get_site_logo( $show = 'url' ) {
+ return jetpack_get_site_logo( $show );
+}
+endif;
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/inc/functions.php b/plugins/jetpack/modules/theme-tools/site-logo/inc/functions.php
new file mode 100644
index 00000000..23a8f23e
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/inc/functions.php
@@ -0,0 +1,116 @@
+<?php
+/**
+ * Functions and template tags for using site logos.
+ *
+ * @package Jetpack
+ */
+
+/**
+ * Retrieve the site logo URL or ID (URL by default). Pass in the string 'id' for ID.
+ *
+ * @uses get_option()
+ * @uses esc_url_raw()
+ * @uses set_url_scheme()
+ * @return mixed The URL or ID of our site logo, false if not set
+ * @since 1.0
+ */
+function jetpack_get_site_logo( $show = 'url' ) {
+ $logo = site_logo()->logo;
+
+ // Return false if no logo is set
+ if ( ! isset( $logo['id'] ) || 0 == $logo['id'] ) {
+ return false;
+ }
+
+ // Return the ID if specified, otherwise return the URL by default
+ if ( 'id' == $show ) {
+ return $logo['id'];
+ } else {
+ return esc_url_raw( set_url_scheme( $logo['url'] ) );
+ }
+}
+
+/**
+ * Determine if a site logo is assigned or not.
+ *
+ * @uses get_option
+ * @return boolean True if there is an active logo, false otherwise
+ */
+function jetpack_has_site_logo() {
+ return site_logo()->has_site_logo();
+}
+
+/**
+ * Output an <img> tag of the site logo, at the size specified
+ * in the theme's add_theme_support() declaration.
+ *
+ * @uses Site_Logo::logo
+ * @uses Site_Logo::theme_size()
+ * @uses jetpack_has_site_logo()
+ * @uses jetpack_is_customize_preview()
+ * @uses esc_url()
+ * @uses home_url()
+ * @uses esc_attr()
+ * @uses wp_get_attachment_image()
+ * @uses apply_filters()
+ * @since 1.0
+ */
+function jetpack_the_site_logo() {
+ $logo = site_logo()->logo;
+ $size = site_logo()->theme_size();
+ $html = '';
+
+ // If no logo is set, but we're in the Customizer, leave a placeholder (needed for the live preview).
+ if ( ! jetpack_has_site_logo() ) {
+ if ( jetpack_is_customize_preview() ) {
+ $html = sprintf( '<a href="%1$s" class="site-logo-link" style="display:none;"><img class="site-logo" data-size="%2$s" /></a>',
+ esc_url( home_url( '/' ) ),
+ esc_attr( $size )
+ );
+ }
+ }
+
+ // We have a logo. Logo is go.
+ else {
+ $html = sprintf( '<a href="%1$s" class="site-logo-link" rel="home" itemprop="url">%2$s</a>',
+ esc_url( home_url( '/' ) ),
+ wp_get_attachment_image(
+ $logo['id'],
+ $size,
+ false,
+ array(
+ 'class' => "site-logo attachment-$size",
+ 'data-size' => $size,
+ 'itemprop' => "logo"
+ )
+ )
+ );
+ }
+
+ echo apply_filters( 'jetpack_the_site_logo', $html, $logo, $size );
+}
+
+/**
+ * Whether the site is being previewed in the Customizer.
+ * Duplicate of core function until 4.0 is released.
+ *
+ * @global WP_Customize_Manager $wp_customize Customizer instance.
+ * @return bool True if the site is being previewed in the Customizer, false otherwise.
+ */
+function jetpack_is_customize_preview() {
+ global $wp_customize;
+
+ return is_a( $wp_customize, 'WP_Customize_Manager' ) && $wp_customize->is_preview();
+}
+
+/**
+ * Sanitize the string of classes used for header text.
+ * Limit to A-Z,a-z,0-9,(space),(comma),_,-
+ *
+ * @return string Sanitized string of CSS classes.
+ */
+function jetpack_sanitize_header_text_classes( $classes ) {
+ $classes = preg_replace( '/[^A-Za-z0-9\,\ ._-]/', '', $classes );
+
+ return $classes;
+}
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-control.js b/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-control.js
new file mode 100644
index 00000000..e44c3923
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-control.js
@@ -0,0 +1,154 @@
+/**
+ * JS for handling the Site Logo Customizer control.
+ */
+(function( wp, $ ){
+ // nice shortcut
+ var api = wp.customize;
+ /**
+ * The Customizer looks for wp.customizer.controlConstructor[type] functions
+ * where type == the type member of a WP_Customize_Control
+ */
+ api.controlConstructor.site_logo = api.Control.extend({
+ /**
+ * This method is called when the control is ready to run.
+ * Do all of your setup and event binding here.
+ */
+ ready: function() {
+ // this.container is a jQuery object of your container
+
+ // grab the bits of data from the title for specifying this control
+ var data = this.container.find( '.customize-control-title' ).data();
+
+ // Use specific l10n data for this control where available
+ this.l10n = data.l10n;
+ // Grab mime type
+ this.mime = data.mime;
+
+ // Set up image container and button elements. Cache for re-use.
+ this.$imgContainer = $( '#customize-control-site_logo .current' );
+ this.$btnContainer = $( '#customize-control-site_logo .actions' );
+ this.$img = $( '<img class="site-logo-thumbnail" />' ).prependTo( this.$imgContainer );
+ this.$placeholder = $( '<span>' + this.l10n.placeholder + '</span>' ).prependTo( this.$imgContainer );
+ this.$btnAdd = $( '<button type="button" class="button new">' + this.l10n.upload + '</button>' ).prependTo( this.$btnContainer );
+ this.$btnChange = $( '<button type="button" class="button change">' + this.l10n.change + '</button>' ).prependTo( this.$btnContainer );
+ this.$btnRemove = $( '<button type="button" class="button remove">' + this.l10n.remove + '</button>' ).prependTo( this.$btnContainer );
+
+ // handy shortcut so we don't have to us _.bind every time we add a callback
+ _.bindAll( this, 'removeImg', 'upload', 'render', 'pick' );
+
+ this.$btnAdd.on( 'click', this.upload );
+ this.$btnChange.on( 'click', this.upload );
+ this.$btnRemove.on( 'click', this.removeImg );
+
+ // Call render method whenever setting is changed.
+ this.setting.bind( 'change', this.render );
+ // Do initial rendering.
+ this.render();
+ },
+ /**
+ * Remember that _.bind was used to maintain `this` as the control
+ * object rather than the usual jQuery way of binding to the DOM element.
+ */
+ upload: function( event ) {
+ event.preventDefault();
+
+ if ( ! this.frame ) {
+ this.initFrame();
+ }
+
+ this.frame.open();
+ },
+ /**
+ * Set the media frame so that it can be reused and accessed when needed.
+ */
+ initFrame: function() {
+ this.frame = wp.media({
+ // The title of the media modal
+ title: this.l10n.choose,
+ // restrict to specified mime type
+ library: {
+ type: this.mime
+ },
+ // Customize the submit button.
+ button: {
+ // Set the text of the button.
+ text: this.l10n.set
+ },
+ // Just one, thanks.
+ multiple: false
+ });
+
+ // When an image is selected, run a callback.
+ this.frame.on( 'select', this.pick );
+ },
+ /**
+ * Fired when an image is selected in the media modal. Gets the selected
+ * image information, and sets it within the control.
+ */
+ pick: function() {
+ // get the attachment from the modal frame
+ var attachment = this.frame.state().get( 'selection' ).first().toJSON();
+ attachment = this.reduceMembers( attachment );
+ // set the setting - the callback will take care of rendering
+ this.setting( attachment );
+ },
+ /**
+ * Reduces the attachment object to just the few desired members.
+ * @param {object} attachment An attachment object provided by the
+ * medial modal.
+ * @return {object} A reduced media object.
+ */
+ reduceMembers: function( attachment ) {
+ var desired = [
+ 'id',
+ 'sizes',
+ 'url'
+ ],
+ output = {};
+ $.each( desired, function( i, key ){
+ output[key] = attachment[key];
+ });
+ return output;
+ },
+ /**
+ * Called on init and whenever a setting is changed. Shows the thumbnail
+ * when there is one or the upload button when there isn't.
+ */
+ render: function() {
+ var value = this.setting();
+
+ if ( value && value.url ) {
+ this.$placeholder.hide();
+ if ( ! value.sizes || ! value.sizes.medium ) {
+ this.$img.attr( 'src', value.url );
+ } else {
+ this.$img.attr( 'src', value.sizes.medium.url );
+ }
+ this.$img.show();
+ this.$btnRemove.show();
+ this.$btnChange.show();
+ this.$btnAdd.hide();
+ } else {
+ this.$img.hide();
+ this.$placeholder.show();
+ this.$btnRemove.hide();
+ this.$btnChange.hide();
+ this.$btnAdd.show();
+ }
+ },
+ /**
+ * Called when the "Remove Image" link is clicked. Sets thes setting back
+ * to its default state.
+ * @param {object} event jQuery Event object from click event
+ */
+ removeImg: function( event ) {
+ event.preventDefault();
+ this.setting( {
+ url: '',
+ id: 0
+ } );
+ }
+
+ });
+
+})( this.wp, jQuery ); \ No newline at end of file
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-control.min.js b/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-control.min.js
new file mode 100644
index 00000000..171d98e8
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-control.min.js
@@ -0,0 +1 @@
+(function(a,c){var b=a.customize;b.controlConstructor.site_logo=b.Control.extend({ready:function(){var d=this.container.find(".customize-control-title").data();this.l10n=d.l10n;this.mime=d.mime;this.$imgContainer=c("#customize-control-site_logo .current");this.$btnContainer=c("#customize-control-site_logo .actions");this.$img=c('<img class="site-logo-thumbnail" />').prependTo(this.$imgContainer);this.$placeholder=c("<span>"+this.l10n.placeholder+"</span>").prependTo(this.$imgContainer);this.$btnAdd=c('<button type="button" class="button new">'+this.l10n.upload+"</button>").prependTo(this.$btnContainer);this.$btnChange=c('<button type="button" class="button change">'+this.l10n.change+"</button>").prependTo(this.$btnContainer);this.$btnRemove=c('<button type="button" class="button remove">'+this.l10n.remove+"</button>").prependTo(this.$btnContainer);_.bindAll(this,"removeImg","upload","render","pick");this.$btnAdd.on("click",this.upload);this.$btnChange.on("click",this.upload);this.$btnRemove.on("click",this.removeImg);this.setting.bind("change",this.render);this.render()},upload:function(d){d.preventDefault();if(!this.frame){this.initFrame()}this.frame.open()},initFrame:function(){this.frame=a.media({title:this.l10n.choose,library:{type:this.mime},button:{text:this.l10n.set},multiple:false});this.frame.on("select",this.pick)},pick:function(){var d=this.frame.state().get("selection").first().toJSON();d=this.reduceMembers(d);this.setting(d)},reduceMembers:function(f){var e=["id","sizes","url"],d={};c.each(e,function(h,g){d[g]=f[g]});return d},render:function(){var d=this.setting();if(d&&d.url){this.$placeholder.hide();if(!d.sizes||!d.sizes.medium){this.$img.attr("src",d.url)}else{this.$img.attr("src",d.sizes.medium.url)}this.$img.show();this.$btnRemove.show();this.$btnChange.show();this.$btnAdd.hide()}else{this.$img.hide();this.$placeholder.show();this.$btnRemove.hide();this.$btnChange.hide();this.$btnAdd.show()}},removeImg:function(d){d.preventDefault();this.setting({url:"",id:0})}})})(this.wp,jQuery); \ No newline at end of file
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-header-text.js b/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-header-text.js
new file mode 100644
index 00000000..48736bc9
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-header-text.js
@@ -0,0 +1,24 @@
+/* global site_logo_header_classes */
+/**
+ * JS for handling the "Display Header Text" setting's realtime preview.
+ */
+(function($){
+ var api = wp.customize,
+ $classes = site_logo_header_classes;
+
+ api( 'site_logo_header_text', function( value ) {
+ value.bind( function( to ) {
+ if ( true === to ) {
+ $( $classes ).css({
+ 'position': 'static',
+ 'clip': 'auto'
+ });
+ } else {
+ $( $classes ).css({
+ 'position': 'absolute',
+ 'clip': 'rect(1px 1px 1px 1px)'
+ });
+ }
+ });
+ });
+})(jQuery); \ No newline at end of file
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-header-text.min.js b/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-header-text.min.js
new file mode 100644
index 00000000..39c56ec0
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo-header-text.min.js
@@ -0,0 +1 @@
+!function(t){var i=wp.customize,o=site_logo_header_classes;i("site_logo_header_text",function(i){i.bind(function(i){t(o).css(!0===i?{position:"static",clip:"auto"}:{position:"absolute",clip:"rect(1px 1px 1px 1px)"})})})}(jQuery); \ No newline at end of file
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo.js b/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo.js
new file mode 100644
index 00000000..b0c1c1f5
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo.js
@@ -0,0 +1,43 @@
+/**
+ * JS for handling the Site Logo real-time display in the Customizer preview frame.
+ */
+(function($){
+ var api = wp.customize,
+ $body, $anchor, $logo, size;
+
+ function cacheSelectors() {
+ $body = $( 'body' );
+ $anchor = $( '.site-logo-link' );
+ $logo = $( '.site-logo' );
+ size = $logo.attr( 'data-size' );
+ }
+
+ api( 'site_logo', function( value ){
+ value.bind( function( newVal ){
+ // grab selectors the first time through
+ if ( ! $body ) {
+ cacheSelectors();
+ }
+
+ // Let's update our preview logo.
+ if ( newVal && newVal.url ) {
+ // If the source was smaller than the size required by the theme, give the biggest we've got.
+ if ( ! newVal.sizes[ size ] ) {
+ size = 'full';
+ }
+
+ $logo.attr({
+ height: newVal.sizes[ size ].height,
+ width: newVal.sizes[ size ].width,
+ src: newVal.sizes[ size ].url
+ });
+
+ $anchor.show();
+ $body.addClass( 'has-site-logo' );
+ } else {
+ $anchor.hide();
+ $body.removeClass( 'has-site-logo' );
+ }
+ });
+ });
+})(jQuery); \ No newline at end of file
diff --git a/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo.min.js b/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo.min.js
new file mode 100644
index 00000000..a6fe41eb
--- /dev/null
+++ b/plugins/jetpack/modules/theme-tools/site-logo/js/site-logo.min.js
@@ -0,0 +1 @@
+(function(d){var e=wp.customize,c,f,g,a;e("site_logo",function(e){e.bind(function(b){c||(c=d("body"),f=d(".site-logo-link"),g=d(".site-logo"),a=g.attr("data-size"));b&&b.url?(b.sizes[a]||(a="full"),g.attr({height:b.sizes[a].height,width:b.sizes[a].width,src:b.sizes[a].url}),f.show(),c.addClass("has-site-logo")):(f.hide(),c.removeClass("has-site-logo"))})})})(jQuery); \ No newline at end of file
diff --git a/plugins/jetpack/modules/social-links/social-links.php b/plugins/jetpack/modules/theme-tools/social-links.php
index b84aff93..53a64b87 100644
--- a/plugins/jetpack/modules/social-links/social-links.php
+++ b/plugins/jetpack/modules/theme-tools/social-links.php
@@ -1,5 +1,4 @@
<?php
-
/**
* Social Links.
*
@@ -8,9 +7,17 @@
* 'after_setup_theme' action:
*
* add_theme_support( 'social-links', array(
- * 'facebook', 'twitter', 'linkedin', 'tumblr',
+ * 'facebook', 'twitter', 'linkedin', 'tumblr', 'google_plus',
* ) );
*/
+
+function jetpack_theme_supports_social_links() {
+ if ( current_theme_supports( 'social-links' ) && function_exists( 'publicize_init' ) ) {
+ new Social_Links();
+ }
+}
+add_action( 'init', 'jetpack_theme_supports_social_links', 30 );
+
class Social_Links {
/**
@@ -36,6 +43,13 @@ class Social_Links {
private $services = array();
/**
+ * An array of the services the theme supports
+ *
+ * @var array
+ */
+ private $theme_supported_services = array();
+
+ /**
* Constructor.
*/
public function __construct() {
@@ -44,23 +58,13 @@ class Social_Links {
/* An array of named arguments must be passed as the second parameter
* of add_theme_support().
*/
- if ( ! isset( $theme_support[0] ) || empty( $theme_support[0] ) )
+ if ( empty( $theme_support[0] ) )
return;
+ $this->theme_supported_services = $theme_support[0];
$this->links = Jetpack_Options::get_option( 'social_links', array() );
- global $publicize;
-
- if ( is_a( $publicize, 'Publicize' ) ) {
- $this->publicize = $publicize;
- $this->services = array_intersect(
- array_keys( $this->publicize->get_services( 'connected' ) ),
- $theme_support[0]
- );
-
- add_action( 'customize_register', array( $this, 'customize_register' ) );
- add_filter( 'sanitize_option_jetpack_options', array( $this, 'sanitize_link' ) );
- }
+ $this->admin_setup();
add_filter( 'jetpack_has_social_links', array( $this, 'has_social_links' ) );
add_filter( 'jetpack_get_social_links', array( $this, 'get_social_links' ) );
@@ -71,6 +75,40 @@ class Social_Links {
}
}
+ public function admin_setup() {
+ if ( ! current_user_can( 'manage_options' ) ) {
+ return;
+ }
+
+ if ( ! is_admin() && ! $this->is_customize_preview() ) {
+ return;
+ }
+
+ $this->publicize = publicize_init();
+ $publicize_services = $this->publicize->get_services( 'connected' );
+ $this->services = array_intersect( array_keys( $publicize_services ), $this->theme_supported_services );
+
+ add_action( 'publicize_connected', array( $this, 'check_links' ), 20 );
+ add_action( 'publicize_disconnected', array( $this, 'check_links' ), 20 );
+ add_action( 'customize_register', array( $this, 'customize_register' ) );
+ add_filter( 'sanitize_option_jetpack_options', array( $this, 'sanitize_link' ) );
+ }
+
+ /**
+ * Compares the currently saved links with the connected services and removes
+ * links from services that are no longer connected.
+ *
+ * @return void
+ */
+ public function check_links() {
+ $active_links = array_intersect_key( $this->links, array_flip( $this->services ) );
+
+ if ( $active_links !== $this->links ) {
+ $this->links = $active_links;
+ Jetpack_Options::update_option( 'social_links', $active_links );
+ }
+ }
+
/**
* Add social link dropdown to the Customizer.
*
@@ -83,6 +121,12 @@ class Social_Links {
) );
foreach ( $this->services as $service ) {
+ $choices = $this->get_customize_select( $service );
+
+ if ( empty( $choices ) ) {
+ continue;
+ }
+
$wp_customize->add_setting( "jetpack_options[social_links][$service]", array(
'type' => 'option',
'default' => '',
@@ -93,7 +137,7 @@ class Social_Links {
'section' => 'jetpack_social_links',
'settings' => "jetpack_options[social_links][$service]",
'type' => 'select',
- 'choices' => $this->get_customize_select( $service ),
+ 'choices' => $choices,
) );
}
}
@@ -158,12 +202,30 @@ class Social_Links {
);
$connected_services = $this->publicize->get_services( 'connected' );
- if ( isset( $connected_services[ $service ] ) )
- foreach ( $connected_services[ $service ] as $c )
- $choices[ $this->publicize->get_profile_link( $service, $c ) ] = $this->publicize->get_display_name( $service, $c );
+ if ( isset( $connected_services[ $service ] ) ) {
+ foreach ( $connected_services[ $service ] as $c ) {
+ $profile_link = $this->publicize->get_profile_link( $service, $c );
+
+ if ( false === $profile_link ) {
+ continue;
+ }
+
+ $choices[ $profile_link ] = $this->publicize->get_display_name( $service, $c );
+ }
+ }
+
+ if ( 1 === count( $choices ) ) {
+ return array();
+ }
return $choices;
}
-}
-$jetpack_social_links = new Social_Links;
+ /**
+ * Back-compat function for versions prior to 4.0.
+ */
+ private function is_customize_preview() {
+ global $wp_customize;
+ return is_a( $wp_customize, 'WP_Customize_Manager' ) && $wp_customize->is_preview();
+ }
+}
diff --git a/plugins/jetpack/modules/tiled-gallery.php b/plugins/jetpack/modules/tiled-gallery.php
index e0e1e435..1dc7ae23 100644
--- a/plugins/jetpack/modules/tiled-gallery.php
+++ b/plugins/jetpack/modules/tiled-gallery.php
@@ -2,10 +2,12 @@
/**
* Module Name: Tiled Galleries
- * Module Description: Create elegant magazine-style mosaic layouts for your photos without using an external graphic editor.
+ * Module Description: Display your image galleries in a variety of sleek, graphic arrangements.
* First Introduced: 2.1
- * Requires Connection: Yes
+ * Requires Connection: No
* Auto Activate: No
+ * Module Tags: Photos and Videos
+ * Sort Order: 24
*/
function jetpack_load_tiled_gallery() {
@@ -24,4 +26,4 @@ function jetpack_tiled_gallery_configuration_load() {
exit;
}
-jetpack_load_tiled_gallery(); \ No newline at end of file
+jetpack_load_tiled_gallery();
diff --git a/plugins/jetpack/modules/tiled-gallery/tiled-gallery.php b/plugins/jetpack/modules/tiled-gallery/tiled-gallery.php
index 519293a6..7cf17cc3 100644
--- a/plugins/jetpack/modules/tiled-gallery/tiled-gallery.php
+++ b/plugins/jetpack/modules/tiled-gallery/tiled-gallery.php
@@ -4,7 +4,13 @@
// Here the constrained array element is the dimension of a row, group or an image in the tiled gallery.
include_once dirname( __FILE__ ) . '/math/class-constrained-array-rounding.php';
+// Layouts
+include_once dirname( __FILE__ ) . '/tiled-gallery/tiled-gallery-rectangular.php';
+include_once dirname( __FILE__ ) . '/tiled-gallery/tiled-gallery-square.php';
+include_once dirname( __FILE__ ) . '/tiled-gallery/tiled-gallery-circle.php';
+
class Jetpack_Tiled_Gallery {
+ private static $talaveras = array( 'rectangular', 'square', 'circle', 'rectangle', 'columns' );
public function __construct() {
add_action( 'admin_init', array( $this, 'settings_api_init' ) );
@@ -29,7 +35,8 @@ class Jetpack_Tiled_Gallery {
'type' => '',
'grayscale' => false,
'link' => '',
- ), $atts );
+ 'columns' => 3
+ ), $atts, 'gallery' );
$this->atts['id'] = (int) $this->atts['id'];
$this->float = is_rtl() ? 'right' : 'left';
@@ -44,8 +51,14 @@ class Jetpack_Tiled_Gallery {
$this->atts['orderby'] = 'menu_order ID';
}
- if ( 'RAND' == $this->atts['order'] )
- $this->atts['orderby'] = 'none';
+ if ( 'rand' == strtolower( $this->atts['order'] ) ) {
+ $this->atts['orderby'] = 'rand';
+ }
+
+ // We shouldn't have more than 20 columns.
+ if ( ! is_numeric( $this->atts['columns'] ) || 20 < $this->atts['columns'] ) {
+ $this->atts['columns'] = 3;
+ }
}
public function get_attachments() {
@@ -73,16 +86,13 @@ class Jetpack_Tiled_Gallery {
return $attachments;
}
- public function get_attachment_link( $attachment_id, $orig_file ) {
- if ( isset( $this->atts['link'] ) && $this->atts['link'] == 'file' )
- return $orig_file;
- else
- return get_attachment_link( $attachment_id );
- }
-
- public function default_scripts_and_styles() {
+ public static function default_scripts_and_styles() {
wp_enqueue_script( 'tiled-gallery', plugins_url( 'tiled-gallery/tiled-gallery.js', __FILE__ ), array( 'jquery' ) );
- wp_enqueue_style( 'tiled-gallery', plugins_url( 'tiled-gallery/tiled-gallery.css', __FILE__ ), array(), '2012-09-21' );
+ if( is_rtl() ) {
+ wp_enqueue_style( 'tiled-gallery', plugins_url( 'tiled-gallery/rtl/tiled-gallery-rtl.css', __FILE__ ), array(), '2012-09-21' );
+ } else {
+ wp_enqueue_style( 'tiled-gallery', plugins_url( 'tiled-gallery/tiled-gallery.css', __FILE__ ), array(), '2012-09-21' );
+ }
}
public function gallery_shortcode( $val, $atts ) {
@@ -100,191 +110,35 @@ class Jetpack_Tiled_Gallery {
if ( is_feed() || defined( 'IS_HTML_EMAIL' ) )
return '';
- if ( method_exists( $this, $this->atts['type'] . '_talavera' ) ) {
+ if ( in_array( $this->atts['type'], self::$talaveras ) ) {
// Enqueue styles and scripts
- $this->default_scripts_and_styles();
- $gallery_html = call_user_func_array( array( $this, $this->atts['type'] . '_talavera' ), array( $attachments ) );
+ self::default_scripts_and_styles();
+
+ // Generate gallery HTML
+ $gallery_class = 'Jetpack_Tiled_Gallery_Layout_' . ucfirst( $this->atts['type'] );
+ $gallery = new $gallery_class( $attachments, $this->atts['link'], $this->atts['grayscale'], (int) $this->atts['columns'] );
+ $gallery_html = $gallery->HTML();
if ( $gallery_html && class_exists( 'Jetpack' ) && class_exists( 'Jetpack_Photon' ) ) {
// Tiled Galleries in Jetpack require that Photon be active.
// If it's not active, run it just on the gallery output.
- if ( ! in_array( 'photon', Jetpack::get_active_modules() ) )
+ if ( ! in_array( 'photon', Jetpack::get_active_modules() ) && ! Jetpack::is_development_mode() )
$gallery_html = Jetpack_Photon::filter_the_content( $gallery_html );
}
- return $gallery_html;
+ return trim( preg_replace( '/\s+/', ' ', $gallery_html ) ); // remove any new lines from the output so that the reader parses it better
}
return '';
}
- public function rectangular_talavera( $attachments ) {
- $grouper = new Jetpack_Tiled_Gallery_Grouper( $attachments );
-
- Jetpack_Tiled_Gallery_Shape::reset_last_shape();
-
- $output = $this->generate_carousel_container();
- foreach ( $grouper->grouped_images as $row ) {
- $output .= '<div class="gallery-row" style="' . esc_attr( 'width: ' . $row->width . 'px; height: ' . ( $row->height - 4 ) . 'px;' ) . '">';
- foreach( $row->groups as $group ) {
- $count = count( $group->images );
- $output .= '<div class="gallery-group images-' . esc_attr( $count ) . '" style="' . esc_attr( 'width: ' . $group->width . 'px; height: ' . $group->height . 'px;' ) . '">';
- foreach ( $group->images as $image ) {
-
- $size = 'large';
- if ( $image->width < 250 )
- $size = 'small';
-
- $image_title = $image->post_title;
- $orig_file = wp_get_attachment_url( $image->ID );
- $link = $this->get_attachment_link( $image->ID, $orig_file );
-
- $img_src = add_query_arg( array( 'w' => $image->width, 'h' => $image->height ), $orig_file );
-
- $output .= '<div class="tiled-gallery-item tiled-gallery-item-' . esc_attr( $size ) . '"><a href="' . esc_url( $link ) . '"><img ' . $this->generate_carousel_image_args( $image ) . ' src="' . esc_url( $img_src ) . '" width="' . esc_attr( $image->width ) . '" height="' . esc_attr( $image->height ) . '" align="left" title="' . esc_attr( $image_title ) . '" /></a>';
-
- if ( $this->atts['grayscale'] == true ) {
- $img_src_grayscale = jetpack_photon_url( $img_src, array( 'filter' => 'grayscale' ) );
- $output .= '<a href="'. esc_url( $link ) . '"><img ' . $this->generate_carousel_image_args( $image ) . ' class="grayscale" src="' . esc_url( $img_src_grayscale ) . '" width="' . esc_attr( $image->width ) . '" height="' . esc_attr( $image->height ) . '" align="left" title="' . esc_attr( $image_title ) . '" /></a>';
- }
-
- if ( trim( $image->post_excerpt ) )
- $output .= '<div class="tiled-gallery-caption">' . wptexturize( $image->post_excerpt ) . '</div>';
-
- $output .= '</div>';
- }
- $output .= '</div>';
- }
- $output .= '</div>';
- }
- $output .= '</div>';
- return $output;
- }
-
- public function square_talavera( $attachments ) {
- $content_width = self::get_content_width();
- $images_per_row = 3;
- $margin = 2;
-
- $margin_space = ( $images_per_row * $margin ) * 2;
- $size = floor( ( $content_width - $margin_space ) / $images_per_row );
- $remainder = count( $attachments ) % $images_per_row;
- if ( $remainder > 0 ) {
- $remainder_space = ( $remainder * $margin ) * 2;
- $remainder_size = ceil( ( $content_width - $remainder_space - $margin ) / $remainder );
- }
- $output = $this->generate_carousel_container();
- $c = 1;
- foreach( $attachments as $image ) {
- if ( $remainder > 0 && $c <= $remainder )
- $img_size = $remainder_size;
- else
- $img_size = $size;
-
- $orig_file = wp_get_attachment_url( $image->ID );
- $link = $this->get_attachment_link( $image->ID, $orig_file );
- $image_title = $image->post_title;
-
- $img_src = add_query_arg( array( 'w' => $img_size, 'h' => $img_size, 'crop' => 1 ), $orig_file );
-
- $output .= '<div class="tiled-gallery-item">';
- $output .= '<a border="0" href="' . esc_url( $link ) . '"><img ' . $this->generate_carousel_image_args( $image ) . ' style="' . esc_attr( 'margin: ' . $margin . 'px' ) . '" src="' . esc_url( $img_src ) . '" width=' . esc_attr( $img_size ) . ' height=' . esc_attr( $img_size ) . ' title="' . esc_attr( $image_title ) . '" /></a>';
-
- // Grayscale effect
- if ( $this->atts['grayscale'] == true ) {
- $src = urlencode( $image->guid );
- $output .= '<a border="0" href="' . esc_url( $link ) . '"><img ' . $this->generate_carousel_image_args( $image ) . ' style="margin: 2px" class="grayscale" src="' . esc_url( 'http://en.wordpress.com/imgpress?url=' . urlencode( $image->guid ) . '&resize=' . $img_size . ',' . $img_size . '&filter=grayscale' ) . '" width=' . esc_attr( $img_size ) . ' height=' . esc_attr( $img_size ) . ' title="' . esc_attr( $image_title ) . '" /></a>';
- }
-
- // Captions
- if ( trim( $image->post_excerpt ) )
- $output .= '<div class="tiled-gallery-caption">' . wptexturize( $image->post_excerpt ) . '</div>';
- $output .= '</div>';
- $c ++;
- }
- $output .= '</div>';
- return $output;
- }
-
- public function circle_talavera( $attachments ) {
- return $this->square_talavera( $attachments );
- }
-
- public function rectangle_talavera( $attachments ) {
- return $this->rectangular_talavera( $attachments );
- }
-
- function generate_carousel_container() {
- global $post;
-
- $html = '<div '. $this->gallery_classes() . ' data-original-width="' . esc_attr( self::get_content_width() ) . '">';
- $blog_id = (int) get_current_blog_id();
-
- if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
- $likes_blog_id = $blog_id;
- } else {
- $likes_blog_id = Jetpack_Options::get_option( 'id' );
- }
-
- $extra_data = array( 'data-carousel-extra' => array( 'blog_id' => $blog_id, 'permalink' => get_permalink( isset( $post->ID ) ? $post->ID : 0 ), 'likes_blog_id' => $likes_blog_id ) );
-
- foreach ( (array) $extra_data as $data_key => $data_values ) {
- $html = str_replace( '<div ', '<div ' . esc_attr( $data_key ) . "='" . json_encode( $data_values ) . "' ", $html );
- }
-
- return $html;
- }
-
- function generate_carousel_image_args( $image ) {
- $attachment_id = $image->ID;
- $orig_file = wp_get_attachment_url( $attachment_id );
- $meta = wp_get_attachment_metadata( $attachment_id );
- $size = isset( $meta['width'] ) ? intval( $meta['width'] ) . ',' . intval( $meta['height'] ) : '';
- $img_meta = ( ! empty( $meta['image_meta'] ) ) ? (array) $meta['image_meta'] : array();
- $comments_opened = intval( comments_open( $attachment_id ) );
-
- $medium_file_info = wp_get_attachment_image_src( $attachment_id, 'medium' );
- $medium_file = isset( $medium_file_info[0] ) ? $medium_file_info[0] : '';
-
- $large_file_info = wp_get_attachment_image_src( $attachment_id, 'large' );
- $large_file = isset( $large_file_info[0] ) ? $large_file_info[0] : '';
- $attachment_title = wptexturize( $image->post_title );
- $attachment_desc = wpautop( wptexturize( $image->post_content ) );
-
- // Not yet providing geo-data, need to "fuzzify" for privacy
- if ( ! empty( $img_meta ) ) {
- foreach ( $img_meta as $k => $v ) {
- if ( 'latitude' == $k || 'longitude' == $k )
- unset( $img_meta[$k] );
- }
- }
-
- $img_meta = json_encode( array_map( 'strval', $img_meta ) );
-
- $output = sprintf(
- 'data-attachment-id="%1$d" data-orig-file="%2$s" data-orig-size="%3$s" data-comments-opened="%4$s" data-image-meta="%5$s" data-image-title="%6$s" data-image-description="%7$s" data-medium-file="%8$s" data-large-file="%9$s"',
- esc_attr( $attachment_id ),
- esc_url( wp_get_attachment_url( $attachment_id ) ),
- esc_attr( $size ),
- esc_attr( $comments_opened ),
- esc_attr( $img_meta ),
- esc_attr( $attachment_title ),
- esc_attr( $attachment_desc ),
- esc_url( $medium_file ),
- esc_url( $large_file )
- );
- return $output;
- }
-
- public function gallery_classes() {
- $classes = 'class="tiled-gallery type-' . esc_attr( $this->atts['type'] ) . ' tiled-gallery-unresized"';
- return $classes;
- }
-
public static function gallery_already_redefined() {
global $shortcode_tags;
- if ( ! isset( $shortcode_tags[ 'gallery' ] ) || $shortcode_tags[ 'gallery' ] !== 'gallery_shortcode' )
- return true;
+ $redefined = false;
+ if ( ! isset( $shortcode_tags[ 'gallery' ] ) || $shortcode_tags[ 'gallery' ] !== 'gallery_shortcode' ) {
+ $redefined = true;
+ }
+ return apply_filters( 'jetpack_tiled_gallery_shortcode_redefined', $redefined );
}
public static function init() {
@@ -318,6 +172,7 @@ class Jetpack_Tiled_Gallery {
$types['rectangular'] = __( 'Tiled Mosaic', 'jetpack' );
$types['square'] = __( 'Square Tiles', 'jetpack' );
$types['circle'] = __( 'Circles', 'jetpack' );
+ $types['columns'] = __( 'Tiled Columns', 'jetpack' );
return $types;
}
@@ -326,6 +181,10 @@ class Jetpack_Tiled_Gallery {
return ( get_option( 'tiled_galleries' ) ? 'rectangular' : 'default' );
}
+ static function get_talaveras() {
+ return self::$talaveras;
+ }
+
/**
* Add a checkbox field to the Carousel section in Settings > Media
* for setting tiled galleries as the default.
@@ -350,261 +209,5 @@ class Jetpack_Tiled_Gallery {
}
}
-class Jetpack_Tiled_Gallery_Shape {
- static $shapes_used = array();
-
- public function __construct( $images ) {
- $this->images = $images;
- $this->images_left = count( $images );
- }
-
- public function sum_ratios( $number_of_images = 3 ) {
- return array_sum( array_slice( wp_list_pluck( $this->images, 'ratio' ), 0, $number_of_images ) );
- }
-
- public function next_images_are_symmetric() {
- return $this->images_left > 2 && $this->images[0]->ratio == $this->images[2]->ratio;
- }
-
- public function is_not_as_previous( $n = 1 ) {
- return ! in_array( get_class( $this ), array_slice( self::$shapes_used, -$n ) );
- }
-
- public function is_wide_theme() {
- return Jetpack::get_content_width() > 1000;
- }
-
- public static function set_last_shape( $last_shape ) {
- self::$shapes_used[] = $last_shape;
- }
-
- public static function reset_last_shape() {
- self::$shapes_used = array();
- }
-}
-
-class Jetpack_Tiled_Gallery_Three extends Jetpack_Tiled_Gallery_Shape {
- public $shape = array( 1, 1, 1 );
-
- public function is_possible() {
- $ratio = $this->sum_ratios( 3 );
- return $this->images_left > 2 && $this->is_not_as_previous() &&
- ( ( $ratio < 2.5 ) || ( $ratio < 5 && $this->next_images_are_symmetric() ) || $this->is_wide_theme() );
- }
-}
-
-class Jetpack_Tiled_Gallery_Four extends Jetpack_Tiled_Gallery_Shape {
- public $shape = array( 1, 1, 1, 1 );
-
- public function is_possible() {
- return $this->is_not_as_previous() && $this->sum_ratios( 4 ) < 3.5 &&
- ( $this->images_left == 4 || ( $this->images_left != 8 && $this->images_left > 5 ) );
- }
-}
-
-class Jetpack_Tiled_Gallery_Five extends Jetpack_Tiled_Gallery_Shape {
- public $shape = array( 1, 1, 1, 1, 1 );
-
- public function is_possible() {
- return $this->is_wide_theme() && $this->is_not_as_previous() && $this->sum_ratios( 5 ) < 5 &&
- ( $this->images_left == 5 || ( $this->images_left != 10 && $this->images_left > 6 ) );
- }
-}
-
-class Jetpack_Tiled_Gallery_Two_One extends Jetpack_Tiled_Gallery_Shape {
- public $shape = array( 2, 1 );
-
- public function is_possible() {
- return $this->is_not_as_previous( 3 ) && $this->images_left >= 2 &&
- $this->images[2]->ratio < 1.6 && $this->images[0]->ratio >=0.9 && $this->images[1]->ratio >= 0.9;
- }
-}
-
-class Jetpack_Tiled_Gallery_One_Two extends Jetpack_Tiled_Gallery_Shape {
- public $shape = array( 1, 2 );
-
- public function is_possible() {
- return $this->is_not_as_previous( 3 ) && $this->images_left >= 2 &&
- $this->images[0]->ratio < 1.6 && $this->images[1]->ratio >=0.9 && $this->images[2]->ratio >= 0.9;
- }
-}
-
-class Jetpack_Tiled_Gallery_One_Three extends Jetpack_Tiled_Gallery_Shape {
- public $shape = array( 1, 3 );
-
- public function is_possible() {
- return $this->is_not_as_previous() && $this->images_left > 3 &&
- $this->images[0]->ratio < 0.8 && $this->images[1]->ratio >=0.9 && $this->images[2]->ratio >= 0.9 && $this->images[3]->ratio >= 0.9;
- }
-}
-
-class Jetpack_Tiled_Gallery_Symmetric_Row extends Jetpack_Tiled_Gallery_Shape {
- public $shape = array( 1, 2, 1 );
-
- public function is_possible() {
- return $this->is_not_as_previous() && $this->images_left >= 3 && $this->images_left != 5 &&
- $this->images[0]->ratio < 0.8 && $this->images[0]->ratio == $this->images[3]->ratio;
- }
-}
-
-class Jetpack_Tiled_Gallery_Grouper {
- public $margin = 4;
- public function __construct( $attachments ) {
- $content_width = Jetpack_Tiled_Gallery::get_content_width();
- $ua_info = new Jetpack_User_Agent_Info();
-
- $this->last_shape = '';
- $this->images = $this->get_images_with_sizes( $attachments );
- $this->grouped_images = $this->get_grouped_images();
- $this->apply_content_width( $content_width - 5 ); //reduce the margin hack to 5px. It will be further reduced when we fix more themes and the rounding error.
- }
-
- public function get_current_row_size() {
- $images_left = count( $this->images );
- if ( $images_left < 3 )
- return array_fill( 0, $images_left, 1 );
-
- foreach ( array( 'One_Three', 'One_Two', 'Five', 'Four', 'Three', 'Two_One', 'Symmetric_Row' ) as $shape_name ) {
- $class_name = "Jetpack_Tiled_Gallery_$shape_name";
- $shape = new $class_name( $this->images );
- if ( $shape->is_possible() ) {
- Jetpack_Tiled_Gallery_Shape::set_last_shape( $class_name );
- return $shape->shape;
- }
- }
-
- Jetpack_Tiled_Gallery_Shape::set_last_shape( 'Two' );
- return array( 1, 1 );
- }
-
- public function get_images_with_sizes( $attachments ) {
- $images_with_sizes = array();
-
- foreach ( $attachments as $image ) {
- $meta = wp_get_attachment_metadata( $image->ID );
- $image->width_orig = ( $meta['width'] > 0 )? $meta['width'] : 1;
- $image->height_orig = ( $meta['height'] > 0 )? $meta['height'] : 1;
- $image->ratio = $image->width_orig / $image->height_orig;
- $image->ratio = $image->ratio? $image->ratio : 1;
- $images_with_sizes[] = $image;
- }
-
- return $images_with_sizes;
- }
-
- public function read_row() {
- $vector = $this->get_current_row_size();
-
- $row = array();
- foreach ( $vector as $group_size ) {
- $row[] = new Jetpack_Tiled_Gallery_Group( array_splice( $this->images, 0, $group_size ) );
- }
-
- return $row;
- }
-
- public function get_grouped_images() {
- $grouped_images = array();
-
- while( !empty( $this->images ) ) {
- $grouped_images[] = new Jetpack_Tiled_Gallery_Row( $this->read_row() );
- }
-
- return $grouped_images;
- }
-
- // todo: split in functions
- // todo: do not stretch images
- public function apply_content_width( $width ) {
- foreach ( $this->grouped_images as $row ) {
- $row->width = $width;
- $row->raw_height = 1 / $row->ratio * ( $width - $this->margin * ( count( $row->groups ) - $row->weighted_ratio ) );
- $row->height = round( $row->raw_height );
-
- $this->calculate_group_sizes( $row );
- }
- }
-
- public function calculate_group_sizes( $row ) {
- // Storing the calculated group heights in an array for rounding them later while preserving their sum
- // This fixes the rounding error that can lead to a few ugly pixels sticking out in the gallery
- $group_widths_array = array();
- foreach ( $row->groups as $group ) {
- $group->height = $row->height;
- // Storing the raw calculations in a separate property to prevent rounding errors from cascading down and for diagnostics
- $group->raw_width = ( $row->raw_height - $this->margin * count( $group->images ) ) * $group->ratio + $this->margin;
- $group_widths_array[] = $group->raw_width;
- }
- $rounded_group_widths_array = Jetpack_Constrained_Array_Rounding::get_rounded_constrained_array( $group_widths_array, $row->width );
-
- foreach ( $row->groups as $group ) {
- $group->width = array_shift( $rounded_group_widths_array );
- $this->calculate_image_sizes( $group );
- }
- }
-
- public function calculate_image_sizes( $group ) {
- // Storing the calculated image heights in an array for rounding them later while preserving their sum
- // This fixes the rounding error that can lead to a few ugly pixels sticking out in the gallery
- $image_heights_array = array();
- foreach ( $group->images as $image ) {
- $image->width = $group->width - $this->margin;
- // Storing the raw calculations in a separate property for diagnostics
- $image->raw_height = ( $group->raw_width - $this->margin ) / $image->ratio;
- $image_heights_array[] = $image->raw_height;
- }
-
- $image_height_sum = $group->height - count( $image_heights_array ) * $this->margin;
- $rounded_image_heights_array = Jetpack_Constrained_Array_Rounding::get_rounded_constrained_array( $image_heights_array, $image_height_sum );
-
- foreach ( $group->images as $image ) {
- $image->height = array_shift( $rounded_image_heights_array );
- }
- }
-}
-
-class Jetpack_Tiled_Gallery_Row {
- public function __construct( $groups ) {
- $this->groups = $groups;
- $this->ratio = $this->get_ratio();
- $this->weighted_ratio = $this->get_weighted_ratio();
- }
-
- public function get_ratio() {
- $ratio = 0;
- foreach ( $this->groups as $group ) {
- $ratio += $group->ratio;
- }
- return $ratio > 0? $ratio : 1;
- }
-
- public function get_weighted_ratio() {
- $weighted_ratio = 0;
- foreach ( $this->groups as $group ) {
- $weighted_ratio += $group->ratio * count( $group->images );
- }
- return $weighted_ratio > 0 ? $weighted_ratio : 1;
- }
-}
-
-class Jetpack_Tiled_Gallery_Group {
- public function __construct( $images ) {
- $this->images = $images;
- $this->ratio = $this->get_ratio();
- }
-
- public function get_ratio() {
- $ratio = 0;
- foreach ( $this->images as $image ) {
- if ( $image->ratio )
- $ratio += 1/$image->ratio;
- }
- if ( !$ratio )
- return 1;
-
- return 1/$ratio;
- }
-}
-
add_action( 'init', array( 'Jetpack_Tiled_Gallery', 'init' ) );
diff --git a/plugins/jetpack/modules/tiled-gallery/tiled-gallery/rtl/tiled-gallery-rtl.css b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/rtl/tiled-gallery-rtl.css
index ef12ca43..a91af001 100644
--- a/plugins/jetpack/modules/tiled-gallery/tiled-gallery/rtl/tiled-gallery-rtl.css
+++ b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/rtl/tiled-gallery-rtl.css
@@ -1,4 +1,4 @@
-/* This file was automatically generated on Jul 31 2013 21:21:12 */
+/* This file was automatically generated on May 26 2014 22:30:22 */
/* =Tiled Gallery Default Styles
-------------------------------------------------------------- */
@@ -23,7 +23,6 @@
}
.tiled-gallery .gallery-row {
overflow: hidden;
- margin-bottom: 2px;
}
.tiled-gallery .tiled-gallery-item a { /* Needs to reset some properties for theme compatibility */
background: transparent;
diff --git a/plugins/jetpack/modules/tiled-gallery/tiled-gallery/templates/carousel-container.php b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/templates/carousel-container.php
new file mode 100644
index 00000000..38f16dfc
--- /dev/null
+++ b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/templates/carousel-container.php
@@ -0,0 +1,18 @@
+<?php
+if ( defined( 'JSON_HEX_AMP' ) ) {
+ // see shortcodes/slideshow.php
+ // This is nice to have, but not strictly necessary since we use _wp_specialchars() below
+ $extra = json_encode( $this->get_container_extra_data(), JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT );
+} else {
+ $extra = json_encode( $this->get_container_extra_data() );
+}
+?>
+<div
+ class="tiled-gallery type-<?php echo $this->type; ?> tiled-gallery-unresized"
+ data-original-width="<?php echo esc_attr( Jetpack_Tiled_Gallery::get_content_width() ); ?>"
+ <?php if ( isset( $extra ) ): ?>
+ data-carousel-extra='<?php echo _wp_specialchars( wp_check_invalid_utf8( $extra ), ENT_QUOTES, false, true ); ?>'
+ <?php endif; ?>
+ >
+ <?php $this->template( "$this->type-layout", $context ); ?>
+</div>
diff --git a/plugins/jetpack/modules/tiled-gallery/tiled-gallery/templates/circle-layout.php b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/templates/circle-layout.php
new file mode 100644
index 00000000..7c8430dd
--- /dev/null
+++ b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/templates/circle-layout.php
@@ -0,0 +1,3 @@
+<?php
+$this->template( 'square-layout', $context );
+
diff --git a/plugins/jetpack/modules/tiled-gallery/tiled-gallery/templates/partials/carousel-image-args.php b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/templates/partials/carousel-image-args.php
new file mode 100644
index 00000000..02c2863f
--- /dev/null
+++ b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/templates/partials/carousel-image-args.php
@@ -0,0 +1,18 @@
+<?php
+if ( defined( 'JSON_HEX_AMP' ) ) {
+ // see shortcodes/slideshow.php
+ // This is nice to have, but not strictly necessary since we use _wp_specialchars() below
+ $fuzzy_image_meta = json_encode( array_map( 'strval', $item->fuzzy_image_meta() ), JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT );
+} else {
+ $fuzzy_image_meta = json_encode( array_map( 'strval', $item->fuzzy_image_meta() ) );
+}
+?>
+data-attachment-id="<?php echo esc_attr( $item->image->ID ); ?>"
+data-orig-file="<?php echo esc_url( wp_get_attachment_url( $item->image->ID ) ); ?>"
+data-orig-size="<?php echo esc_attr( $item->meta_width() ); ?>,<?php echo esc_attr( $item->meta_height() ); ?>"
+data-comments-opened="<?php echo esc_attr( comments_open( $item->image->ID ) ); ?>"
+data-image-meta="<?php echo _wp_specialchars( wp_check_invalid_utf8( $fuzzy_image_meta ), ENT_QUOTES, false, true ); ?>"
+data-image-title="<?php echo esc_attr( wptexturize( $item->image->post_title ) ); ?>"
+data-image-description="<?php echo esc_attr( wpautop( wptexturize( $item->image->post_content ) ) ); ?>"
+data-medium-file="<?php echo esc_url( $item->medium_file() ); ?>"
+data-large-file="<?php echo esc_url( $item->large_file() ); ?>"
diff --git a/plugins/jetpack/modules/tiled-gallery/tiled-gallery/templates/partials/item.php b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/templates/partials/item.php
new file mode 100644
index 00000000..7e8c8a07
--- /dev/null
+++ b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/templates/partials/item.php
@@ -0,0 +1,49 @@
+<?php
+$add_link = 'none' !== $this->link; ?>
+<div class="tiled-gallery-item<?php if ( isset( $item->size ) ) echo " tiled-gallery-item-$item->size"; ?>">
+ <?php if ( $add_link ): ?>
+ <a href="<?php echo $item->link; ?>" border="0">
+ <?php endif; ?>
+ <img
+ <?php $this->partial( 'carousel-image-args', array( 'item' => $item ) ); ?>
+ src="<?php echo esc_url( $item->img_src ); ?>"
+ width="<?php echo esc_attr( $item->image->width ); ?>"
+ height="<?php echo esc_attr( $item->image->height ); ?>"
+ data-original-width="<?php echo esc_attr( $item->image->width ); ?>"
+ data-original-height="<?php echo esc_attr( $item->image->height ); ?>"
+ title="<?php echo esc_attr( $item->image_title ); ?>"
+ alt="<?php echo esc_attr( $item->image_alt ); ?>"
+ style="width: <?php echo esc_attr( $item->image->width ); ?>px; height: <?php echo esc_attr( $item->image->height ); ?>px;"
+ />
+ <?php if ( $add_link ): ?>
+ </a>
+ <?php endif; ?>
+
+ <?php if ( $this->grayscale == true ): ?>
+ <?php if ( $add_link ): ?>
+ <a href="<?php echo $item->link; ?>" border="0">
+ <?php endif; ?>
+ <img
+ class="grayscale"
+ src="<?php echo esc_url( $item->img_src_grayscale ); ?>"
+ width="<?php echo esc_attr( $item->image->width ); ?>"
+ height="<?php echo esc_attr( $item->image->height ); ?>"
+ data-original-width="<?php echo esc_attr( $item->image->width ); ?>"
+ data-original-height="<?php echo esc_attr( $item->image->height ); ?>"
+ title="<?php echo esc_attr( $item->image_title ); ?>"
+ align="left"
+ alt="<?php echo esc_attr( $item->image_alt ); ?>"
+ style="width: <?php echo esc_attr( $item->image->width ); ?>px; height: <?php echo esc_attr( $item->image->height ); ?>px;"
+ />
+ <?php if ( $add_link ): ?>
+ </a>
+ <?php endif; ?>
+ <?php endif; ?>
+
+ <?php if ( trim( $item->image->post_excerpt ) ): ?>
+ <div class="tiled-gallery-caption">
+ <?php echo wptexturize( $item->image->post_excerpt ); ?>
+ </div>
+ <?php endif; ?>
+</div>
+
diff --git a/plugins/jetpack/modules/tiled-gallery/tiled-gallery/templates/rectangular-layout.php b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/templates/rectangular-layout.php
new file mode 100644
index 00000000..3869134f
--- /dev/null
+++ b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/templates/rectangular-layout.php
@@ -0,0 +1,23 @@
+<?php
+foreach ( $rows as $row ): ?>
+ <div
+ class="gallery-row"
+ style="width: <?php echo esc_attr( $row->width ); ?>px; height: <?php echo esc_attr( $row->height ); ?>px;"
+ data-original-width="<?php echo esc_attr( $row->width ); ?>"
+ data-original-height="<?php echo esc_attr( $row->height ); ?>"
+
+ >
+ <?php foreach ( $row->groups as $group ): ?>
+ <div
+ class="gallery-group images-<?php echo esc_attr( count( $group->images ) ); ?>"
+ style="width: <?php echo esc_attr( $group->width ); ?>px; height: <?php echo esc_attr( $group->height ); ?>px;"
+ data-original-width="<?php echo esc_attr( $group->width ); ?>"
+ data-original-height="<?php echo esc_attr( $group->height ); ?>"
+ >
+ <?php foreach( $group->items( $needs_attachment_link, $grayscale ) as $item ): ?>
+ <?php $this->partial( 'item', array( 'item' => $item, 'link' => $link ) ); ?>
+ <?php endforeach; ?>
+ </div> <!-- close group -->
+ <?php endforeach; ?>
+ </div> <!-- close row -->
+<?php endforeach; ?>
diff --git a/plugins/jetpack/modules/tiled-gallery/tiled-gallery/templates/square-layout.php b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/templates/square-layout.php
new file mode 100644
index 00000000..9e5439a1
--- /dev/null
+++ b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/templates/square-layout.php
@@ -0,0 +1,19 @@
+<?php
+foreach ( $rows as $row ): ?>
+ <div class="gallery-row"
+ style="width: <?php echo esc_attr( $row->width ); ?>px; height: <?php echo esc_attr( $row->height ); ?>px;"
+ data-original-width="<?php echo esc_attr( $row->width ); ?>"
+ data-original-height="<?php echo esc_attr( $row->height ); ?>"
+ >
+ <?php $add_link = 'none' !== $link; ?>
+ <?php foreach ( $row->images as $item ): ?>
+ <div class="gallery-group"
+ style="width: <?php echo esc_attr( $row->group_size ); ?>px; height: <?php echo esc_attr( $row->group_size ); ?>px;"
+ data-original-width="<?php echo esc_attr( $row->group_size ); ?>"
+ data-original-height="<?php echo esc_attr( $row->group_size ); ?>"
+ >
+ <?php $this->partial( 'item', array( 'item' => $item, 'link' => $link ) ); ?>
+ </div>
+ <?php endforeach; ?>
+ </div>
+<?php endforeach; ?>
diff --git a/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-circle.php b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-circle.php
new file mode 100644
index 00000000..c140e863
--- /dev/null
+++ b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-circle.php
@@ -0,0 +1,8 @@
+<?php
+include_once dirname( __FILE__ ) . '/tiled-gallery-square.php';
+
+class Jetpack_Tiled_Gallery_Layout_Circle extends Jetpack_Tiled_Gallery_Layout_Square {
+ protected $type = 'circle';
+}
+
+
diff --git a/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-item.php b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-item.php
new file mode 100644
index 00000000..355ee406
--- /dev/null
+++ b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-item.php
@@ -0,0 +1,74 @@
+<?php
+abstract class Jetpack_Tiled_Gallery_Item {
+ public $image;
+
+ public function __construct( $attachment_image, $needs_attachment_link, $grayscale ) {
+ $this->image = $attachment_image;
+ $this->grayscale = $grayscale;
+
+ $this->image_title = $this->image->post_title;
+ $this->image_alt = get_post_meta( $this->image->ID, '_wp_attachment_image_alt', true );
+ $this->orig_file = wp_get_attachment_url( $this->image->ID );
+ $this->link = $needs_attachment_link ? get_attachment_link( $this->image->ID ) : $this->orig_file;
+
+ $this->img_src = add_query_arg( array( 'w' => $this->image->width, 'h' => $this->image->height, 'crop' => true ), $this->orig_file );
+
+ }
+
+ public function fuzzy_image_meta() {
+ $meta = wp_get_attachment_metadata( $this->image->ID );
+ $img_meta = ( ! empty( $meta['image_meta'] ) ) ? (array) $meta['image_meta'] : array();
+ if ( ! empty( $img_meta ) ) {
+ foreach ( $img_meta as $k => $v ) {
+ if ( 'latitude' == $k || 'longitude' == $k )
+ unset( $img_meta[$k] );
+ }
+ }
+
+ return $img_meta;
+ }
+
+ public function meta_width() {
+ $meta = wp_get_attachment_metadata( $this->image->ID );
+ return isset( $meta['width'] ) ? intval( $meta['width'] ) : '';
+ }
+
+ public function meta_height() {
+ $meta = wp_get_attachment_metadata( $this->image->ID );
+ return isset( $meta['height'] ) ? intval( $meta['height'] ) : '';
+ }
+
+ public function medium_file() {
+ $medium_file_info = wp_get_attachment_image_src( $this->image->ID, 'medium' );
+ $medium_file = isset( $medium_file_info[0] ) ? $medium_file_info[0] : '';
+ return $medium_file;
+ }
+
+ public function large_file() {
+ $large_file_info = wp_get_attachment_image_src( $this->image->ID, 'large' );
+ $large_file = isset( $large_file_info[0] ) ? $large_file_info[0] : '';
+ return $large_file;
+ }
+}
+
+class Jetpack_Tiled_Gallery_Rectangular_Item extends Jetpack_Tiled_Gallery_Item {
+ public function __construct( $attachment_image, $needs_attachment_link, $grayscale ) {
+ parent::__construct( $attachment_image, $needs_attachment_link, $grayscale );
+ $this->img_src_grayscale = jetpack_photon_url( $this->img_src, array( 'filter' => 'grayscale' ) );
+
+ $this->size = 'large';
+
+ if ( $this->image->width < 250 )
+ $this->size = 'small';
+ }
+}
+
+class Jetpack_Tiled_Gallery_Square_Item extends Jetpack_Tiled_Gallery_Item {
+ public function __construct( $attachment_image, $needs_attachment_link, $grayscale ) {
+ parent::__construct( $attachment_image, $needs_attachment_link, $grayscale );
+ $this->img_src_grayscale = jetpack_photon_url( $this->img_src, array( 'filter' => 'grayscale', 'resize' => array( $this->image->width, $this->image->height ) ) );
+ }
+}
+
+class Jetpack_Tiled_Gallery_Circle_Item extends Jetpack_Tiled_Gallery_Square_Item {
+}
diff --git a/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-layout.php b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-layout.php
new file mode 100644
index 00000000..7171112d
--- /dev/null
+++ b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-layout.php
@@ -0,0 +1,80 @@
+<?php
+abstract class Jetpack_Tiled_Gallery_Layout {
+ // Template whitelist
+ private static $templates = array( 'carousel-container', 'circle-layout', 'rectangular-layout', 'square-layout' );
+ private static $partials = array( 'carousel-image-args', 'item' );
+
+ protected $type; // Defined in child classes
+ public $attachments;
+ public $link;
+ public $grayscale;
+ public $columns;
+ public function __construct( $attachments, $link, $grayscale, $columns ) {
+
+ $this->attachments = $attachments;
+ $this->link = $link;
+ $this->needs_attachment_link = ! ( isset( $link ) && $link == 'file' );
+ $this->grayscale = $grayscale;
+ $this->columns = $columns;
+ }
+
+ public function HTML( $context = array() ) {
+ // Render the carousel container template, which will take the
+ // appropriate strategy to fill it
+ ob_start();
+ $this->template( 'carousel-container', array_merge( $context, array(
+ 'attachments' => $this->attachments,
+ 'link' => $this->link,
+ 'needs_attachment_link' => $this->needs_attachment_link,
+ 'grayscale' => $this->grayscale
+ ) ) );
+ $html = ob_get_clean();
+
+ return $html;
+ }
+
+ private function template( $name, $context = null ) {
+ if ( ! in_array( $name, self::$templates ) ) {
+ return;
+ }
+
+ if ( isset( $context ) ) {
+ extract( $context );
+ }
+
+ require dirname( __FILE__ ) . "/templates/$name.php";
+ }
+
+ private function partial( $name, $context = null ) {
+ if ( ! in_array( $name, self::$partials ) ) {
+ return;
+ }
+
+ if ( isset( $context ) ) {
+ extract( $context );
+ }
+
+ require dirname( __FILE__ ) . "/templates/partials/$name.php";
+ }
+
+ protected function get_container_extra_data() {
+ global $post;
+
+ $blog_id = (int) get_current_blog_id();
+
+ if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
+ $likes_blog_id = $blog_id;
+ } else {
+ $likes_blog_id = Jetpack_Options::get_option( 'id' );
+ }
+
+ if ( class_exists( 'Jetpack_Carousel' ) || in_array( 'carousel', Jetpack::get_active_modules() ) || 'carousel' == $this->link ) {
+ $extra_data = array( 'blog_id' => $blog_id, 'permalink' => get_permalink( isset( $post->ID ) ? $post->ID : 0 ), 'likes_blog_id' => $likes_blog_id );
+ } else {
+ $extra_data = null;
+ }
+
+ return $extra_data;
+ }
+}
+
diff --git a/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-rectangular.php b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-rectangular.php
new file mode 100644
index 00000000..5fdd83be
--- /dev/null
+++ b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-rectangular.php
@@ -0,0 +1,221 @@
+<?php
+require_once dirname( __FILE__ ) . '/tiled-gallery-layout.php';
+require_once dirname( __FILE__ ) . '/tiled-gallery-shape.php';
+require_once dirname( __FILE__ ) . '/tiled-gallery-item.php';
+
+class Jetpack_Tiled_Gallery_Layout_Rectangular extends Jetpack_Tiled_Gallery_Layout {
+ protected $type = 'rectangular';
+
+ public function HTML( $context = array() ) {
+ $grouper = new Jetpack_Tiled_Gallery_Grouper( $this->attachments );
+ Jetpack_Tiled_Gallery_Shape::reset_last_shape();
+
+ return parent::HTML( array( 'rows' => $grouper->grouped_images ) );
+ }
+}
+
+class Jetpack_Tiled_Gallery_Layout_Columns extends Jetpack_Tiled_Gallery_Layout {
+ protected $type = 'rectangular'; // It doesn't need separate template for now
+
+ public function HTML( $context = array() ) {
+ $grouper = new Jetpack_Tiled_Gallery_Grouper( $this->attachments, array( 'Three_Columns', 'Two' ) );
+
+ return parent::HTML( array( 'rows' => $grouper->grouped_images ) );
+ }
+}
+
+// Alias
+class Jetpack_Tiled_Gallery_Layout_Rectangle extends Jetpack_Tiled_Gallery_Layout_Rectangular {}
+
+// Image grouping and HTML generation logic
+class Jetpack_Tiled_Gallery_Grouper {
+ public $margin = 4;
+
+ // This list is ordered. If you put a shape that's likely to occur on top, it will happen all the time.
+ public $shapes = array(
+ 'Reverse_Symmetric_Row',
+ 'Long_Symmetric_Row',
+ 'Symmetric_Row',
+ 'One_Three',
+ 'Three_One',
+ 'One_Two',
+ 'Five',
+ 'Four',
+ 'Three',
+ 'Two_One',
+ 'Panoramic'
+ );
+
+ public function __construct( $attachments, $shapes = array() ) {
+ $content_width = Jetpack_Tiled_Gallery::get_content_width();
+ $ua_info = new Jetpack_User_Agent_Info();
+
+ $this->overwrite_shapes( $shapes );
+ $this->last_shape = '';
+ $this->images = $this->get_images_with_sizes( $attachments );
+ $this->grouped_images = $this->get_grouped_images();
+ $this->apply_content_width( $content_width );
+ }
+
+ public function overwrite_shapes( $shapes ) {
+ if ( ! empty( $shapes ) ) {
+ $this->shapes = $shapes;
+ }
+ }
+
+ public function get_current_row_size() {
+ $images_left = count( $this->images );
+ if ( $images_left < 3 )
+ return array_fill( 0, $images_left, 1 );
+
+ foreach ( $this->shapes as $shape_name ) {
+ $class_name = "Jetpack_Tiled_Gallery_$shape_name";
+ $shape = new $class_name( $this->images );
+ if ( $shape->is_possible() ) {
+ Jetpack_Tiled_Gallery_Shape::set_last_shape( $class_name );
+ return $shape->shape;
+ }
+ }
+
+ Jetpack_Tiled_Gallery_Shape::set_last_shape( 'Two' );
+ return array( 1, 1 );
+ }
+
+ public function get_images_with_sizes( $attachments ) {
+ $images_with_sizes = array();
+
+ foreach ( $attachments as $image ) {
+ $meta = wp_get_attachment_metadata( $image->ID );
+ $image->width_orig = ( isset( $meta['width'] ) && $meta['width'] > 0 )? $meta['width'] : 1;
+ $image->height_orig = ( isset( $meta['height'] ) && $meta['height'] > 0 )? $meta['height'] : 1;
+ $image->ratio = $image->width_orig / $image->height_orig;
+ $image->ratio = $image->ratio? $image->ratio : 1;
+ $images_with_sizes[] = $image;
+ }
+
+ return $images_with_sizes;
+ }
+
+ public function read_row() {
+ $vector = $this->get_current_row_size();
+
+ $row = array();
+ foreach ( $vector as $group_size ) {
+ $row[] = new Jetpack_Tiled_Gallery_Group( array_splice( $this->images, 0, $group_size ) );
+ }
+
+ return $row;
+ }
+
+ public function get_grouped_images() {
+ $grouped_images = array();
+
+ while( !empty( $this->images ) ) {
+ $grouped_images[] = new Jetpack_Tiled_Gallery_Row( $this->read_row() );
+ }
+
+ return $grouped_images;
+ }
+
+ // todo: split in functions
+ // todo: do not stretch images
+ public function apply_content_width( $width ) {
+ foreach ( $this->grouped_images as $row ) {
+ $row->width = $width;
+ $row->raw_height = 1 / $row->ratio * ( $width - $this->margin * ( count( $row->groups ) - $row->weighted_ratio ) );
+ $row->height = round( $row->raw_height );
+
+ $this->calculate_group_sizes( $row );
+ }
+ }
+
+ public function calculate_group_sizes( $row ) {
+ // Storing the calculated group heights in an array for rounding them later while preserving their sum
+ // This fixes the rounding error that can lead to a few ugly pixels sticking out in the gallery
+ $group_widths_array = array();
+ foreach ( $row->groups as $group ) {
+ $group->height = $row->height;
+ // Storing the raw calculations in a separate property to prevent rounding errors from cascading down and for diagnostics
+ $group->raw_width = ( $row->raw_height - $this->margin * count( $group->images ) ) * $group->ratio + $this->margin;
+ $group_widths_array[] = $group->raw_width;
+ }
+ $rounded_group_widths_array = Jetpack_Constrained_Array_Rounding::get_rounded_constrained_array( $group_widths_array, $row->width );
+
+ foreach ( $row->groups as $group ) {
+ $group->width = array_shift( $rounded_group_widths_array );
+ $this->calculate_image_sizes( $group );
+ }
+ }
+
+ public function calculate_image_sizes( $group ) {
+ // Storing the calculated image heights in an array for rounding them later while preserving their sum
+ // This fixes the rounding error that can lead to a few ugly pixels sticking out in the gallery
+ $image_heights_array = array();
+ foreach ( $group->images as $image ) {
+ $image->width = $group->width - $this->margin;
+ // Storing the raw calculations in a separate property for diagnostics
+ $image->raw_height = ( $group->raw_width - $this->margin ) / $image->ratio;
+ $image_heights_array[] = $image->raw_height;
+ }
+
+ $image_height_sum = $group->height - count( $image_heights_array ) * $this->margin;
+ $rounded_image_heights_array = Jetpack_Constrained_Array_Rounding::get_rounded_constrained_array( $image_heights_array, $image_height_sum );
+
+ foreach ( $group->images as $image ) {
+ $image->height = array_shift( $rounded_image_heights_array );
+ }
+ }
+}
+
+class Jetpack_Tiled_Gallery_Row {
+ public function __construct( $groups ) {
+ $this->groups = $groups;
+ $this->ratio = $this->get_ratio();
+ $this->weighted_ratio = $this->get_weighted_ratio();
+ }
+
+ public function get_ratio() {
+ $ratio = 0;
+ foreach ( $this->groups as $group ) {
+ $ratio += $group->ratio;
+ }
+ return $ratio > 0? $ratio : 1;
+ }
+
+ public function get_weighted_ratio() {
+ $weighted_ratio = 0;
+ foreach ( $this->groups as $group ) {
+ $weighted_ratio += $group->ratio * count( $group->images );
+ }
+ return $weighted_ratio > 0 ? $weighted_ratio : 1;
+ }
+}
+
+class Jetpack_Tiled_Gallery_Group {
+ public function __construct( $images ) {
+ $this->images = $images;
+ $this->ratio = $this->get_ratio();
+ }
+
+ public function get_ratio() {
+ $ratio = 0;
+ foreach ( $this->images as $image ) {
+ if ( $image->ratio )
+ $ratio += 1/$image->ratio;
+ }
+ if ( !$ratio )
+ return 1;
+
+ return 1/$ratio;
+ }
+
+ public function items( $needs_attachment_link, $grayscale ) {
+ $items = array();
+ foreach ( $this->images as $image ) {
+ $items[] = new Jetpack_Tiled_Gallery_Rectangular_Item( $image, $needs_attachment_link, $grayscale );
+ }
+
+ return $items;
+ }
+}
+
diff --git a/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-shape.php b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-shape.php
new file mode 100644
index 00000000..a95d274f
--- /dev/null
+++ b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-shape.php
@@ -0,0 +1,209 @@
+<?php
+class Jetpack_Tiled_Gallery_Shape {
+ static $shapes_used = array();
+
+ public function __construct( $images ) {
+ $this->images = $images;
+ $this->images_left = count( $images );
+ }
+
+ public function sum_ratios( $number_of_images = 3 ) {
+ return array_sum( array_slice( wp_list_pluck( $this->images, 'ratio' ), 0, $number_of_images ) );
+ }
+
+ public function next_images_are_symmetric() {
+ return $this->images_left > 2 && $this->images[0]->ratio == $this->images[2]->ratio;
+ }
+
+ public function is_not_as_previous( $n = 1 ) {
+ return ! in_array( get_class( $this ), array_slice( self::$shapes_used, -$n ) );
+ }
+
+ public function is_wide_theme() {
+ return Jetpack::get_content_width() > 1000;
+ }
+
+ public function image_is_landscape( $image ) {
+ return $image->ratio >= 1 && $image->ratio < 2;
+ }
+
+ public function image_is_portrait( $image ) {
+ return $image->ratio < 1;
+ }
+
+ public function image_is_panoramic( $image ) {
+ return $image->ratio >= 2;
+ }
+
+ public static function set_last_shape( $last_shape ) {
+ self::$shapes_used[] = $last_shape;
+ }
+
+ public static function reset_last_shape() {
+ self::$shapes_used = array();
+ }
+}
+
+class Jetpack_Tiled_Gallery_Three extends Jetpack_Tiled_Gallery_Shape {
+ public $shape = array( 1, 1, 1 );
+
+ public function is_possible() {
+ $ratio = $this->sum_ratios( 3 );
+ $has_enough_images = $this->images_left >= 3 && ! in_array( $this->images_left, array( 4, 6 ) );
+ return $has_enough_images && $this->is_not_as_previous( 3 ) &&
+ ( ( $ratio < 2.5 ) || ( $ratio < 5 && $this->next_images_are_symmetric() ) || $this->is_wide_theme() );
+ }
+}
+
+class Jetpack_Tiled_Gallery_Four extends Jetpack_Tiled_Gallery_Shape {
+ public $shape = array( 1, 1, 1, 1 );
+
+ public function is_possible() {
+ return $this->is_not_as_previous() &&
+ (
+ ( $this->sum_ratios( 4 ) < 3.5 && $this->images_left > 5 ) ||
+ ( $this->sum_ratios( 4 ) < 7 && $this->images_left == 4 )
+ );
+ }
+}
+
+class Jetpack_Tiled_Gallery_Five extends Jetpack_Tiled_Gallery_Shape {
+ public $shape = array( 1, 1, 1, 1, 1 );
+
+ public function is_possible() {
+ return $this->is_wide_theme() && $this->is_not_as_previous() && $this->sum_ratios( 5 ) < 5 &&
+ ( $this->images_left == 5 || ( $this->images_left != 10 && $this->images_left > 6 ) );
+ }
+}
+
+class Jetpack_Tiled_Gallery_Two_One extends Jetpack_Tiled_Gallery_Shape {
+ public $shape = array( 2, 1 );
+
+ public function is_possible() {
+ return $this->is_not_as_previous( 3 ) && $this->images_left >= 2 &&
+ $this->images[2]->ratio < 1.6 && $this->images[0]->ratio >= 0.9 && $this->images[0]->ratio < 2.0 && $this->images[1]->ratio >= 0.9 && $this->images[1]->ratio < 2.0;
+ }
+}
+
+class Jetpack_Tiled_Gallery_One_Two extends Jetpack_Tiled_Gallery_Shape {
+ public $shape = array( 1, 2 );
+
+ public function is_possible() {
+ return $this->is_not_as_previous( 3 ) && $this->images_left >= 2 &&
+ $this->images[0]->ratio < 1.6 && $this->images[1]->ratio >= 0.9 && $this->images[1]->ratio < 2.0 && $this->images[2]->ratio >= 0.9 && $this->images[2]->ratio < 2.0;
+ }
+}
+
+class Jetpack_Tiled_Gallery_One_Three extends Jetpack_Tiled_Gallery_Shape {
+ public $shape = array( 1, 3 );
+
+ public function is_possible() {
+ return $this->is_not_as_previous( 3 ) && $this->images_left > 3 &&
+ $this->image_is_portrait( $this->images[0] ) &&
+ $this->image_is_landscape( $this->images[1] ) &&
+ $this->image_is_landscape( $this->images[2] ) &&
+ $this->image_is_landscape( $this->images[3] );
+ }
+}
+
+class Jetpack_Tiled_Gallery_Three_One extends Jetpack_Tiled_Gallery_Shape {
+ public $shape = array( 3, 1 );
+
+ public function is_possible() {
+ return $this->is_not_as_previous( 3 ) && $this->images_left > 3 &&
+ $this->image_is_portrait( $this->images[3] ) &&
+ $this->image_is_landscape( $this->images[0] ) &&
+ $this->image_is_landscape( $this->images[1] ) &&
+ $this->image_is_landscape( $this->images[2] );
+ }
+}
+
+class Jetpack_Tiled_Gallery_Panoramic extends Jetpack_Tiled_Gallery_Shape {
+ public $shape = array( 1 );
+
+ public function is_possible() {
+ return $this->image_is_panoramic( $this->images[0] );
+ }
+}
+
+class Jetpack_Tiled_Gallery_Symmetric_Row extends Jetpack_Tiled_Gallery_Shape {
+ public $shape = array( 1, 2, 1 );
+
+ public function is_possible() {
+ return $this->is_not_as_previous( 5 ) &&
+ $this->images_left > 3 &&
+ $this->images_left != 5 &&
+ $this->image_is_portrait( $this->images[0] ) &&
+ $this->image_is_landscape( $this->images[1] ) &&
+ $this->image_is_landscape( $this->images[2] ) &&
+ $this->image_is_portrait( $this->images[3] );
+ }
+}
+class Jetpack_Tiled_Gallery_Reverse_Symmetric_Row extends Jetpack_Tiled_Gallery_Shape {
+ public $shape = array( 2, 1, 2 );
+
+ public function is_possible() {
+ return $this->is_not_as_previous( 5 ) && $this->images_left > 15 &&
+ $this->image_is_landscape( $this->images[0] ) &&
+ $this->image_is_landscape( $this->images[1] ) &&
+ $this->image_is_portrait( $this->images[2] ) &&
+ $this->image_is_landscape( $this->images[3] ) &&
+ $this->image_is_landscape( $this->images[4] );
+ }
+}
+
+class Jetpack_Tiled_Gallery_Long_Symmetric_Row extends Jetpack_Tiled_Gallery_Shape {
+ public $shape = array( 3, 1, 3 );
+
+ public function is_possible() {
+ return $this->is_not_as_previous( 5 ) && $this->images_left > 15 &&
+ $this->image_is_landscape( $this->images[0] ) &&
+ $this->image_is_landscape( $this->images[1] ) &&
+ $this->image_is_landscape( $this->images[2] ) &&
+ $this->image_is_portrait( $this->images[3] ) &&
+ $this->image_is_landscape( $this->images[4] ) &&
+ $this->image_is_landscape( $this->images[5] ) &&
+ $this->image_is_landscape( $this->images[6] );
+ }
+}
+
+class Jetpack_Tiled_Gallery_Three_Columns extends Jetpack_Tiled_Gallery_Shape {
+ public $shape = array();
+
+ public function __construct( $images ) {
+ parent::__construct( $images );
+
+ $total_ratio = $this->sum_ratios( $this->images_left );
+ $approximate_column_ratio = $total_ratio / 3;
+ $column_one_images = $column_two_images = $column_three_images = $sum = 0;
+
+ foreach ( $this->images as $image ) {
+ if ( $sum <= $approximate_column_ratio ) {
+ $column_one_images++;
+ }
+
+ if ( $sum > $approximate_column_ratio && $sum <= 2 * $approximate_column_ratio ) {
+ $column_two_images++;
+ }
+ $sum += $image->ratio;
+ }
+
+ $column_three_images = $this->images_left - $column_two_images - $column_one_images;
+
+ if ( $column_one_images ) {
+ $this->shape[] = $column_one_images;
+ }
+
+ if ( $column_two_images ) {
+ $this->shape[] = $column_two_images;
+ }
+
+ if ( $column_three_images ) {
+ $this->shape[] = $column_three_images;
+ }
+ }
+
+ public function is_possible() {
+ return ! empty( $this->shape );
+ }
+}
diff --git a/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-square.php b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-square.php
new file mode 100644
index 00000000..8d15e386
--- /dev/null
+++ b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery-square.php
@@ -0,0 +1,70 @@
+<?php
+require_once dirname( __FILE__ ) . '/tiled-gallery-layout.php';
+require_once dirname( __FILE__ ) . '/tiled-gallery-item.php';
+
+class Jetpack_Tiled_Gallery_Layout_Square extends Jetpack_Tiled_Gallery_Layout {
+ protected $type = 'square';
+
+ private function compute_items() {
+ $content_width = Jetpack_Tiled_Gallery::get_content_width();
+ $images_per_row = $this->columns;
+ $margin = 2;
+
+ $margin_space = ( $images_per_row * $margin ) * 2;
+ $size = floor( ( $content_width - $margin_space ) / $images_per_row );
+ $img_size = $remainder_size = $size;
+ $remainder = count( $this->attachments ) % $images_per_row;
+ if ( $remainder > 0 ) {
+ $remainder_space = ( $remainder * $margin ) * 2;
+ $remainder_size = floor( ( $content_width - $remainder_space ) / $remainder );
+ }
+
+ $c = 1;
+ $items_in_row = 0;
+ $rows = array();
+ $row = new stdClass;
+ $row->images = array();
+ foreach( $this->attachments as $image ) {
+ if ( $remainder > 0 && $c <= $remainder ) {
+ $img_size = $remainder_size;
+ } else {
+ $img_size = $size;
+ }
+
+ $image->width = $image->height = $img_size;
+
+ $item = new Jetpack_Tiled_Gallery_Square_Item( $image, $this->needs_attachment_link, $this->grayscale );
+
+ $row->images[] = $item;
+ $c ++;
+ $items_in_row++;
+
+ if ( $images_per_row === $items_in_row || $remainder + 1 == $c ) {
+ $rows[] = $row;
+ $items_in_row = 0;
+
+ $row->height = $img_size + $margin * 2;
+ $row->width = $content_width;
+ $row->group_size = $img_size + 2 * $margin;
+
+ $row = new stdClass;
+ $row->images = array();
+ }
+ }
+
+ if ( ! empty( $row->images ) ) {
+ $row->height = $img_size + $margin * 2;
+ $row->width = $content_width;
+ $row->group_size = $img_size + 2 * $margin;
+
+ $rows[] = $row;
+ }
+
+ return $rows;
+ }
+
+ public function HTML( $context = array() ) {
+ return parent::HTML( array( 'rows' => $this->compute_items() ) );
+ }
+}
+
diff --git a/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery.css b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery.css
index 1d96d004..09792d30 100644
--- a/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery.css
+++ b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery.css
@@ -21,7 +21,6 @@
}
.tiled-gallery .gallery-row {
overflow: hidden;
- margin-bottom: 2px;
}
.tiled-gallery .tiled-gallery-item a { /* Needs to reset some properties for theme compatibility */
background: transparent;
diff --git a/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery.js b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery.js
index bedb5b52..3dd5b769 100644
--- a/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery.js
+++ b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery.js
@@ -1,153 +1,164 @@
-( function($) {
-
-var TiledGallery = function() {
- this.resizeTimeout = null;
-
- this.populate();
-
- var self = this;
-
- $( window ).on( 'resize', function () {
- clearTimeout( self.resizeTimeout );
-
- self.resizeTimeout = setTimeout( function () { self.resize(); }, 150 );
- } );
-
- // Make any new galleries loaded by Infinite Scroll flexible
- $( 'body' ).on( 'post-load', $.proxy( self.initialize, self ) );
-
- // Populate and set up captions on newdash galleries.
- $( document ).on( 'page-rendered.wpcom-newdash', $.proxy( self.populate, self ) );
+/* jshint onevar:false, smarttabs:true */
- this.resize();
-};
-
-TiledGallery.prototype.populate = function() {
- this.gallery = $( '.tiled-gallery' );
- this.item = this.gallery.find( '.tiled-gallery-item' );
- this.caption = this.gallery.find( '.tiled-gallery-caption' );
-
- this.Captions();
-};
+( function($) {
-TiledGallery.prototype.initialize = function() {
- var self = this;
+ function TiledGalleryCollection() {
+ this.galleries = [];
+ this.findAndSetupNewGalleries();
+ }
- self.populate();
+ TiledGalleryCollection.prototype.findAndSetupNewGalleries = function() {
+ var self = this;
+ $( '.tiled-gallery.tiled-gallery-unresized' ).each( function() {
+ self.galleries.push( new TiledGallery( $( this ) ) );
+ } );
+ };
- // After each image load, run resize in case all images in the gallery are loaded.
- self.gallery.find( 'img' ).off( 'load.tiled-gallery' ).on( 'load.tiled-gallery', function () {
- self.resize();
- } );
+ TiledGalleryCollection.prototype.resizeAll = function() {
+ $.each(this.galleries, function(i, gallery) {
+ gallery.resize();
+ } );
+ };
+
+ function TiledGallery( galleryElem ) {
+ this.gallery = galleryElem;
+
+ this.addCaptionEvents();
+
+ // Resize when initialized to fit the gallery to window dimensions
+ this.resize();
+
+ // Displays the gallery and prevents it from being initialized again
+ this.gallery.removeClass( 'tiled-gallery-unresized' );
+ }
+
+ /**
+ * Selector for all resizeable elements inside a Tiled Gallery
+ */
+
+ TiledGallery.prototype.resizeableElementsSelector = '.gallery-row, .gallery-group, .tiled-gallery-item img';
+
+ /**
+ * Story
+ */
+
+ TiledGallery.prototype.addCaptionEvents = function() {
+ // Hide captions
+ this.gallery.find( '.tiled-gallery-caption' ).hide();
+
+ // Add hover effects to bring the caption up and down for each item
+ this.gallery.find( '.tiled-gallery-item' ).hover(
+ function() { $( this ).find( '.tiled-gallery-caption' ).stop(true, true).slideDown( 'fast' ); },
+ function() { $( this ).find( '.tiled-gallery-caption' ).stop(true, true).slideUp( 'fast' ); }
+ );
+ };
+
+ TiledGallery.prototype.getExtraDimension = function( el, attribute, mode ) {
+ if ( mode === 'horizontal' ) {
+ var left = ( attribute === 'border' ) ? 'borderLeftWidth' : attribute + 'Left';
+ var right = ( attribute === 'border' ) ? 'borderRightWidth' : attribute + 'Right';
+ return ( parseInt( el.css( left ), 10 ) || 0 ) + ( parseInt( el.css( right ), 10 ) || 0 );
+ } else if ( mode === 'vertical' ) {
+ var top = ( attribute === 'border' ) ? 'borderTopWidth' : attribute + 'Top';
+ var bottom = ( attribute === 'border' ) ? 'borderBottomWidth' : attribute + 'Bottom';
+ return ( parseInt( el.css( top ), 10 ) || 0 ) + ( parseInt( el.css( bottom ), 10 ) || 0 );
+ } else {
+ return 0;
+ }
+ };
- // Run resize now in case all images loaded from cache.
- self.resize();
-};
+ TiledGallery.prototype.resize = function() {
+ // Resize everything in the gallery based on the ratio of the current content width
+ // to the original content width;
+ var originalWidth = this.gallery.data( 'original-width' );
+ var currentWidth = this.gallery.parent().width();
+ var resizeRatio = Math.min( 1, currentWidth / originalWidth );
-/**
- * Story
- */
-TiledGallery.prototype.Captions = function() {
- /* Hide captions */
- this.caption.hide();
+ var self = this;
+ this.gallery.find( this.resizeableElementsSelector ).each( function () {
+ var thisGalleryElement = $( this );
- this.item.hover(
- function() { $( this ).find( '.tiled-gallery-caption' ).slideDown( 'fast' ); },
- function() { $( this ).find( '.tiled-gallery-caption' ).slideUp( 'fast' ); }
- );
-};
+ var marginWidth = self.getExtraDimension( thisGalleryElement, 'margin', 'horizontal' );
+ var marginHeight = self.getExtraDimension( thisGalleryElement, 'margin', 'vertical' );
-TiledGallery.prototype.resize = function() {
- var resizeableElements = '.gallery-row, .gallery-group, .tiled-gallery-item img';
+ var paddingWidth = self.getExtraDimension( thisGalleryElement, 'padding', 'horizontal' );
+ var paddingHeight = self.getExtraDimension( thisGalleryElement, 'padding', 'vertical' );
- this.gallery.each( function ( galleryIndex, galleryElement ) {
- var thisGallery = $( galleryElement );
+ var borderWidth = self.getExtraDimension( thisGalleryElement, 'border', 'horizontal' );
+ var borderHeight = self.getExtraDimension( thisGalleryElement, 'border', 'vertical' );
- // All images must be loaded before proceeding.
- var imagesLoaded = true;
+ // Take all outer dimensions into account when resizing so that images
+ // scale with constant empty space between them
+ var outerWidth = thisGalleryElement.data( 'original-width' ) + paddingWidth + borderWidth + marginWidth;
+ var outerHeight = thisGalleryElement.data( 'original-height' ) + paddingHeight + borderHeight + marginHeight;
- thisGallery.find( 'img' ).each( function () {
- if ( ! this.complete ) {
- imagesLoaded = false;
- return false;
- }
+ // Subtract margins so that images don't overflow on small browser windows
+ thisGalleryElement
+ .width( Math.floor( resizeRatio * outerWidth ) - marginWidth )
+ .height( Math.floor( resizeRatio * outerHeight ) - marginHeight );
} );
+ };
- if ( ! imagesLoaded ) {
- var loadCallback = arguments.callee;
+ /**
+ * Resizing logic
+ */
- // Once all of the images have loaded,
- // re-call this containing function.
- $( window ).load( function () {
- loadCallback( null, thisGallery );
- } );
+ var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
- return;
- }
+ function attachResizeInAnimationFrames( tiledGalleries ) {
+ var resizing = false;
+ var resizeTimeout = null;
- if ( ! thisGallery.data( 'sizes-set' ) ) {
- // Maintain a record of the original widths and heights of these elements
- // for proper scaling.
- thisGallery.data( 'sizes-set', true );
-
- thisGallery.find( resizeableElements ).each( function () {
- var thisGalleryElement = $( this );
-
- // Don't change margins, but remember what they were so they can be
- // accounted for in size calculations. When the screen width gets
- // small enough, ignoring the margins can cause images to overflow
- // into new rows.
- var extraWidth = ( parseInt( thisGalleryElement.css( 'marginLeft' ), 10 ) || 0 ) + ( parseInt( thisGalleryElement.css( 'marginRight' ), 10 ) || 0 );
- var extraHeight = ( parseInt( thisGalleryElement.css( 'marginTop' ), 10 ) || 0 ) + ( parseInt( thisGalleryElement.css( 'marginBottom' ), 10 ) || 0 )
-
- // In some situations, tiled galleries in Firefox have shown scrollbars on the images because
- // the .outerWidth() call on the image returns a value larger than the container. Restrict
- // widths used in the resizing functions to the maximum width of the container.
- var parentElement = $( thisGalleryElement.parents( resizeableElements ).get( 0 ) );
-
- if ( parentElement && parentElement.data( 'original-width' ) ) {
- thisGalleryElement
- .data( 'original-width', Math.min( parentElement.data( 'original-width' ), thisGalleryElement.outerWidth( true ) ) )
- .data( 'original-height', Math.min( parentElement.data( 'original-height' ), thisGalleryElement.outerHeight( true ) ) );
- }
- else {
- thisGalleryElement
- .data( 'original-width', thisGalleryElement.outerWidth( true ) )
- .data( 'original-height', thisGalleryElement.outerHeight( true ) );
- }
-
- thisGalleryElement
- .data( 'extra-width', extraWidth )
- .data( 'extra-height', extraHeight );
- } );
+ function handleFrame() {
+ tiledGalleries.resizeAll();
+ if ( resizing ) {
+ requestAnimationFrame( handleFrame );
+ }
}
- // Resize everything in the gallery based on the ratio of the current content width
- // to the original content width;
- var originalWidth = thisGallery.data( 'original-width' );
- var currentWidth = thisGallery.parent().width();
- var resizeRatio = Math.min( 1, currentWidth / originalWidth );
+ $( window ).resize( function() {
+ clearTimeout( resizeTimeout );
- thisGallery.find( resizeableElements ).each( function () {
- var thisGalleryElement = $( this );
+ if ( ! resizing ) {
+ requestAnimationFrame( handleFrame );
+ }
+ resizing = true;
+ resizeTimeout = setTimeout( function() {
+ resizing = false;
+ }, 15 );
+ } );
+ }
- thisGalleryElement
- .width( Math.floor( resizeRatio * thisGalleryElement.data( 'original-width' ) ) - thisGalleryElement.data( 'extra-width' ) )
- .height( Math.floor( resizeRatio * thisGalleryElement.data( 'original-height' ) ) - thisGalleryElement.data( 'extra-height' ) );
+ function attachPlainResize( tiledGalleries ) {
+ $( window ).resize( function() {
+ tiledGalleries.resizeAll();
} );
+ }
- thisGallery.removeClass( 'tiled-gallery-unresized' );
- } );
-};
+ /**
+ * Ready, set...
+ */
-/**
- * Ready, set...
- */
-$( document ).ready( function() {
+ $( document ).ready( function() {
+ var tiledGalleries = new TiledGalleryCollection();
- // Instance!
- var TiledGalleryInstance = new TiledGallery;
+ $( 'body' ).on( 'post-load', function() {
+ tiledGalleries.findAndSetupNewGalleries();
+ } );
+ $( document ).on( 'page-rendered.wpcom-newdash', function() {
+ tiledGalleries.findAndSetupNewGalleries();
+ } );
-});
+ // Chrome is a unique snow flake and will start lagging on occasion
+ // It helps if we only resize on animation frames
+ //
+ // For other browsers it seems like there is no lag even if we resize every
+ // time there is an event
+ if ( window.chrome && requestAnimationFrame ) {
+ attachResizeInAnimationFrames( tiledGalleries );
+ } else {
+ attachPlainResize( tiledGalleries );
+ }
+ });
-})(jQuery); \ No newline at end of file
+})(jQuery);
diff --git a/plugins/jetpack/modules/tonesque.php b/plugins/jetpack/modules/tonesque.php
index 6d6e6141..88c13090 100644
--- a/plugins/jetpack/modules/tonesque.php
+++ b/plugins/jetpack/modules/tonesque.php
@@ -1,10 +1,6 @@
<?php
/**
- * Themes must declare that they support this module by adding
- * add_theme_support( 'tonesque' ); on 'after_setup_theme'.
+ * Deprecated. No longer needed.
+ *
+ * @package Jetpack
*/
-function jetpack_load_tonesque() {
- if ( current_theme_supports( 'tonesque' ) )
- jetpack_require_lib( 'tonesque' );
-}
-add_action( 'init', 'jetpack_load_tonesque' );
diff --git a/plugins/jetpack/modules/vaultpress.php b/plugins/jetpack/modules/vaultpress.php
index f4739761..7fbc6193 100644
--- a/plugins/jetpack/modules/vaultpress.php
+++ b/plugins/jetpack/modules/vaultpress.php
@@ -1,9 +1,9 @@
<?php
/**
* Module Name: VaultPress
- * Module Description: Realtime backup and security scanning for your WordPress site.
+ * Module Description: Protect your site with automatic backups and security scans. (Subscription required.)
* First Introduced: 0:1.2
- * Sort Order: 7
+ * Sort Order: 32
* Deactivate: false
* Free: false
* Requires Connection: Yes
diff --git a/plugins/jetpack/modules/verification-tools.php b/plugins/jetpack/modules/verification-tools.php
new file mode 100644
index 00000000..87d4c0f2
--- /dev/null
+++ b/plugins/jetpack/modules/verification-tools.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * Module Name: Site Verification
+ * Module Description: Verify your site or domain with Google Webmaster Tools, Pinterest, and others.
+ * First Introduced: 3.0
+ * Sort Order: 33
+ * Requires Connection: No
+ * Auto Activate: Yes
+ */
+
+function jetpack_load_verification_tools() {
+ include dirname( __FILE__ ) . "/verification-tools/blog-verification-tools.php";
+}
+
+function jetpack_verification_tools_loaded() {
+ Jetpack::enable_module_configurable( __FILE__ );
+ Jetpack::module_configuration_load( __FILE__, 'jetpack_verification_tools_configuration_load' );
+}
+add_action( 'jetpack_modules_loaded', 'jetpack_verification_tools_loaded' );
+
+function jetpack_verification_tools_configuration_load() {
+ wp_safe_redirect( admin_url( 'tools.php' ) );
+ exit;
+}
+
+jetpack_load_verification_tools();
diff --git a/plugins/jetpack/modules/verification-tools/blog-verification-tools.php b/plugins/jetpack/modules/verification-tools/blog-verification-tools.php
new file mode 100644
index 00000000..4a6bd4fa
--- /dev/null
+++ b/plugins/jetpack/modules/verification-tools/blog-verification-tools.php
@@ -0,0 +1,122 @@
+<?php
+
+// Edit here to add new services
+function jetpack_verification_services() {
+ return array(
+ 'google' => array(
+ 'name' =>'Google Webmaster Tools',
+ 'key' =>'google-site-verification',
+ 'format' =>'dBw5CvburAxi537Rp9qi5uG2174Vb6JwHwIRwPSLIK8',
+ 'url' => 'https://www.google.com/webmasters/tools/',
+ ),
+ 'bing' => array(
+ 'name' =>'Bing Webmaster Center',
+ 'key' =>'msvalidate.01',
+ 'format' =>'12C1203B5086AECE94EB3A3D9830B2E',
+ 'url' => 'http://www.bing.com/webmaster/',
+ ),
+ 'pinterest' => array(
+ 'name' => 'Pinterest Site Verification',
+ 'key' => 'p:domain_verify',
+ 'format' => 'f100679e6048d45e4a0b0b92dce1efce',
+ 'url' => 'https://pinterest.com/website/verify/',
+ ),
+ );
+}
+
+
+function jetpack_verification_options_init() {
+ register_setting( 'verification_services_codes_fields', 'verification_services_codes', 'jetpack_verification_validate' );
+}
+add_action( 'admin_init', 'jetpack_verification_options_init' );
+
+function jetpack_verification_print_meta() {
+ $verification_services_codes = get_option( 'verification_services_codes' );
+ if ( is_array( $verification_services_codes ) ) {
+ $ver_output = "<!-- Jetpack Site Verification Tags -->\n";
+ foreach ( jetpack_verification_services() as $name => $service ) {
+ if ( is_array( $service ) && !empty( $verification_services_codes["$name"] ) ) {
+ $ver_tag = sprintf( '<meta name="%s" content="%s" />', esc_attr( $service["key"] ), esc_attr( $verification_services_codes["$name"] ) );
+ $ver_output .= apply_filters( 'jetpack_site_verification_output', $ver_tag );
+ $ver_output .= "\n";
+ }
+ }
+ echo $ver_output;
+ }
+}
+add_action( 'wp_head', 'jetpack_verification_print_meta', 1 );
+
+function jetpack_verification_get_code( $code ){
+ $pattern = '/content=["\']?([^"\' ]*)["\' ]/is';
+ preg_match( $pattern, $code, $match );
+ if ( $match ){
+ return urldecode( $match[1] );
+ } else {
+ return false;
+ }
+}
+
+function jetpack_verification_validate( $verification_services_codes ) {
+ foreach ( $verification_services_codes as $key => &$code ) {
+ // Parse html meta tags if present
+ if ( stripos( $code, 'meta' ) )
+ $code = jetpack_verification_get_code( $code );
+
+ $code = esc_attr( trim( $code ) );
+
+ // limit length to 100 chars.
+ $code = substr( $code, 0, 100 );
+
+ do_action( 'jetpack_site_verification_validate', $key, $code );
+ }
+ return $verification_services_codes;
+}
+
+function jetpack_verification_options_form() {
+ $verification_services_codes = get_option( 'verification_services_codes' );
+ ?>
+<form method="post" action="options.php">
+ <?php settings_fields( 'verification_services_codes_fields' ); ?>
+ <table class="form-table">
+ <?php
+ foreach ( jetpack_verification_services() as $key => $service ) {
+ echo "<tr valign='top'>
+ <th scope='row'>" . esc_html( $service['name'] ) . "</th>
+ <td>
+ <input value='" . esc_attr( $verification_services_codes["$key"] ) . "' size='50' name='verification_services_codes[" . esc_attr( $key ) . "]' type='text' />
+ </td>
+ </tr><tr>
+ <td colspan='2'><small>
+ <label for='verification_services_codes[" . esc_attr( $key ) . "]'>" . esc_html( __( 'Example:' , 'jetpack' ) ) . " <code>&lt;meta name='" . esc_attr( $service['key'] ) . "' content='<strong>" . esc_attr( $service['format'] ) . "</strong>'&gt;</code></label>
+ </small></td>
+ </tr>";
+ }
+ ?>
+ </table>
+ <p class="submit">
+ <input type="submit" class="button-primary" value="<?php _e( 'Save Changes' , 'jetpack' ); ?>" />
+ </p>
+</form>
+<?php
+}
+
+function jetpack_verification_tool_box() {
+ global $current_user;
+
+ if ( !apply_filters( 'jetpack_enable_site_verification', true ) )
+ return;
+
+ $list = array();
+ foreach ( jetpack_verification_services() as $key => $service ) {
+ $list[] = '<a href="' . esc_url( $service['url'] ) . '">' . esc_html( $service['name'] ) . '</a>';
+ }
+ $last = array_pop( $list );
+
+ if ( current_user_can( 'manage_options' ) ) {
+ echo '<div class="tool-box"><h3 class="title">' . __( 'Website Verification Services' , 'jetpack' ) . ' <a href="http://support.wordpress.com/webmaster-tools/" target="_blank">(?)</a></h3>';
+ echo '<p>' . sprintf( esc_html( __( 'Enter your meta key "content" value to verify your blog with %s' , 'jetpack' ) ), implode( ', ', $list ) ) . ' ' . __( 'and' , 'jetpack' ) . ' ' . $last . '.</p>';
+ jetpack_verification_options_form();
+ echo '</div>';
+ }
+}
+add_action( 'tool_box', 'jetpack_verification_tool_box', 25 );
diff --git a/plugins/jetpack/modules/videopress.php b/plugins/jetpack/modules/videopress.php
index 093dba28..f80b74c5 100644
--- a/plugins/jetpack/modules/videopress.php
+++ b/plugins/jetpack/modules/videopress.php
@@ -1,13 +1,18 @@
<?php
/**
* Module Name: VideoPress
- * Module Description: Quite possibly the easiest way to upload beautiful videos to your blog.
+ * Module Description: Upload and embed videos right on your site. (Subscription required.)
* First Introduced: 2.5
* Free: false
* Requires Connection: Yes
- * Sort Order: 100
+ * Sort Order: 27
+ * Module Tags: Photos and Videos
*/
+Jetpack::dns_prefetch( array(
+ '//v0.wordpress.com',
+) );
+
function jetpack_load_videopress() {
include dirname( __FILE__ ) . "/videopress/videopress.php";
}
diff --git a/plugins/jetpack/modules/videopress/class.videopress-player.php b/plugins/jetpack/modules/videopress/class.videopress-player.php
index 31502d37..5242de89 100644
--- a/plugins/jetpack/modules/videopress/class.videopress-player.php
+++ b/plugins/jetpack/modules/videopress/class.videopress-player.php
@@ -78,7 +78,7 @@ class VideoPress_Player {
$cache_key_pieces[] = get_current_blog_id();
$cache_key_pieces[] = $guid;
- if ( $width > 0 )
+ if ( $maxwidth > 0 )
$cache_key_pieces[] = $maxwidth;
if ( is_ssl() )
$cache_key_pieces[] = 'ssl';
@@ -664,18 +664,18 @@ class VideoPress_Player {
return <<<OBJECT
<script type="text/javascript">if(typeof swfobject!=="undefined"){swfobject.registerObject("{$this->video_id}", "{$this->video->players->swf->version}");}</script>
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="{$this->video->calculated_width}" height="{$this->video->calculated_height}" id="{$this->video_id}"{$standby}>
- <param name="movie" value="{$flash_player_url}" />
- {$flash_params}
- <param name="flashvars" value="{$flash_vars}" />
- <!--[if !IE]>-->
- <object type="application/x-shockwave-flash" data="{$flash_player_url}" width="{$this->video->calculated_width}" height="{$this->video->calculated_height}"{$standby}>
- {$flash_params}
- <param name="flashvars" value="{$flash_vars}" />
- <!--<![endif]-->
- {$thumbnail_html}{$description}<p class="robots-nocontent">{$flash_help}</p>
- <!--[if !IE]>-->
- </object>
- <!--<![endif]-->
+ <param name="movie" value="{$flash_player_url}" />
+ {$flash_params}
+ <param name="flashvars" value="{$flash_vars}" />
+ <!--[if !IE]>-->
+ <object type="application/x-shockwave-flash" data="{$flash_player_url}" width="{$this->video->calculated_width}" height="{$this->video->calculated_height}"{$standby}>
+ {$flash_params}
+ <param name="flashvars" value="{$flash_vars}" />
+ <!--<![endif]-->
+ {$thumbnail_html}{$description}<p class="robots-nocontent">{$flash_help}</p>
+ <!--[if !IE]>-->
+ </object>
+ <!--<![endif]-->
</object>
OBJECT;
}
diff --git a/plugins/jetpack/modules/videopress/shortcode.php b/plugins/jetpack/modules/videopress/shortcode.php
index 3aa174cf..9a501475 100644
--- a/plugins/jetpack/modules/videopress/shortcode.php
+++ b/plugins/jetpack/modules/videopress/shortcode.php
@@ -72,8 +72,7 @@ class Jetpack_VideoPress_Shortcode {
) );
// Enqueue VideoPress scripts
- $js_url = ( is_ssl() ) ? 'https://v0.wordpress.com/js/videopress.js' : 'http://s0.videopress.com/js/videopress.js';
- wp_enqueue_script( 'videopress', $js_url, array( 'jquery', 'swfobject' ), '1.09' );
+ self::enqueue_scripts();
require_once( dirname( __FILE__ ) . '/class.videopress-video.php' );
require_once( dirname( __FILE__ ) . '/class.videopress-player.php' );
@@ -99,6 +98,18 @@ class Jetpack_VideoPress_Shortcode {
else
return false;
}
+
+ /**
+ * Enqueue scripts needed to play VideoPress videos
+ *
+ * @uses is_ssl()
+ * @uses wp_enqueue_script()
+ * @return null
+ */
+ public static function enqueue_scripts() {
+ $js_url = ( is_ssl() ) ? 'https://v0.wordpress.com/js/videopress.js' : 'http://s0.videopress.com/js/videopress.js';
+ wp_enqueue_script( 'videopress', $js_url, array( 'jquery', 'swfobject' ), '1.09' );
+ }
}
// Initialize the shortcode handler.
diff --git a/plugins/jetpack/modules/videopress/videopress-admin-rtl.css b/plugins/jetpack/modules/videopress/videopress-admin-rtl.css
new file mode 100644
index 00000000..41c86793
--- /dev/null
+++ b/plugins/jetpack/modules/videopress/videopress-admin-rtl.css
@@ -0,0 +1,97 @@
+/**
+ * VideoPress admin media styles
+ */
+.videopress-modal-backdrop {
+ background: #000;
+ opacity: 0.7;
+ position: absolute;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+ z-index: 100;
+}
+
+.videopress-modal {
+ padding: 10px 20px;
+ background: white;
+ position: absolute;
+ top: 0;
+ width: 440px;
+ overflow: hidden;
+ right: 50%;
+ margin-right: -220px;
+ z-index: 101;
+ box-shadow: -2px 2px 5px 2px rgba( 0, 0, 0, 0.5 );
+ -webkit-border-bottom-left-radius: 2px;
+ -webkit-border-bottom-right-radius: 2px;
+ border-bottom-left-radius: 2px;
+ border-bottom-right-radius: 2px;
+}
+
+.videopress-modal .submit {
+ text-align: left;
+ padding: 10px 0 5px;
+}
+
+.videopress-preview {
+ display: block;
+ float: left;
+ width: 65%;
+ margin-top: 18px;
+ background: black;
+ min-height: 97px;
+ text-decoration: none;
+}
+
+.vp-preview span.videopress-preview-unavailable {
+ width: 65%;
+ float: left;
+ text-align: right;
+ margin-left: 0;
+}
+
+.videopress-preview img {
+ float: right;
+ width: 100%;
+}
+
+.videopress-preview span {
+ display: block;
+ padding-top: 40px;
+ color: white !important;
+ text-align: center;
+}
+
+.vp-setting .help {
+ margin: 0 35% 4px 0;
+}
+
+.media-sidebar .vp-setting input[type="checkbox"] {
+ float: right;
+ margin-top: 10px;
+}
+
+.vp-setting label {
+ float: right;
+ margin: 8px 5px 0 8px;
+ max-width: 135px;
+}
+
+.vp-setting input[type='radio'] {
+ float: right;
+ margin-top: 9px;
+ width: auto;
+}
+
+.vp-preview span {
+ margin-top: 18px;
+}
+
+.uploader-videopress {
+ margin: 16px;
+}
+
+.uploader-videopress .videopress-errors div {
+ margin: 16px 0;
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/videopress/videopress-admin-rtl.min.css b/plugins/jetpack/modules/videopress/videopress-admin-rtl.min.css
new file mode 100644
index 00000000..f547b1f9
--- /dev/null
+++ b/plugins/jetpack/modules/videopress/videopress-admin-rtl.min.css
@@ -0,0 +1 @@
+.videopress-modal-backdrop{background:#000;opacity:.7;position:absolute;top:0;width:100%;height:100%;overflow:hidden;z-index:100}.videopress-modal{padding:10px 20px;background:#fff;position:absolute;top:0;width:440px;overflow:hidden;right:50%;margin-right:-220px;z-index:101;box-shadow:-2px 2px 5px 2px rgba(0,0,0,.5);-webkit-border-bottom-left-radius:2px;-webkit-border-bottom-right-radius:2px;border-bottom-left-radius:2px;border-bottom-right-radius:2px}.videopress-modal .submit{text-align:left;padding:10px 0 5px}.videopress-preview{display:block;float:left;width:65%;margin-top:18px;background:#000;min-height:97px;text-decoration:none}.vp-preview span.videopress-preview-unavailable{width:65%;float:left;text-align:right;margin-left:0}.videopress-preview img{float:right;width:100%}.videopress-preview span{display:block;padding-top:40px;color:#fff!important;text-align:center}.vp-setting .help{margin:0 35% 4px 0}.media-sidebar .vp-setting input[type=checkbox]{float:right;margin-top:10px}.vp-setting label{float:right;margin:8px 5px 0 8px;max-width:135px}.vp-setting input[type=radio]{float:right;margin-top:9px;width:auto}.vp-preview span{margin-top:18px}.uploader-videopress{margin:16px}.uploader-videopress .videopress-errors div{margin:16px 0} \ No newline at end of file
diff --git a/plugins/jetpack/modules/videopress/videopress-admin.js b/plugins/jetpack/modules/videopress/videopress-admin.js
index c4a30ca2..c7851117 100644
--- a/plugins/jetpack/modules/videopress/videopress-admin.js
+++ b/plugins/jetpack/modules/videopress/videopress-admin.js
@@ -1,3 +1,6 @@
+/* jshint onevar: false, smarttabs: true, devel: true */
+/* global VideoPressAdminSettings, setUserSetting */
+
/**
* VideoPress Admin
*
@@ -26,8 +29,9 @@
}, media.controller.Library.prototype.defaults ),
initialize: function() {
- if ( ! this.get('library') )
+ if ( ! this.get('library') ) {
this.set( 'library', media.query({ videopress: true }) );
+ }
media.controller.Library.prototype.initialize.apply( this, arguments );
},
@@ -37,8 +41,9 @@
* so we hi-jack it a little bit.
*/
saveContentMode: function() {
- if ( 'videopress' !== this.get('router') )
+ if ( 'videopress' !== this.get('router') ) {
return;
+ }
var mode = this.frame.content.mode(),
view = this.frame.router.get();
@@ -46,8 +51,9 @@
if ( view && view.get( mode ) ) {
// Map the Upload a Video back to the regular Upload Files.
- if ( 'upload_videopress' === mode )
+ if ( 'upload_videopress' === mode ) {
mode = 'upload';
+ }
setUserSetting( 'libraryContent', mode );
}
@@ -69,10 +75,11 @@
initialize: function() {
var that = this;
- if ( ! window.addEventListener )
- window.attachEvent( "onmessage", function() { return that.messageHandler.apply( that, arguments ); } );
- else
- window.addEventListener( "message", function() { return that.messageHandler.apply( that, arguments ); }, false );
+ if ( ! window.addEventListener ) {
+ window.attachEvent( 'onmessage', function() { return that.messageHandler.apply( that, arguments ); } );
+ } else {
+ window.addEventListener( 'message', function() { return that.messageHandler.apply( that, arguments ); }, false );
+ }
return media.View.prototype.initialize.apply( this, arguments );
},
@@ -134,8 +141,9 @@
},
messageHandler: function( event ) {
- if ( ! event.origin.match( /\.wordpress\.com$/ ) )
+ if ( ! event.origin.match( /\.wordpress\.com$/ ) ) {
return;
+ }
if ( event.data.indexOf && event.data.indexOf( 'vpUploadResult::' ) === 0 ) {
var result = JSON.parse( event.data.substr( 16 ) );
@@ -146,7 +154,7 @@
return;
}
- if ( 'success' == result.code && result.data ) {
+ if ( 'success' === result.code && result.data ) {
var that = this, controller = this.controller,
state = controller.states.get( 'videopress' );
@@ -245,8 +253,9 @@
var UploaderWindow = media.view.UploaderWindow;
media.view.UploaderWindow = UploaderWindow.extend({
show: function() {
- if ( 'videopress' != this.controller.state().get('id') )
+ if ( 'videopress' !== this.controller.state().get('id') ) {
UploaderWindow.prototype.show.apply( this, arguments );
+ }
return this;
}
@@ -257,9 +266,37 @@
*/
var AttachmentsBrowser = media.view.AttachmentsBrowser;
media.view.AttachmentsBrowser = AttachmentsBrowser.extend({
+ /**
+ * Snag the Core 3.9.2 versions as a quick fix to avoid
+ * the breakage introduced by r29364-core
+ */
+ updateContent: function() {
+ var view = this;
+
+ if( ! this.attachments ) {
+ this.createAttachments();
+ }
+
+ if ( ! this.collection.length ) {
+ this.toolbar.get( 'spinner' ).show();
+ this.collection.more().done(function() {
+ if ( ! view.collection.length ) {
+ view.createUploader();
+ }
+ view.toolbar.get( 'spinner' ).hide();
+ });
+ } else {
+ view.toolbar.get( 'spinner' ).hide();
+ }
+ },
+ /**
+ * Empty out to avoid breakage.
+ */
+ toggleUploader: function() {},
createUploader: function() {
- if ( 'videopress' != this.controller.state().get('id') )
+ if ( 'videopress' !== this.controller.state().get('id') ) {
return AttachmentsBrowser.prototype.createUploader.apply( this, arguments );
+ }
}
});
@@ -273,11 +310,13 @@
var view = _.first( this.views.get( '.media-frame-router' ) ),
viewSettings = {};
- if ( VideoPress.caps.read_videos )
+ if ( VideoPress.caps.read_videos ) {
viewSettings.browse = { text: VideoPress.l10n.VideoPressLibraryRouter, priority: 40 };
+ }
- if ( VideoPress.caps.upload_videos )
+ if ( VideoPress.caps.upload_videos ) {
viewSettings.upload_videopress = { text: VideoPress.l10n.uploadVideoRouter, priority: 20 };
+ }
view.set( viewSettings );
@@ -285,14 +324,15 @@
wp.Uploader.queue.on( 'add', this.VideoPress.disableUpload, this );
// Map the Upload Files view to the Upload a Video one (upload_videopress vs. upload)
- if ( 'upload' === this.content.mode() && VideoPress.caps.upload_videos )
+ if ( 'upload' === this.content.mode() && VideoPress.caps.upload_videos ) {
this.content.mode( 'upload_videopress' );
- else
+ } else {
this.content.mode( 'browse' );
+ }
},
// When navigated away from the VideoPress router.
- deactivate: function( view ) {
+ deactivate: function( /*view*/ ) {
wp.Uploader.queue.off( 'add', this.VideoPress.disableUpload );
},
@@ -320,10 +360,11 @@
},
// Create a custom toolbar
- createToolbar: function( toolbar ) {
+ createToolbar: function( /*toolbar*/ ) {
// Alow an option to hide the toolbar.
- if ( this.options.VideoPress && this.options.VideoPress.hideToolbar )
+ if ( this.options.VideoPress && this.options.VideoPress.hideToolbar ) {
return this;
+ }
var controller = this;
this.toolbar.set( new media.view.Toolbar({
@@ -400,8 +441,9 @@
this.model = controller.model;
this.guid = this.model.get( 'vp_guid' );
- if ( ! this.$frame )
+ if ( ! this.$frame ) {
this.$frame = $( '.media-frame-content' );
+ }
this.$el.html( this.template( { 'video' : this.model.get( 'vp_embed' ) } ) );
this.$modal = this.$( '.videopress-modal' );
@@ -427,8 +469,9 @@
var $form = $( '#videopress-settings' );
// Not on a configuration screen
- if ( ! $form.length )
+ if ( ! $form.length ) {
return;
+ }
var $access = $form.find( 'input[name="videopress-access"]' ),
$upload = $form.find( 'input[name="videopress-upload"]' );
@@ -437,8 +480,9 @@
var access = $access.filter( ':checked' ).val();
$upload.attr( 'disabled', ! access );
- if ( ! access )
+ if ( ! access ) {
$upload.attr( 'checked', false );
+ }
});
$access.trigger( 'change' );
@@ -447,7 +491,7 @@
// Media -> VideoPress menu
$(document).on( 'click', '#videopress-browse', function() {
- var frame = wp.media({
+ wp.media({
state: 'videopress',
states: [ new media.controller.VideoPress() ],
VideoPress: { hideToolbar: true }
@@ -455,4 +499,4 @@
return false;
});
-})(jQuery); \ No newline at end of file
+})(jQuery);
diff --git a/plugins/jetpack/modules/videopress/videopress-admin.min.css b/plugins/jetpack/modules/videopress/videopress-admin.min.css
new file mode 100644
index 00000000..51b65e77
--- /dev/null
+++ b/plugins/jetpack/modules/videopress/videopress-admin.min.css
@@ -0,0 +1 @@
+.videopress-modal-backdrop{background:#000;opacity:.7;position:absolute;top:0;width:100%;height:100%;overflow:hidden;z-index:100}.videopress-modal{padding:10px 20px;background:#fff;position:absolute;top:0;width:440px;overflow:hidden;left:50%;margin-left:-220px;z-index:101;box-shadow:2px 2px 5px 2px rgba(0,0,0,.5);-webkit-border-bottom-right-radius:2px;-webkit-border-bottom-left-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:2px}.videopress-modal .submit{text-align:right;padding:10px 0 5px}.videopress-preview{display:block;float:right;width:65%;margin-top:18px;background:#000;min-height:97px;text-decoration:none}.vp-preview span.videopress-preview-unavailable{width:65%;float:right;text-align:left;margin-right:0}.videopress-preview img{float:left;width:100%}.videopress-preview span{display:block;padding-top:40px;color:#fff!important;text-align:center}.vp-setting .help{margin:0 0 4px 35%}.media-sidebar .vp-setting input[type=checkbox]{float:left;margin-top:10px}.vp-setting label{float:left;margin:8px 8px 0 5px;max-width:135px}.vp-setting input[type=radio]{float:left;margin-top:9px;width:auto}.vp-preview span{margin-top:18px}.uploader-videopress{margin:16px}.uploader-videopress .videopress-errors div{margin:16px 0} \ No newline at end of file
diff --git a/plugins/jetpack/modules/videopress/videopress.php b/plugins/jetpack/modules/videopress/videopress.php
index 84739be2..28771fb6 100644
--- a/plugins/jetpack/modules/videopress/videopress.php
+++ b/plugins/jetpack/modules/videopress/videopress.php
@@ -124,7 +124,7 @@ class Jetpack_VideoPress {
// Ask WordPress.com for a list of VideoPress blogs
$result = $this->query( 'jetpack.vpGetBlogs' );
- if ( ! is_wp_error() )
+ if ( ! is_wp_error( $result ) )
$options['blogs'] = $result;
// If there's at least one available blog, let's use it.
@@ -261,7 +261,7 @@ class Jetpack_VideoPress {
<table id="menu" class="form-table">
<tr>
<th scope="row" colspan="2">
- <p><?php _e( 'Please note that the VideoPress module requires a WordPress.com account with an active <a href="http://store.wordpress.com/premium-upgrades/videopress/" target="_blank">VideoPress subscription</a>.</p>', 'jetpack' ); ?></p>
+ <p><?php _e( 'Please note that the VideoPress module requires a WordPress.com account with an active <a href="http://store.wordpress.com/premium-upgrades/videopress/" target="_blank">VideoPress subscription</a>.', 'jetpack' ); ?></p>
</th>
</tr>
<tr>
@@ -473,7 +473,7 @@ class Jetpack_VideoPress {
'order' => 'desc',
'paged' => 1,
's' => '',
- ), (array) $args );
+ ), (array) $args, 'wpvideo' );
$args['posts_per_page'] = absint( $args['posts_per_page'] );
@@ -516,7 +516,7 @@ class Jetpack_VideoPress {
'vp_share' => null,
'vp_rating' => null,
- ), $changes );
+ ), $changes, 'wpvideo' );
if ( ! is_null( $changes['vp_share'] ) )
$changes['vp_share'] = (bool) $changes['vp_share'];
diff --git a/plugins/jetpack/modules/widget-visibility.php b/plugins/jetpack/modules/widget-visibility.php
index f96dc61c..fffef6a4 100644
--- a/plugins/jetpack/modules/widget-visibility.php
+++ b/plugins/jetpack/modules/widget-visibility.php
@@ -2,10 +2,12 @@
/**
* Module Name: Widget Visibility
- * Module Description: Control what pages your widgets appear on.
+ * Module Description: Specify which widgets appear on which pages of your site.
* First Introduced: 2.4
* Requires Connection: No
* Auto Activate: Yes
+ * Sort Order: 17
+ * Module Tags: Appearance
*/
include dirname( __FILE__ ) . "/widget-visibility/widget-conditions.php";
diff --git a/plugins/jetpack/modules/widget-visibility/widget-conditions.php b/plugins/jetpack/modules/widget-visibility/widget-conditions.php
index 580b708c..cd48a309 100644
--- a/plugins/jetpack/modules/widget-visibility/widget-conditions.php
+++ b/plugins/jetpack/modules/widget-visibility/widget-conditions.php
@@ -6,6 +6,8 @@
*/
class Jetpack_Widget_Conditions {
+ static $passed_template_redirect = false;
+
public static function init() {
if ( is_admin() ) {
add_action( 'sidebar_admin_setup', array( __CLASS__, 'widget_admin_setup' ) );
@@ -14,14 +16,20 @@ class Jetpack_Widget_Conditions {
add_action( 'wp_ajax_widget_conditions_options', array( __CLASS__, 'widget_conditions_options' ) );
}
else {
- add_action( 'widget_display_callback', array( __CLASS__, 'filter_widget' ) );
- add_action( 'sidebars_widgets', array( __CLASS__, 'sidebars_widgets' ) );
+ add_filter( 'widget_display_callback', array( __CLASS__, 'filter_widget' ) );
+ add_filter( 'sidebars_widgets', array( __CLASS__, 'sidebars_widgets' ) );
+ add_action( 'template_redirect', array( __CLASS__, 'template_redirect' ) );
}
}
public static function widget_admin_setup() {
+ if( is_rtl() ) {
+ wp_enqueue_style( 'widget-conditions', plugins_url( 'widget-conditions/rtl/widget-conditions-rtl.css', __FILE__ ) );
+ } else {
+ wp_enqueue_style( 'widget-conditions', plugins_url( 'widget-conditions/widget-conditions.css', __FILE__ ) );
+ }
wp_enqueue_style( 'widget-conditions', plugins_url( 'widget-conditions/widget-conditions.css', __FILE__ ) );
- wp_enqueue_script( 'widget-conditions', plugins_url( 'widget-conditions/widget-conditions.js', __FILE__ ), array( 'jquery', 'jquery-ui-core' ), 20130129, true );
+ wp_enqueue_script( 'widget-conditions', plugins_url( 'widget-conditions/widget-conditions.js', __FILE__ ), array( 'jquery', 'jquery-ui-core' ), 20140721, true );
}
/**
@@ -43,6 +51,12 @@ class Jetpack_Widget_Conditions {
<?php
}
break;
+ case 'loggedin':
+ ?>
+ <option value="loggedin" <?php selected( 'loggedin', $minor ); ?>><?php _e( 'Logged In', 'jetpack' ); ?></option>
+ <option value="loggedout" <?php selected( 'loggedout', $minor ); ?>><?php _e( 'Logged Out', 'jetpack' ); ?></option>
+ <?php
+ break;
case 'author':
?>
<option value=""><?php _e( 'All author pages', 'jetpack' ); ?></option>
@@ -54,6 +68,15 @@ class Jetpack_Widget_Conditions {
<?php
}
break;
+ case 'role':
+ global $wp_roles;
+
+ foreach ( $wp_roles->roles as $role_key => $role ) {
+ ?>
+ <option value="<?php echo esc_attr( $role_key ); ?>" <?php selected( $role_key, $minor ); ?> ><?php echo esc_html( $role['name'] ); ?></option>
+ <?php
+ }
+ break;
case 'tag':
?>
<option value=""><?php _e( 'All tag pages', 'jetpack' ); ?></option>
@@ -86,6 +109,7 @@ class Jetpack_Widget_Conditions {
?>
<option value="front" <?php selected( 'front', $minor ); ?>><?php _e( 'Front page', 'jetpack' ); ?></option>
<option value="posts" <?php selected( 'posts', $minor ); ?>><?php _e( 'Posts page', 'jetpack' ); ?></option>
+ <option value="archive" <?php selected( 'archive', $minor ); ?>><?php _e( 'Archive page', 'jetpack' ); ?></option>
<option value="404" <?php selected( '404', $minor ); ?>><?php _e( '404 error page', 'jetpack' ); ?></option>
<option value="search" <?php selected( 'search', $minor ); ?>><?php _e( 'Search results', 'jetpack' ); ?></option>
<optgroup label="<?php esc_attr_e( 'Post type:', 'jetpack' ); ?>">
@@ -110,6 +134,32 @@ class Jetpack_Widget_Conditions {
</optgroup>
<?php
break;
+ case 'taxonomy':
+ ?>
+ <option value=""><?php _e( 'All taxonomy pages', 'jetpack' ); ?></option>
+ <?php
+
+ $taxonomies = get_taxonomies( array( '_builtin' => false ), 'objects' );
+ usort( $taxonomies, array( __CLASS__, 'strcasecmp_name' ) );
+
+ foreach ( $taxonomies as $taxonomy ) {
+ ?>
+ <optgroup label="<?php esc_attr_e( $taxonomy->labels->name . ':', 'jetpack' ); ?>">
+ <option value="<?php echo esc_attr( $taxonomy->name ); ?>" <?php selected( $taxonomy->name, $minor ); ?>><?php echo 'All ' . esc_html( $taxonomy->name ) . ' pages'; ?></option>
+ <?php
+
+ $terms = get_terms( array( $taxonomy->name ), array( 'number' => 250, 'hide_empty' => false ) );
+ foreach ( $terms as $term ) {
+ ?>
+ <option value="<?php echo esc_attr( $taxonomy->name . '_tax_' . $term->term_id ); ?>" <?php selected( $taxonomy->name . '_tax_' . $term->term_id, $minor ); ?>><?php echo esc_html( $term->name ); ?></option>
+ <?php
+ }
+
+ ?>
+ </optgroup>
+ <?php
+ }
+ break;
}
}
@@ -155,25 +205,38 @@ class Jetpack_Widget_Conditions {
foreach ( $conditions['rules'] as $rule ) {
?>
<div class="condition">
- <div class="alignleft">
+ <div class="selection alignleft">
<select class="conditions-rule-major" name="conditions[rules_major][]">
<option value="" <?php selected( "", $rule['major'] ); ?>><?php echo esc_html_x( '-- Select --', 'Used as the default option in a dropdown list', 'jetpack' ); ?></option>
<option value="category" <?php selected( "category", $rule['major'] ); ?>><?php esc_html_e( 'Category', 'jetpack' ); ?></option>
<option value="author" <?php selected( "author", $rule['major'] ); ?>><?php echo esc_html_x( 'Author', 'Noun, as in: "The author of this post is..."', 'jetpack' ); ?></option>
+ <?php
+ // this doesn't work on .com because of caching
+ if( ! ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ) {
+ ?>
+ <option value="loggedin" <?php selected( "loggedin", $rule['major'] ); ?>><?php echo esc_html_x( 'User', 'Noun', 'jetpack' ); ?></option>
+ <option value="role" <?php selected( "role", $rule['major'] ); ?>><?php echo esc_html_x( 'Role', 'Noun, as in: "The user role of that can access this widget is..."', 'jetpack' ); ?></option>
+ <?php } ?>
<option value="tag" <?php selected( "tag", $rule['major'] ); ?>><?php echo esc_html_x( 'Tag', 'Noun, as in: "This post has one tag."', 'jetpack' ); ?></option>
<option value="date" <?php selected( "date", $rule['major'] ); ?>><?php echo esc_html_x( 'Date', 'Noun, as in: "This page is a date archive."', 'jetpack' ); ?></option>
<option value="page" <?php selected( "page", $rule['major'] ); ?>><?php echo esc_html_x( 'Page', 'Example: The user is looking at a page, not a post.', 'jetpack' ); ?></option>
+ <?php if ( get_taxonomies( array( '_builtin' => false ) ) ) : ?>
+ <option value="taxonomy" <?php selected( "taxonomy", $rule['major'] ); ?>><?php echo esc_html_x( 'Taxonomy', 'Noun, as in: "This post has one taxonomy."', 'jetpack' ); ?></option>
+ <?php endif; ?>
</select>
<?php _ex( 'is', 'Widget Visibility: {Rule Major [Page]} is {Rule Minor [Search results]}', 'jetpack' ); ?>
<select class="conditions-rule-minor" name="conditions[rules_minor][]" <?php if ( ! $rule['major'] ) { ?> disabled="disabled"<?php } ?> data-loading-text="<?php esc_attr_e( 'Loading...', 'jetpack' ); ?>">
<?php self::widget_conditions_options_echo( $rule['major'], $rule['minor'] ); ?>
</select>
- <span class="condition-conjunction"><?php echo esc_html_x( 'or', 'Shown between widget visibility conditions.', 'jetpack' ); ?></span>
+
</div>
- <div class="condition-control alignright">
+ <div class="condition-control">
+ <span class="condition-conjunction"><?php echo esc_html_x( 'or', 'Shown between widget visibility conditions.', 'jetpack' ); ?></span>
+ <div class="actions alignright">
<a href="#" class="delete-condition"><?php esc_html_e( 'Delete', 'jetpack' ); ?></a> | <a href="#" class="add-condition"><?php esc_html_e( 'Add', 'jetpack' ); ?></a>
+ </div>
</div>
- <br class="clear" />
+
</div><!-- .condition -->
<?php
}
@@ -248,14 +311,29 @@ class Jetpack_Widget_Conditions {
foreach ( $widgets as $position => $widget_id ) {
// Find the conditions for this widget.
- list( $basename, $suffix ) = explode( "-", $widget_id, 2 );
+ if ( preg_match( '/^(.+?)-(\d+)$/', $widget_id, $matches ) ) {
+ $id_base = $matches[1];
+ $widget_number = intval( $matches[2] );
+ }
+ else {
+ $id_base = $widget_id;
+ $widget_number = null;
+ }
- if ( ! isset( $settings[$basename] ) )
- $settings[$basename] = get_option( 'widget_' . $basename );
+ if ( ! isset( $settings[$id_base] ) ) {
+ $settings[$id_base] = get_option( 'widget_' . $id_base );
+ }
- if ( isset( $settings[$basename][$suffix] ) ) {
- if ( false === self::filter_widget( $settings[$basename][$suffix] ) )
+ // New multi widget (WP_Widget)
+ if ( ! is_null( $widget_number ) ) {
+ if ( isset( $settings[$id_base][$widget_number] ) && false === self::filter_widget( $settings[$id_base][$widget_number] ) ) {
unset( $widget_areas[$widget_area][$position] );
+ }
+ }
+
+ // Old single widget
+ else if ( ! empty( $settings[ $id_base ] ) && false === self::filter_widget( $settings[$id_base] ) ) {
+ unset( $widget_areas[$widget_area][$position] );
}
}
}
@@ -263,6 +341,10 @@ class Jetpack_Widget_Conditions {
return $widget_areas;
}
+ public static function template_redirect() {
+ self::$passed_template_redirect = true;
+ }
+
/**
* Determine whether the widget should be displayed based on conditions set by the user.
*
@@ -270,95 +352,158 @@ class Jetpack_Widget_Conditions {
* @return array Settings to display or bool false to hide.
*/
public static function filter_widget( $instance ) {
- global $post, $wp_query;
+ global $wp_query;
if ( empty( $instance['conditions'] ) || empty( $instance['conditions']['rules'] ) )
return $instance;
+ // Store the results of all in-page condition lookups so that multiple widgets with
+ // the same visibility conditions don't result in duplicate DB queries.
+ static $condition_result_cache = array();
+
$condition_result = false;
foreach ( $instance['conditions']['rules'] as $rule ) {
- switch ( $rule['major'] ) {
- case 'date':
- switch ( $rule['minor'] ) {
- case '':
- $condition_result = is_date();
- break;
- case 'month':
- $condition_result = is_month();
- break;
- case 'day':
- $condition_result = is_day();
- break;
- case 'year':
- $condition_result = is_year();
- break;
- }
- break;
- case 'page':
- // Previously hardcoded post type options.
- if ( 'post' == $rule['minor'] )
- $rule['minor'] = 'post_type-post';
- else if ( ! $rule['minor'] )
- $rule['minor'] = 'post_type-page';
-
- switch ( $rule['minor'] ) {
- case '404':
- $condition_result = is_404();
- break;
- case 'search':
- $condition_result = is_search();
- break;
- case 'archive':
- $condition_result = is_archive();
- break;
- case 'posts':
- $condition_result = $wp_query->is_posts_page;
- break;
- case 'home':
- $condition_result = is_home();
- break;
- case 'front':
- $condition_result = is_front_page();
- break;
- default:
- if ( substr( $rule['minor'], 0, 10 ) == 'post_type-' )
- $condition_result = is_singular( substr( $rule['minor'], 10 ) );
- else {
- // $rule['minor'] is a page ID
- $condition_result = is_page( $rule['minor'] );
+ $condition_key = $rule['major'] . ":" . $rule['minor'];
+
+ if ( isset( $condition_result_cache[ $condition_key ] ) ) {
+ $condition_result = $condition_result_cache[ $condition_key ];
+ }
+ else {
+ switch ( $rule['major'] ) {
+ case 'date':
+ switch ( $rule['minor'] ) {
+ case '':
+ $condition_result = is_date();
+ break;
+ case 'month':
+ $condition_result = is_month();
+ break;
+ case 'day':
+ $condition_result = is_day();
+ break;
+ case 'year':
+ $condition_result = is_year();
+ break;
+ }
+ break;
+ case 'page':
+ // Previously hardcoded post type options.
+ if ( 'post' == $rule['minor'] )
+ $rule['minor'] = 'post_type-post';
+ else if ( ! $rule['minor'] )
+ $rule['minor'] = 'post_type-page';
+
+ switch ( $rule['minor'] ) {
+ case '404':
+ $condition_result = is_404();
+ break;
+ case 'search':
+ $condition_result = is_search();
+ break;
+ case 'archive':
+ $condition_result = is_archive();
+ break;
+ case 'posts':
+ $condition_result = $wp_query->is_posts_page;
+ break;
+ case 'home':
+ $condition_result = is_home();
+ break;
+ case 'front':
+ if ( current_theme_supports( 'infinite-scroll' ) )
+ $condition_result = is_front_page();
+ else {
+ $condition_result = is_front_page() && !is_paged();
+ }
+ break;
+ default:
+ if ( substr( $rule['minor'], 0, 10 ) == 'post_type-' ) {
+ $condition_result = is_singular( substr( $rule['minor'], 10 ) );
+ } elseif ( $rule['minor'] == get_option( 'page_for_posts' ) ) {
+ // If $rule['minor'] is a page ID which is also the posts page
+ $condition_result = $wp_query->is_posts_page;
+ } else {
+ // $rule['minor'] is a page ID
+ $condition_result = is_page( $rule['minor'] );
+ }
+ break;
+ }
+ break;
+ case 'tag':
+ if ( ! $rule['minor'] && is_tag() )
+ $condition_result = true;
+ else if ( is_singular() && $rule['minor'] && has_tag( $rule['minor'] ) )
+ $condition_result = true;
+ else {
+ $tag = get_tag( $rule['minor'] );
+
+ if ( $tag && is_tag( $tag->slug ) )
+ $condition_result = true;
+ }
+ break;
+ case 'category':
+ if ( ! $rule['minor'] && is_category() )
+ $condition_result = true;
+ else if ( is_category( $rule['minor'] ) )
+ $condition_result = true;
+ else if ( is_singular() && $rule['minor'] && in_array( 'category', get_post_taxonomies() ) && has_category( $rule['minor'] ) )
+ $condition_result = true;
+ break;
+ case 'loggedin':
+ $condition_result = is_user_logged_in();
+ if ( 'loggedin' !== $rule['minor'] ) {
+ $condition_result = ! $condition_result;
+ }
+ break;
+ case 'author':
+ $post = get_post();
+ if ( ! $rule['minor'] && is_author() )
+ $condition_result = true;
+ else if ( $rule['minor'] && is_author( $rule['minor'] ) )
+ $condition_result = true;
+ else if ( is_singular() && $rule['minor'] && $rule['minor'] == $post->post_author )
+ $condition_result = true;
+ break;
+ case 'role':
+ if( is_user_logged_in() ) {
+ global $current_user;
+ get_currentuserinfo();
+
+ $user_roles = $current_user->roles;
+
+ if( in_array( $rule['minor'], $user_roles ) ) {
+ $condition_result = true;
+ } else {
+ $condition_result = false;
}
- break;
- }
- break;
- case 'tag':
- if ( ! $rule['minor'] && is_tag() )
- $condition_result = true;
- else if ( is_singular() && $rule['minor'] && has_tag( $rule['minor'] ) )
- $condition_result = true;
- else {
- $tag = get_tag( $rule['minor'] );
-
- if ( $tag && is_tag( $tag->slug ) )
+
+ } else {
+ $condition_result = false;
+ }
+ break;
+ case 'taxonomy':
+ $term = explode( '_tax_', $rule['minor'] ); // $term[0] = taxonomy name; $term[1] = term id
+
+ if ( isset( $term[1] ) && is_tax( $term[0], $term[1] ) )
$condition_result = true;
- }
- break;
- case 'category':
- if ( ! $rule['minor'] && is_category() )
- $condition_result = true;
- else if ( is_category( $rule['minor'] ) )
- $condition_result = true;
- else if ( is_singular() && $rule['minor'] && has_category( $rule['minor'] ) )
- $condition_result = true;
- break;
- case 'author':
- if ( ! $rule['minor'] && is_author() )
- $condition_result = true;
- else if ( $rule['minor'] && is_author( $rule['minor'] ) )
- $condition_result = true;
- else if ( is_singular() && $rule['minor'] && $rule['minor'] == $post->post_author )
- $condition_result = true;
- break;
+ else if ( isset( $term[1] ) && is_singular() && $term[1] && has_term( $term[1], $term[0] ) )
+ $condition_result = true;
+ else if ( is_singular() && $post_id = get_the_ID() ){
+ $terms = get_the_terms( $post_id, $rule['minor'] ); // Does post have terms in taxonomy?
+ if( $terms && ! is_wp_error( $terms ) ) {
+ $condition_result = true;
+ }
+ }
+ break;
+ }
+
+ if ( $condition_result || self::$passed_template_redirect ) {
+ // Some of the conditions will return false when checked before the template_redirect
+ // action has been called, like is_page(). Only store positive lookup results, which
+ // won't be false positives, before template_redirect, and everything after.
+ $condition_result_cache[ $condition_key ] = $condition_result;
+ }
}
if ( $condition_result )
diff --git a/plugins/jetpack/modules/widget-visibility/widget-conditions/rtl/widget-conditions-rtl.css b/plugins/jetpack/modules/widget-visibility/widget-conditions/rtl/widget-conditions-rtl.css
index 58b9e149..94cf4502 100644
--- a/plugins/jetpack/modules/widget-visibility/widget-conditions/rtl/widget-conditions-rtl.css
+++ b/plugins/jetpack/modules/widget-visibility/widget-conditions/rtl/widget-conditions-rtl.css
@@ -1,5 +1,16 @@
-/* This file was automatically generated on Mar 14 2013 17:20:54 */
+/* This file was automatically generated on Jul 14 2014 00:47:30 */
+.wp-customizer .expanded .widget-conditional .widget-conditional-inner {
+ width: 98%;
+ -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
+ -moz-box-sizing: border-box; /* Firefox, other Gecko */
+ box-sizing: border-box;
+}
+
+.wp-customizer .expanded .widget-conditional .form{
+ overflow: scroll;
+ margin-bottom: 20px;
+}
.widget-liquid-right .widget.expanded {
overflow: visible;
}
@@ -9,11 +20,21 @@
.widget-conditional .widget-conditional-inner {
background: #F9F9F9;
border: 1px solid #DFDFDF;
- padding: 12px 12px 0;
+ padding: 12px 10px 0;
+
+}
+.widget-conditional {
+ margin-bottom: 12px;
+}
+.widget-conditional .conditions{
+ margin-bottom: 12px;
}
.widget-conditional .condition,
.widget-conditional .condition-top {
- margin-bottom: 12px;
+ clear:both;
+}
+.widget-conditional .condition {
+ padding-top: 12px;
}
.widget-conditional .condition select {
width: 120px;
@@ -21,9 +42,18 @@
.widget-conditional .condition-top select {
width: auto;
}
-.widget-conditional .condition .alignright {
+.widget-conditional .condition-control {
padding-top: 4px;
+ clear: both;
+ margin-top: -20px;
+}
+.widget-conditional .selection {
+ margin-left: 70px;
+}
+.widget-conditional .condition .actions {
+ margin-top: -28px;
}
+
.widget-conditional .condition-control a {
text-decoration: none;
}
@@ -32,10 +62,17 @@
}
.widget-control-actions .alignright {
text-align: left;
+ color:#999;
}
.wp-core-ui .button.display-options {
margin-left: 5px;
}
.wp-core-ui .button.display-options:hover {
text-decoration: none;
-} \ No newline at end of file
+}
+
+.wp-customizer .widget-conditional select {
+ min-width: 0;
+ max-width: none;
+ height: auto;
+}
diff --git a/plugins/jetpack/modules/widget-visibility/widget-conditions/widget-conditions-rtl.css b/plugins/jetpack/modules/widget-visibility/widget-conditions/widget-conditions-rtl.css
new file mode 100644
index 00000000..94a7180d
--- /dev/null
+++ b/plugins/jetpack/modules/widget-visibility/widget-conditions/widget-conditions-rtl.css
@@ -0,0 +1,73 @@
+.wp-customizer .expanded .widget-conditional .widget-conditional-inner {
+ width: 98%;
+ -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
+ -moz-box-sizing: border-box; /* Firefox, other Gecko */
+ box-sizing: border-box;
+}
+
+.wp-customizer .expanded .widget-conditional .form{
+ overflow: scroll;
+ margin-bottom: 20px;
+}
+.widget-liquid-right .widget.expanded {
+ overflow: visible;
+}
+.widget-conditional-hide {
+ display: none;
+}
+.widget-conditional .widget-conditional-inner {
+ background: #F9F9F9;
+ border: 1px solid #DFDFDF;
+ padding: 12px 10px 0;
+
+}
+.widget-conditional {
+ margin-bottom: 12px;
+}
+.widget-conditional .conditions{
+ margin-bottom: 12px;
+}
+.widget-conditional .condition,
+.widget-conditional .condition-top {
+ clear:both;
+}
+.widget-conditional .condition {
+ padding-top: 12px;
+}
+.widget-conditional .condition select {
+ width: 120px;
+}
+.widget-conditional .condition-top select {
+ width: auto;
+}
+.widget-conditional .condition-control {
+ padding-top: 4px;
+ clear: both;
+ margin-top: -20px;
+}
+.widget-conditional .selection {
+ margin-left: 70px;
+}
+.widget-conditional .condition .actions {
+ margin-top: -28px;
+}
+
+.widget-conditional .condition-control a {
+ text-decoration: none;
+}
+.widget-conditional .condition:last-child .condition-conjunction {
+ display: none;
+}
+
+.wp-core-ui .button.display-options {
+ margin-left: 5px;
+}
+.wp-core-ui .button.display-options:hover {
+ text-decoration: none;
+}
+
+.wp-customizer .widget-conditional select {
+ min-width: 0;
+ max-width: none;
+ height: auto;
+}
diff --git a/plugins/jetpack/modules/widget-visibility/widget-conditions/widget-conditions-rtl.min.css b/plugins/jetpack/modules/widget-visibility/widget-conditions/widget-conditions-rtl.min.css
new file mode 100644
index 00000000..f4495f69
--- /dev/null
+++ b/plugins/jetpack/modules/widget-visibility/widget-conditions/widget-conditions-rtl.min.css
@@ -0,0 +1 @@
+.wp-customizer .expanded .widget-conditional .widget-conditional-inner{width:98%;-moz-box-sizing:border-box;box-sizing:border-box}.wp-customizer .expanded .widget-conditional .form{overflow:scroll;margin-bottom:20px}.widget-liquid-right .widget.expanded{overflow:visible}.widget-conditional-hide{display:none}.widget-conditional .widget-conditional-inner{background:#F9F9F9;border:1px solid #DFDFDF;padding:12px 10px 0}.widget-conditional,.widget-conditional .conditions{margin-bottom:12px}.widget-conditional .condition,.widget-conditional .condition-top{clear:both}.widget-conditional .condition{padding-top:12px}.widget-conditional .condition select{width:120px}.widget-conditional .condition-top select{width:auto}.widget-conditional .condition-control{padding-top:4px;clear:both;margin-top:-20px}.widget-conditional .selection{margin-left:70px}.widget-conditional .condition .actions{margin-top:-28px}.widget-conditional .condition-control a{text-decoration:none}.widget-conditional .condition:last-child .condition-conjunction{display:none}.wp-core-ui .button.display-options{margin-left:5px}.wp-core-ui .button.display-options:hover{text-decoration:none}.wp-customizer .widget-conditional select{min-width:0;max-width:none;height:auto} \ No newline at end of file
diff --git a/plugins/jetpack/modules/widget-visibility/widget-conditions/widget-conditions.css b/plugins/jetpack/modules/widget-visibility/widget-conditions/widget-conditions.css
index bdd41f66..4ae0b29b 100644
--- a/plugins/jetpack/modules/widget-visibility/widget-conditions/widget-conditions.css
+++ b/plugins/jetpack/modules/widget-visibility/widget-conditions/widget-conditions.css
@@ -1,3 +1,14 @@
+.wp-customizer .expanded .widget-conditional .widget-conditional-inner {
+ width: 98%;
+ -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
+ -moz-box-sizing: border-box; /* Firefox, other Gecko */
+ box-sizing: border-box;
+}
+
+.wp-customizer .expanded .widget-conditional .form{
+ overflow: scroll;
+ margin-bottom: 20px;
+}
.widget-liquid-right .widget.expanded {
overflow: visible;
}
@@ -7,11 +18,21 @@
.widget-conditional .widget-conditional-inner {
background: #F9F9F9;
border: 1px solid #DFDFDF;
- padding: 12px 12px 0;
+ padding: 12px 10px 0;
+
+}
+.widget-conditional {
+ margin-bottom: 12px;
+}
+.widget-conditional .conditions{
+ margin-bottom: 12px;
}
.widget-conditional .condition,
.widget-conditional .condition-top {
- margin-bottom: 12px;
+ clear:both;
+}
+.widget-conditional .condition {
+ padding-top: 12px;
}
.widget-conditional .condition select {
width: 120px;
@@ -19,21 +40,34 @@
.widget-conditional .condition-top select {
width: auto;
}
-.widget-conditional .condition .alignright {
+.widget-conditional .condition-control {
padding-top: 4px;
+ clear: both;
+ margin-top: -20px;
+}
+.widget-conditional .selection {
+ margin-right: 70px;
+}
+.widget-conditional .condition .actions {
+ margin-top: -28px;
}
+
.widget-conditional .condition-control a {
text-decoration: none;
}
.widget-conditional .condition:last-child .condition-conjunction {
display: none;
}
-.widget-control-actions .alignright {
- text-align: right;
-}
+
.wp-core-ui .button.display-options {
margin-right: 5px;
}
.wp-core-ui .button.display-options:hover {
text-decoration: none;
-} \ No newline at end of file
+}
+
+.wp-customizer .widget-conditional select {
+ min-width: 0;
+ max-width: none;
+ height: auto;
+}
diff --git a/plugins/jetpack/modules/widget-visibility/widget-conditions/widget-conditions.js b/plugins/jetpack/modules/widget-visibility/widget-conditions/widget-conditions.js
index 0458d663..709085ae 100644
--- a/plugins/jetpack/modules/widget-visibility/widget-conditions/widget-conditions.js
+++ b/plugins/jetpack/modules/widget-visibility/widget-conditions/widget-conditions.js
@@ -1,18 +1,42 @@
+/* jshint onevar: false, smarttabs: true */
+/* global ajaxurl */
+/* global isRtl */
+
jQuery( function( $ ) {
+ var widgets_shell = $( 'div#widgets-right' );
+
+ if ( ! widgets_shell.length || ! $( widgets_shell ).find( '.widget-control-actions' ).length ) {
+ widgets_shell = $( 'form#customize-controls' );
+ }
+
function setWidgetMargin( $widget ) {
+
+ if ( $( 'body' ).hasClass( 'wp-customizer' ) ) {
+ // set the inside widget 2 top this way we can see the widget settings
+ $widget.find('.widget-inside').css( 'top', 0 );
+
+ return;
+ }
+
if ( $widget.hasClass( 'expanded' ) ) {
// The expanded widget must be at least 400px wide in order to
// contain the visibility settings. IE wasn't handling the
// margin-left value properly.
- if ( $widget.attr( 'style' ) )
+ if ( $widget.attr( 'style' ) ) {
$widget.data( 'original-style', $widget.attr( 'style' ) );
+ }
var currentWidth = $widget.width();
if ( currentWidth < 400 ) {
var extra = 400 - currentWidth;
- $widget.css( 'position', 'relative' ).css( 'left', '-' + extra + 'px' ).css( 'width', '400px' );
+ if( isRtl ) {
+ $widget.css( 'position', 'relative' ).css( 'right', '-' + extra + 'px' ).css( 'width', '400px' );
+ } else {
+ $widget.css( 'position', 'relative' ).css( 'left', '-' + extra + 'px' ).css( 'width', '400px' );
+ }
+
}
}
else if ( $widget.data( 'original-style' ) ) {
@@ -24,10 +48,10 @@ jQuery( function( $ ) {
}
}
- $( "a.display-options" ).each( function() {
+ $( 'a.display-options' ).each( function() {
var $displayOptionsButton = $( this ),
- $widget = $displayOptionsButton.closest( "div.widget" );
- $displayOptionsButton.insertBefore( $widget.find( "input.widget-control-save" ) );
+ $widget = $displayOptionsButton.closest( 'div.widget' );
+ $displayOptionsButton.insertBefore( $widget.find( 'input.widget-control-save' ) );
// Widgets with no configurable options don't show the Save button's container.
$displayOptionsButton
@@ -40,59 +64,64 @@ jQuery( function( $ ) {
} );
- $( "div#widgets-right" ).on( "click", "a.add-condition", function( e ) {
+ widgets_shell.on( 'click.widgetconditions', 'a.add-condition', function( e ) {
e.preventDefault();
- var $condition = $( this ).closest( "div.condition" ),
+ var $condition = $( this ).closest( 'div.condition' ),
$conditionClone = $condition.clone().insertAfter( $condition );
- $conditionClone.find( "select.conditions-rule-major" ).val( "" );
- $conditionClone.find( "select.conditions-rule-minor" ).html( "" ).attr( "disabled" );
- } ).on( "click", "a.display-options", function ( e ) {
+ $conditionClone.find( 'select.conditions-rule-major' ).val( '' );
+ $conditionClone.find( 'select.conditions-rule-minor' ).html( '' ).attr( 'disabled' );
+ } );
+
+ widgets_shell.on( 'click.widgetconditions', 'a.display-options', function ( e ) {
e.preventDefault();
var $displayOptionsButton = $( this ),
- $widget = $displayOptionsButton.closest( "div.widget" );
+ $widget = $displayOptionsButton.closest( 'div.widget' );
- $widget.find( "div.widget-conditional" ).toggleClass( "widget-conditional-hide" );
- $( this ).toggleClass( "active" );
- $widget.toggleClass( "expanded" );
+ $widget.find( 'div.widget-conditional' ).toggleClass( 'widget-conditional-hide' );
+ $( this ).toggleClass( 'active' );
+ $widget.toggleClass( 'expanded' );
setWidgetMargin( $widget );
- if ( $( this ).hasClass( 'active' ) )
+ if ( $( this ).hasClass( 'active' ) ) {
$widget.find( 'input[name=widget-conditions-visible]' ).val( '1' );
- else
+ } else {
$widget.find( 'input[name=widget-conditions-visible]' ).val( '0' );
+ }
} );
- $( "div#widgets-right" ).on( "click", "a.delete-condition", function( e ) {
+ widgets_shell.on( 'click.widgetconditions', 'a.delete-condition', function( e ) {
e.preventDefault();
- var $condition = $( this ).closest( "div.condition" );
+ var $condition = $( this ).closest( 'div.condition' );
- if ( $condition.is( ":first-child" ) && $condition.is( ":last-child" ) ) {
- $( this ).closest( "div.widget" ).find( "a.display-options" ).click();
- $condition.find( "select.conditions-rule-major" ).val( "" ).change();
+ if ( $condition.is( ':first-child' ) && $condition.is( ':last-child' ) ) {
+ $( this ).closest( 'div.widget' ).find( 'a.display-options' ).click();
+ $condition.find( 'select.conditions-rule-major' ).val( '' ).change();
} else {
$condition.detach();
}
- } ).on( "click", "div.widget-top", function() {
- var $widget = $( this ).closest( "div.widget" ),
- $displayOptionsButton = $widget.find( "a.display-options" );
+ } );
+
+ widgets_shell.on( 'click.widgetconditions', 'div.widget-top', function() {
+ var $widget = $( this ).closest( 'div.widget' ),
+ $displayOptionsButton = $widget.find( 'a.display-options' );
- if ( $displayOptionsButton.hasClass( "active" ) ) {
- $displayOptionsButton.attr( "opened", "true" );
+ if ( $displayOptionsButton.hasClass( 'active' ) ) {
+ $displayOptionsButton.attr( 'opened', 'true' );
}
- if ( $displayOptionsButton.attr( "opened" ) ) {
- $displayOptionsButton.removeAttr( "opened" );
- $widget.toggleClass( "expanded" );
+ if ( $displayOptionsButton.attr( 'opened' ) ) {
+ $displayOptionsButton.removeAttr( 'opened' );
+ $widget.toggleClass( 'expanded' );
setWidgetMargin( $widget );
}
} );
- $( document ).on( "change", "select.conditions-rule-major", function() {
+ $( document ).on( 'change.widgetconditions', 'select.conditions-rule-major', function() {
var $conditionsRuleMajor = $ ( this );
- var $conditionsRuleMinor = $conditionsRuleMajor.siblings( "select.conditions-rule-minor:first" );
+ var $conditionsRuleMinor = $conditionsRuleMajor.siblings( 'select.conditions-rule-minor:first' );
if ( $conditionsRuleMajor.val() ) {
$conditionsRuleMinor.html( '' ).append( $( '<option/>' ).text( $conditionsRuleMinor.data( 'loading-text' ) ) );
@@ -103,10 +132,10 @@ jQuery( function( $ ) {
};
jQuery.post( ajaxurl, data, function( html ) {
- $conditionsRuleMinor.html( html ).removeAttr( "disabled" );
+ $conditionsRuleMinor.html( html ).removeAttr( 'disabled' );
} );
} else {
- $conditionsRuleMajor.siblings( "select.conditions-rule-minor" ).attr( "disabled", "disabled" ).html( "" );
+ $conditionsRuleMajor.siblings( 'select.conditions-rule-minor' ).attr( 'disabled', 'disabled' ).html( '' );
}
} );
} );
diff --git a/plugins/jetpack/modules/widget-visibility/widget-conditions/widget-conditions.min.css b/plugins/jetpack/modules/widget-visibility/widget-conditions/widget-conditions.min.css
new file mode 100644
index 00000000..7893ca82
--- /dev/null
+++ b/plugins/jetpack/modules/widget-visibility/widget-conditions/widget-conditions.min.css
@@ -0,0 +1 @@
+.wp-customizer .expanded .widget-conditional .widget-conditional-inner{width:98%;-moz-box-sizing:border-box;box-sizing:border-box}.wp-customizer .expanded .widget-conditional .form{overflow:scroll;margin-bottom:20px}.widget-liquid-right .widget.expanded{overflow:visible}.widget-conditional-hide{display:none}.widget-conditional .widget-conditional-inner{background:#F9F9F9;border:1px solid #DFDFDF;padding:12px 10px 0}.widget-conditional,.widget-conditional .conditions{margin-bottom:12px}.widget-conditional .condition,.widget-conditional .condition-top{clear:both}.widget-conditional .condition{padding-top:12px}.widget-conditional .condition select{width:120px}.widget-conditional .condition-top select{width:auto}.widget-conditional .condition-control{padding-top:4px;clear:both;margin-top:-20px}.widget-conditional .selection{margin-right:70px}.widget-conditional .condition .actions{margin-top:-28px}.widget-conditional .condition-control a{text-decoration:none}.widget-conditional .condition:last-child .condition-conjunction{display:none}.wp-core-ui .button.display-options{margin-right:5px}.wp-core-ui .button.display-options:hover{text-decoration:none}.wp-customizer .widget-conditional select{min-width:0;max-width:none;height:auto} \ No newline at end of file
diff --git a/plugins/jetpack/modules/widgets.php b/plugins/jetpack/modules/widgets.php
index c2100ccd..cacfb46e 100644
--- a/plugins/jetpack/modules/widgets.php
+++ b/plugins/jetpack/modules/widgets.php
@@ -1,11 +1,12 @@
<?php
/**
* Module Name: Extra Sidebar Widgets
- * Module Description: Easily add images, Twitter updates, and your site's RSS links to your theme's sidebar.
- * Sort Order: 13
+ * Module Description: Add images, Twitter streams, your site’s RSS links, and more to your sidebar.
+ * Sort Order: 4
* First Introduced: 1.2
* Requires Connection: No
* Auto Activate: Yes
+ * Module Tags: Social, Appearance
*/
function jetpack_load_widgets() {
@@ -14,7 +15,13 @@ function jetpack_load_widgets() {
foreach ( Jetpack::glob_php( dirname( __FILE__ ) . '/widgets' ) as $file ) {
$widgets_include[] = $file;
}
-
+ /**
+ * Modify which Jetpack Widgets to register.
+ *
+ * @since 2.2.1
+ *
+ * @param array $widgets_include An array of widgets to be registered.
+ */
$widgets_include = apply_filters( 'jetpack_widgets_to_include', $widgets_include );
foreach( $widgets_include as $include ) {
@@ -35,18 +42,10 @@ function jetpack_widgets_configuration_load() {
}
/**
- * Loads file for front-end widget styles.
- */
-function jetpack_widgets_styles() {
- wp_enqueue_style( 'jetpack-widgets', plugins_url( 'widgets/widgets.css', __FILE__ ), array(), '20121003' );
-}
-add_action( 'wp_enqueue_scripts', 'jetpack_widgets_styles' );
-
-/**
* Add the "(Jetpack)" suffix to the widget names
*/
function jetpack_widgets_add_suffix( $widget_name ) {
- return sprintf( __( '%s (Jetpack)', 'jetpack' ), $widget_name );
+ return sprintf( __( '%s (Jetpack)', 'jetpack' ), $widget_name );
}
add_filter( 'jetpack_widget_name', 'jetpack_widgets_add_suffix' );
diff --git a/plugins/jetpack/modules/widgets/contact-info.php b/plugins/jetpack/modules/widgets/contact-info.php
new file mode 100644
index 00000000..233c3b40
--- /dev/null
+++ b/plugins/jetpack/modules/widgets/contact-info.php
@@ -0,0 +1,266 @@
+<?php
+
+if ( ! class_exists( 'Jetpack_Contact_Info_Widget' ) ) {
+
+ //register Contact_Info_Widget widget
+ function jetpack_contact_info_widget_init() {
+ register_widget( 'Jetpack_Contact_Info_Widget' );
+ }
+
+ add_action( 'widgets_init', 'jetpack_contact_info_widget_init' );
+
+ /**
+ * Makes a custom Widget for displaying Resturant Location, Hours and Contact Info available.
+ *
+ * @package WordPress
+ */
+ class Jetpack_Contact_Info_Widget extends WP_Widget {
+
+ /**
+ * Constructor
+ *
+ * @return void
+ **/
+ function __construct() {
+ $widget_ops = array(
+ 'classname' => 'widget_contact_info',
+ 'description' => __( 'Display your location, hours, and contact information.', 'jetpack' )
+ );
+ parent::__construct(
+ 'widget_contact_info',
+ apply_filters( 'jetpack_widget_name', __( 'Contact Info', 'jetpack' ) ),
+ $widget_ops
+ );
+ $this->alt_option_name = 'widget_contact_info';
+ }
+
+
+ /**
+ * Return an associative array of default values
+ *
+ * These values are used in new widgets.
+ *
+ * @return array Array of default values for the Widget's options
+ */
+ public function defaults() {
+ return array(
+ 'title' => __( 'Hours & Info', 'jetpack' ),
+ 'address' => __( "3999 Mission Boulevard,\nSan Diego CA 92109", 'jetpack' ),
+ 'phone' => _x( '1-202-555-1212', 'Example of a phone number', 'jetpack' ),
+ 'hours' => __( "Lunch: 11am - 2pm \nDinner: M-Th 5pm - 11pm, Fri-Sat:5pm - 1am", 'jetpack' ),
+ 'showmap' => 1,
+ 'lat' => null,
+ 'lon' => null
+ );
+ }
+ /**
+ * Outputs the HTML for this widget.
+ *
+ * @param array An array of standard parameters for widgets in this theme
+ * @param array An array of settings for this widget instance
+ * @return void Echoes it's output
+ **/
+ function widget( $args, $instance ) {
+ $instance = wp_parse_args( $instance, $this->defaults() );
+
+ extract( $args, EXTR_SKIP );
+
+ echo $before_widget;
+
+ if ( $instance['title'] != '' )
+ echo $before_title . $instance['title'] . $after_title;
+
+
+ $map_link = 0;
+
+
+ if ( $instance['address'] != '' ) {
+
+ $showmap = $instance['showmap'];
+
+ if ( $showmap && $this->has_good_map( $instance ) ) {
+
+ $lat = $instance['lat'];
+ $lon = $instance['lon'];
+
+ echo $this->build_map( $lat, $lon );
+ }
+
+ $map_link = $this->build_map_link( $instance['address'] );
+
+ echo '<div class="confit-address"><a href="' . esc_url( $map_link ) . '" target="_blank">' . str_replace( "\n", "<br/>", esc_html( $instance['address'] ) ) . "</a></div>";
+
+
+ }
+
+
+ if ( $instance['phone'] != '' ) {
+
+ if( wp_is_mobile() ) {
+ echo '<div class="confit-phone"><a href="'. esc_url( 'tel:'. $instance['phone'] ) . '">' . esc_html( $instance['phone'] ) . "</a></div>";
+ } else {
+ echo '<div class="confit-phone">' . esc_html( $instance['phone'] ) . '</div>';
+ }
+
+ }
+
+
+ if ( $instance['hours'] != '' ) {
+ echo '<div class="confit-hours">' . str_replace( "\n", "<br/>", esc_html( $instance['hours'] ) ) . "</div>";
+ }
+
+
+ echo $after_widget;
+
+ }
+
+
+ /**
+ * Deals with the settings when they are saved by the admin. Here is
+ * where any validation should be dealt with.
+ **/
+ function update( $new_instance, $old_instance ) {
+ $update_lat_lon = false;
+ if ( $this->urlencode_address( $old_instance['address'] ) != $this->urlencode_address( $new_instance['address'] ) ) {
+ $update_lat_lon = true;
+ }
+
+ $instance = array();
+ $instance['title'] = wp_kses( $new_instance['title'], array() );
+ $instance['address'] = wp_kses( $new_instance['address'], array() );
+ $instance['phone'] = wp_kses( $new_instance['phone'], array() );
+ $instance['hours'] = wp_kses( $new_instance['hours'], array() );
+ $instance['lat'] = isset( $old_instance['lat'] ) ? floatval( $old_instance['lat'] ) : 0;
+ $instance['lon'] = isset( $old_instance['lon'] ) ? floatval( $old_instance['lon'] ) : 0;
+
+ if ( ! $instance['lat'] || ! $instance['lon'] ) {
+ $update_lat_lon = true;
+ }
+
+ if ( $instance['address'] && $update_lat_lon ) {
+
+ // Get the lat/lon of the user specified address.
+ $address = $this->urlencode_address( $instance['address'] );
+ $path = "http://maps.googleapis.com/maps/api/geocode/json?sensor=false&address=" . $address;
+ $json = wp_remote_retrieve_body( wp_remote_get( $path ) );
+
+ if ( ! $json ) {
+ // The read failed :(
+ esc_html_e( "There was a problem getting the data to display this address on a map. Please refresh your browser and try again.", 'jetpack' );
+ die();
+ }
+
+ $json_obj = json_decode( $json );
+
+ if ( $err = $json_obj->status == "ZERO_RESULTS" ) {
+ // The address supplied does not have a matching lat / lon.
+ // No map is available.
+ $instance['lat'] = "0";
+ $instance['lon'] = "0";
+ } else {
+
+ $loc = $json_obj->results[0]->geometry->location;
+
+ $lat = floatval( $loc->lat );
+ $lon = floatval( $loc->lng );
+
+ $instance['lat'] = "$lat";
+ $instance['lon'] = "$lon";
+ }
+ }
+
+ if ( ! isset( $new_instance['showmap'] ) ) {
+ $instance['showmap'] = 0;
+ } else {
+ $instance['showmap'] = intval( $new_instance['showmap'] );
+ }
+
+ return $instance;
+ }
+
+
+ /**
+ * Displays the form for this widget on the Widgets page of the WP Admin area.
+ **/
+ function form( $instance ) {
+ $instance = wp_parse_args( $instance, $this->defaults() );
+ extract( $instance );
+
+ $disabled = !$this->has_good_map( $instance );
+ ?>
+ <p><label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"><?php esc_html_e( 'Title:', 'jetpack' ); ?></label>
+
+ <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" /></p>
+
+ <p><label for="<?php echo esc_attr( $this->get_field_id( 'address' ) ); ?>"><?php esc_html_e( 'Address:', 'jetpack' ); ?></label>
+ <textarea class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'address' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'address' ) ); ?>"><?php echo esc_textarea( $address ); ?></textarea>
+ <?php
+ if ( $this->has_good_map( $instance ) ) {
+ ?>
+ <input class="" id="<?php echo esc_attr( $this->get_field_id( 'showmap' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'showmap' ) ); ?>" value="1" type="checkbox" <?php checked( $showmap , 1); ?> />
+ <label for="<?php echo esc_attr( $this->get_field_id( 'showmap' ) ); ?>"><?php esc_html_e( 'Show map', 'jetpack' ); ?></label></p>
+ <?php
+ } else {
+ ?>
+ <span class="error-message"><?php _e( 'Sorry. We can not plot this address. A map will not be displayed. Is the address formatted correctly?', 'jetpack' ); ?></span></p>
+ <input id="<?php echo esc_attr( $this->get_field_id( 'showmap' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'showmap' ) ); ?>" value="<?php echo( intval( $instance['showmap'] ) ); ?>" type="hidden" />
+ <?php
+ }
+ ?>
+
+ <p><label for="<?php echo esc_attr( $this->get_field_id( 'phone' ) ); ?>"><?php esc_html_e( 'Phone:', 'jetpack' ); ?></label>
+ <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'phone' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'phone' ) ); ?>" type="text" value="<?php echo esc_attr( $phone ); ?>" /></p>
+
+ <p><label for="<?php echo esc_attr( $this->get_field_id( 'hours' ) ); ?>"><?php esc_html_e( 'Hours:', 'jetpack' ); ?></label>
+
+ <textarea class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'hours' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'hours' ) ); ?>"><?php echo esc_textarea( $hours ); ?></textarea></p>
+
+ <?php
+ }
+
+
+ function build_map_link( $address ) {
+ // Google map urls have lots of available params but zoom (z) and query (q) are enough.
+ return "http://maps.google.com/maps?z=16&q=" . $this->urlencode_address( $address );
+ }
+
+
+ function build_map( $lat, $lon ) {
+
+ wp_enqueue_script( "jquery" );
+ wp_enqueue_script( "google-maps", "https://maps.googleapis.com/maps/api/js?sensor=false" );
+ wp_enqueue_script( "contact-info-map-js", plugins_url( 'contact-info/contact-info-map.js', __FILE__ ), array( 'jquery', 'google-maps' ), 20150127 );
+ wp_enqueue_style( "contact-info-map-css", plugins_url( 'contact-info/contact-info-map.css', __FILE__ ), null, 20150127 );
+
+ $lat = esc_attr( $lat );
+ $lon = esc_attr( $lon );
+ $html = <<<EOT
+ <div class="contact-map">
+ <input type="hidden" class="contact-info-map-lat" value="$lat" />
+ <input type="hidden" class="contact-info-map-lon" value="$lon" />
+ <div class="contact-info-map-canvas"></div></div>
+EOT;
+
+ return $html;
+ }
+
+
+ function urlencode_address( $address ) {
+
+ $address = strtolower( $address );
+ $address = preg_replace( "/\s+/", " ", trim( $address ) ); // Get rid of any unwanted whitespace
+ $address = str_ireplace( " ", "+", $address ); // Use + not %20
+ urlencode( $address );
+
+ return $address;
+ }
+
+
+ function has_good_map( $instance ) {
+ // The lat and lon of an address that could not be plotted will have values of 0 and 0.
+ return ! ( $instance['lat'] == "0" && $instance['lon'] == "0" );
+ }
+
+ }
+
+}
diff --git a/plugins/jetpack/modules/widgets/contact-info/contact-info-map.css b/plugins/jetpack/modules/widgets/contact-info/contact-info-map.css
new file mode 100644
index 00000000..47629e9b
--- /dev/null
+++ b/plugins/jetpack/modules/widgets/contact-info/contact-info-map.css
@@ -0,0 +1,11 @@
+.contact-info-map-canvas {
+ height: 216px;
+ margin: 0;
+ padding: 0;
+ overflow: hidden;
+}
+
+/* Prevent Google maps controls from being hidden */
+.gmnoprint img {
+ max-width: none !important;
+}
diff --git a/plugins/jetpack/modules/widgets/contact-info/contact-info-map.js b/plugins/jetpack/modules/widgets/contact-info/contact-info-map.js
new file mode 100644
index 00000000..c93fbcf8
--- /dev/null
+++ b/plugins/jetpack/modules/widgets/contact-info/contact-info-map.js
@@ -0,0 +1,23 @@
+/* global google */
+/* jshint unused:false */
+if (jQuery) {
+ jQuery().ready(function() {
+ jQuery('div.contact-map').each(function(){
+ // get lat and lon from hidden input values
+ var lat = jQuery(this).find('.contact-info-map-lat').val(),
+ lon = jQuery(this).find('.contact-info-map-lon').val(),
+ lat_lon = new google.maps.LatLng( lat, lon ),
+ mapOptions = {
+ zoom: 16,
+ center: lat_lon,
+ mapTypeId: google.maps.MapTypeId.ROADMAP
+ },
+ map = new google.maps.Map(jQuery(this).find('.contact-info-map-canvas')[0], mapOptions),
+ marker = new google.maps.Marker({
+ map: map,
+ position: lat_lon
+ });
+
+ });
+ });
+}
diff --git a/plugins/jetpack/modules/widgets/facebook-likebox.php b/plugins/jetpack/modules/widgets/facebook-likebox.php
index 8cb7e02b..9bad358d 100644
--- a/plugins/jetpack/modules/widgets/facebook-likebox.php
+++ b/plugins/jetpack/modules/widgets/facebook-likebox.php
@@ -18,9 +18,9 @@ class WPCOM_Widget_Facebook_LikeBox extends WP_Widget {
private $default_height = 432;
private $default_width = 200;
- private $max_width = 400;
+ private $max_width = 9999;
private $min_width = 0;
- private $max_height = 999;
+ private $max_height = 9999;
private $min_height = 100;
private $default_colorscheme = 'light';
private $allowed_colorschemes = array( 'light', 'dark' );
@@ -54,7 +54,7 @@ class WPCOM_Widget_Facebook_LikeBox extends WP_Widget {
$title = apply_filters( 'widget_title', $instance['title'] );
- $page_url = ( is_ssl() ) ? str_replace( 'http://', 'https://', $like_args['href'] ) : $like_args['href'];
+ $page_url = set_url_scheme( $like_args['href'], 'https' );
$like_args['show_faces'] = (bool) $like_args['show_faces'] ? 'true' : 'false';
$like_args['stream'] = (bool) $like_args['stream'] ? 'true' : 'false';
@@ -68,13 +68,20 @@ class WPCOM_Widget_Facebook_LikeBox extends WP_Widget {
$like_args['locale'] = $locale;
$like_args = urlencode_deep( $like_args );
- $like_url = add_query_arg( $like_args, sprintf( '%swww.facebook.com/plugins/likebox.php', ( is_ssl() ) ? 'https://' : 'http://' ) );
+ $like_url = add_query_arg(
+ $like_args,
+ 'https://www.facebook.com/plugins/likebox.php'
+ );
echo $before_widget;
if ( ! empty( $title ) ) :
echo $before_title;
- ?><a href="<?php echo esc_url( $page_url ); ?>"><?php echo esc_html( $title ); ?></a><?php
+
+ $likebox_widget_title = '<a href="' . esc_url( $page_url ) . '">' . esc_html( $title ) . '</a>';
+
+ echo apply_filters( 'jetpack_facebook_likebox_title', $likebox_widget_title, $title, $page_url );
+
echo $after_title;
endif;
diff --git a/plugins/jetpack/modules/widgets/gallery.php b/plugins/jetpack/modules/widgets/gallery.php
index 0d33f5c5..0b525c63 100644
--- a/plugins/jetpack/modules/widgets/gallery.php
+++ b/plugins/jetpack/modules/widgets/gallery.php
@@ -21,7 +21,7 @@ class Jetpack_Gallery_Widget extends WP_Widget {
);
$control_ops = array( 'width' => 250 );
- add_action( 'admin_init', array( $this, 'admin_init' ) );
+ add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_scripts' ) );
$this->WP_Widget( 'gallery', apply_filters( 'jetpack_widget_name', __( 'Gallery', 'jetpack' ) ), $widget_ops, $control_ops );
}
@@ -31,6 +31,8 @@ class Jetpack_Gallery_Widget extends WP_Widget {
* @param array $instance The settings for the particular instance of the widget
*/
public function widget( $args, $instance ) {
+ $instance = wp_parse_args( (array) $instance, $this->defaults() );
+
$this->enqueue_frontend_scripts();
extract( $args );
@@ -106,15 +108,17 @@ class Jetpack_Gallery_Widget extends WP_Widget {
public function get_attachments( $instance ){
$ids = explode( ',', $instance['ids'] );
- $order = ( isset( $instance['random'] ) && $instance['random'] ) ? 'rand' : 'post__in';
+ if ( isset( $instance['random'] ) && 'on' == $instance['random'] ) {
+ shuffle( $ids );
+ }
$attachments_query = new WP_Query( array(
- 'post__in' => $ids,
- 'post_status' => 'inherit',
- 'post_type' => 'attachment',
- 'post_mime_type' => 'image',
- 'posts_per_page' => -1,
- 'orderby' => $order
+ 'post__in' => $ids,
+ 'post_status' => 'inherit',
+ 'post_type' => 'attachment',
+ 'post_mime_type' => 'image',
+ 'posts_per_page' => -1,
+ 'orderby' => 'post__in',
) );
$attachments = $attachments_query->get_posts();
@@ -132,20 +136,16 @@ class Jetpack_Gallery_Widget extends WP_Widget {
* @return string String of HTML representing a rectangular gallery
*/
public function rectangular_widget( $args, $instance ) {
- if ( ! class_exists( 'Jetpack_Tiled_Gallery' ) )
+ if ( ! class_exists( 'Jetpack_Tiled_Gallery' )
+ && ! class_exists( 'Jetpack_Tiled_Gallery_Layout_Rectangular') ) {
return;
+ }
$widget_tiled_gallery = new Jetpack_Tiled_Gallery();
-
- $widget_tiled_gallery->set_atts( array(
- 'link' => $instance['link'],
- ) );
-
$widget_tiled_gallery->default_scripts_and_styles();
- $html = $widget_tiled_gallery->rectangular_talavera( $instance['attachments'] );
-
- return $html;
+ $layout = new Jetpack_Tiled_Gallery_Layout_Rectangular( $instance['attachments'], $instance['link'], false, 3 );
+ return $layout->HTML();
}
/**
@@ -156,21 +156,16 @@ class Jetpack_Gallery_Widget extends WP_Widget {
* @return string String of HTML representing a square gallery
*/
public function square_widget( $args, $instance ) {
- if ( ! class_exists( 'Jetpack_Tiled_Gallery' ) )
+ if ( ! class_exists( 'Jetpack_Tiled_Gallery' )
+ && ! class_exists( 'Jetpack_Tiled_Gallery_Layout_Square') ) {
return;
+ }
$widget_tiled_gallery = new Jetpack_Tiled_Gallery();
-
- $widget_tiled_gallery->set_atts( array(
- 'link' => $instance['link'],
- //'columns' => $instance['columns']
- ) );
-
$widget_tiled_gallery->default_scripts_and_styles();
- $html = $widget_tiled_gallery->circle_talavera( $instance['attachments'] );
-
- return $html;
+ $layout = new Jetpack_Tiled_Gallery_Layout_Square( $instance['attachments'], $instance['link'], false, 3 );
+ return $layout->HTML();
}
/**
@@ -181,23 +176,16 @@ class Jetpack_Gallery_Widget extends WP_Widget {
* @return string String of HTML representing a circular gallery
*/
public function circle_widget( $args, $instance ) {
- if ( ! class_exists( 'Jetpack_Tiled_Gallery' ) )
+ if ( ! class_exists( 'Jetpack_Tiled_Gallery' )
+ && ! class_exists( 'Jetpack_Tiled_Gallery_Layout_Circle') ) {
return;
+ }
$widget_tiled_gallery = new Jetpack_Tiled_Gallery();
-
- // Tell the Tiled_Gallery what we want the images to link to
- $widget_tiled_gallery->set_atts( array(
- 'link' => $instance['link'],
- //'columns' => $instance['columns'],
- 'type' => 'circle'
- ) );
-
$widget_tiled_gallery->default_scripts_and_styles();
- $html = $widget_tiled_gallery->circle_talavera( $instance['attachments'] );
-
- return $html;
+ $layout = new Jetpack_Tiled_Gallery_Layout_Circle( $instance['attachments'], $instance['link'], false, 3 );
+ return $layout->HTML();
}
/**
@@ -215,6 +203,9 @@ class Jetpack_Gallery_Widget extends WP_Widget {
if ( ! class_exists( 'Jetpack_Slideshow_Shortcode' ) )
return;
+ if ( count( $instance['attachments'] ) < 1 )
+ return;
+
$slideshow = new Jetpack_Slideshow_Shortcode();
$slideshow->enqueue_scripts();
@@ -242,12 +233,15 @@ class Jetpack_Gallery_Widget extends WP_Widget {
if ( intval( $content_width ) > 0 )
$max_width = min( intval( $content_width ), $max_width );
+ $color = Jetpack_Options::get_option( 'slideshow_background_color', 'black' );
+
$js_attr = array(
'gallery' => $gallery,
'selector' => $gallery_instance,
'width' => $max_width,
'height' => $max_height,
'trans' => 'fade',
+ 'color' => $color,
);
$html = $slideshow->slideshow_js( $js_attr );
@@ -300,8 +294,11 @@ class Jetpack_Gallery_Widget extends WP_Widget {
foreach ( $instance as $key => $value ) {
$value = trim( $value );
- if ( isset( $allowed_values[ $key ] ) && $allowed_values[ $key ] && ! array_key_exists( $value, $allowed_values[ $key ] ) )
+ if ( isset( $allowed_values[ $key ] ) && $allowed_values[ $key ] && ! array_key_exists( $value, $allowed_values[ $key ] ) ) {
$instance[ $key ] = $defaults[ $key ];
+ } else {
+ $instance[ $key ] = sanitize_text_field( $value );
+ }
}
return $instance;
@@ -362,10 +359,10 @@ class Jetpack_Gallery_Widget extends WP_Widget {
wp_enqueue_script( 'gallery-widget' );
}
- public function admin_init() {
+ public function enqueue_admin_scripts() {
global $pagenow;
- if ( 'widgets.php' == $pagenow ) {
+ if ( 'widgets.php' == $pagenow || 'customize.php' == $pagenow ) {
wp_enqueue_media();
wp_enqueue_script( 'gallery-widget-admin', plugins_url( '/gallery/js/admin.js', __FILE__ ), array(
@@ -378,8 +375,11 @@ class Jetpack_Gallery_Widget extends WP_Widget {
);
wp_localize_script( 'gallery-widget-admin', '_wpGalleryWidgetAdminSettings', $js_settings );
-
- wp_enqueue_style( 'gallery-widget-admin', plugins_url( '/gallery/css/admin.css', __FILE__ ) );
+ if( is_rtl() ) {
+ wp_enqueue_style( 'gallery-widget-admin', plugins_url( '/gallery/css/rtl/admin-rtl.css', __FILE__ ) );
+ } else {
+ wp_enqueue_style( 'gallery-widget-admin', plugins_url( '/gallery/css/admin.css', __FILE__ ) );
+ }
}
}
}
diff --git a/plugins/jetpack/modules/widgets/gallery/css/admin-rtl.css b/plugins/jetpack/modules/widgets/gallery/css/admin-rtl.css
new file mode 100644
index 00000000..4562d229
--- /dev/null
+++ b/plugins/jetpack/modules/widgets/gallery/css/admin-rtl.css
@@ -0,0 +1,11 @@
+.gallery-widget-thumbs-wrapper {
+ margin: -5px 0 0.3em 0;
+}
+
+.gallery-widget-thumbs img {
+ border: 1px solid #ccc;
+ padding: 2px;
+ background-color: #fff;
+ margin: 0 0 5px 5px;
+ float: right;
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/widgets/gallery/css/admin-rtl.min.css b/plugins/jetpack/modules/widgets/gallery/css/admin-rtl.min.css
new file mode 100644
index 00000000..1ef4ed3f
--- /dev/null
+++ b/plugins/jetpack/modules/widgets/gallery/css/admin-rtl.min.css
@@ -0,0 +1 @@
+.gallery-widget-thumbs-wrapper{margin:-5px 0 .3em}.gallery-widget-thumbs img{border:1px solid #ccc;padding:2px;background-color:#fff;margin:0 0 5px 5px;float:right} \ No newline at end of file
diff --git a/plugins/jetpack/modules/widgets/gallery/css/admin.min.css b/plugins/jetpack/modules/widgets/gallery/css/admin.min.css
new file mode 100644
index 00000000..3f1ee26a
--- /dev/null
+++ b/plugins/jetpack/modules/widgets/gallery/css/admin.min.css
@@ -0,0 +1 @@
+.gallery-widget-thumbs-wrapper{margin:-5px 0 .3em}.gallery-widget-thumbs img{border:1px solid #ccc;padding:2px;background-color:#fff;margin:0 5px 5px 0;float:left} \ No newline at end of file
diff --git a/plugins/jetpack/modules/widgets/gallery/js/admin.js b/plugins/jetpack/modules/widgets/gallery/js/admin.js
index 58afb347..234eafc2 100644
--- a/plugins/jetpack/modules/widgets/gallery/js/admin.js
+++ b/plugins/jetpack/modules/widgets/gallery/js/admin.js
@@ -1,25 +1,28 @@
+/* jshint onevar: false, multistr: true */
+/* global _wpMediaViewsL10n, _wpGalleryWidgetAdminSettings */
+
(function($){
var $ids;
var $thumbs;
$(function(){
- $( '.widgets-holder-wrap, .editwidget' ).on( 'click', '.gallery-widget-choose-images', function( event ) {
+ $( document.body ) .on( 'click', '.widget-content .gallery-widget-choose-images', function( event ) {
event.preventDefault();
var widget_form = $( this ).closest( 'form' );
- $ids = widget_form.find( '.gallery-widget-ids' );
+ $ids = widget_form.find( '.gallery-widget-ids' );
$thumbs = widget_form.find( '.gallery-widget-thumbs' );
var idsString = $ids.val();
var attachments = getAttachments( idsString );
- var selection = null;
- var editing = false;
+ var selection = null;
+ var editing = false;
if ( attachments ) {
- var selection = getSelection( attachments );
+ selection = getSelection( attachments );
editing = true;
}
@@ -40,7 +43,7 @@
// Setup an onchange handler to toggle various options when changing style. The different style options
// require different form inputs to be presented in the widget; this event will keep the UI in sync
// with the selected style
- $( ".widget-inside" ).on( 'change', '.gallery-widget-style', setupStyleOptions);
+ $( '.widget-inside' ).on( 'change', '.gallery-widget-style', setupStyleOptions);
// Setup the Link To options for all forms currently on the page. Does the same as the onChange handler, but
// is called once to display the correct form inputs for each widget on the page
@@ -48,9 +51,6 @@
});
var media = wp.media,
- Attachment = media.model.Attachment,
- Attachments = media.model.Attachments,
- Query = media.model.Query,
l10n;
// Link any localized strings.
@@ -67,34 +67,51 @@
createStates: function() {
var options = this.options;
- this.states.add([
- new media.controller.WidgetGalleryEdit({
- library: options.selection,
- editing: options.editing,
- menu: 'gallery'
- }),
- new media.controller.GalleryAdd({
-
- })
- ]);
- }
- });
-
- /**
- * wp.media.controller.WidgetGalleryEdit
- *
- * Removes the gallery settings sidebar when editing widgets...settings are instead handled
- * via the standard widget interface form
- *
- */
- media.controller.WidgetGalleryEdit = media.controller.GalleryEdit.extend({
- gallerySettings: function( browser ) {
- return;
+ // `CollectionEdit` and `CollectionAdd` were only introduced in r27214-core,
+ // so they may not be available yet.
+ if ( 'CollectionEdit' in media.controller ) {
+ this.states.add([
+ new media.controller.CollectionEdit({
+ type: 'image',
+ collectionType: 'gallery',
+ title: l10n.editGalleryTitle,
+ SettingsView: media.view.Settings.Gallery,
+ library: options.selection,
+ editing: options.editing,
+ menu: 'gallery'
+ }),
+ new media.controller.CollectionAdd({
+ type: 'image',
+ collectionType: 'gallery',
+ title: l10n.addToGalleryTitle
+ })
+ ]);
+ } else {
+ // If `CollectionEdit` is not available, then use the old approach.
+
+ if ( ! ( 'WidgetGalleryEdit' in media.controller ) ) {
+ // Remove the gallery settings sidebar when editing widgets.
+ media.controller.WidgetGalleryEdit = media.controller.GalleryEdit.extend({
+ gallerySettings: function( /*browser*/ ) {
+ return;
+ }
+ });
+ }
+
+ this.states.add([
+ new media.controller.WidgetGalleryEdit({
+ library: options.selection,
+ editing: options.editing,
+ menu: 'gallery'
+ }),
+ new media.controller.GalleryAdd({ })
+ ]);
+ }
}
});
function setupStyleOptions(){
- $( '.widget-inside .gallery-widget-style' ).each( function( i ){
+ $( '.widget-inside .gallery-widget-style' ).each( function( /*i*/ ){
var style = $( this ).val();
var form = $( this ).parents( 'form' );
@@ -136,14 +153,15 @@
* Take a csv string of ids (as stored in db) and fetch a full Attachments collection
*/
function getAttachments( idsString ) {
- if( ! idsString )
+ if ( ! idsString ) {
return null;
+ }
// Found in /wp-includes/js/media-editor.js
var shortcode = wp.shortcode.next( 'gallery', '[gallery ids="' + idsString + '"]' );
// Ignore the rest of the match object, to give attachments() below what it expects
- shortcode = shortcode.shortcode;
+ shortcode = shortcode.shortcode;
var attachments = wp.media.gallery.attachments( shortcode );
@@ -185,8 +203,9 @@
selection = selection || state.get( 'selection' );
- if ( ! selection )
+ if ( ! selection ) {
return;
+ }
// Map the Models down into a simple array of ids that can be easily imploded to a csv string
var ids = selection.map( function( model ){
@@ -195,7 +214,7 @@
var id_string = ids.join( ',' );
- $ids.val( id_string );
+ $ids.val( id_string ).trigger( 'change' );
setupThumbs( selection, $thumbs );
}, this );
diff --git a/plugins/jetpack/modules/widgets/gallery/templates/form.php b/plugins/jetpack/modules/widgets/gallery/templates/form.php
index 08833657..f24cf1c2 100644
--- a/plugins/jetpack/modules/widgets/gallery/templates/form.php
+++ b/plugins/jetpack/modules/widgets/gallery/templates/form.php
@@ -1,5 +1,5 @@
<p>
- <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php esc_html_e( 'Title:' , 'jetpack' ); ?>
+ <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php esc_html_e( 'Title:', 'jetpack' ); ?>
<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>"
type="text" value="<?php echo esc_attr( $instance['title'] ); ?>" />
</label>
@@ -7,7 +7,7 @@
<p>
<label>
- <?php esc_html_e( 'Images:' , 'jetpack' ); ?>
+ <?php esc_html_e( 'Images:', 'jetpack' ); ?>
</label>
</p>
@@ -36,11 +36,11 @@
</div>
<p>
- <a class="button gallery-widget-choose-images" title="Choose Images"><span class="wp-media-buttons-icon"></span> Choose Images</a>
+ <a class="button gallery-widget-choose-images"><span class="wp-media-buttons-icon"></span> <?php esc_html_e( 'Choose Images', 'jetpack' ); ?></a>
</p>
<p class="gallery-widget-link-wrapper">
- <label for="<?php echo $this->get_field_id( 'link' ); ?>"><?php esc_html_e( 'Link To:' , 'jetpack' ); ?></label>
+ <label for="<?php echo $this->get_field_id( 'link' ); ?>"><?php esc_html_e( 'Link To:', 'jetpack' ); ?></label>
<select name="<?php echo $this->get_field_name( 'link' ); ?>" id="<?php echo $this->get_field_id( 'link' ); ?>" class="widefat">
<?php foreach ( $allowed_values['link'] as $key => $label ) {
$selected = '';
@@ -49,13 +49,13 @@
$selected = "selected='selected' ";
} ?>
- <option value="<?php echo $key; ?>" <?php echo $selected; ?>><?php esc_html_e( $label , 'jetpack' ); ?></option>
+ <option value="<?php echo $key; ?>" <?php echo $selected; ?>><?php echo esc_html( $label, 'jetpack' ); ?></option>
<?php } ?>
</select>
</p>
<p>
- <label for="<?php echo $this->get_field_id( 'random' ); ?>"><?php esc_html_e( 'Random Order:' , 'jetpack' ); ?></label>
+ <label for="<?php echo $this->get_field_id( 'random' ); ?>"><?php esc_html_e( 'Random Order:', 'jetpack' ); ?></label>
<?php $checked = '';
if ( isset( $instance['random'] ) && $instance['random'] )
@@ -66,7 +66,7 @@
</p>
<p class="gallery-widget-style-wrapper">
- <label for="<?php echo $this->get_field_id( 'type' ); ?>"><?php esc_html_e( 'Style:' , 'jetpack' ); ?></label>
+ <label for="<?php echo $this->get_field_id( 'type' ); ?>"><?php esc_html_e( 'Style:', 'jetpack' ); ?></label>
<select name="<?php echo $this->get_field_name( 'type' ); ?>" id="<?php echo $this->get_field_id( 'type' ); ?>" class="widefat gallery-widget-style">
<?php foreach ( $allowed_values['type'] as $key => $label ) {
$selected = '';
@@ -75,7 +75,7 @@
$selected = "selected='selected' ";
} ?>
- <option value="<?php echo $key; ?>" <?php echo $selected; ?>><?php esc_html_e( $label, 'jetpack' ); ?></option>
+ <option value="<?php echo $key; ?>" <?php echo $selected; ?>><?php echo esc_html( $label, 'jetpack' ); ?></option>
<?php } ?>
</select>
</p>
diff --git a/plugins/jetpack/modules/widgets/goodreads.php b/plugins/jetpack/modules/widgets/goodreads.php
new file mode 100644
index 00000000..5a56644e
--- /dev/null
+++ b/plugins/jetpack/modules/widgets/goodreads.php
@@ -0,0 +1,144 @@
+<?php
+/**
+ * Register the widget for use in Appearance -> Widgets
+ */
+add_action( 'widgets_init', 'jetpack_goodreads_widget_init' );
+
+function jetpack_goodreads_widget_init() {
+ register_widget( 'WPCOM_Widget_Goodreads' );
+}
+
+/**
+ * Goodreads widget class
+ * Display a user's Goodreads shelf.
+ * Customize user_id, title, and shelf
+ *
+ */
+class WPCOM_Widget_Goodreads extends WP_Widget {
+
+ private $goodreads_widget_id = 0;
+
+ function __construct() {
+ parent::__construct(
+ 'wpcom-goodreads',
+ apply_filters( 'jetpack_widget_name', __( 'Goodreads', 'jetpack' ) ),
+ array(
+ 'classname' => 'widget_goodreads',
+ 'description' => __( 'Display your books from Goodreads', 'jetpack' )
+ )
+ );
+ // For user input sanitization and display
+ $this->shelves = array(
+ 'read' => _x( 'Read', 'past participle: books I have read', 'jetpack' ),
+ 'currently-reading' => __( 'Currently Reading', 'jetpack' ),
+ 'to-read' => _x( 'To Read', 'my list of books to read', 'jetpack' )
+ );
+
+ if ( is_active_widget( '', '', 'wpcom-goodreads' ) ) {
+ add_action( 'wp_print_styles', array( $this, 'enqueue_style' ) );
+ }
+ }
+
+ function enqueue_style() {
+ if ( is_rtl() ) {
+ wp_enqueue_style( 'goodreads-widget', plugins_url( 'goodreads/css/rtl/goodreads-rtl.css', __FILE__ ) );
+ } else {
+ wp_enqueue_style( 'goodreads-widget', plugins_url( 'goodreads/css/goodreads.css', __FILE__ ) );
+ }
+ }
+
+ function widget( $args, $instance ) {
+ $title = apply_filters( 'widget_title', $instance['title'] );
+
+ if ( empty( $instance['user_id'] ) || 'invalid' === $instance['user_id'] ) {
+ if ( current_user_can('edit_theme_options') ) {
+ echo $args['before_widget'];
+ echo '<p>' . sprintf(
+ __( 'You need to enter your numeric user ID for the <a href="%1$s">Goodreads Widget</a> to work correctly. <a href="%2$s">Full instructions</a>.', 'jetpack' ),
+ esc_url( admin_url( 'widgets.php' ) ),
+ 'http://support.wordpress.com/widgets/goodreads-widget/#goodreads-user-id'
+ ) . '</p>';
+ echo $args['after_widget'];
+ }
+ return;
+ }
+
+ if ( !array_key_exists( $instance['shelf'], $this->shelves ) )
+ return;
+
+ $instance['user_id'] = absint( $instance['user_id'] );
+
+ // Set widget ID based on shelf.
+ $this->goodreads_widget_id = $instance['user_id'] . '_' . $instance['shelf'];
+
+ if ( empty( $title ) ) $title = esc_html__( 'Goodreads', 'jetpack' );
+
+ echo $args['before_widget'];
+ echo $args['before_title'] . $title . $args['after_title'];
+
+ $goodreads_url = 'https://www.goodreads.com/review/custom_widget/' . urlencode( $instance['user_id'] ) . '.' . urlencode( $instance['title'] ) . ':%20' . urlencode( $instance['shelf'] ) . '?cover_position=&cover_size=small&num_books=5&order=d&shelf=' . urlencode( $instance['shelf'] ) . '&sort=date_added&widget_bg_transparent=&widget_id=' . esc_attr( $this->goodreads_widget_id ) ;
+
+ echo '<div class="gr_custom_widget" id="gr_custom_widget_' . esc_attr( $this->goodreads_widget_id ). '"></div>' . "\n";
+ echo '<script src="' . esc_url( $goodreads_url ) . '"></script>' . "\n";
+
+ echo $args['after_widget'];
+
+ do_action( 'jetpack_stats_extra', 'widget', 'goodreads' );
+ }
+
+ function goodreads_user_id_exists( $user_id ) {
+ $url = "http://www.goodreads.com/user/show/$user_id/";
+ $response = wp_remote_head( $url, array( 'httpversion'=>'1.1', 'timeout'=>3, 'redirection'=> 2 ) );
+ if ( wp_remote_retrieve_response_code( $response ) === 200 )
+ return true;
+ else
+ return false;
+ }
+
+ function update( $new_instance, $old_instance ) {
+ $instance = $old_instance;
+
+ $instance['user_id'] = trim( wp_kses( stripslashes( $new_instance['user_id'] ), array() ) );
+ if ( ! empty( $instance['user_id'] ) && ( ! isset( $old_instance['user_id'] ) || $instance['user_id'] !== $old_instance['user_id'] ) ) {
+ if ( ! $this->goodreads_user_id_exists( $instance['user_id'] ) ) {
+ $instance['user_id'] = 'invalid';
+ }
+ }
+ $instance['title'] = wp_kses( stripslashes( $new_instance['title'] ), array() );
+ $shelf = wp_kses( stripslashes( $new_instance['shelf'] ), array() );
+ if ( array_key_exists( $shelf, $this->shelves ) )
+ $instance['shelf'] = $shelf;
+
+ return $instance;
+ }
+
+ function form( $instance ) {
+ //Defaults
+ $instance = wp_parse_args( (array) $instance, array( 'user_id' => '', 'title' => 'Goodreads', 'shelf' => 'read' ) );
+
+ echo '<p><label for="' . esc_attr( $this->get_field_id( 'title' ) ) . '">' . esc_html__( 'Title:', 'jetpack' ) . '
+ <input class="widefat" id="' . esc_attr( $this->get_field_id( 'title' ) ) . '" name="' . esc_attr( $this->get_field_name( 'title' ) ) . '" type="text" value="' . esc_attr( $instance['title'] ) . '" />
+ </label></p>
+ <p><label for="' . esc_attr( $this->get_field_id( 'user_id' ) ) . '">';
+ if ( 'invalid' === $instance['user_id'] ) {
+ $invalid_notice = _x( 'Invalid User ID, please verify and re-enter your', 'Goodreads numeric user id', 'jetpack' );
+ echo '<span class="error">' . $invalid_notice . '</span>&nbsp;';
+ $instance['user_id'] = '';
+ }
+ $goodreads_id = sprintf (
+ __( 'Goodreads numeric user id <a href="%s" target="_blank">(instructions)</a>:', 'jetpack' ),
+ 'http://support.wordpress.com/widgets/goodreads-widget/#goodreads-user-id'
+ );
+ echo $goodreads_id;
+ echo '<input class="widefat" id="' . esc_attr( $this->get_field_id( 'user_id' ) ) . '" name="' . esc_attr( $this->get_field_name( 'user_id' ) ) . '" type="text" value="' . esc_attr( $instance['user_id'] ) . '" />
+ </label></p>
+ <p><label for="' . esc_attr( $this->get_field_id( 'shelf' ) ) . '">' . esc_html__( 'Shelf:', 'jetpack' ) . '
+ <select class="widefat" id="' . esc_attr( $this->get_field_id( 'shelf' ) ) . '" name="' . esc_attr( $this->get_field_name( 'shelf' ) ) . '" >';
+ foreach( $this->shelves as $_shelf_value => $_shelf_display ) {
+ echo "\t<option value='" . esc_attr( $_shelf_value ) . "'" . selected( $_shelf_value, $instance['shelf'] ) . ">" . $_shelf_display . "</option>\n";
+ }
+ echo '</select>
+ </label></p>
+ ';
+ }
+}
diff --git a/plugins/jetpack/modules/widgets/goodreads/css/goodreads.css b/plugins/jetpack/modules/widgets/goodreads/css/goodreads.css
new file mode 100644
index 00000000..d329cb7e
--- /dev/null
+++ b/plugins/jetpack/modules/widgets/goodreads/css/goodreads.css
@@ -0,0 +1,48 @@
+div[class^="gr_custom_container"] {
+ /* customize your Goodreads widget container here*/
+ border: 1px solid gray;
+ border-radius:10px;
+ padding: 10px 5px 10px 5px;
+ background-color: #FFF;
+ color: #000;
+}
+
+div[class^="gr_custom_container"] a {
+ color: #000;
+}
+
+h2[class^="gr_custom_header"] {
+ /* customize your Goodreads header here*/
+ display: none;
+}
+div[class^="gr_custom_each_container"] {
+ /* customize each individual book container here */
+ width: 100%;
+ clear: both;
+ margin-bottom: 10px;
+ overflow: auto;
+ padding-bottom: 4px;
+ border-bottom: 1px solid #aaa;
+}
+div[class^="gr_custom_book_container"] {
+ /* customize your book covers here */
+ float: right;
+ overflow: hidden;
+ height: 60px;
+ margin-left: 4px;
+ width: 39px;
+}
+div[class^="gr_custom_author"] {
+ /* customize your author names here */
+ font-size: 10px;
+}
+div[class^="gr_custom_tags"] {
+ /* customize your tags here */
+ font-size: 10px;
+ color: gray;
+}
+div[class^="gr_custom_review"] {
+}
+div[class^="gr_custom_rating"] {
+ display: none;
+}
diff --git a/plugins/jetpack/modules/widgets/goodreads/css/rtl/goodreads-rtl.css b/plugins/jetpack/modules/widgets/goodreads/css/rtl/goodreads-rtl.css
new file mode 100644
index 00000000..ff600c49
--- /dev/null
+++ b/plugins/jetpack/modules/widgets/goodreads/css/rtl/goodreads-rtl.css
@@ -0,0 +1,50 @@
+/* This file was automatically generated on Nov 19 2013 15:54:57 */
+
+div[class^="gr_custom_container"] {
+ /* customize your Goodreads widget container here*/
+ border: 1px solid gray;
+ border-radius:10px;
+ padding: 10px 5px 10px 5px;
+ background-color: #FFF;
+ color: #000;
+}
+
+div[class^="gr_custom_container"] a {
+ color: #000;
+}
+
+h2[class^="gr_custom_header"] {
+ /* customize your Goodreads header here*/
+ display: none;
+}
+div[class^="gr_custom_each_container"] {
+ /* customize each individual book container here */
+ width: 100%;
+ clear: both;
+ margin-bottom: 10px;
+ overflow: auto;
+ padding-bottom: 4px;
+ border-bottom: 1px solid #aaa;
+}
+div[class^="gr_custom_book_container"] {
+ /* customize your book covers here */
+ float: left;
+ overflow: hidden;
+ height: 60px;
+ margin-right: 4px;
+ width: 39px;
+}
+div[class^="gr_custom_author"] {
+ /* customize your author names here */
+ font-size: 10px;
+}
+div[class^="gr_custom_tags"] {
+ /* customize your tags here */
+ font-size: 10px;
+ color: gray;
+}
+div[class^="gr_custom_review"] {
+}
+div[class^="gr_custom_rating"] {
+ display: none;
+}
diff --git a/plugins/jetpack/modules/widgets/gravatar-profile.css b/plugins/jetpack/modules/widgets/gravatar-profile.css
index 9b1e70cc..f9e3ffc8 100644
--- a/plugins/jetpack/modules/widgets/gravatar-profile.css
+++ b/plugins/jetpack/modules/widgets/gravatar-profile.css
@@ -31,7 +31,8 @@
}
.grofile-thumbnail {
- width: 100%;
+ width: 500px;
+ max-width: 100%;
}
@media
only screen and (-webkit-min-device-pixel-ratio: 1.5),
@@ -42,4 +43,4 @@ only screen and (min-device-pixel-ratio: 1.5) {
background-image: url('//0.gravatar.com/images/grav-share-sprite-2x.png');
background-size: 16px 784px;
}
-} \ No newline at end of file
+}
diff --git a/plugins/jetpack/modules/widgets/gravatar-profile.php b/plugins/jetpack/modules/widgets/gravatar-profile.php
index 190427fe..efaf85aa 100644
--- a/plugins/jetpack/modules/widgets/gravatar-profile.php
+++ b/plugins/jetpack/modules/widgets/gravatar-profile.php
@@ -31,6 +31,12 @@ class Jetpack_Gravatar_Profile_Widget extends WP_Widget {
}
function widget( $args, $instance ) {
+
+ $instance = wp_parse_args( $instance, array(
+ 'title' => '',
+ 'email' => ''
+ ) );
+
$title = apply_filters( 'widget_title', $instance['title'] );
if ( !$instance['email'] ) {
@@ -59,7 +65,7 @@ class Jetpack_Gravatar_Profile_Widget extends WP_Widget {
'urls' => array(),
'accounts' => array(),
) );
- $gravatar_url = add_query_arg( 's', 200, $profile['thumbnailUrl'] ); // the default grav returned by grofiles is super small
+ $gravatar_url = add_query_arg( 's', 320, $profile['thumbnailUrl'] ); // the default grav returned by grofiles is super small
wp_enqueue_style(
'gravatar-profile-widget',
@@ -76,10 +82,10 @@ class Jetpack_Gravatar_Profile_Widget extends WP_Widget {
);
?>
- <img src="<?php echo esc_url( $gravatar_url ); ?>" class="grofile-thumbnail no-grav" style="width: auto; max-width: 200px;" />
+ <img src="<?php echo esc_url( $gravatar_url ); ?>" class="grofile-thumbnail no-grav" alt="<?php echo esc_attr( $profile['displayName'] ); ?>" />
<div class="grofile-meta">
<h4><a href="<?php echo esc_url( $profile['profileUrl'] ); ?>"><?php echo esc_html( $profile['displayName'] ); ?></a></h4>
- <p><?php echo wp_kses_data( $profile['aboutMe'] ); ?></p>
+ <p><?php echo wp_kses_post( $profile['aboutMe'] ); ?></p>
</div>
<?php
@@ -92,7 +98,7 @@ class Jetpack_Gravatar_Profile_Widget extends WP_Widget {
?>
- <h4><a href="<?php echo esc_url( $profile['profileUrl'] ); ?>" class="grofile-full-link"><?php esc_html_e( 'View Full Profile &rarr;', 'jetpack' ); ?></a></h4>
+ <p><a href="<?php echo esc_url( $profile['profileUrl'] ); ?>" class="grofile-full-link"><?php echo esc_html( apply_filters( 'jetpack_gravatar_full_profile_title', __( 'View Full Profile &rarr;', 'jetpack' ) ) ); ?></a></p>
<?php
@@ -112,13 +118,16 @@ class Jetpack_Gravatar_Profile_Widget extends WP_Widget {
return;
?>
- <h4><?php esc_html_e( 'Personal Links', 'jetpack' ); ?></h4>
+ <h4><?php echo esc_html( apply_filters( 'jetpack_gravatar_personal_links_title', __( 'Personal Links', 'jetpack' ) ) ); ?></h4>
<ul class="grofile-urls grofile-links">
<?php foreach( $personal_links as $personal_link ) : ?>
<li>
<a href="<?php echo esc_url( $personal_link['value'] ); ?>">
- <?php echo esc_html( $personal_link['title'] ); ?>
+ <?php
+ $link_title = ( ! empty( $personal_link['title'] ) ) ? $personal_link['title'] : $personal_link['value'];
+ echo esc_html( $link_title );
+ ?>
</a>
</li>
<?php endforeach; ?>
@@ -132,7 +141,7 @@ class Jetpack_Gravatar_Profile_Widget extends WP_Widget {
return;
?>
- <h4><?php esc_html_e( 'Verified Services', 'jetpack' ); ?></h4>
+ <h4><?php echo esc_html( apply_filters( 'jetpack_gravatar_verified_services_title', __( 'Verified Services', 'jetpack' ) ) ); ?></h4>
<ul class="grofile-urls grofile-accounts">
<?php foreach( $accounts as $account ) :
@@ -263,20 +272,20 @@ class Jetpack_Gravatar_Profile_Widget extends WP_Widget {
$cache_key = 'grofile-' . $hashed_email;
if( ! $profile = get_transient( $cache_key ) ) {
- $profile_url = esc_url_raw( sprintf( '%s.gravatar.com/%s.php', ( is_ssl() ? 'https://secure' : 'http://www' ), $hashed_email ), array( 'http', 'https' ) );
+ $profile_url = esc_url_raw( sprintf( '%s.gravatar.com/%s.json', ( is_ssl() ? 'https://secure' : 'http://www' ), $hashed_email ), array( 'http', 'https' ) );
$expire = 300;
$response = wp_remote_get( $profile_url, array( 'User-Agent' => 'WordPress.com Gravatar Profile Widget' ) );
$response_code = wp_remote_retrieve_response_code( $response );
if ( 200 == $response_code ) {
$profile = wp_remote_retrieve_body( $response );
- $profile = unserialize( $profile );
+ $profile = json_decode( $profile, true );
if ( is_array( $profile ) && ! empty( $profile['entry'] ) && is_array( $profile['entry'] ) ) {
$expire = 900; // cache for 15 minutes
$profile = $profile['entry'][0];
} else {
- // Something strange happend. Cache for 5 minutes.
+ // Something strange happened. Cache for 5 minutes.
$profile = array();
}
diff --git a/plugins/jetpack/modules/widgets/image-widget.php b/plugins/jetpack/modules/widgets/image-widget.php
index 03d4d5c7..11a86729 100644
--- a/plugins/jetpack/modules/widgets/image-widget.php
+++ b/plugins/jetpack/modules/widgets/image-widget.php
@@ -6,19 +6,60 @@
* First Introduced: 1.2
*/
+/**
+* Register the widget for use in Appearance -> Widgets
+*/
+add_action( 'widgets_init', 'jetpack_image_widget_init' );
+function jetpack_image_widget_init() {
+ register_widget( 'Jetpack_Image_Widget' );
+}
+
class Jetpack_Image_Widget extends WP_Widget {
+ /**
+ * Register widget with WordPress.
+ */
+ public function __construct() {
+ parent::__construct(
+ 'image',
+ apply_filters( 'jetpack_widget_name', esc_html__( 'Image', 'jetpack' ) ),
+ array(
+ 'classname' => 'widget_image',
+ 'description' => __( 'Display an image in your sidebar', 'jetpack' )
+ )
+ );
- function Jetpack_Image_Widget() {
- $widget_ops = array( 'classname' => 'widget_image', 'description' => __( "Display an image in your sidebar", 'jetpack' ) );
- $control_ops = array( 'width' => 400 );
- $this->WP_Widget( 'image', __( 'Image (Jetpack)', 'jetpack' ), $widget_ops, $control_ops );
+ if ( is_active_widget( false, false, $this->id_base ) || is_active_widget( false, false, 'monster' ) ) {
+ add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_style' ) );
+ }
}
- function widget( $args, $instance ) {
+ /**
+ * Loads file for front-end widget style.
+ *
+ * @uses wp_enqueue_style(), plugins_url()
+ */
+ public function enqueue_style() {
+ wp_enqueue_style( 'jetpack_image_widget', plugins_url( 'image-widget/style.css', __FILE__ ), array(), '20140808' );
+ }
+
+ /**
+ * Front-end display of widget.
+ *
+ * @see WP_Widget::widget()
+ *
+ * @param array $args Widget arguments.
+ * @param array $instance Saved values from database.
+ */
+ public function widget( $args, $instance ) {
extract( $args );
echo $before_widget;
+ $instance = wp_parse_args( $instance, array(
+ 'title' => '',
+ 'img_url' => ''
+ ) );
+
$title = apply_filters( 'widget_title', $instance['title'] );
if ( $title )
@@ -38,10 +79,14 @@ class Jetpack_Image_Widget extends WP_Widget {
if ( '' != $instance['img_height'] )
$output .= 'height="' . esc_attr( $instance['img_height'] ) .'" ';
$output .= '/>';
- if ( '' != $instance['link'] )
+ if ( '' != $instance['link'] && ! empty( $instance['link_target_blank'] ) )
+ $output = '<a target="_blank" href="' . esc_attr( $instance['link'] ) . '">' . $output . '</a>';
+ if ( '' != $instance['link'] && empty( $instance['link_target_blank'] ) )
$output = '<a href="' . esc_attr( $instance['link'] ) . '">' . $output . '</a>';
- if ( '' != $instance['caption'] )
- $output = '[caption align="align' . esc_attr( $instance['align'] ) . '" width="' . esc_attr( $instance['img_width'] ) .'" caption="' . esc_attr( $instance['caption'] ) . '"]' . $output . '[/caption]';
+ if ( '' != $instance['caption'] ) {
+ $caption = apply_filters( 'widget_text', $instance['caption'] );
+ $output = '[caption align="align' . esc_attr( $instance['align'] ) . '" width="' . esc_attr( $instance['img_width'] ) .'"]' . $output . ' ' . $caption . '[/caption]'; // wp_kses_post caption on update
+ }
echo '<div class="jetpack-image-container">' . do_shortcode( $output ) . '</div>';
}
@@ -49,38 +94,69 @@ class Jetpack_Image_Widget extends WP_Widget {
echo "\n" . $after_widget;
}
- function update( $new_instance, $old_instance ) {
+ /**
+ * Sanitize widget form values as they are saved.
+ *
+ * @see WP_Widget::update()
+ *
+ * @param array $new_instance Values just sent to be saved.
+ * @param array $old_instance Previously saved values from database.
+ *
+ * @return array Updated safe values to be saved.
+ */
+ public function update( $new_instance, $old_instance ) {
+ $allowed_caption_html = array(
+ 'a' => array(
+ 'href' => array(),
+ 'title' => array(),
+ ),
+ 'b' => array(),
+ 'em' => array(),
+ 'i' => array(),
+ 'p' => array(),
+ 'strong' => array()
+ );
+
$instance = $old_instance;
- $instance['title'] = strip_tags( $new_instance['title'] );
- $instance['img_url'] = esc_url( $new_instance['img_url'], null, 'display' );
- $instance['alt_text'] = strip_tags( $new_instance['alt_text'] );
- $instance['img_title'] = strip_tags( $new_instance['img_title'] );
- $instance['caption'] = strip_tags( $new_instance['caption'] );
- $instance['align'] = $new_instance['align'];
- $instance['img_width'] = absint( $new_instance['img_width'] );
- $instance['img_height'] = absint( $new_instance['img_height'] );
- $instance['link'] = esc_url( $new_instance['link'], null, 'display' );
+ $instance['title'] = strip_tags( $new_instance['title'] );
+ $instance['img_url'] = esc_url( $new_instance['img_url'], null, 'display' );
+ $instance['alt_text'] = strip_tags( $new_instance['alt_text'] );
+ $instance['img_title'] = strip_tags( $new_instance['img_title'] );
+ $instance['caption'] = wp_kses( stripslashes($new_instance['caption'] ), $allowed_caption_html );
+ $instance['align'] = $new_instance['align'];
+ $instance['img_width'] = absint( $new_instance['img_width'] );
+ $instance['img_height'] = absint( $new_instance['img_height'] );
+ $instance['link'] = esc_url( $new_instance['link'], null, 'display' );
+ $instance['link_target_blank'] = isset( $new_instance['link_target_blank'] ) ? (bool) $new_instance['link_target_blank'] : false;
return $instance;
}
- function form( $instance ) {
+ /**
+ * Back-end widget form.
+ *
+ * @see WP_Widget::form()
+ *
+ * @param array $instance Previously saved values from database.
+ */
+ public function form( $instance ) {
// Defaults
- $instance = wp_parse_args( (array) $instance, array( 'title' => '', 'img_url' => '', 'alt_text' => '', 'img_title' => '', 'caption' => '', 'align' => 'none', 'img_width' => '', 'img_height' => '', 'link' => '' ) );
-
- $title = esc_attr( $instance['title'] );
- $img_url = esc_url( $instance['img_url'], null, 'display' );
- $alt_text = esc_attr( $instance['alt_text'] );
- $img_title = esc_attr( $instance['img_title'] );
- $caption = esc_attr( $instance['caption'] );
- $align = esc_attr( $instance['align'] );
- $img_width = esc_attr( $instance['img_width'] );
- $img_height = esc_attr( $instance['img_height'] );
+ $instance = wp_parse_args( (array) $instance, array( 'title' => '', 'img_url' => '', 'alt_text' => '', 'img_title' => '', 'caption' => '', 'align' => 'none', 'img_width' => '', 'img_height' => '', 'link' => '', 'link_target_blank' => false ) );
+
+ $title = esc_attr( $instance['title'] );
+ $img_url = esc_url( $instance['img_url'], null, 'display' );
+ $alt_text = esc_attr( $instance['alt_text'] );
+ $img_title = esc_attr( $instance['img_title'] );
+ $caption = esc_textarea( $instance['caption'] );
+ $align = esc_attr( $instance['align'] );
+ $img_width = esc_attr( $instance['img_width'] );
+ $img_height = esc_attr( $instance['img_height'] );
+ $link_target_blank = checked( $instance['link_target_blank'], true, false );
if ( !empty( $instance['img_url'] ) ) {
- // Download the url to a local temp file and then process it with getimagesize so we can filter out domains which are blocking us
- $tmp_file = download_url( $instance['img_url'], 30 );
+ // Download the url to a local temp file and then process it with getimagesize so we can optimize browser layout
+ $tmp_file = download_url( $instance['img_url'], 10 );
if ( ! is_wp_error( $tmp_file ) ) {
$size = getimagesize( $tmp_file );
@@ -117,7 +193,7 @@ class Jetpack_Image_Widget extends WP_Widget {
<input class="widefat" id="' . $this->get_field_id( 'img_title' ) . '" name="' . $this->get_field_name( 'img_title' ) . '" type="text" value="' . $img_title . '" />
</label></p>
<p><label for="' . $this->get_field_id( 'caption' ) . '">' . esc_html__( 'Caption:', 'jetpack' ) . ' <a href="http://support.wordpress.com/widgets/image-widget/#image-widget-caption" target="_blank">( ? )</a>
- <input class="widefat" id="' . $this->get_field_id( 'caption' ) . '" name="' . $this->get_field_name( 'caption' ) . '" type="text" value="' . $caption . '" />
+ <textarea class="widefat" id="' . $this->get_field_id( 'caption' ) . '" name="' . $this->get_field_name( 'caption' ) . '" rows="2" cols="20">' . $caption . '</textarea>
</label></p>';
$alignments = array(
@@ -145,12 +221,10 @@ class Jetpack_Image_Widget extends WP_Widget {
<small>' . esc_html__( "If empty, we will attempt to determine the image size.", 'jetpack' ) . '</small></p>
<p><label for="' . $this->get_field_id( 'link' ) . '">' . esc_html__( 'Link URL (when the image is clicked):', 'jetpack' ) . '
<input class="widefat" id="' . $this->get_field_id( 'link' ) . '" name="' . $this->get_field_name( 'link' ) . '" type="text" value="' . $link . '" />
+ </label>
+ <label for="' . $this->get_field_id( 'link_target_blank' ) . '">
+ <input type="checkbox" name="' . $this->get_field_name( 'link_target_blank' ) . '" id="' . $this->get_field_id( 'link_target_blank' ) . '" value="1"' . $link_target_blank . '/>
+ ' . esc_html__( 'Open link in a new window/tab', 'jetpack' ) . '
</label></p>';
}
-
-} //Class Jetpack_Image_Widget
-
-function jetpack_image_widget_init() {
- register_widget( 'Jetpack_Image_Widget' );
-}
-add_action( 'widgets_init', 'jetpack_image_widget_init' );
+} // Class Jetpack_Image_Widget
diff --git a/plugins/jetpack/modules/widgets/widgets.css b/plugins/jetpack/modules/widgets/image-widget/style.css
index a2d62957..ae650f2a 100644
--- a/plugins/jetpack/modules/widgets/widgets.css
+++ b/plugins/jetpack/modules/widgets/image-widget/style.css
@@ -1,5 +1,5 @@
/*
- * Widget styles for Jetpack
+ * Image Widget styles for Jetpack
*/
/* Clear floats */
diff --git a/plugins/jetpack/modules/widgets/readmill.php b/plugins/jetpack/modules/widgets/readmill.php
deleted file mode 100644
index 2fe189eb..00000000
--- a/plugins/jetpack/modules/widgets/readmill.php
+++ /dev/null
@@ -1,138 +0,0 @@
-<?php
-class Jetpack_Readmill_Widget extends WP_Widget {
- var $default_title, $default_size;
-
- /**
- * Registers the widget with WordPress.
- */
- function __construct() {
- parent::__construct(
- 'jetpack_readmill_widget', // Base ID
- apply_filters( 'jetpack_widget_name', esc_html__( 'Send To Readmill', 'jetpack' ) ),
- array(
- 'description' => esc_html__( 'Readmill is the best book reader for phones and tablets. With this widget you can enable users to send a book to their device with one click.', 'jetpack' ),
- )
- );
-
- if ( is_active_widget( false, false, $this->id_base ) || is_active_widget( false, false, 'monster' ) ) {
- add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_script' ) );
- }
-
- $this->default_title = __( 'Send To Readmill', 'jetpack' );
- $this->default_size = 'large';
- }
-
- function enqueue_script() {
- wp_enqueue_script( 'readmill', 'https://platform.readmill.com/send.js', array(), '20130220', false );
- }
-
- /**
- * Back-end widget form.
- *
- * @see WP_Widget::form()
- *
- * @param array $instance Previously saved values from database.
- */
- function form( $instance ) {
- $title = isset( $instance['title' ] ) ? $instance['title'] : false;
- if ( false === $title ) {
- $title = $this->default_title;
- }
-
- $epub_link = isset( $instance['epub_link'] ) ? $instance['epub_link'] : '';
- $buy_link = isset( $instance['buy_link'] ) ? $instance['buy_link'] : '';
- $size = isset( $instance['size'] ) ? $instance['size'] : $this->default_size;
- ?>
-
- <p><?php printf( __( "Just enter the URL to your book, make sure it's a PDF or EPUB file, and you are ready to go. For more help, head to <a href='%s'>the Readmill WordPress Widget support page</a>.", 'jetpack' ), 'http://en.support.wordpress.com/widgets/readmill/' ); ?></p>
-
- <p>
- <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php esc_html_e( 'Title:', 'jetpack' ); ?></label>
- <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" />
- </p>
-
- <p>
- <label for="<?php echo $this->get_field_id( 'epub_link' ); ?>"><?php esc_html_e( 'Download URL:', 'jetpack' ); ?></label>
- <input class="widefat" id="<?php echo $this->get_field_id( 'epub_link' ); ?>" name="<?php echo $this->get_field_name( 'epub_link' ); ?>" type="text" value="<?php echo esc_attr( $epub_link ); ?>" />
- </p>
-
- <p>
- <label for="<?php echo $this->get_field_id( 'buy_link' ); ?>"><?php esc_html_e( 'Item URL:', 'jetpack' ); ?></label>
- <input class="widefat" id="<?php echo $this->get_field_id( 'buy_link' ); ?>" name="<?php echo $this->get_field_name( 'buy_link' ); ?>" type="text" value="<?php echo esc_attr( $buy_link ); ?>" />
- </p>
-
- <p>
- <label><?php esc_html_e( 'What size icon?', 'jetpack' ); ?></label>
- <ul>
- <li><label><input id="<?php echo $this->get_field_id( 'size' ); ?>-few" name="<?php echo $this->get_field_name( 'size' ); ?>" type="radio" value="large" <?php checked( 'large', $size ); ?> /> <?php esc_html_e( 'Large', 'jetpack' ); ?></label></li>
- <li><label><input id="<?php echo $this->get_field_id( 'size' ); ?>-lots" name="<?php echo $this->get_field_name( 'size' ); ?>" type="radio" value="small" <?php checked( 'small', $size ); ?> /> <?php esc_html_e( 'Small', 'jetpack' ); ?></label></li>
- </ul>
- </p>
-
- <?php
- }
-
- /**
- * Sanitize widget form values as they are saved.
- *
- * @see WP_Widget::update()
- *
- * @param array $new_instance Values just sent to be saved.
- * @param array $old_instance Previously saved values from database.
- *
- * @return array Updated safe values to be saved.
- */
- function update( $new_instance, $old_instance ) {
- $instance = array();
- $instance['title'] = wp_kses( $new_instance['title'], array() );
- $instance['epub_link'] = wp_kses( $new_instance['epub_link'], array() );
- $instance['buy_link'] = wp_kses( $new_instance['buy_link'], array() );
- $instance['size'] = wp_kses( $new_instance['size'], array() );
-
- if ( $this->default_title === $instance['title'] ) {
- $instance['title'] = false; // Store as false in case of language change
- }
-
- return $instance;
- }
-
- /**
- * Front-end display of widget.
- *
- * @see WP_Widget::widget()
- *
- * @param array $args Widget arguments.
- * @param array $instance Saved values from database.
- */
- function widget( $args, $instance ) {
- $title = isset( $instance['title' ] ) ? $instance['title'] : false;
-
- if ( false === $title )
- $title = $this->default_title;
-
- $title = apply_filters( 'widget_title', $title );
-
- echo $args['before_widget'];
-
- if ( ! empty( $title ) )
- echo $args['before_title'] . $title . $args['after_title'];
-
- $epub_link = isset( $instance['epub_link'] ) ? $instance['epub_link'] : '';
- $buy_link = isset( $instance['buy_link'] ) ? $instance['buy_link'] : '';
- $size = isset( $instance['size'] ) ? $instance['size'] : $this->default_size;
-
- if ( empty( $epub_link ) && current_user_can( 'edit_theme_options' ) ) :
- ?><p><?php esc_html_e( 'Your ePub link is empty. Provide an ePub link to display the Send to Readmill widget.', 'jetpack' ); ?></p><?php
- else :
- ?><a class="send-to-readmill" href="https://readmill.com" data-download-url="<?php echo esc_attr( $epub_link ); ?>" data-buy-url="<?php echo esc_attr( $epub_link ); ?>" data-display="<?php echo esc_attr( $size ); ?>">Send to Readmill</a><?php
- endif;
-
- echo $args['after_widget'];
- }
-}
-
-function jetpack_readmill_widget_init() {
- register_widget( 'Jetpack_Readmill_Widget' );
-}
-
-add_action( 'widgets_init', 'jetpack_readmill_widget_init' );
diff --git a/plugins/jetpack/modules/widgets/rsslinks-widget.php b/plugins/jetpack/modules/widgets/rsslinks-widget.php
index cd930ccb..04545bc9 100644
--- a/plugins/jetpack/modules/widgets/rsslinks-widget.php
+++ b/plugins/jetpack/modules/widgets/rsslinks-widget.php
@@ -9,11 +9,13 @@
class Jetpack_RSS_Links_Widget extends WP_Widget {
function Jetpack_RSS_Links_Widget() {
- $widget_ops = array('classname' => 'widget_rss_links', 'description' => __("Links to your blog's RSS feeds", 'jetpack') );
- $this->WP_Widget('rss_links', __('RSS Links (Jetpack)', 'jetpack'), $widget_ops);
+ $widget_ops = array( 'classname' => 'widget_rss_links', 'description' => __( "Links to your blog's RSS feeds", 'jetpack' ) );
+ $this->WP_Widget( 'rss_links', __( 'RSS Links (Jetpack)', 'jetpack' ), $widget_ops );
}
- function widget($args, $instance) {
+ function widget( $args, $instance ) {
+ $instance = wp_parse_args( (array) $instance, $this->defaults() );
+
extract( $args );
$title = apply_filters( 'widget_title', $instance['title'] );
@@ -25,12 +27,12 @@ class Jetpack_RSS_Links_Widget extends WP_Widget {
if ( 'text' == $instance['format'] ) echo '<ul>';
if ( 'posts' == $instance['display'] ) {
- $this->_rss_link('posts', $instance);
+ $this->_rss_link( 'posts', $instance);
} elseif ( 'comments' == $instance['display'] ) {
- $this->_rss_link('comments', $instance);
+ $this->_rss_link( 'comments', $instance);
} elseif ( 'posts-comments' == $instance['display'] ) {
- $this->_rss_link('posts', $instance);
- $this->_rss_link('comments', $instance);
+ $this->_rss_link( 'posts', $instance );
+ $this->_rss_link( 'comments', $instance );
}
if ( 'text' == $instance['format'] ) echo '</ul>';
@@ -38,7 +40,21 @@ class Jetpack_RSS_Links_Widget extends WP_Widget {
echo "\n" . $after_widget;
}
- function update($new_instance, $old_instance) {
+ /**
+ * Return an associative array of default values
+ * These values are used in new widgets as well as when sanitizing input.
+ *
+ * @return array Array of default values for the Widget's options
+ */
+ function defaults() {
+ return array(
+ 'title' => '',
+ 'display' => 'posts-comments',
+ 'format' => 'text'
+ );
+ }
+
+ function update( $new_instance, $old_instance ) {
$instance = $old_instance;
$instance['title'] = wp_filter_nohtml_kses( $new_instance['title'] );
@@ -50,8 +66,8 @@ class Jetpack_RSS_Links_Widget extends WP_Widget {
return $instance;
}
- function form($instance) {
- $instance = wp_parse_args( (array) $instance, array('title' => '', 'display' => 'posts-comments', 'format' => 'text') );
+ function form( $instance ) {
+ $instance = wp_parse_args( (array) $instance, $this->defaults() );
$title = stripslashes( $instance['title'] );
$display = $instance['display'];
@@ -59,71 +75,71 @@ class Jetpack_RSS_Links_Widget extends WP_Widget {
$image_size = isset( $instance['imagesize'] ) ? $instance['imagesize'] : 0 ;
$image_color = isset( $instance['imagecolor'] ) ? $instance['imagecolor'] : 'red';
- echo '<p><label for="' . $this->get_field_id('title') . '">' . esc_html__('Title:', 'jetpack') . '
- <input class="widefat" id="' . $this->get_field_id('title') . '" name="' . $this->get_field_name('title') . '" type="text" value="' . esc_attr($title) . '" />
+ echo '<p><label for="' . $this->get_field_id( 'title' ) . '">' . esc_html__( 'Title:', 'jetpack' ) . '
+ <input class="widefat" id="' . $this->get_field_id( 'title' ) . '" name="' . $this->get_field_name( 'title' ) . '" type="text" value="' . esc_attr( $title ) . '" />
</label></p>';
$displays = array(
- 'posts' => __('Posts', 'jetpack'),
- 'comments' => __('Comments', 'jetpack'),
- 'posts-comments' => __('Posts & Comments', 'jetpack')
+ 'posts' => __( 'Posts', 'jetpack' ),
+ 'comments' => __( 'Comments', 'jetpack' ),
+ 'posts-comments' => __( 'Posts & Comments', 'jetpack' )
);
- echo '<p><label for="' . $this->get_field_id('display') . '">' . esc_html__('Feed(s) to Display:', 'jetpack') . '
- <select class="widefat" id="' . $this->get_field_id('display') . '" name="' . $this->get_field_name('display') . '">';
+ echo '<p><label for="' . $this->get_field_id( 'display' ) . '">' . esc_html__( 'Feed(s) to Display:', 'jetpack' ) . '
+ <select class="widefat" id="' . $this->get_field_id( 'display' ) . '" name="' . $this->get_field_name( 'display' ) . '">';
foreach ( $displays as $display_option => $label ) {
- echo '<option value="' . esc_attr($display_option) . '"';
+ echo '<option value="' . esc_attr( $display_option ) . '"';
if ( $display_option == $display ) echo ' selected="selected"';
- echo '>' . esc_html($label) . '</option>' . "\n";
+ echo '>' . esc_html( $label ) . '</option>' . "\n";
}
echo '</select></label></p>';
$formats = array(
- 'text' => __('Text Link', 'jetpack'),
- 'image' => __('Image Link', 'jetpack'),
- 'text-image' => __('Text & Image Links', 'jetpack')
+ 'text' => __( 'Text Link', 'jetpack' ),
+ 'image' => __( 'Image Link', 'jetpack' ),
+ 'text-image' => __( 'Text & Image Links', 'jetpack' )
);
- echo '<p><label for="' . $this->get_field_id('format') . '">' . __('Format:', 'jetpack') . '
- <select class="widefat" id="' . $this->get_field_id('format') . '" name="' . $this->get_field_name('format') . '" onchange="if ( this.value == \'text\' ) jQuery( \'#' . $this->get_field_id('image-settings') . '\' ).fadeOut(); else jQuery( \'#' . $this->get_field_id('image-settings') . '\' ).fadeIn();">';
+ echo '<p><label for="' . $this->get_field_id( 'format' ) . '">' . __( 'Format:', 'jetpack' ) . '
+ <select class="widefat" id="' . $this->get_field_id( 'format' ) . '" name="' . $this->get_field_name( 'format' ) . '" onchange="if ( this.value == \'text\' ) jQuery( \'#' . $this->get_field_id( 'image-settings' ) . '\' ).fadeOut(); else jQuery( \'#' . $this->get_field_id( 'image-settings' ) . '\' ).fadeIn();">';
foreach ( $formats as $format_option => $label ) {
- echo '<option value="' . esc_attr($format_option) . '"';
+ echo '<option value="' . esc_attr( $format_option ) . '"';
if ( $format_option == $format ) echo ' selected="selected"';
- echo '>' . esc_html($label) . '</option>' . "\n";
+ echo '>' . esc_html( $label ) . '</option>' . "\n";
}
echo '</select></label></p>';
- echo '<div id="' . $this->get_field_id('image-settings') . '"';
+ echo '<div id="' . $this->get_field_id( 'image-settings' ) . '"';
if ( 'text' == $format ) echo ' style="display: none;"';
- echo '><h3>' . esc_html__('Image Settings:', 'jetpack') . '</h3>';
+ echo '><h3>' . esc_html__( 'Image Settings:', 'jetpack' ) . '</h3>';
$sizes = array(
- 'small' => __('Small', 'jetpack'),
- 'medium' => __('Medium', 'jetpack'),
- 'large' => __('Large', 'jetpack')
+ 'small' => __( 'Small', 'jetpack' ),
+ 'medium' => __( 'Medium', 'jetpack' ),
+ 'large' => __( 'Large', 'jetpack' )
);
- echo '<p><label for="' . $this->get_field_id('imagesize') . '">' . esc_html__('Image Size:', 'jetpack') . '
- <select class="widefat" id="' . $this->get_field_id('imagesize') . '" name="' . $this->get_field_name('imagesize') . '">';
+ echo '<p><label for="' . $this->get_field_id( 'imagesize' ) . '">' . esc_html__( 'Image Size:', 'jetpack' ) . '
+ <select class="widefat" id="' . $this->get_field_id( 'imagesize' ) . '" name="' . $this->get_field_name( 'imagesize' ) . '">';
foreach ( $sizes as $size => $label ) {
- echo '<option value="' . esc_attr($size) . '"';
+ echo '<option value="' . esc_attr( $size) . '"';
if ( $size == $image_size ) echo ' selected="selected"';
- echo '>' . esc_html($label) . '</option>' . "\n";
+ echo '>' . esc_html( $label ) . '</option>' . "\n";
}
echo '</select></label></p>';
$colors = array(
- 'red' => __('Red', 'jetpack'),
- 'orange' => __('Orange', 'jetpack'),
- 'green' => __('Green', 'jetpack'),
- 'blue' => __('Blue', 'jetpack'),
- 'purple' => __('Purple', 'jetpack'),
- 'pink' => __('Pink', 'jetpack'),
- 'silver' => __('Silver', 'jetpack'),
+ 'red' => __( 'Red', 'jetpack' ),
+ 'orange' => __( 'Orange', 'jetpack' ),
+ 'green' => __( 'Green', 'jetpack' ),
+ 'blue' => __( 'Blue', 'jetpack' ),
+ 'purple' => __( 'Purple', 'jetpack' ),
+ 'pink' => __( 'Pink', 'jetpack' ),
+ 'silver' => __( 'Silver', 'jetpack' ),
);
- echo '<p><label for="' . $this->get_field_id('imagecolor') . '">' . esc_html__('Image Color:', 'jetpack') . '
- <select class="widefat" id="' . $this->get_field_id('imagecolor') . '" name="' . $this->get_field_name('imagecolor') . '">';
+ echo '<p><label for="' . $this->get_field_id( 'imagecolor' ) . '">' . esc_html__( 'Image Color:', 'jetpack' ) . '
+ <select class="widefat" id="' . $this->get_field_id( 'imagecolor' ) . '" name="' . $this->get_field_name( 'imagecolor' ) . '">';
foreach ( $colors as $color => $label ) {
- echo '<option value="' . esc_attr($color) . '"';
+ echo '<option value="' . esc_attr( $color) . '"';
if ( $color == $image_color ) echo ' selected="selected"';
- echo '>' . esc_html($label) . '</option>' . "\n";
+ echo '>' . esc_html( $label ) . '</option>' . "\n";
}
echo '</select></label></p></div>';
}
@@ -137,16 +153,23 @@ class Jetpack_RSS_Links_Widget extends WP_Widget {
$rss_type = 'comments_rss2_url';
}
- $subscribe_to = sprintf( __( 'Subscribe to %s', 'jetpack'), $type_text );
+ $subscribe_to = sprintf( __( 'Subscribe to %s', 'jetpack' ), $type_text );
$link_item = '';
$format = $args['format'];
+
+ if ( apply_filters( 'jetpack_rsslinks_widget_target_blank', false ) ) {
+ $link_target = '_blank';
+ } else {
+ $link_target = '_self';
+ }
+
if ( 'image' == $format || 'text-image' == $format )
- $link_item = '<a href="' . get_bloginfo($rss_type) . '" title="' . esc_attr( $subscribe_to ) . '"><img src="' . esc_url( plugins_url( '_inc/images/rss/' . $args['imagecolor'] . '-' . $args['imagesize'] . '.png', dirname( dirname( __FILE__ ) ) ) ) . '" alt="RSS Feed" /></a>';
+ $link_item = '<a target="' . $link_target . '" href="' . get_bloginfo( $rss_type ) . '" title="' . esc_attr( $subscribe_to ) . '"><img src="' . esc_url( plugins_url( 'images/rss/' . $args['imagecolor'] . '-' . $args['imagesize'] . '.png', dirname( dirname( __FILE__ ) ) ) ) . '" alt="RSS Feed" /></a>';
if ( 'text-image' == $format )
- $link_item .= '&nbsp;<a href="' . get_bloginfo($rss_type) . '" title="' . esc_attr( $subscribe_to ) . '">' . esc_html__('RSS - ' . $type_text, 'jetpack'). '</a>';
+ $link_item .= '&nbsp;<a target="' . $link_target . '" href="' . get_bloginfo( $rss_type ) . '" title="' . esc_attr( $subscribe_to ) . '">' . esc_html__( 'RSS - ' . $type_text, 'jetpack' ). '</a>';
if ( 'text' == $format )
- $link_item = '<a href="' . get_bloginfo($rss_type) . '" title="' . esc_attr( $subscribe_to ) . '">' . esc_html__('RSS - ' . $type_text, 'jetpack'). '</a>';
+ $link_item = '<a target="' . $link_target . '" href="' . get_bloginfo( $rss_type ) . '" title="' . esc_attr( $subscribe_to ) . '">' . esc_html__( 'RSS - ' . $type_text, 'jetpack' ). '</a>';
if ( 'text' == $format )
echo '<li>';
@@ -162,7 +185,7 @@ class Jetpack_RSS_Links_Widget extends WP_Widget {
} //Class Jetpack_RSS_Links_Widget
function jetpack_rss_links_widget_init() {
- register_widget('Jetpack_RSS_Links_Widget');
+ register_widget( 'Jetpack_RSS_Links_Widget' );
}
add_action( 'widgets_init', 'jetpack_rss_links_widget_init' );
?>
diff --git a/plugins/jetpack/modules/widgets/top-posts.php b/plugins/jetpack/modules/widgets/top-posts.php
index 252903aa..31d1d3d2 100644
--- a/plugins/jetpack/modules/widgets/top-posts.php
+++ b/plugins/jetpack/modules/widgets/top-posts.php
@@ -41,13 +41,13 @@ class Jetpack_Top_Posts_Widget extends WP_Widget {
$this->default_title = __( 'Top Posts &amp; Pages', 'jetpack' );
if ( is_active_widget( false, false, $this->id_base ) ) {
- add_action( 'wp_print_styles', array( $this, 'enqueue_style' ) );
+ add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_style' ) );
}
}
function enqueue_style() {
- wp_register_style( 'widget-grid-and-list', plugins_url( 'widget-grid-and-list.css', __FILE__ ) );
- wp_enqueue_style( 'widget-grid-and-list' );
+ wp_register_style( 'jetpack-top-posts-widget', plugins_url( 'top-posts/style.css', __FILE__ ), array(), '20141013' );
+ wp_enqueue_style( 'jetpack-top-posts-widget' );
}
function form( $instance ) {
@@ -124,6 +124,7 @@ class Jetpack_Top_Posts_Widget extends WP_Widget {
if ( $count < 1 || 10 < $count ) {
$count = 10;
}
+ $count = apply_filters( 'jetpack_top_posts_widget_count', $count );
if ( isset( $instance['display'] ) && in_array( $instance['display'], array( 'grid', 'list', 'text' ) ) ) {
$display = $instance['display'];
@@ -134,13 +135,10 @@ class Jetpack_Top_Posts_Widget extends WP_Widget {
if ( 'text' != $display ) {
$get_image_options = array(
'fallback_to_avatars' => true,
- 'gravatar_default' => apply_filters( 'jetpack_static_url', is_ssl() ? 'https' : 'http' . '://en.wordpress.com/i/logo/white-gray-80.png' ),
+ /** This filter is documented in modules/shortcodes/audio.php */
+ 'gravatar_default' => apply_filters( 'jetpack_static_url', set_url_scheme( 'http://en.wordpress.com/i/logo/white-gray-80.png' ) ),
);
if ( 'grid' == $display ) {
- if ( $count %2 != 0 ) {
- $count++;
- }
-
$get_image_options['avatar_size'] = 200;
} else {
$get_image_options['avatar_size'] = 40;
@@ -190,9 +188,12 @@ class Jetpack_Top_Posts_Widget extends WP_Widget {
foreach ( $posts as $post ) :
?>
<div class="widget-grid-view-image">
- <a href="<?php echo esc_url( $post['permalink'] ); ?>" title="<?php echo esc_attr( wp_kses( $post['title'], array() ) ); ?>" class="bump-view" data-bump-view="tp"><img src="<?php echo esc_url( $post['image'] ); ?>" /></a>
+ <?php do_action( 'jetpack_widget_top_posts_before_post', $post['post_id'] ); ?>
+ <a href="<?php echo esc_url( $post['permalink'] ); ?>" title="<?php echo esc_attr( wp_kses( $post['title'], array() ) ); ?>" class="bump-view" data-bump-view="tp">
+ <img src="<?php echo esc_url( $post['image'] ); ?>" alt="<?php echo esc_attr( wp_kses( $post['title'], array() ) ); ?>" />
+ </a>
+ <?php do_action( 'jetpack_widget_top_posts_after_post', $post['post_id'] ); ?>
</div>
-
<?php
endforeach;
echo "</div>\n";
@@ -201,8 +202,16 @@ class Jetpack_Top_Posts_Widget extends WP_Widget {
foreach ( $posts as $post ) :
?>
<li>
- <img src="<?php echo esc_url( $post['image'] ); ?>" class='widgets-list-layout-blavatar' />
- <div class="widgets-list-layout-links"><a href="<?php echo esc_url( $post['permalink'] ); ?>" class="bump-view" data-bump-view="tp"><?php echo esc_html( wp_kses( $post['title'], array() ) ); ?></a></div>
+ <?php do_action( 'jetpack_widget_top_posts_before_post', $post['post_id'] ); ?>
+ <a href="<?php echo esc_url( $post['permalink'] ); ?>" title="<?php echo esc_attr( wp_kses( $post['title'], array() ) ); ?>" class="bump-view" data-bump-view="tp">
+ <img src="<?php echo esc_url( $post['image'] ); ?>" class='widgets-list-layout-blavatar' alt="<?php echo esc_attr( wp_kses( $post['title'], array() ) ); ?>" />
+ </a>
+ <div class="widgets-list-layout-links">
+ <a href="<?php echo esc_url( $post['permalink'] ); ?>" class="bump-view" data-bump-view="tp">
+ <?php echo esc_html( wp_kses( $post['title'], array() ) ); ?>
+ </a>
+ </div>
+ <?php do_action( 'jetpack_widget_top_posts_after_post', $post['post_id'] ); ?>
</li>
<?php
endforeach;
@@ -211,9 +220,17 @@ class Jetpack_Top_Posts_Widget extends WP_Widget {
break;
default :
echo '<ul>';
- foreach ( $posts as $post ) {
- echo '<li><a href="' . esc_url( $post['permalink'] ) . '" class="bump-view" data-bump-view="tp">' . esc_html( $post['title'] ) . "</a></li>\n";
- }
+ foreach ( $posts as $post ) :
+ ?>
+ <li>
+ <?php do_action( 'jetpack_widget_top_posts_before_post', $post['post_id'] ); ?>
+ <a href="<?php echo esc_url( $post['permalink'] ); ?>" class="bump-view" data-bump-view="tp">
+ <?php echo esc_html( wp_kses( $post['title'], array() ) ); ?>
+ </a>
+ <?php do_action( 'jetpack_widget_top_posts_after_post', $post['post_id'] ); ?>
+ </li>
+ <?php
+ endforeach;
echo '</ul>';
}
@@ -221,8 +238,17 @@ class Jetpack_Top_Posts_Widget extends WP_Widget {
}
function get_by_views( $count ) {
- global $wpdb;
- $post_view_posts = stats_get_csv( 'postviews', array( 'days' => 2, 'limit' => 11 ) );
+ $days = (int) apply_filters( 'jetpack_top_posts_days', 2 );
+
+ if ( $days < 1 ) {
+ $days = 2;
+ }
+
+ if ( $days > 10 ) {
+ $days = 10;
+ }
+
+ $post_view_posts = stats_get_csv( 'postviews', array( 'days' => absint( $days ), 'limit' => 11 ) );
if ( !$post_view_posts ) {
return array();
}
@@ -294,6 +320,6 @@ class Jetpack_Top_Posts_Widget extends WP_Widget {
break; // only need to load and show x number of likes
}
- return $posts;
+ return apply_filters( 'jetpack_widget_get_top_posts', $posts, $post_ids, $count );
}
}
diff --git a/plugins/jetpack/modules/widgets/widget-grid-and-list.css b/plugins/jetpack/modules/widgets/top-posts/style.css
index 984016c9..c301ee16 100644
--- a/plugins/jetpack/modules/widgets/widget-grid-and-list.css
+++ b/plugins/jetpack/modules/widgets/top-posts/style.css
@@ -1,3 +1,7 @@
+/*
+ * Top Posts Widget styles for Jetpack
+ */
+
/* 2-Column Grid Layout */
.widgets-grid-layout {
diff --git a/plugins/jetpack/modules/widgets/twitter-timeline.php b/plugins/jetpack/modules/widgets/twitter-timeline.php
index 75235294..e794b8fa 100644
--- a/plugins/jetpack/modules/widgets/twitter-timeline.php
+++ b/plugins/jetpack/modules/widgets/twitter-timeline.php
@@ -29,11 +29,29 @@ class Jetpack_Twitter_Timeline_Widget extends WP_Widget {
);
if ( is_active_widget( false, false, $this->id_base ) || is_active_widget( false, false, 'monster' ) ) {
- wp_enqueue_script( 'twitter-widgets', '//platform.twitter.com/widgets.js', '', '', true );
+ add_action( 'wp_footer', array( $this, 'library' ) );
}
}
/**
+ * Enqueue Twitter's widget library
+ */
+ public function library() {
+ ?>
+ <script type="text/javascript">
+ !function(d,s,id){
+ var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';
+ if(!d.getElementById(id)){
+ js=d.createElement(s);
+ js.id=id;js.src=p+"://platform.twitter.com/widgets.js";
+ fjs.parentNode.insertBefore(js,fjs);
+ }
+ }(document,"script","twitter-wjs");
+ </script>
+ <?php
+ }
+
+ /**
* Front-end display of widget.
*
* @see WP_Widget::widget()
@@ -72,7 +90,21 @@ class Jetpack_Twitter_Timeline_Widget extends WP_Widget {
echo ' ' . esc_attr( $att ) . '="' . esc_attr( $instance[$att] ) . '"';
}
- echo '>' . esc_html__( 'My Tweets', 'jetpack' ) . '</a>';
+ echo '>';
+
+ $timeline_placeholder = __( 'My Tweets', 'jetpack' );
+
+ /**
+ * Filter the Timeline placeholder text
+ *
+ * @since 3.4
+ *
+ * @param string $timeline_placeholder Timeline placeholder text
+ */
+ $timeline_placeholder = apply_filters( 'jetpack_twitter_timeline_placeholder', $timeline_placeholder );
+
+ echo esc_html( $timeline_placeholder ) . '</a>';
+
// End tag output
echo $args['after_widget'];
@@ -92,14 +124,14 @@ class Jetpack_Twitter_Timeline_Widget extends WP_Widget {
* @return array Updated safe values to be saved.
*/
public function update( $new_instance, $old_instance ) {
- $non_hex_regex = '/[^a-f0-9]/';
- $instance = array();
- $instance['title'] = sanitize_text_field( $new_instance['title'] );
- $instance['width'] = (int) $new_instance['width'];
- $instance['height'] = (int) $new_instance['height'];
- $instance['width'] = ( 0 !== (int) $new_instance['width'] ) ? (int) $new_instance['width'] : 225;
- $instance['height'] = ( 0 !== (int) $new_instance['height'] ) ? (int) $new_instance['height'] : 400;
- $instance['tweet-limit'] = (int) $new_instance['tweet-limit'];
+ $hex_regex = '/#([a-f]|[A-F]|[0-9]){3}(([a-f]|[A-F]|[0-9]){3})?\b/';
+ $instance = array();
+ $instance['title'] = sanitize_text_field( $new_instance['title'] );
+ $instance['width'] = (int) $new_instance['width'];
+ $instance['height'] = (int) $new_instance['height'];
+ $instance['width'] = ( 0 !== (int) $new_instance['width'] ) ? (int) $new_instance['width'] : '';
+ $instance['height'] = ( 0 !== (int) $new_instance['height'] ) ? (int) $new_instance['height'] : '';
+ $instance['tweet-limit'] = ( 0 !== (int) $new_instance['tweet-limit'] ) ? (int) $new_instance['tweet-limit'] : null;
// If they entered something that might be a full URL, try to parse it out
if ( is_string( $new_instance['widget-id'] ) ) {
@@ -112,9 +144,11 @@ class Jetpack_Twitter_Timeline_Widget extends WP_Widget {
$instance['widget-id'] = is_numeric( $instance['widget-id'] ) ? $instance['widget-id'] : '';
foreach ( array( 'link-color', 'border-color' ) as $color ) {
- $clean = preg_replace( $non_hex_regex, '', sanitize_text_field( $new_instance[$color] ) );
- if ( $clean )
- $instance[$color] = '#' . $clean;
+ $new_color = sanitize_text_field( $new_instance[$color] );
+ if ( preg_match( $hex_regex, $new_color ) ) {
+ $instance[$color] = $new_color;
+ }
+
}
$instance['theme'] = 'light';
@@ -151,6 +185,7 @@ class Jetpack_Twitter_Timeline_Widget extends WP_Widget {
'border-color' => '#e8e8e8',
'theme' => 'light',
'chrome' => array(),
+ 'tweet-limit' => null,
);
$instance = wp_parse_args( (array) $instance, $defaults );
@@ -171,10 +206,10 @@ class Jetpack_Twitter_Timeline_Widget extends WP_Widget {
<input class="widefat" id="<?php echo $this->get_field_id( 'height' ); ?>" name="<?php echo $this->get_field_name( 'height' ); ?>" type="text" value="<?php echo esc_attr( $instance['height'] ); ?>" />
</p>
- <p>
- <label for="<?php echo $this->get_field_id( 'tweet-limit' ); ?>"><?php esc_html_e( '# of Tweets Shown:', 'jetpack' ); ?></label>
- <input class="widefat" id="<?php echo $this->get_field_id( 'tweet-limit' ); ?>" name="<?php echo $this->get_field_name( 'tweet-limit' ); ?>" type="text" value="<?php echo esc_attr( $instance['tweet-limit'] ); ?>" />
- </p>
+ <p>
+ <label for="<?php echo $this->get_field_id( 'tweet-limit' ); ?>"><?php esc_html_e( '# of Tweets Shown:', 'jetpack' ); ?></label>
+ <input class="widefat" id="<?php echo $this->get_field_id( 'tweet-limit' ); ?>" name="<?php echo $this->get_field_name( 'tweet-limit' ); ?>" type="number" min="1" max="20" value="<?php echo esc_attr( $instance['tweet-limit'] ); ?>" />
+ </p>
<p><small>
<?php
@@ -197,7 +232,7 @@ class Jetpack_Twitter_Timeline_Widget extends WP_Widget {
<input type="checkbox"<?php checked( in_array( 'noheader', $instance['chrome'] ) ); ?> id="<?php echo $this->get_field_id( 'chrome-noheader' ); ?>" name="<?php echo $this->get_field_name( 'chrome' ); ?>[]" value="noheader" /> <label for="<?php echo $this->get_field_id( 'chrome-noheader' ); ?>"><?php esc_html_e( 'No Header', 'jetpack' ); ?></label><br />
<input type="checkbox"<?php checked( in_array( 'nofooter', $instance['chrome'] ) ); ?> id="<?php echo $this->get_field_id( 'chrome-nofooter' ); ?>" name="<?php echo $this->get_field_name( 'chrome' ); ?>[]" value="nofooter" /> <label for="<?php echo $this->get_field_id( 'chrome-nofooter' ); ?>"><?php esc_html_e( 'No Footer', 'jetpack' ); ?></label><br />
<input type="checkbox"<?php checked( in_array( 'noborders', $instance['chrome'] ) ); ?> id="<?php echo $this->get_field_id( 'chrome-noborders' ); ?>" name="<?php echo $this->get_field_name( 'chrome' ); ?>[]" value="noborders" /> <label for="<?php echo $this->get_field_id( 'chrome-noborders' ); ?>"><?php esc_html_e( 'No Borders', 'jetpack' ); ?></label><br />
- <input type="checkbox"<?php checked( in_array( 'noscrollbar', $instance['chrome'] ) ); ?> id="<?php echo $this->get_field_id( 'chrome-noscrollbar' ); ?>" name="<?php echo $this->get_field_name( 'chrome' ); ?>[]" value="noscrollbar" /> <label for="<?php echo $this->get_field_id( 'chrome-noscrollbar' ); ?>"><?php esc_html_e( 'No Scrollbar', 'jetpack' ); ?></label><br />
+ <input type="checkbox"<?php checked( in_array( 'noscrollbar', $instance['chrome'] ) ); ?> id="<?php echo $this->get_field_id( 'chrome-noscrollbar' ); ?>" name="<?php echo $this->get_field_name( 'chrome' ); ?>[]" value="noscrollbar" /> <label for="<?php echo $this->get_field_id( 'chrome-noscrollbar' ); ?>"><?php esc_html_e( 'No Scrollbar', 'jetpack' ); ?></label><br />
<input type="checkbox"<?php checked( in_array( 'transparent', $instance['chrome'] ) ); ?> id="<?php echo $this->get_field_id( 'chrome-transparent' ); ?>" name="<?php echo $this->get_field_name( 'chrome' ); ?>[]" value="transparent" /> <label for="<?php echo $this->get_field_id( 'chrome-transparent' ); ?>"><?php esc_html_e( 'Transparent Background', 'jetpack' ); ?></label>
</p>
diff --git a/plugins/jetpack/modules/widgets/wordpress-post-widget.php b/plugins/jetpack/modules/widgets/wordpress-post-widget.php
new file mode 100644
index 00000000..a3c724e1
--- /dev/null
+++ b/plugins/jetpack/modules/widgets/wordpress-post-widget.php
@@ -0,0 +1,222 @@
+<?php
+/**
+ * Plugin Name: Display Recent WordPress Posts Widget
+ * Description: Displays recent posts from a WordPress.com or Jetpack-enabled self-hosted WordPress site.
+ * Version: 1.0
+ * Author: Brad Angelcyk, Kathryn Presner, Justin Shreve, Carolyn Sonnek
+ * Author URI: http://automattic.com
+ * License: GPL2
+ */
+add_action( 'widgets_init', 'jetpack_display_posts_widget' );
+function jetpack_display_posts_widget() {
+ register_widget( 'Jetpack_Display_Posts_Widget' );
+}
+
+/*
+ * Display a list of recent posts from a WordPress.com or Jetpack-enabled blog.
+ */
+class Jetpack_Display_Posts_Widget extends WP_Widget {
+
+ public function __construct() {
+ parent::__construct(
+ // internal id
+ 'jetpack_display_posts_widget',
+ // wp-admin title
+ apply_filters( 'jetpack_widget_name', __( 'Display WordPress Posts', 'jetpack' ) ),
+ array(
+ 'description' => __( 'Displays a list of recent posts from another WordPress.com or Jetpack-enabled blog.', 'jetpack' ),
+ )
+ );
+ }
+
+ /**
+ * Expiring transients have a name length maximum of 45 characters,
+ * so this function returns an abbreviated MD5 hash to use instead of
+ * the full URI.
+ */
+ public function get_site_hash( $site ) {
+ return substr( md5( $site ), 0, 21 );
+ }
+
+ public function get_site_info( $site ) {
+ $site_hash = $this->get_site_hash( $site );
+ $data_from_cache = get_transient( 'display_posts_site_info_' . $site_hash );
+ if ( false === $data_from_cache ) {
+ $response = wp_remote_get( sprintf( 'https://public-api.wordpress.com/rest/v1/sites/%s', urlencode( $site ) ) );
+ set_transient( 'display_posts_site_info_' . $site_hash, $response, 10 * MINUTE_IN_SECONDS );
+ } else {
+ $response = $data_from_cache;
+ }
+
+ if ( is_wp_error( $response ) ) {
+ return false;
+ }
+
+ $site_info = json_decode( $response ['body'] );
+ if ( ! isset( $site_info->ID ) ) {
+ return false;
+ }
+
+ return $site_info;
+ }
+
+ /*
+ * Set up the widget display on the front end
+ */
+ public function widget( $args, $instance ) {
+ $title = apply_filters( 'widget_title', $instance['title'] );
+
+ wp_enqueue_style( 'jetpack_display_posts_widget', plugins_url( 'wordpress-post-widget/style.css', __FILE__ ) );
+
+ $site_info = $this->get_site_info( $instance['url'] );
+
+ echo $args['before_widget'];
+
+ if ( false === $site_info ) {
+ echo '<p>' . __( 'We cannot load blog data at this time.', 'jetpack' ) . '</p>';
+ echo $args['after_widget'];
+ return;
+ }
+
+ if ( ! empty( $title ) ) {
+ echo $args['before_title'] . esc_html( $title . ': ' . $site_info->name ) . $args['after_title'];
+ } else {
+ echo $args['before_title'] . esc_html( $site_info->name ) . $args['after_title'];
+ }
+
+ $site_hash = $this->get_site_hash( $instance['url'] );
+ $data_from_cache = get_transient( 'display_posts_post_info_' . $site_hash );
+ if ( false === $data_from_cache ) {
+ $response = wp_remote_get( sprintf( 'https://public-api.wordpress.com/rest/v1/sites/%d/posts/', $site_info->ID ) );
+ set_transient( 'display_posts_post_info_' . $site_hash, $response, 10 * MINUTE_IN_SECONDS );
+ } else {
+ $response = $data_from_cache;
+ }
+
+ if ( is_wp_error( $response ) ) {
+ echo '<p>' . __( 'We cannot load blog data at this time.', 'jetpack' ) . '</p>';
+ echo $args['after_widget'];
+ return;
+ }
+
+ $posts_info = json_decode( $response['body'] );
+
+ echo '<div class="jetpack-display-remote-posts">';
+
+ if ( isset( $posts_info->error ) && 'jetpack_error' == $posts_info->error ) {
+ echo '<p>' . __( 'We cannot display posts for this blog.', 'jetpack' ) . '</p>';
+ echo '</div><!-- .jetpack-display-remote-posts -->';
+ echo $args['after_widget'];
+ return;
+ }
+
+ $number_of_posts = min( $instance['number_of_posts'], count( $posts_info->posts ) );
+
+ for ( $i = 0; $i < $number_of_posts; $i++ ) {
+ $single_post = $posts_info->posts[$i];
+ $post_title = ( $single_post->title ) ? $single_post->title : '( No Title )';
+
+ echo '<h4><a href="' . esc_url( $single_post->URL ) . '">' . esc_html( $post_title ) . '</a></h4>' . "\n";
+ if ( ( $instance['featured_image'] == true ) && ( ! empty ( $single_post->featured_image) ) ) {
+ $featured_image = ( $single_post->featured_image ) ? $single_post->featured_image : '';
+ echo '<a title="' . esc_attr( $post_title ) . '" href="' . esc_url( $single_post->URL ) . '"><img src="' . $featured_image . '" alt="' . esc_attr( $post_title ) . '"/></a>';
+ }
+
+ if ( $instance['show_excerpts'] == true ) {
+ $post_excerpt = ( $single_post->excerpt ) ? $single_post->excerpt : '';
+ echo $post_excerpt;
+ }
+ }
+
+ echo '</div><!-- .jetpack-display-remote-posts -->';
+ echo $args['after_widget'];
+ }
+
+ public function form( $instance ) {
+ if ( isset( $instance[ 'title' ] ) ) {
+ $title = $instance[ 'title' ];
+ } else {
+ $title = __( 'Recent Posts', 'jetpack' );
+ }
+
+ if ( isset( $instance[ 'url' ] ) ) {
+ $url = $instance[ 'url' ];
+ } else {
+ $url = '';
+ }
+
+ if ( isset( $instance[ 'number_of_posts' ] ) ) {
+ $number_of_posts = $instance[ 'number_of_posts' ];
+ } else {
+ $number_of_posts = 5;
+ }
+
+ if ( isset( $instance[ 'featured_image'] ) ) {
+ $featured_image = $instance[ 'featured_image'];
+ } else {
+ $featured_image = false;
+ }
+
+ if ( isset( $instance[ 'show_excerpts'] ) ) {
+ $show_excerpts = $instance[ 'show_excerpts'];
+ } else {
+ $show_excerpts = false;
+ }
+
+ ?>
+ <p>
+ <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:', 'jetpack' ); ?></label>
+ <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" />
+ </p>
+
+ <p>
+ <label for="<?php echo $this->get_field_id( 'url' ); ?>"><?php _e( 'Blog URL:', 'jetpack' ); ?></label>
+ <input class="widefat" id="<?php echo $this->get_field_id( 'url' ); ?>" name="<?php echo $this->get_field_name( 'url' ); ?>" type="text" value="<?php echo esc_attr( $url ); ?>" />
+ <p>
+ <?php _e( "Enter a WordPress.com or Jetpack WordPress site URL.", 'jetpack' ); ?>
+ </p>
+ </p>
+ <p>
+ <label for="<?php echo $this->get_field_id( 'number_of_posts' ); ?>"><?php _e( 'Number of Posts to Display:', 'jetpack' ); ?></label>
+ <select name="<?php echo $this->get_field_name( 'number_of_posts' ); ?>">
+ <?php
+ for ($i = 1; $i <= 10; $i++) {
+ echo '<option value="' . $i . '" '.selected( $number_of_posts, $i ).'>' . $i . '</option>';
+ }
+ ?>
+ </select>
+ </p>
+ <p>
+ <label for="<?php echo $this->get_field_id( 'featured_image' ); ?>"><?php _e( 'Show Featured Image:', 'jetpack' ); ?></label>
+ <input type="checkbox" name="<?php echo $this->get_field_name( 'featured_image' ); ?>" <?php checked( $featured_image, 1 ); ?> />
+ </p>
+ <p>
+ <label for="<?php echo $this->get_field_id( 'show_excerpts' ); ?>"><?php _e( 'Show Excerpts:', 'jetpack' ); ?></label>
+ <input type="checkbox" name="<?php echo $this->get_field_name( 'show_excerpts' ); ?>" <?php checked( $show_excerpts, 1 ); ?> />
+ </p>
+
+ <?php
+ }
+
+ public function update( $new_instance, $old_instance ) {
+ $instance = array();
+ $instance['title'] = ( ! empty( $new_instance['title'] ) ) ? strip_tags( $new_instance['title'] ) : '';
+ $instance['url'] = ( ! empty( $new_instance['url'] ) ) ? strip_tags( $new_instance['url'] ) : '';
+ $instance['url'] = str_replace( "http://", "", $instance['url'] );
+ $instance['url'] = untrailingslashit( $instance['url'] );
+
+ // Normalize www.
+ $site_info = $this->get_site_info( $instance['url'] );
+ if ( ! $site_info && 'www.' === substr( $instance['url'], 0, 4 ) ) {
+ $site_info = $this->get_site_info( substr( $instance['url'], 4 ) );
+ if ( $site_info ) {
+ $instance['url'] = substr( $instance['url'], 4 );
+ }
+ }
+
+ $instance['number_of_posts'] = ( ! empty( $new_instance['number_of_posts'] ) ) ? intval( $new_instance['number_of_posts'] ) : '';
+ $instance['featured_image'] = ( ! empty( $new_instance['featured_image'] ) ) ? true : '';
+ $instance['show_excerpts'] = ( ! empty( $new_instance['show_excerpts'] ) ) ? true : '';
+ return $instance;
+ }
+}
diff --git a/plugins/jetpack/modules/widgets/wordpress-post-widget/style.css b/plugins/jetpack/modules/widgets/wordpress-post-widget/style.css
new file mode 100644
index 00000000..651ec153
--- /dev/null
+++ b/plugins/jetpack/modules/widgets/wordpress-post-widget/style.css
@@ -0,0 +1,24 @@
+.jetpack-display-remote-posts {
+ margin: 5px 0 20px 0;
+}
+
+.jetpack-display-remote-posts h4 {
+ font-size: 90%;
+ margin: 5px 0;
+ padding: 0;
+}
+
+.jetpack-display-remote-posts h4 a {
+ text-decoration: none;
+}
+
+.jetpack-display-remote-posts p {
+ margin: 0 !important;
+ padding: 0;
+ line-height: 1.4em !important;
+ font-size: 90%;
+}
+
+.jetpack-display-remote-posts img {
+ max-width: 100%;
+}
diff --git a/plugins/jetpack/modules/wpcc.php b/plugins/jetpack/modules/wpcc.php
index df16b530..88c13090 100644
--- a/plugins/jetpack/modules/wpcc.php
+++ b/plugins/jetpack/modules/wpcc.php
@@ -1,24 +1,6 @@
<?php
-
/**
- * Module Name: WordPress.com Connect
- * Module Description: Let users login with their WordPress.com Credentials, through <a href="http://jetpack.me/support/wpcc/">WordPress.com Connect</a>
- * Sort Order: 50
- * First Introduced: 2.4
- * Requires Connection: No
- * Auto Activate: No
+ * Deprecated. No longer needed.
+ *
+ * @package Jetpack
*/
-
-if ( ! class_exists( 'WPCC_Sign_On' ) )
- require_once( dirname( __FILE__ ) . '/wpcc/wpcc-sign-on.php' );
-
-add_action( 'jetpack_modules_loaded', 'jetpack_wpcc_loaded' );
-function jetpack_wpcc_loaded() {
- Jetpack::enable_module_configurable( __FILE__ );
- Jetpack::module_configuration_load( __FILE__, 'jetpack_wpcc_configuration_load' );
-}
-
-function jetpack_wpcc_configuration_load() {
- wp_safe_redirect( admin_url( 'options-general.php#wpcc-sign-on-section' ) );
- exit;
-}
diff --git a/plugins/jetpack/modules/wpcc/wpcc-sign-on.css b/plugins/jetpack/modules/wpcc/wpcc-sign-on.css
deleted file mode 100644
index 478b3b9a..00000000
--- a/plugins/jetpack/modules/wpcc/wpcc-sign-on.css
+++ /dev/null
@@ -1,11 +0,0 @@
-
-#loginform {
- overflow: hidden;
- padding-bottom: 26px;
-}
-
-#wpcc-sign-on {
- display: block;
- float: right;
- margin:1em 0 0;
-}
diff --git a/plugins/jetpack/modules/wpcc/wpcc-sign-on.js b/plugins/jetpack/modules/wpcc/wpcc-sign-on.js
deleted file mode 100644
index 318e6921..00000000
--- a/plugins/jetpack/modules/wpcc/wpcc-sign-on.js
+++ /dev/null
@@ -1,4 +0,0 @@
-
-jQuery(document).ready(function($){
- $( '#loginform' ).append( $( '#wpcc-sign-on' ) );
-});
diff --git a/plugins/jetpack/modules/wpcc/wpcc-sign-on.php b/plugins/jetpack/modules/wpcc/wpcc-sign-on.php
deleted file mode 100644
index 47638b8a..00000000
--- a/plugins/jetpack/modules/wpcc/wpcc-sign-on.php
+++ /dev/null
@@ -1,437 +0,0 @@
-<?php
-/**
- * Plugin Name: WPCC Sign On
- * Plugin URI: https://github.com/Automattic/wpcc-sign-on
- * Description: A single-sign-on via WordPress.com for your WordPress.org site!
- * Author: Automatticians
- * Version: 1.0
- * Author URI: http://automattic.com/
- */
-
-class WPCC_Sign_On {
- static $instance = null;
-
- var $request_token_url, // Fixed URL.
- $authenticate_url, // Fixed URL.
- $user_data_url, // Fixed URL.
- $new_app_url_base, // Fixed URL.
- $options_prefix, // Where the options are in the DB.
- $options, // Options Array.
- $client_id, // Option.
- $client_secret, // Option.
- $new_user_override, // Option.
- $match_by_email, // Option.
- $wpcc_state,
- $secret,
- $user_data;
-
- function __construct() {
- if ( self::$instance ) {
- return self::$instance;
- }
-
- self::$instance = $this;
-
- $this->request_token_url = 'https://public-api.wordpress.com/oauth2/token';
- $this->authenticate_url = 'https://public-api.wordpress.com/oauth2/authenticate';
- $this->user_data_url = 'https://public-api.wordpress.com/rest/v1/me/';
- $this->new_app_url_base = 'https://developer.wordpress.com/apps/new/';
- $this->options_prefix = $this->in_jetpack() ? 'jetpack_' : '';
- $this->options = $this->fetch_options();
- $this->client_id = $this->options['client_id'];
- $this->client_secret = $this->options['client_secret'];
- $this->new_user_override = $this->options['new_user_override'];
- $this->match_by_email = $this->options['match_by_email'];
-
- add_action( 'admin_init', array( $this, 'admin_init' ) );
-
- if ( empty( $this->client_id ) ) {
- return;
- }
-
- add_action( 'login_init', array( $this, 'login_init' ) );
- add_action( 'login_enqueue_scripts', array( $this, 'login_enqueue_scripts' ) );
- add_action( 'login_form', array( $this, 'login_form' ) );
- }
-
- function in_jetpack() {
- return '/modules/wpcc' == substr( dirname( __FILE__ ), ( 0 - strlen( '/modules/wpcc' ) ) );
- }
-
- function fetch_options() {
- $options = $this->in_jetpack() ? Jetpack_Options::get_option( 'wpcc_options' ) : get_option( 'wpcc_options' );
- $args = wp_parse_args( $options, $this->default_options() );
-
- $args['new_user_override'] = defined( 'WPCC_NEW_USER_OVERRIDE' ) ? WPCC_NEW_USER_OVERRIDE : false;
- $args['match_by_email'] = defined( 'WPCC_MATCH_BY_EMAIL' ) ? WPCC_MATCH_BY_EMAIL : true;
-
- return $args;
- }
-
- function default_options() {
- return array(
- 'client_id' => '',
- 'client_secret' => '',
- 'new_user_override' => false,
- 'match_by_email' => true,
- );
- }
-
- function admin_init() {
- // Create the section
- add_settings_section(
- 'wpcc',
- esc_html__( 'WordPress.com Connect', 'jetpack' ),
- array( $this, 'wpcc_settings_section' ),
- 'general'
- );
-
- add_settings_field(
- 'wpcc_sign_on_client_id',
- sprintf( '<label for="wpcc_sign_on_client_id">%1$s</label>', __( 'WPCC Client ID', 'jetpack' ) ),
- array( $this, 'wpcc_sign_on_client_id_cb' ),
- 'general',
- 'wpcc'
- );
- add_settings_field(
- 'wpcc_sign_on_client_secret',
- sprintf( '<label for="wpcc_sign_on_client_secret">%1$s</label>', __( 'WPCC Client Secret', 'jetpack' ) ),
- array( $this, 'wpcc_sign_on_client_secret_cb' ),
- 'general',
- 'wpcc'
- );
-
- register_setting( 'general', "{$this->options_prefix}wpcc_options", array( $this, 'sanitize_options' ) );
-
- if ( ! empty( $this->client_id ) && ! empty( $this->client_secret ) ) {
- add_action( 'show_user_profile', array( $this, 'edit_profile_fields' ) ); // For their own profile
- add_action( 'edit_user_profile', array( $this, 'edit_profile_fields' ) ); // For folks editing others profiles
- } else {
- add_action( 'admin_notices', array( $this, 'no_credentials_admin_notice' ) );
- }
-
- if ( $user_ID = get_current_user_id() ) {
- $this->wpcc_state = "localuser{$user_ID}";
- }
- }
-
- function no_credentials_admin_notice() {
- $disable_url = wp_nonce_url( Jetpack::admin_url( 'action=deactivate&module=wpcc' ), 'jetpack_deactivate-wpcc' );
- ?>
- <div id="wpcc-needs-config" class="updated">
- <p class="alignright"><a href="<?php echo esc_url( $disable_url ); ?>"><?php _e( 'Close', 'jetpack' ); ?></a></p>
- <p><?php printf( __( '<strong>Almost done.</strong> Before WordPress.com Connect can finish activating, you\'ll need to <a href="%s">register your website as an application on WordPress.com</a>', 'jetpack' ), esc_url( admin_url( 'options-general.php#wpcc-sign-on-section' ) ) ); ?></p>
- </div>
- <?php
- }
-
- function sanitize_options( $options ) {
- if ( ! empty( $options['client_id'] ) ) {
- $options['client_id'] = intval( $options['client_id'] );
- }
-
- if ( ! empty( $options['client_secret'] ) ) {
- $options['client_secret'] = sanitize_text_field( $options['client_secret'] );
- }
-
- return $options;
- }
-
- function wpcc_settings_section() {
- ?>
-
- <p id="wpcc-sign-on-section">
- <?php
- if ( empty( $this->client_id ) || empty( $this->client_secret ) ) {
- printf( __( 'Visit WordPress.com to <a href="%s">register a new WPCC client id and secret key</a>.', 'jetpack' ), $this->get_new_app_url() );
- } else {
- printf( __( 'Visit WordPress.com to <a href="%s">manage your WPCC client settings</a>.', 'jetpack' ), $this->get_edit_app_url() );
- }
- ?>
- </p>
- <script>
- jQuery('#wpcc-sign-on-section a').attr( 'target', '_blank' );
- </script>
-
- <?php
- }
-
- function wpcc_sign_on_client_id_cb() {
- echo '<input class="regular-text code" autocomplete="off" type="text" id="wpcc_sign_on_client_id" name="' . $this->options_prefix . 'wpcc_options[client_id]" value="' . esc_attr( $this->client_id ) . '" />';
- }
-
- function wpcc_sign_on_client_secret_cb() {
- echo '<input class="regular-text code" autocomplete="off" type="text" id="wpcc_sign_on_client_secret" name="' . $this->options_prefix . 'wpcc_options[client_secret]" value="' . esc_attr( $this->client_secret ) . '" />';
- }
-
- function edit_profile_fields( $user ) {
- if ( isset( $_GET['wpcc'] ) && 'purge' == $_GET['wpcc'] ) {
- delete_user_meta( $user->ID, 'wpcom_user_id' );
- delete_user_meta( $user->ID, 'wpcom_user_data' );
- }
- ?>
-
- <h3><?php _e( 'WordPress.com Connect', 'jetpack' ); ?></h3>
- <p><?php _e( 'Connecting with WordPress.com Connect enables you to log on via your WordPress.com account.', 'jetpack' ); ?></p>
-
- <?php if ( ( $user_data = get_user_meta( $user->ID, 'wpcom_user_data', true ) ) && ! empty( $user_data->ID ) ) : /* If the user is currently connected... */ ?>
-
- <table class="form-table wpcc-form-table">
- <tbody>
- <tr>
- <td>
- <div class="profile-card">
- <img src="<?php echo esc_url( $user_data->avatar_URL ); ?>" height="48" width="48" />
- <p class="connected"><strong><?php _e( 'Connected', 'jetpack' ); ?></strong></p>
- <p><?php echo esc_html( $user_data->username ); ?></p>
- </div>
- <p><a class="button button-secondary" href="<?php echo esc_url( add_query_arg( 'wpcc', 'purge' ) ); ?>"><?php _e( 'Unlink This Account', 'jetpack' ); ?></a></p>
- </td>
- </tr>
- </tbody>
- </table>
-
- <style>
- .wpcc-form-table td {
- padding-left: 0;
- }
-
- .wpcc-form-table .profile-card {
- padding: 10px;
- background: #fff;
- overflow: hidden;
- max-width: 400px;
- box-shadow: 0 2px 5px rgba( 0, 0, 0, 0.4 );
- margin-bottom: 1em;
- }
-
- .wpcc-form-table .profile-card img {
- float: left;
- margin-right: 1em;
- }
-
- .wpcc-form-table .profile-card .connected {
- float: right;
- margin-right: 0.5em;
- color: #0a0;
- }
-
- .wpcc-form-table .profile-card p {
- margin-top: 0.7em;
- font-size: 1.2em;
- }
- </style>
-
- <?php elseif ( get_current_user_id() == $user->ID ) : ?>
-
- <?php echo $this->button( array( 'redirect_uri' => add_query_arg( 'for', 'profile', wp_login_url() ) ) ); ?>
-
- <?php else : ?>
-
- <p><?php _e( 'This profile is not currently linked to a WordPress.com Profile.', 'jetpack' ); ?></p>
-
- <?php endif;
- }
-
- function verify_connection( $get_args = array() ) {
- if ( empty( $_GET['state'] ) ) {
- wp_die( __( 'Warning! State variable missing after authentication.', 'jetpack' ) );
- }
-
- if ( $_GET['state'] != $this->wpcc_state ) {
- wp_die( __( 'Warning! State mismatch. Authentication attempt may have been compromised.', 'jetpack' ) );
- }
-
- $redirect_uri = wp_login_url();
-
- if ( $get_args ) {
- $redirect_uri = add_query_arg( $get_args, $redirect_uri );
- }
-
- $args = array(
- 'client_id' => $this->client_id,
- 'redirect_uri' => $redirect_uri,
- 'client_secret' => $this->client_secret,
- 'code' => sanitize_text_field( $_GET['code'] ), // The code from the previous request
- 'grant_type' => 'authorization_code',
- );
-
- $response = wp_remote_post( $this->request_token_url, array( 'body' => $args ) );
-
- if ( is_wp_error( $response ) ) {
- wp_die( __( 'Warning! Could not confirm request token url!', 'jetpack' ) );
- }
-
- $this->secret = json_decode( wp_remote_retrieve_body( $response ) );
-
- $args = array(
- 'headers' => array(
- 'Authorization' => sprintf( 'Bearer %s', $this->secret->access_token ),
- ),
- );
-
- $response = wp_remote_get( $this->user_data_url, $args );
-
- if ( is_wp_error( $response ) ) {
- wp_die( __( 'Warning! Could not fetch user data!', 'jetpack' ) );
- }
-
- $this->user_data = json_decode( wp_remote_retrieve_body( $response ) );
-
- return $this->user_data;
- }
-
- function login_init() {
- // Set the wpcc_state
- $this->wpcc_state = md5( mt_rand() );
- if ( isset( $_COOKIE['wpcc_state'] ) ) {
- $this->wpcc_state = $_COOKIE['wpcc_state'];
- } else {
- setcookie( 'wpcc_state', $this->wpcc_state );
- }
-
- if ( isset( $_GET['for'] ) && ( 'profile' == $_GET['for'] ) ) {
- $user_ID = get_current_user_id();
-
- $this->wpcc_state = "localuser{$user_ID}";
- $user_data = $this->verify_connection( array( 'for' => 'profile' ) );
-
- update_user_meta( get_current_user_id(), 'wpcom_user_id', $user_data->ID );
- update_user_meta( get_current_user_id(), 'wpcom_user_data', $user_data );
-
- wp_safe_redirect( admin_url( 'profile.php' ) );
- exit;
- }
-
- // If they just got forwarded back ...
- if ( isset( $_GET['code'] ) ) {
-
- $user_data = $this->verify_connection();
-
- $this->auth_user( $user_data );
- }
- }
-
- function login_enqueue_scripts() {
- wp_enqueue_style( 'wpcc-sign-on', plugins_url( 'wpcc-sign-on.css', __FILE__ ), 0, filemtime( dirname( __FILE__ ) . '/wpcc-sign-on.css' ) );
- wp_enqueue_script( 'wpcc-sign-on', plugins_url( 'wpcc-sign-on.js', __FILE__ ), array( 'jquery' ), filemtime( dirname( __FILE__ ) . '/wpcc-sign-on.js' ) );
- }
-
- function login_form() {
- if( ! did_action( 'login_init' ) )
- return;
-
- echo $this->button();
- }
-
- function button( $args = array() ) {
- $defaults = array(
- 'response_type' => 'code',
- 'client_id' => $this->client_id,
- 'state' => $this->wpcc_state,
- 'redirect_uri' => wp_login_url(),
- );
-
- $args = wp_parse_args( $args, $defaults );
-
- if ( ! empty( $_REQUEST['redirect_to'] ) ) {
- $args['redirect_uri'] = add_query_arg( 'redirect_to', $_REQUEST['redirect_to'], $args['redirect_uri'] );
- }
-
- $url = add_query_arg( $args, $this->authenticate_url );
-
- return sprintf( '<a id="wpcc-sign-on" href="%1$s"><img src="//s0.wp.com/i/wpcc-button.png" width="231" /></a>', esc_url( $url ) );
- }
-
- function auth_user( $user_data ) {
-
- if ( ! $user_data->verified ) {
- return false;
- }
-
- $user = $this->get_user_by_wpcom_id( $user_data->ID );
-
- // If we don't have one by wpcom_user_id, try by the email?
- if ( empty( $user ) && $this->match_by_email ) {
- $user = get_user_by( 'email', $user_data->email );
- if ( $user ) {
- update_user_meta( $user->ID, 'wpcom_user_id', $user_data->ID );
- }
- }
-
- // If we've still got nothing, create the user.
- if ( empty( $user ) && ( get_option( 'users_can_register' ) || $this->new_user_override ) ) {
- $username = $user_data->username;
-
- if ( username_exists( $username ) ) {
- $username .= '_' . $user_data->ID;
- }
-
- if ( username_exists( $username ) )
- $username .= '_' . mt_rand();
-
- $password = wp_generate_password( 20 );
- $user_id = wp_create_user( $username, $password, $user_data->email );
- $user = get_userdata( $user_id );
-
- $user->display_name = $user_data->display_name;
- wp_update_user( $user );
-
- update_user_meta( $user->ID, 'wpcom_user_id', $user_data->ID );
- }
-
- if ( $user ) {
- // Cache the user's details, so we can present it back to them on their user screen.
- update_user_meta( $user->ID, 'wpcom_user_data', $user_data );
- wp_set_auth_cookie( $user->ID );
-
- $_request_redirect_to = isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
- $redirect_to = user_can( $user, 'edit_posts' ) ? admin_url() : admin_url( 'profile.php' );
- wp_safe_redirect( apply_filters( 'login_redirect', $redirect_to, $_request_redirect_to, $user ) );
- exit;
- }
-
- add_action( 'login_message', array( $this, 'cant_find_user' ) );
- }
-
- function get_user_by_wpcom_id( $wpcom_user_id ) {
- $user_query = new WP_User_Query( array(
- 'meta_key' => 'wpcom_user_id',
- 'meta_value' => intval( $wpcom_user_id ),
- ) );
-
- $users = $user_query->get_results();
-
- return ( is_array( $users ) && ! empty( $users ) ) ? array_shift( $users ) : $users;
- }
-
- function cant_find_user( $message ) {
- $err_format = __( 'We couldn\'t find an account with the email <strong><code>%1$s</code></strong> to log you in with. If you already have an account on <strong>%2$s</strong>, please make sure that <strong><code>%1$s</code></strong> is configured as the email address, or that you have connected to WordPress.com on your profile page.', 'jetpack' );
- if ( ! $this->match_by_email ) {
- $err_format = __( 'We couldn\'t find any account on <strong>%2$s</strong> that is linked to your WordPress.com account to log you in with. If you already have an account on <strong>%2$s</strong>, please make sure that you have connected to WordPress.com on your profile page.', 'jetpack' );
- }
- $err = sprintf( $err_format, $this->user_data->email, get_bloginfo( 'name' ) );
- $message .= sprintf( '<p class="message" id="login_error">%s</p>', $err );
- return $message;
- }
-
- function get_new_app_url() {
- $args = array(
- 'for' => 'jetpack',
- 'title' => urlencode( get_bloginfo( 'name' ) ),
- 'description' => urlencode( get_bloginfo( 'description' ) ),
- 'url' => urlencode( site_url() ),
- 'redirect_uri' => urlencode( wp_login_url() ),
- );
- return add_query_arg( $args, $this->new_app_url_base );
- }
-
- function get_edit_app_url( $client_id = null ) {
- if ( empty( $client_id ) ) {
- $client_id = $this->client_id;
- }
- return sprintf( 'https://developer.wordpress.com/apps/%d/', $client_id );
- }
-}
-
-new WPCC_Sign_On;
diff --git a/plugins/jetpack/modules/wpgroho.js b/plugins/jetpack/modules/wpgroho.js
index 24e161b7..07a78b13 100644
--- a/plugins/jetpack/modules/wpgroho.js
+++ b/plugins/jetpack/modules/wpgroho.js
@@ -1,3 +1,4 @@
+/* global WPGroHo:true, Gravatar */
WPGroHo = jQuery.extend( {
my_hash: '',
data: {},
@@ -5,7 +6,7 @@ WPGroHo = jQuery.extend( {
syncProfileData: function( hash, id ) {
if ( !WPGroHo.data[hash] ) {
WPGroHo.data[hash] = {};
- a = jQuery( 'div.grofile-hash-map-' + hash + ' span' ).each( function() {
+ jQuery( 'div.grofile-hash-map-' + hash + ' span' ).each( function() {
WPGroHo.data[hash][this.className] = jQuery( this ).text();
} );
}
@@ -23,7 +24,7 @@ WPGroHo = jQuery.extend( {
}
}, WPGroHo );
-jQuery( document ).ready( function( $ ) {
+jQuery( document ).ready( function() {
Gravatar.profile_cb = function( h, d ) {
WPGroHo.syncProfileData( h, d );
};