Git Product home page Git Product logo

automattic / pym-shortcode Goto Github PK

View Code? Open in Web Editor NEW
14.0 8.0 7.0 1.12 MB

A WordPress solution to embed iframes that are responsive horizontally and vertically using the NPR Visuals Team's https://blog.apps.npr.org/pym.js/

Home Page: https://wordpress.org/plugins/pym-shortcode/

License: GNU General Public License v2.0

JavaScript 43.91% PHP 42.24% Shell 12.48% CSS 1.37%
wordpress-plugin shortcode pym wordpress-shortcode wordpress-block gutenberg-blocks

pym-shortcode's Introduction

Pym.js Embeds

This plugin allows the use of NPR's Pym.js responsive iframe script on WordPress sites, through the use of shortcodes and Gutenberg blocks.

For detailed examples, ➡️ read the docs! ⬅️

For a detailed changelog, read readme.txt!

For the most-recent release, see the list of releases.

pym-shortcode's People

Contributors

aschweigert avatar benlk avatar claudiulodro avatar eidietrich avatar kaylima avatar lchheng avatar rclations avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pym-shortcode's Issues

Release checklist for tagging version 1.3.2.4

This checklist takes about four hours to run fully.

Team Prep Work

  • check for upstream updates to release.sh in INN/docs and copy them into this plugin
  • write release announcement
    • GitHub release drafted
      • can be copied from release.txt
      • includes encouragement to say hi if you're using the plugin. (This fulfills the "who's using our stuff?" goal in WPBuddy/largo#1495)
    • labs.inn.org blog post written and saved as draft, based on changelog
    • MailChimp campaign for Largo User mailing list drafted: WPBuddy/largo#1796
  • identify non-Github documentation for this plugin
    • note the location of that documentation
  • update outside documentation for this plugin

Before merging

The owner of the release needs to complete the following steps BEFORE merging the version-bump branch and tagging the release:

  • resolve all secret issues, private issues, or issues with the plugin that are otherwise documented outside of this public repository
  • resolve all GitHub maintainer security advisories: merge and publish.
  • update and sort the changelog
    • make sure changelog has all items from this release, and all PRs and issues are linked
    • check that ordering and grouping of items is logical.
    • New features list
    • Dev-facing updates
    • Bugfixes
    • Potentially breaking changes and upgrade notices
    • Which versions of PHP was this tested against? (why) List the PHP versions that we're sure of and that WordPress supports. (See WPBuddy/largo#1801)
  • update description
    • in readme.txt
    • in plugin description comment
  • bump version number
    • in readme.txt
    • in pym-shortcode.php
    • in readme.md
    • in docs/maintainer-notes.md
  • testing as described in https://github.com/INN/pym-shortcode/blob/master/docs/maintainer-notes.md

Release process

After release is published

  • update plugins on our sites (inndev? ccs?)
  • publish update announcement blog post
  • tweet announcement and schedule 2-5 for the next 7 days (via TweetDeck, HootSuite, or similar) with simple download prompt or tweets detailing new features, like "Newsroom Staff Pages should be clean and useful. We think so too. See Largo 0.X's new...." Make sure these tweets get cross-tweeted between INN accounts.
  • add to Nerd Alert for following week
  • create the release ticket for the next milestone from this one
  • prune stale and merged branches
  • notify maintainers of related plugins: News Project, WP AMP,

Override pym_id to resize after following links in iframe?

I'm so glad you've created this plugin! 😁

I have some clients who want to use it to embed event registration and membership forms from another application. To work well, the iframe needs to resize at each screen of the process.

The Pym docs show how to do this (jump to Example: Resizing after following links in the iframe), and I've tried to follow the instructions. I am using a local WordPress test site and the following code on each page of my silly little child site:

    <script src="https://pym.nprapps.org/pym.v1.min.js"></script>
    <script>
      var pymChild = new pym.Child({ id: '[UNIQUE ID FOR EACH PAGE]' })
    </script>

(I've also tried replacing id with pym_id - no effect that I can see.)

The iframe loads beautifully for the first page, but when I click through to other pages inside the iframe, the iframe height doesn't change. The ID of the parent div is always pym_0, where I would expect it to be replaced with my specific unique ID from the child page.

Any tips? I don't mind forking the plugin and making my own changes, but if there's a way I can make it work with the existing code, that would be best for my clients.

Thanks!

Dealing with persistence?

Sometimes you need a different embed code, like the Seamus ones:

<div id="responsive-embed-budget_by_dollar"></div>
<script type=text/javascript>
    (function(jQuery) {
        if (typeof jQuery !== 'undefined' && typeof jQuery.getScript === 'function') {
            // add randomness to id to support for multiple graphic instances in one story
            var el = document.getElementById("responsive-embed-budget_by_dollar");
            el.id = el.id + "-" + Math.random().toString(36).substr(2,5);
            jQuery.getScript("//pym.nprapps.org/pym.v1.min.js").done(function () {
                jQuery(function () { // Wait for page load
                    var pymParent = new pym.Parent(
                        el.id,
                        'http://f.benlk.com/graphics/budget_by_dollar/child.html',
                        {}
                    );

                    jQuery.getScript("//carebot.nprapps.org/carebot-tracker.v0.min.js").done(function () {
                        var tracker = new CarebotTracker.VisibilityTracker(el.id, function(result) {
                            // Ignore Carebot events to empty embeds, keeps listening after unloading the page
                            if (pymParent.el.getElementsByTagName('iframe').length !== 0) {
                                pymParent.sendMessage('on-screen', result.bucket);
                            }
                        });
                        // Check if there is already an scroll tracker somewhere on the page
                        if (!document.querySelector("[data-carebot-scroll]")) {
                            pymParent.el.setAttribute("data-carebot-scroll", "");
                            var scrollTracker = new CarebotTracker.ScrollTracker('storytext', function(percent, seconds) {
                                // Ignore Carebot events to empty embeds, keeps listening after unloading the page
                                if (pymParent.el.getElementsByTagName('iframe').length !== 0) {
                                    pymParent.sendMessage('scroll-depth', JSON.stringify({percent: percent,seconds: seconds}));
                                }
                            });
                        }
                    });

                });
            });
        } else {
            console.error('could not load graphic: jQuery is not on the page.');
        }
    })(window.jQuery);
</script> 

Do we want this plugin to handle that? Do we want to make a different plugin, supporting the same shortcode, that does a different type of initialization?

Provide a sample shortcode to allow testing

We got a support ticket from a user who doesn't have access to the list of active plugins, who wanted to know whether it was active.

  • assemble a demo shortcode
  • add the demo shortcode to the plugin's docs or FAQ in the readme, under a heading something like "I don't have access to my site's plugins page. How can I tell if this shortcode is active?" with a response along the lines of "create a draft post with this shortcode and preview it; you should see something like this:"

docs: HTTPS concerns

  • How do you serve pym.js if the embedded page's domain has an SSL cert (and can/will be served over HTTPS) but the parent page's domain does not have an SSL certificate?
  • How do you detect HTTPS problems?
    • embed not sizing correctly
    • open embed in new tab

Tag 1.3.2.1

Gutenberg Block failing for me on Wordpress.com

Without warning, this plugin stopped working on WP.com today. The Pym JS library doesn't load. Support has asked me to contact yall (what up INN friends!!). If you have any ideas, I'd love to know. I don't see any updates to the plugin recently, and it had been working for weeks up until now.

I did have a notion that Gutenberg might be a culprit, but the same problem crops up in the classic editor. We have a business account, so we can use unfiltered html in the advanced editor, and that works fine.

php error with latest version?

All my shortcodes are broken now that I'm unable to activate this plugin -- Here's the message I get:

Parse error: syntax error, unexpected T_STRING, expecting T_CONSTANT_ENCAPSED_STRING or '(' in /home/mattstiles/webapps/heyelise/wp-content/plugins/pym-shortcode/inc/shortcode.php on line 8

Halp?

Content does not appear on page load, but does on window resize

I'm using pym for a quiz that gets it's content from a Google Sheet. When I load the page, nothing appears. In the inspector, I can see pym is showing up, but the height is 0. If I resize the window in any way, it starts working and the quiz appears.

Here's the page I'm referring to: http://www.sciencefriday.com/segments/quiz/
And the page pym is drawing from: http://scifri.github.io/newsquiz/index.html

I'm guessing this bug could be coming from one of the javascript files this quiz is using, which include jquery.js, tabletop.js, and script.js. Not sure if there's a documented problem with using pym with one of these.

The quiz code is from the Mother Jones open source quiz tool: https://github.com/motherjones/newsquiz

Allow passing a class name to target DIV

We have a couple size-based class names in our site styles, and it's been handy to use those to size embeds. When we're just writing HTML, it's easy to do something like:

<div class="interactive medium" data-pym-src="..."></div>

Would be great to be able to:

[pym src="..." class="interactive medium"]

Write PHP tests

  • fab wp.tests_setup:pym
  • review code for things that will need to be tested especially
  • create list of high-priority tests and low-priority tests
    • assume that WordPress settings functions work
  • Write tests for pym_shortcode( $atts, $context, $tag )
    • alternate src is included if set
    • otherwise, src is the path in the plugins directory plugins_url( '/js/pym.js',$whatever_the_pym_plugin_file_path_is )
    • page contains markup corresponding to placed source code
    • a post with n shortcodes contains each of echo '<div id="pym_' . $n . '"></div>';

React is dropping className for class

Keep an eye on facebook/react#13525 and update this plugin when Gutenberg switches from className to class.

  • add a deprecated block method to support upgrading from className to class
  • are changes in the shortcode necessary? Do those too.
  • changelog docs

Release checklist for tagging version 1.3.2.3

Drawing from Largo's 0.7.0 release checklist issue WPBuddy/largo#1798, the SCAMP 0.3 tag checklist INN/doubleclick-for-wp#83, Automattic/republication-tracker-tool#63, and other issues:

Team Prep Work

  • copy this issue into this plugin's docs folder with relevant instructions for testing
  • check for upstream updates to release.sh in INN/docs into this plugin
  • write release announcement
    • GitHub release drafted
      • can be copied from changelog.md
      • includes encouragement to say hi if you're using the plugin. (This fulfills the "who's using our stuff?" goal in WPBuddy/largo#1495)
    • labs.inn.org blog post written and saved as draft, based on changelog
    • MailChimp campaign for Largo User mailing list drafted: WPBuddy/largo#1796
  • identify non-Github documentation for this plugin
    • note the location of that documentation
  • update outside documentation for this plugin

Before merging

The owner of the release needs to complete the following steps BEFORE merging the version-bump branch and tagging the release:

  • resolve all secret issues, private issues, or issues with the plugin that are otherwise documented outside of this public repository
  • resolve all GitHub maintainer security advisories: merge and publish.
  • update and sort the changelog
    • make sure changelog has all items from this release, and all PRs and issues are linked
    • check that ordering and grouping of items is logical.
    • New features list
    • Dev-facing updates
    • Bugfixes
    • Potentially breaking changes and upgrade notices
    • Which versions of PHP was this tested against? (why) List the PHP versions that we're sure of and that WordPress supports. (See WPBuddy/largo#1801)
  • update description
    • in readme.txt
    • in plugin description comment
  • bump version number
    • in readme.txt
    • in pym-shortcode.php
    • in readme.md
    • in docs/maintainer-notes.md
  • testing as described in https://github.com/INN/pym-shortcode/blob/master/docs/maintainer-notes.md

Release process

After release is published

  • update plugins on our sites (inndev? ccs?)
  • publish update announcement blog post
  • tweet announcement and schedule 2-5 for the next 7 days (via TweetDeck, HootSuite, or similar) with simple download prompt or tweets detailing new features, like "Newsroom Staff Pages should be clean and useful. We think so too. See Largo 0.X's new...." Make sure these tweets get cross-tweeted between INN accounts.
  • add to Nerd Alert for following week
  • create the release ticket for the next milestone from this one -> #71
  • prune stale and merged branches
  • notify maintainers of related plugins: News Project, WP AMP

rename text domain

When did I introduce the text domain? Can we rename it from pym-shortcode to pym-embeds without affecting stuff?

I mean, this plugin doesn't ship with translation files at the moment, so how hard could it be?

Because shortcodes and blocks are processed at different times, a shortcode can be output without necessary dependencies on the page

Originally reported in #34, the ticket for adding Gutenberg support to the plugin.

With the following post_content:

<!-- wp:shortcode -->
[pym src="https://f.benlk.com/graphics/heartbeat-abortion-bills/child.html"]
<!-- /wp:shortcode -->

<!-- wp:paragraph -->
<p>the preceding is a shortcode block.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The following is the Pym Embed:</p>
<!-- /wp:paragraph -->

<!-- wp:pym-shortcode/pym {"src":"http://blog.apps.npr.org/pym.js/examples/table/child.html","align":"full"} /-->

The following output:

<div id="pym_1" class="pym  "></div>
<script>var pym_1 = new pym.Parent('pym_1', 'https://f.benlk.com/graphics/heartbeat-abortion-bills/child.html', {})</script>
<p>the preceding is a shortcode block.</p>
<p>The following is the Pym Embed:</p>
<div id="pym_0" class="pym alignfull "></div>
<script src="http://pym-shortcode.test/wp-content/plugins/pym-shortcode/js/pym.v1.min.js"></script><script>var pym_0 = new pym.Parent('pym_0', 'http://blog.apps.npr.org/pym.js/examples/table/child.html', {})</script>

After dumping the filters hooked on 'the_content' with global $wp_filter; var_dump( $wp_filter['the_content'], true );, I found that the block rendering filter do_blocks runs before the shortcode renderer do_shortcode.

Thus, in a post with one block and one shortcode, the first block gets the id pym_0 and the first shortcode gets the id pym_1.

Because the current behavior of the function pym_shortcode() — which is used for the shortcode and the block output — is to output the Pym.js-loading tag <script src="http://pym-shortcode.test/wp-content/plugins/pym-shortcode/js/pym.v1.min.js"></script> only during the first call, for pym_0, the later call to pym_shortcode() earlier in the post_content doesn't output the script tag, which means that pym_1's new pym.Parent call doesn't work, because pym is not yet defined.

Filter allowing theme/plugin devs to put classes on pym shortcode output

For example, if it was desired that all pym embed parent divs should have the class pym_parent:

/**
 * add 'pym_parent' to the classes on the pym field array
 * @param Array $classes
 * @return Array
 */
function my_pym_class_filter( $classes ) {
    $classes[] = 'pym_parent';
    return $classes;
}
add_filter( 'pym_element_classes', 'my_pym_class_filter' );

Update support.inn.org docs

The documentation at https://support.inn.org/article/100-pym-shortcode needs to be updated in the following ways:

  • "There are no plugin settings" is false since version 1.3.2.1 in 2018, when we added a settings page. We can probably strike the words "There are no plugin settings, but" and start the sentence with "There are some...."
  • This page should mention Gutenberg compatibility before the shortcode.
  • Include a link to https://blog.apps.npr.org/pym.js/ and credit NPR somewhere on the page.

Discovered during #68

Provide a setting to allow site admins to opt into using the CDN version of Pym

Wordpress' plugin guidelines require that we include pym.js locally, and that that version be used by default. This is because WordPress forbids loading executable code from CDNs: https://developer.wordpress.org/plugins/wordpress-org/detailed-plugin-guidelines/#8-plugins-may-not-send-executable-code-via-third-party-systems

However, if we created a setting that allowed people to opt into using the NPR-CDN-provided version of Pym.js, and that setting page included sufficient warnings and explanations, we would be able to provide the option of enabling the CDN version to people who are interested in using it without having to set the pymsrc attribute on every single shortcode.

AMP support?

Fallback cases where Pym.js fails to load in the parent

For shortcodes:

  • allow the shortcode to be used as a [pym src=""]foo[/pym] that passes the contents to $content to be used as the innards of the placeholder div: <div id="pym_1" class="pym ">foo</div>

For blocks:

  • for blocks, the placeholder is a link to the embed

Specific to AMP

For whatever WordPress AMP plugins we want to support:

  • provide a transformation that ensures the appropriate Pym JS tags are output as part of the AMP content
  • Investigate whether Pym can use amp-iframe as a pymParent: nprapps/pym.js#182

Use Gutenberg's native `anchor` support for setting the pym parent element ID

We didn't do this in the initial implementation of Gutenberg blocks in #34 because, at the time, it appeared as if there was no way to use Gutenberg's anchor property with a block that was dynamically rendered.

For more history, see the following comments:

Elements of this ticket:

  • remove the shim introduced in #34
  • add a supports declaration for anchor
  • add the anchor output to the pym_shortcode function.

Does the `pymoptions=""` attribute actually support backslashes?

We have this example in readme.txt:

[pym src="child.html" pymoptions=" xdomain: '\\*\.npr\.org' "]

Which is supposed to output: (with supporting code)

pym.Parent('pym_0', 'child.html', { xdomain: '*\.npr\.org' });

But what it actually puts on the page is this:

pym.Parent('pym_0', 'child.html', { xdomain: '\*.npr.org' })

Inside, the $pymoptions variable is this:

error_log( var_export( $pymoptions, true ) );
' xdomain: \'\\*.npr.org\' '

If we esc_js() that, it's this, still not what we're looking for:

' xdomain: \\\'*.npr.org\\\' '

In conclusion: slashes aren't being output correctly.

Add settings page

This would cover several options:

  • provide URL to the plugin's site-hosted version of Pym.js, for use when building embeds
  • #31: option to enable CDN version of pym.js
  • #8: settings to whitelist certain pymsrc options, to prevent contributors/authors from embedding arbitrary JS on the page
  • #19: option to change embed script source for persistence reasons

The full set of features needed:

  • options page
  • "what is my pym.js url" page
  • save option containing options and plugin version number, see existing work in other plugins we've made
  • options:
    • set default pymsrc
    • set override pymsrc
    • plugin version number
  • default pymsrc is respected by embed output
  • override pymsrc is respected by embed output
  • how to test upgrading this plugin on your site docs, for #8.
  • install docs recommending use of CDN, for #8.

Text domain corrections

https://developer.wordpress.org/plugins/internationalization/how-to-internationalize-your-plugin/ says regarding declaring a text domain:

After WordPress 4.6 came out, the Text Domain header is no longer required if it’s the same as the plugin slug. It’s now the default value.

However, this plugin does not declare a text domain, and uses multiple text domains.

In the start and end of this quoted section, we use 'pym_shortcode'

https://github.com/INN/pym-shortcode/blob/7ad2ca8d694e030944d37123622e4820f19d4f17/inc/class-pymsrc-output.php#L123-L138

Elsewhere in the plugin, we use 'pym-embeds':

https://github.com/INN/pym-shortcode/blob/b62b061ba3a0438878b110b18f0c1b1b59faf76d/inc/settings-page.php#L59-L60

https://github.com/INN/pym-shortcode/blob/a8666141cbb12876e36de77fc96578e680e3ef00/inc/info-page.php#L20-L21

Neither of those matches the .org plugin slug of pym-shortcode, which is what is most likely that this plugin has been installed under

  • pick a text domain
  • update all text-domain strings to that domain
  • declare the text domain explicitly
  • add note in PR template about new translatable strings matching the project one

docs: info about Pym.js

  • better link to NPR
  • situations where you would want to use Pym: why use Pym?
  • situations where you would not want to use Pym, or do not need to use Pym

Rename plugin

https://developer.wordpress.org/plugins/wordpress-org/plugin-developer-faq/#can-i-change-my-plugins-name-after-its-approved

Can I change my plugin’s name after it’s approved? #Can I change my plugin’s name after it’s approved?
Yes and no. You can change the display name, but the slug — that part of the plugin URL that is yours — cannot be changed once a plugin is approved. That’s why we warn you, multiple times, upon submission.

To change the display name, edit your main plugin file and change the value of “Plugin Name:” to the new name. You may also want to edit your header in your readme.txt

Right now, the plugin is called "Pym Shortcode".

When we add Gutenberg support in #34, that title will be an incomplete description of the plugin. What should we call it?

Test against WordPress 5.4 RC

Without AMP

Plugin settings:

  • Does the plugin settings page work? /wp-admin/options-general.php?page=pym-embed-settings
  • Does the plugin info page work? /wp-admin/tools.php?page=pym-embeds-info

Shortcode tests:

  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html"]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" pymsrc="https://pym.nprapps.org/pym.v1.min.js"]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" pymoptions=" xdomain: '\\*\.npr\.org' "]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" class="one two three four float-left mw_50"]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" align=""]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" align="none"]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" align="left"]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" align="center"]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" align="right"]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" align="wide"]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" align="full"]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" id="extremely_specific_id"]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" pymsrc="https://pym.nprapps.org/pym.v1.min.js" pymoptions=""]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" pymsrc="https://pym.nprapps.org/pym.v1.min.js" pymoptions=""]

Gutenberg tests:

  • the block, when inserted, prompts users for a URL
  • the block's alignment, custom classes, custom ID, and other options are respected.
  • the block uses the default pymsrc URL if the pymsrc attribute is not set
  • on a site with Gutenberg not installed, the plugin functions
  • on a without Gutenberg installed, the plugin functions

With AMP

Plugin settings:

  • Does the plugin settings page work? /wp-admin/options-general.php?page=pym-embed-settings
  • Does the plugin info page work? /wp-admin/tools.php?page=pym-embeds-info

Shortcode tests:

  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html"]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" pymsrc="https://pym.nprapps.org/pym.v1.min.js"]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" pymoptions=" xdomain: '\\*\.npr\.org' "]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" class="one two three four float-left mw_50"]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" align=""]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" align="none"]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" align="left"]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" align="center"]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" align="right"]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" align="wide"]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" align="full"]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" id="extremely_specific_id"]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" pymsrc="https://pym.nprapps.org/pym.v1.min.js" pymoptions=""]
  • [pym src="https://blog.apps.npr.org/pym.js/examples/table/child.html" pymsrc="https://pym.nprapps.org/pym.v1.min.js" pymoptions=""]

Gutenberg tests:

  • the block, when inserted, prompts users for a URL
  • the block's alignment, custom classes, custom ID, and other options are respected.
  • the block uses the default pymsrc URL if the pymsrc attribute is not set
  • on a site with Gutenberg not installed, the plugin functions
  • on a without Gutenberg installed, the plugin functions

Make pym path configurable

Unfortunately, the version of pym that is bundled here is buggy in certain cases. Also, as changes get made, this means we would have to update this repository and update the wordpress site.
Making the pym path configurable would make it easier to keep up with changes without having to redeploy this plugin.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.