Giter Site home page Giter Site logo

arnowelzel / lightbox-photoswipe Goto Github PK

View Code? Open in Web Editor NEW
27.0 6.0 7.0 2.22 MB

Integration of PhotoSwipe to WordPress

Home Page: https://arnowelzel.de/wp/en/projects/wordpress/lightbox-with-photoswipe

License: GNU General Public License v2.0

JavaScript 75.68% CSS 11.26% PHP 13.05% Makefile 0.01%
lightbox photoswipe wordpress wordpress-plugin

lightbox-photoswipe's Introduction

About me

I'm doing software development since mid 1980ies and also have long term experience in server and network administration. In my regular job I work as tech lead.

My current topics:

  • Event sourcing and CQRS
  • Nextcloud
  • WordPress
  • Android
  • Electronis in general and microcontrollers (ATmega, ESP8266 etc.)

lightbox-photoswipe's People

Contributors

arnowelzel avatar b-e-n-g avatar hristov296 avatar huubl avatar jefferyto avatar maciejmajewski avatar tbiering avatar

Stargazers

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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

lightbox-photoswipe's Issues

Document changes to "stock" PhotoSwipe / differences between skins

First, thanks for creating this plugin πŸ˜„

I was comparing the PhotoSwipe js/css bundled with this plugin and those from "stock" PhotoSwipe, and I noticed that you had made some changes. I think it would nice to document these changes somewhere (maybe in the readme) so that users can know what to expect.

Also, I see that there are four skin options; I think it would be nice again to document the differences between these options (and any changes from the "stock" PhotoSwipe default skin), so that users don't need to try each one to figure out which one to use.

Thanks again!

Add option to use separate picture lists for galleries

At the moment, PhotoSwipe shows all pictures in one post. Some users prefer having one list of pictures for each gallery element and all non-gallery-pictures separately in their posts. This should be an option in the backend or maybe per post.

Add global API to open the Lightbox

Also see https://wordpress.org/support/topic/opening-photoswipe-via-javascript-api/

There may be usecases which require to open the lightbox without clicking in image. This could be done by exposing a global function. For example:

window.lbwpsOpenPhotoSwipe(linkObject)

window.lbwpsOpenPhotoSwipeById(id)

Where linkObject is the image link to open and id would be the ID. Depending on if you have an object or just an ID you can then use the appropriate function.

Usage example:

<a id="image1" href="myimage.jpg" ...><img src="myimage-300x300.jpg" ...></a>

<button type="button" onClick="window.lbwpsOpenPhotoSwipeById('image1');">Open me!</button>

Add support for PhotoSwipe API

Hey Arno,
I'd like to propose a small improvement for the plugin: the ability to access the JavaScript PhotoSwipe object in order to use the PhotoSwipe API. This would allow external JavaScript to control the gallery and access its properties and thus allow easier customization of the gallery. It would also complement the already existing ability to change the PhotoSwipe markup.

Currently, the gallery-object is created as a local variable and thus is inaccessible outside of the local scope.

To solve this, I would suggest to create a global variable that points to the current PhotoSwipe object in order to make it easily accessible.

I am currently writing a very simple extension-plugin to create a dedicated download-button in the gallery and adding this functionality would allow me to use the API instead of accessing the gallery in other hacky ways.
I have already implemented this in a branch on my fork if you're interested: branch/feature-psinstance-api - relevant commit

Let me know if you think this would be a good improvement for the project.

Best regards,
Thomas

Restore captions using "aria-describedby"

Also see https://wordpress.org/support/topic/captions-missing-since-version-2-94

Since version 2.94 captions which are referred using the attribute "aria-describedby" are not supported any longer. The original code using jQuery was:

            if(caption == null) {
                describedby = element.children().first().attr('aria-describedby');
                if(describedby != null ) {
                    description = $('#'+describedby);
                    if(description != null) caption = description.text();
                } else {
                    describedby = element.children().first().attr('figcaption');
                    if(describedby != null ) {
                        caption = element.next().text();
                    }
                }
            }

It seems this code got removed when the frontend script was refactored to work without jQuery.

Move away from Github?

Github will soon be a part of Microsoft and I'm not sure yet, if this is really the direction I want to go.

Therefore I will propably move with all my repositories away from Github. Stay tuned - I'll tell you more details here soon.

Conflict with Yoast SEO

Hi @arnowelzel ,

I have recently updated Lightbox-Photoswipe to latest version and also Yoast SEO to 12.4.

There seems to be a conflict between the two plugins that prevents Lightbox-Photoswipe to work correctly.

As soon as I deactivate Yoast SEO, your plugin starts working again.

Thanks
Luca

[Feature Request] Add loading lazy attribute to the thumbnail image

I would like to propose a feature request to your great plugin. The images in the post are currently loaded as img tags:

<li class="blocks-gallery-item">
    <figure>
        <a href="full.jpg" data-lbwps-width="1920" data-lbwps-height="1080">
            <img
                src="thumbnails.jpg"
                alt=""
                data-id="36724"
                data-full-url="full.jpg"
                data-link="/?attachment_id=36724"
                class="wp-image-36724"
                srcset="260x113.jpeg 260w, 460x200.jpeg 460w, 920x400.jpeg 920w"
                sizes="(max-width: 260px) 100vw, 260px"
                loading="lazy"
            />
        </a>
    </figure>
</li>

My proposal would be to simply add the new native lazy loading attribute to the thumbnail image:

<li class="blocks-gallery-item">
    <figure>
        <a href="full.jpg" data-lbwps-width="1920" data-lbwps-height="1080">
            <img
                src="thumbnails.jpg"
                alt=""
                data-id="36724"
                data-full-url="full.jpg"
                data-link="/?attachment_id=36724"
                class="wp-image-36724"
                srcset="260x113.jpeg 260w, 460x200.jpeg 460w, 920x400.jpeg 920w"
                sizes="(max-width: 260px) 100vw, 260px"
                loading="lazy"
            />
        </a>
    </figure>
</li>

It is already supported in Chrome. I would not integrate a js script to lazy load anymore. To much ovberhead. And this sounds like a simple addition. This would help center pages like this: https://marc.tv/bildergalerien/

Workaround for using CDNs

Also see https://wordpress.org/support/topic/version-1-99-not-working/

A common way for using CDNs in WordPress is to replace the URL of media files with the URL of the CD followed by the former URL of the meda file.

Example:

https://www.server.example/wp-content/uploads/2014/02/prince-in-2014.jpg

will become to:

https://arpzlshoen.cloudimg.io/cdn/n/q90/wp-content/uploads/2014/02/prince-in-2014.jpg

Since the image URL is used to get meta information from WordPress, this may not work any longer when using a CDN.

Possible solutions

For JetPack there is already an automatic replacement: $file = preg_replace('/(i[0-2]\.wp.com\/)/s', '', $url);. Since the base for media files is known (usually /wp-content/uploads - can be checked with wp_upload_dir(), also see https://developer.wordpress.org/reference/functions/wp_upload_dir/) it should be possible to check, wether an image URL is in fact served using a CDN:

  1. Check if the URL contains the upload base path

  2. Strip everything before that path and check if there is a file at that path

Jetpack's Infinite Scroll not working with lightbox-photoswipe plugin active

Hi, I have a problem with getting Jetpack's infinite scroll to work when your plugin is active.

I was able to determine that the response to the request sent by infinite scroll contains some HTML code from site header. It results in following error: Uncaught SyntaxError: Unexpected token < in JSON at position 0 at JSON.parse (<anonymous>) at XMLHttpRequest.xhr.onload (infinity.min.js?ver=8.6.1-is5.0.0:3)

I changed the priority in add_action('wp_head', array($this, 'bufferStart'), 2000); from 2000 to 90 and it works well, however I suppose it's a temporary and dirty hack.

Any thoughts on how this can be solved?

Bug with EXIF display

When displaying EXIF data is enabled, images without EXIF information get the string "(, , ,)" added. This is not correct - without EXIF information, the whole EXIF part should not be generated.

Remove alt attribut from images inside the lightbox

Originally Photoswipe does not add alt attributes to the images inside the lightbox. The modified version does as some users have asked to get the caption as alt attribute as well.

However - the caption may also contain HTML code and this must not be used for the alt attribute. It also makes no sense to have that attribute there. Therefore it's better to remove it again.

Add option to have plugin disabled by default

Also see: https://wordpress.org/support/topic/only-enabling-the-plugin-on-selected-pages/

Eventhough the plugin only adds two additional resources some people prefer maximum possible optimization and like to have the plugin only active on pages which need it.

One solution might be to add an advanced option which reverses the meaning of the post/page specific "disable" option - instead of disabling the plugin it will enable it if checked for a specific post/page.

An automatic solution is not possible since the plugin will uses the final output buffer to add data-lbwps- attributes to image links - but this happens after the script and style queue was already processed by WordPress.

Additional button design

Also see https://wordpress.org/support/topic/idea-of-new-buttons-design/

Some users prefer another design for the buttons - bigger and with different images.

SVG for ">":

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" x="0" y="0" width="60" height="60" viewBox="0 0 60 60" xml:space="preserve">
      <circle class="lightbox-icon-bg" cx="30" cy="30" r="30"></circle>
      <path class="lightbox-icon-arrow" d="M24.2,23.5l6.6,6.5l-6.6,6.5l3.6,3.5L37.8,30l-10.1-9.9L24.2,23.5z"></path>
</svg>

SVG for "<":

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" x="0" y="0" width="60" height="60" viewBox="0 0 60 60" xml:space="preserve">
      <circle class="lightbox-icon-bg" cx="30" cy="30" r="30"></circle>
      <path class="lightbox-icon-arrow" d="M36.8,36.4L30.3,30l6.5-6.4l-3.5-3.4l-10,9.8l10,9.8L36.8,36.4z"></path>
</svg>

SVG for "x":

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" x="0" y="0" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet" fill="#FFF">
      <circle class="lightbox-icon-bg" cx="50" cy="50" r="47.5"></circle>
      <polygon class="lightbox-icon-close" points="64.5,39.8 60.2,35.5 50,45.7 39.8,35.5 35.5,39.8 45.7,50 35.5,60.2 39.8,64.5 50,54.3 60.2,64.5 64.5,60.2 54.3,50"></polygon>
</svg>

Option "Add native lazy loading to images" leads to html-invalid syntax and on-page code print

Hi.

The issue appeared after update to 2.75. The issue has 2 parts below: A) results in invalid html syntax and a more severe one B) that results in on-page print of code. Basically, I've found A) because of B).

A) is the fact that loading="lazy" gets added in a wrong place that results in invalid html syntax.

loading="lazy" gets added after the / in img tag close, that basically turns <img /> into <img / loading="lazy"> whereas correct syntax would be <img loading="lazy" />. My best guess is that you'll need to rewrite your regex to foresee that img tag can be written like <img> or <img /> with backslash. This issue is common for all images, unlike the next one.

B) The second issue below only happens inside WP 'blocks' (woocommerce product guttenberg block to be specific) and results in the following output:
<a href="..." class="wc-block-grid__product-link"><div class="wc-block-grid__product-image">><img width="678" height="678" ...

If you look closer it adds > before <img ... Unlike A) which is not visible on page, this prints on page as text, so that > appears before image. Basically, I've found A) because of B) - I've noticed that after last update extra > symbols appeared on page.

This is also, as A) happens in the same place, because of incorrect preg_replace split of output string, and only if "Add native lazy loading to images" option is enabled. If option "Add native lazy loading to images" is disabled, neither A) or B) happen.

I've located the issue in lightbox-photoswipe.php (Version: 2.75, below lines refferenced for this version)

First here (from line : 599)

    function filterOutput($content)
    {
	    if ('1' === $this->add_lazyloading) {
		    $content = preg_replace_callback(
			    '/(<a.[^>]*href=["\'])(.[^"^\']*?)(["\'])([^>]*)(>)(((?!<\/a>).)*)(<img [^>]+)(>)(.*)(<\/a>)/sU',
			    array( $this, 'outputCallbackProperties' ),
			    $content
		    );
	    }

Preg-replace obviously breaks the output in a wrong way. Then here (from line: 566)

        // Add "lazy loading" to the image if needed
	    if ('1' === $this->add_lazyloading) {
		    if (strpos( $matches[8], 'loading="lazy"' ) === false) {
			    $matches[8] .= ' loading="lazy"';
		    }

		    return $matches[1] . $matches[2] . $matches[3] . $matches[4] . $attr . $matches[5] .
		           $matches[6] . $matches[7] . $matches[8] . $matches[9] . $matches[10] . $matches[11];
	    }

Responsive images for the slideshow?

Hi Arno,

First of all thank you for your plugin. I really like it, am an avid follower of photoswipe, using it in its pure form a lot. Now I am working on a WordPress site and am trying to get responsive images going for the slideshow.

I use the following responsive picture syntax.
It is the Changing image sizes, high-DPI images & different image types use case from here.
https://dev.opera.com/articles/responsive-images/
(Note this is not about art direction, where completely different images are served based on viewport.)

<picture>
	<source
		sizes="(min-width: 640px) 60vw, 100vw"
		srcset="opera-200.webp 200w,
				opera-400.webp 400w,
				opera-800.webp 800w,
				opera-1200.webp 1200w,
				opera-1600.webp 1600w,
				opera-2000.webp 2000w"
		type="image/webp">
	<img
		src="opera-400.jpg" alt="The Oslo Opera House"
		sizes="(min-width: 640px) 60vw, 100vw"
		srcset="opera-200.jpg 200w,
				opera-400.jpg 400w,
				opera-800.jpg 800w,
				opera-1200.jpg 1200w,
				opera-1600.jpg 1600w,
				opera-2000.jpg 2000w">
</picture>

This serves webp format images to browsers that support it and falls back to jpg format images for older browsers.

In fact I also combine this with lazysizes.
The whole thing then looks something like this.

    <picture
      ><source
        sizes="(min-width: 2700px) 1603px, (min-width: 1040px) calc(61.16vw - 36px), calc(100vw - 130px)"
        data-srcset="image_19-2560x3327.jpg 2560w, image_19-2048x2661.jpg 2048w, image_19-1920x2495.jpg 1920w, image_19-1600x2079.jpg 1600w, image_19-1440x1871.jpg 1440w, image_19-1280x1663.jpg 1280w, image_19-1140x1481.jpg 1140w, image_19-1024x1331.jpg 1024w, image_19-960x1248.jpg 960w, image_19-900x1170.jpg 900w, image_19-800x1040.jpg 800w, image_19-768x998.jpg 768w, image_19-640x832.jpg 640w, image_19-525x682.jpg 525w, image_19-425x552.jpg 425w, image_19-320x416.jpg 320w, image_19-240x312.jpg 240w, image_19-180x234.jpg 180w, image_19-120x156.jpg 120w"
        type="image/jpg"/>
      <noscript><img src="image_19-2560x3327.jpg"/></noscript
      ><img
        width="2560"
        height="3327"
        style="max-width: 2560px; max-height: 3327px;"
        class="lazyload"
        src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
        data-src="image_19-425x552.jpg"
        alt=""
        sizes="(min-width: 2700px) 1603px, (min-width: 1040px) calc(61.16vw - 36px), calc(100vw - 130px)"
        data-srcset="image_19-2560x3327.jpg 2560w, image_19-2048x2661.jpg 2048w, image_19-1920x2495.jpg 1920w, image_19-1600x2079.jpg 1600w, image_19-1440x1871.jpg 1440w, image_19-1280x1663.jpg 1280w, image_19-1140x1481.jpg 1140w, image_19-1024x1331.jpg 1024w, image_19-960x1248.jpg 960w, image_19-900x1170.jpg 900w, image_19-800x1040.jpg 800w, image_19-768x998.jpg 768w, image_19-640x832.jpg 640w, image_19-525x682.jpg 525w, image_19-425x552.jpg 425w, image_19-320x416.jpg 320w, image_19-240x312.jpg 240w, image_19-180x234.jpg 180w, image_19-120x156.jpg 120w"
    /></picture>

You might be curious about having the width and height attributes in there, well this is because of this upcoming feature. It helps with reducing page jank.

Regardless of all this, when I wrap this picture element into a link so that it can be shown through your excellent lightbox-photoswipe plugin I have to use the biggest source of that image, because if I don't, and the user is on a moderately large desktop they will either see a too small and blurry or a too large and blurry image in the slideshow. This is because the image dimensions need to be specified with the data attributes. For desktop this is not an issue. But..

This of course leads to loading huge images to users on mobile devices. So while the responsive picture element syntax takes care of that with having all the possible src and srcset attribute values, this is a bit trickier to accomplish when I like to use responsive images in the slideshow.

Short, how do you get responsive images for the slideshow going with your plugin? I can see in the photoswipe documentation that the native picture element and the srcset attribute are not supported. And they don't need to be supported. The picture element is merely the thumbnail that then opens the slideshow. On a large screen this thumbnail has a large size and on mobile it is small.

I guess all this leads to the following question. How could I generate or populate this slide object with the already existing sizes and then feed those to your plugin? More than happy to help you write code, frontend or backend, for this. What do you think?

lbwps_enabled not working

Hi I was trying to use the function:

function my_lbwps_enabled($id, $enabled)
{
if( function_exists( 'is_product' ) )
{
if( is_front_page() ) return false;
}

return $enabled;

}

add_filter( 'lbwps_enabled', 'my_lbwps_enabled', 10, 2 );

but it doesn't work for me. I know that I can exclude the front page in admin but I need to exclude it also from many other pages (all pages from custom types).

Add check for "SCRIPT_DEBUG" wp const?

What do you think about adding a check for the 'SCRIPT_DEBUG" const? That way, if someone wants to examine your js to find out how something works, they can just define the SCRIPT_DEBUG = true and load the unminified version on the website. I was using it on one of my plugins, I can make a PR if you want to see an example

Missing alt tag in lightbox img

Hi Arno,

I appreciate the hard work you put into this and the frequent updates you provide.
We are currently putting some effort in SEO-optimizing our site. In the course of that we discovered a missing alt-tag for the image that opens inside the lightbox even though the alt-tag on the original image is set.

<img class="pswp__img" src="/path/to/img.jpg" style="display: block; width: 473px; height: 473px;">

Add filter and easier configuration for captions

At the moment the frontend script will add the caption based on several sources:

Attribute "data-caption-title" in link
Attribute "data-caption-desc" in link
Element "figcaption" if available in certain ways
Attribute "title" in link
Attribute "alt" in the image (if the backend option for this is enabled)
Attribute "data-description" in the link (if the backend option for this is enabled)
Attribute "data-exif" in the link (if the backend option for this is enabled)

In some cases users might want to have more control which of these sources are actually really used. So the backend should provide a list of all possible caption soures to enable/disable and maybe what should be added or overwrite others.

Add option to ignore links without thumbnails

During the removal of jQuery as dependency, the frontend script was also changed to use all links with lbwsp-attributes and not only those which contain an img element as child.

There may be usecases where you don't want to have plain links to an image to open with a lightbox. It should be possible to choose wether all links should be used or of text links without visible image should be ignored.

Cron task cleanupDatabase() causes warning if DB table not exist

Hi.

Exception message:
WordPress-Datenbank-Fehler Table 'colcms_tickets.tkt_lightbox_photoswipe_img' doesn't exist fΓΌr Abfrage DELETE FROM tkt_lightbox_photoswipe_img where created<("2020-04-12 15:39:32") von do_action_ref_array('lbwps_cleanup'), WP_Hook->do_action, WP_Hook->apply_filters, LightboxPhotoSwipe->cleanupDatabase

I've located the place at lightbox-photoswipe.php:1034

    function cleanupDatabase()
    {
        global $wpdb;

        $table_img = $wpdb->prefix . 'lightbox_photoswipe_img';
        $date = strftime('%Y-%m-%d %H:%M:%S', time()-86400);
        $sql = "DELETE FROM $table_img where created<(\"$date\")";
        $wpdb->query($sql);
    } 

I would suggest checking if table exists before executing db query like so:

    function cleanupDatabase()
    {
        global $wpdb;

        $table_img = $wpdb->prefix . 'lightbox_photoswipe_img';

        if ($wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $table_img ) ) === $table_img) {
            $date = strftime('%Y-%m-%d %H:%M:%S', time()-86400);
            $sql = "DELETE FROM $table_img where created<(\"$date\")";
            $wpdb->query($sql);
        }
    }  

every db connection causes UPDATE

I am digging in a performance issue with my mariadb lately and found this. It seems that your plugin is performing a UPDATE query along side every (? can't verify yet) regular UPDATE or at least every new connection coming in. I am not familiar with the wp_options table, but as far as my log goes, only the photoswipe plugin and the wp_statistics use it - out of a bunch of plugins.
Anyway. Can you confirm this is your intendend behaviour? And if so, is it really necessary to store the db_version, something really static, in a field which gets overwritten every couple of seconds?

EDIT: google helps with wp_options. Okay, I get it now, the value does not get overwritten every couple of seconds - but it gets reset to the same value every couple of seconds. The question is still, is this your intendend behaviour or something to fix.

Thanks for your work anyways πŸ‘

          3551 Query	UPDATE `wp_options` SET `option_value` = '24' WHERE `option_name` = 'lightbox_photoswipe_db_version'
	  3552 Query	UPDATE `wp_options` SET `option_value` = '24' WHERE `option_name` = 'lightbox_photoswipe_db_version'
	  3553 Query	UPDATE `wp_options` SET `option_value` = '24' WHERE `option_name` = 'lightbox_photoswipe_db_version'
	  3553 Query	UPDATE `wp_options` SET `option_value` = '1590480084' WHERE `option_name` = 'wp_statistics_check_useronline'
	  3554 Query	UPDATE `wp_options` SET `option_value` = '24' WHERE `option_name` = 'lightbox_photoswipe_db_version'
	  3554 Query	UPDATE `wp_options` SET `option_value` = '1590480085' WHERE `option_name` = 'wp_statistics_check_useronline'

Add support for videos

Also see https://wordpress.org/support/topic/is-it-possible-to-display-videos-youtube-in-the-lightbox/

According to https://photoswipe.com/documentation/custom-html-in-slides.html PhotoSwipe itself can also display HTML code and not just images so it would be possible to includes video elements on the page as well. However the frontend script only adds images to the gallery and videos would be a total different thing (different selector and additional handling to create the required HTML code for the video).

A problem which is not solved yet: how to open a lightbox for the video? When clicking inside a video frame, that click is sent to the server hosting the video and not any event handler of the frontend.

Handle DOM tree changes (images added via JavaScript)

There are websites which implement galleries which are not loaded completely in the beginning. Instead only a part is loaded and the remaining part gets added using Ajax and adding new images to the DOM tree dynamically when the user clicks a button "more pictures..." below the gallery.

However these new images are missing the event handler for mouse clicks or taps since the handler is only added once after the page has been loaded using lbwpsInit();. A hack for this is to call the initialization again after the DOM tree was changed:

if (typeof lbwpsInit !== 'undefined') {
    lbwpsInit();
}

Unfortunately this will add the event handler to existing image links again. This usually is not a big problem since the event handler calls event.preventDefault(); to cancel all other handlers, but a better way would be to implement an additional handler for DOM tree changes so this hack is not needed.

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.