diff --git a/.github/workflows/build_deploy.yml b/.github/workflows/build_deploy.yml new file mode 100644 index 000000000..b1cfe08c3 --- /dev/null +++ b/.github/workflows/build_deploy.yml @@ -0,0 +1,46 @@ + +name: Build and deploy training documentation to training.plone.org + +on: + push: + branches: + - 'master' + +jobs: + build_deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: 3.8 + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -q -r requirements.txt -c constraints.txt + + - name: Run tests with make test + run: | + make test + + - name: Prepare deploy + run: | + make deploy + + - name: Deploy to server + id: deploy + uses: Pendect/action-rsyncer@v1.1.0 + env: + DEPLOY_KEY: ${{secrets.DEPLOY_KEY_TRAINING}} + with: + flags: '-avzr --delete' + options: '' + ssh_options: '-p ${{secrets.DEPLOY_PORT}}' + src: '_build/html/' + dest: '${{secrets.DEPLOY_USER_TRAINING}}@${{secrets.DEPLOY_SERVER_TRAINING}}:${{secrets.DEPLOY_PATH_TRAINING}}/5' + + - name: Display status from deploy + run: echo "${{ steps.deploy.outputs.status }}" \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 000000000..39ee738eb --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,27 @@ + +name: Test training documentation + +on: + push: + branches-ignore: + - 'master' + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: 3.8 + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -q -r requirements.txt -c constraints.txt + + - name: Run tests with make test + run: | + make test diff --git a/.gitignore b/.gitignore index c61f0230c..c93e9fe02 100644 --- a/.gitignore +++ b/.gitignore @@ -11,10 +11,16 @@ bin/ build/ include/ lib/ -lib64 +lib64/ local/ -pip-selfcheck.json plone_training_config/training/ presentation/ log/ +node_modules/ +/pip-selfcheck.json +/pyvenv.cfg /training.sublime-workspace +/.idea +.python-version +package-lock.json +.vscode/settings.json diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 392ade1a3..000000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "ploneconf.site_sneak"] - path = ploneconf.site_sneak - url = https://github.com/collective/ploneconf.site_sneak.git diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 99adabebc..000000000 --- a/.travis.yml +++ /dev/null @@ -1,22 +0,0 @@ -branches: - only: - - master -sudo: false -language: python -addons: - apt: - packages: - - enchant -python: -- '2.7' -install: -- pip install -q -r requirements.txt -script: - - make test - - make deploy -before_install: -- echo -e "Host docs.plone.org\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config -- openssl aes-256-cbc -K $encrypted_129e1d4a0f4f_key -iv $encrypted_129e1d4a0f4f_iv - -in deploy_key.enc -out $HOME/.ssh/id_rsa -d -after_success: -- "./deploy.sh" diff --git a/CHANGES.rst b/CHANGES.rst index 57b1a7b06..3fe38c3ca 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,7 +5,30 @@ This changelog is only very rough. For the full changelog please refer to https: 1.2.5 (unreleased) ------------------ -======= + +- Language tweaks to WSGI training [polyester] + +- Minor fixes, like using implementer and provider decorators [jensens] + +- Use behavior shortnames as best practice. [jensens] + +- Refine misleading explanation of IFormFieldProvider [jensens] + +- Tweaks to Mastering Plone testing page [tkimnguyen] + +- Fix React and Volto bootstrapping information. [jensens] + +- Fix a typo in Volto redux section and format according to style guide. [jensens] + +- Fix AGX links. [jensens] + +- Get rid of Grok, it is dead. No need any more to mention it here [jensens] + +- Fix a bunch of errors and links-check failure popping up in ``make test`` [jensens] + +- Fix Travis setup, use stages now. See #410. [jensens] + +- Explanation about less variables and development/production mode in the theming training first chapter. [fredvd] - Fixes to Advanced Python Training [oz123] @@ -175,6 +198,9 @@ This changelog is only very rough. For the full changelog please refer to https: - Add support for translations on transifex [macagua] +- Upgrade Vagrant setup to Ubuntu 18.04 LTS + [tschorr] + 1.2.3 (2014-07-11) ------------------ diff --git a/Makefile b/Makefile index d3c235906..fbad018a9 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,8 @@ ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +all: build + .PHONY: help help: @echo "Please use \`make ' where is one of" @@ -46,6 +48,13 @@ help: clean: -rm -rf $(BUILDDIR)/* +bin/python bin/pip: + python3 -m venv . || virtualenv --clear --python=python3 . + +.PHONY: build +build: bin/pip + bin/pip install -r requirements.txt + .PHONY: html html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @@ -192,7 +201,7 @@ doctest: "results in $(BUILDDIR)/doctest/output.txt." .PHONY: test -test: clean linkcheck +test: clean .PHONY: deploy deploy: clean html diff --git a/README.rst b/README.rst index 841dc43f8..f4b04eeca 100644 --- a/README.rst +++ b/README.rst @@ -1,3 +1,6 @@ +.. image:: https://travis-ci.com/plone/training.svg?branch=master + :target: https://travis-ci.com/plone/training + ======== Training ======== @@ -5,7 +8,7 @@ Training `Training `_ is a collection of different trainings, developed and created by the Plone Community. -For a HTML version, please browse to our `Training Website `_. +For a HTML version, please browse to our `Training Website `_. Overview ======== @@ -13,7 +16,7 @@ Overview Different Plone Trainings: - `How to work with content and manage site settings in Plone. `_ -- `How to get you Plone site up and running. `_ +- `How to get your Plone site up and running. `_ - `How to develop customized solutions with Plone. `_ - `How to add enterprise grade search to your Plone site. `_ - `How to style your Plone site. `_ @@ -22,7 +25,14 @@ Different Plone Trainings: Documentation ============= -Documentation on how to use, build and contribute to the trainings can be found on the `About page `_ at Training Website. +Documentation on how to use, build and contribute to the trainings can be found on the `Training Website `_ . + + +The landing page +================ + +The code for the landing page at https://training.plone.org is in another repository: https://github.com/plone/training.plone.org. + Contribute ========== diff --git a/_locales/addons.pot b/_locales/addons.pot new file mode 100644 index 000000000..691854a68 --- /dev/null +++ b/_locales/addons.pot @@ -0,0 +1,488 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) The text and illustrations in this website are licensed by the Plone Foundation under a Creative Commons Attribution 4.0 International license. +# This file is distributed under the same license as the Mastering Plone package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Mastering Plone 1.2.3\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-07-28 20:53-0430\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../addons.rst:2 +# 77b58025b3fc49fc90685e42dacac7ce +msgid "Extend Plone with Add-ons" +msgstr "" + +#: ../addons.rst:4 +# 4359c4b3b0a646f1981df667beac4a3a +msgid "There are more than 2000 addons for Plone. We will cover only a handfull today." +msgstr "" + +#: ../addons.rst:5 +# 66c523e1318c4c2d84f5cf48df5c7c11 +msgid "Using them can saves a lot of time" +msgstr "" + +#: ../addons.rst:6 +# 817f9426cdbe476e8ddd0dfc5caaae5e +msgid "The success of a project often depends on finding the right addon" +msgstr "" + +#: ../addons.rst:7 +# 0cbf88ea3f7d458a9d974fdd0d0e52ec +msgid "Their use, usefulness, quality and complexity varies a lot" +msgstr "" + +#: ../addons.rst:11 +# f9cdec03b6de4fcbaba4360b67ebedb2 +msgid "How to find addons" +msgstr "" + +#: ../addons.rst:13 +# 3e5efa80b353427cbe1d4fcd430a7f1f +msgid "https://pypi.python.org/pypi - use the search form!" +msgstr "" + +#: ../addons.rst:14 +# 4513eb4098124a84bd44000616e33239 +msgid "https://github.com/collective >1200 repos" +msgstr "" + +#: ../addons.rst:15 +# bf7661b7b7a84a6b9d42086ab4ee661a +msgid "https://github.com/plone >260 repos" +msgstr "" + +#: ../addons.rst:16 +# 742ee14a9b944759a7e4877239d466cf +msgid "http://news.gmane.org/gmane.comp.web.zope.plone.user" +msgstr "" + +#: ../addons.rst:17 +# 2073228af2534d02ac5e1cd03836d27a +msgid "google (e.g. `Plone+Slider `_)" +msgstr "" + +#: ../addons.rst:18 +# 44b928fa38b04b80a2d579ad3d643fc3 +msgid "Check shortlist (Plone Paragon) that will come in 2014 on plone.org" +msgstr "" + +#: ../addons.rst:19 +# 5199a166753e495099cf623a627a9e2f +msgid "ask in irc and on the mailing list" +msgstr "" + +#: ../addons.rst:23 +# 84fe0f9926bd4c01bd7d52ddde34a1ea +msgid "A talk on finding and managing addons: http://www.youtube.com/watch?v=Sc6NkqaSjqw" +msgstr "" + +#: ../addons.rst:27 +# 554b30c8681244e6a536143b54107182 +msgid "Some noteable addons" +msgstr "" + +#: ../addons.rst:30 +# 16e25707739940cd9218f172ffbdb708 +msgid "`Products.PloneFormGen `_" +msgstr "" + +#: ../addons.rst:30 +# faec4eb14e824339aeb11b2285108ec7 +msgid "A form generator" +msgstr "" + +#: ../addons.rst:33 +# f445ec2850bc4fb49f3202c48f9bf0d6 +msgid "`collective.plonetruegallery `_" +msgstr "" + +#: ../addons.rst:33 +# e8ea29be05444865bae23aa367e1085e +msgid "Photo galleries with a huge selection of various js-libraries" +msgstr "" + +#: ../addons.rst:36 +# 5e175089ee0c43569ce85f06907644f8 +msgid "`collective.cover `_" +msgstr "" + +#: ../addons.rst:36 +# 8a059255065b4edc9f5fc8be56f41c32 +msgid "UI to create complex landing-pages" +msgstr "" + +#: ../addons.rst:39 +# c65edef34db148fc81b22bbb534dc916 +msgid "`collective.geo `_" +msgstr "" + +#: ../addons.rst:39 +# a2036b80cb8f458a97bbda229b91cd3c +msgid "Flexible bundle of addons to georeference content and display in maps" +msgstr "" + +#: ../addons.rst:42 +# de4a41385fdf4266ae0fd418c5f5d0f4 +msgid "`collective.mailchimp `_" +msgstr "" + +#: ../addons.rst:42 +# a831c9ef7e01403992e2d6210301dfda +msgid "Allows visitors to subcribe to mailchimp newsletters" +msgstr "" + +#: ../addons.rst:45 +# 8a3bdbb45fd240fea1e431907ecaf973 +msgid "`eea.facetednavigation `_" +msgstr "" + +#: ../addons.rst:45 +# b298866dc64843c291725b1b6ed33485 +msgid "Create faceted navigation and searches through the web." +msgstr "" + +#: ../addons.rst:48 +# dbe1d01d6fa8441db6ffce28690bc196 +msgid "`webcouturier.dropdownmenu `_" +msgstr "" + +#: ../addons.rst:48 +# 2d185be58b4248059cbd93d09d90e390 +msgid "Turns global navigation into dropdowns" +msgstr "" + +#: ../addons.rst:51 +# e6825aaa1c354d6780f8f76f190de910 +msgid "`collective.quickupload `_" +msgstr "" + +#: ../addons.rst:51 +# 3c967773f4fa44bd8bfc3d2166c3fbae +msgid "Multi-file upload using drag&drop" +msgstr "" + +#: ../addons.rst:54 +# 5fa8b08f89fd4816bb23845c65414338 +msgid "`Products.Doormat `_" +msgstr "" + +#: ../addons.rst:54 +# b79245797c414659a82adf1c8ee941f2 +msgid "A flexible doormat" +msgstr "" + +#: ../addons.rst:57 +# b3c5aa07d3944278ba2d41b9925a624a +msgid "`collective.behavior.banner `_" +msgstr "" + +#: ../addons.rst:57 +# 8ab50455391744ea9fd681ee58886e97 +msgid "Add decorative banners and sliders" +msgstr "" + +#: ../addons.rst:60 +# ccaf85e29e474d09accf749e9cc3e4a4 +msgid "`plone.app.multilingual `_" +msgstr "" + +#: ../addons.rst:60 +# 7fff1778d4fa46228d34333343ed53b6 +msgid "Allows multilingual sites by translating content" +msgstr "" + +#: ../addons.rst:65 +# 35a511db8722434ba596e944373a5aa4 +msgid "`Plomino `_" +msgstr "" + +#: ../addons.rst:63 +# 5c3c7203c69247a9b33ced99b5b35cbc +msgid "Powerful and flexible web-based application builder for Plone" +msgstr "" + +#: ../addons.rst:68 +# d7fbdc887dba49eb80bba68435b6a4e2 +msgid "Installing Addons" +msgstr "" + +#: ../addons.rst:70 +# fcfc9a38f1d3480db3d2685907d146fc +msgid "Installation is a two-step process." +msgstr "" + +#: ../addons.rst:73 +# 50cf6bcc9a48499193a7bd8b4f4a3348 +msgid "Making the addons code available to Zope" +msgstr "" + +#: ../addons.rst:75 +# 40ce9f190e37463d8bffc7a077b388bd +msgid "First, we must make the addons code available to Zope. This means, that Zope can import the code. Buildout is responsible for this." +msgstr "" + +#: ../addons.rst:77 +# e750e0aa7c024f428b76e07a6f94d9b4 +msgid "Look at ``buildout.cfg`` file in ``/vagrant/buildout``." +msgstr "" + +#: ../addons.rst:79 +# eaa227d8b5684f96bc61d18a4f1850c6 +msgid "In the section ``[instance]`` there is a variable called ``eggs``, which has multiple *eggs* as a value. Add the following eggs:" +msgstr "" + +#: ../addons.rst:81 +# 8f8286c52c884d4aa0d1bd88bd3d21f8 +msgid "We already have added the addons that we will use now:" +msgstr "" + +#: ../addons.rst:83 +# 3924889e61ce45a1bfb30ee4d9ca8ccc +msgid "``Products.PloneFormGen``" +msgstr "" + +#: ../addons.rst:84 +# 3d886d46bb8c489883324f4732173b95 +msgid "``collective.plonetruegallery``" +msgstr "" + +#: ../addons.rst:86 +# 0b62a9f33a544afda75ed1889d3b3ca9 +msgid "Usually, one enters the eggs by adding one more line per egg into the configuration. You must write the egg name indented, this way buildout understands that the current line is part of the last variable and not a new variable." +msgstr "" + +#: ../addons.rst:88 +# c24d12ce1d2e4064984275219db20891 +msgid "If you add new addons here you will have to run buildout and restart the site:" +msgstr "" + +#: ../addons.rst:95 +# d94699058d87469b9cc34c2b72e398ed +msgid "Now the code is importable from within Plone and everything got registered via ZCML." +msgstr "" + +#: ../addons.rst:98 +# 626c79f4313a4b45b8d97a381ef0954d +msgid "Installing addons in your Plone Site" +msgstr "" + +#: ../addons.rst:100 +# ad4532f1e8044f2ab9cb32131c2181af +msgid "Your Plone-site has not yet been told to use the addon. For this, you have to install the addons in your Plone Site." +msgstr "" + +#: ../addons.rst:102 +# 5543b3a4631b426dbc0b8599688a25ce +msgid "In your browser, go the control panel ``@@plone_control_panel``, and open the ``Addons`` Panel. You will see that you can install the addons there." +msgstr "" + +#: ../addons.rst:104 +# 55d25c9765c2424d9527e9b8c69ad167 +msgid "Install **PloneFormGen** and **Plone True Gallery** them now." +msgstr "" + +#: ../addons.rst:106 +# 53549fb25bf8493ca59a1e31361c7da1 +msgid "This is what happens: The GenericSetup profile of the product gets loaded. This does things like:" +msgstr "" + +#: ../addons.rst:108 +# e3656bbf2a264935b1f32b3e41049e5c +msgid "configuring new actions," +msgstr "" + +#: ../addons.rst:109 +# dd3c0cdd81b3460d93d676a8b6c3fdf3 +msgid "registering new content types" +msgstr "" + +#: ../addons.rst:110 +# 52a0775f31144fec9c19a984dd7cdca7 +msgid "registering css- and js-files" +msgstr "" + +#: ../addons.rst:111 +# c3d7802afcf445029a9764dcc4ee7180 +msgid "creating some content/configuration objects in your Plone site." +msgstr "" + +#: ../addons.rst:113 +# 75b2e0ece010472484269eb93997088f +msgid "Let' have a look at what we just installed." +msgstr "" + +#: ../addons.rst:117 +# de4e3278dcab4997814437008b78fc7b +msgid "PloneFormGen" +msgstr "" + +#: ../addons.rst:119 +# a181acd69b3c4c86b340382f36a7a5ba +msgid "Creating forms in Plone:" +msgstr "" + +#: ../addons.rst:121 +# c3e7a78504ce4caa909d762f66e66fda +msgid "pure: html and python in a view" +msgstr "" + +#: ../addons.rst:122 +# 391adca4637b4c69a2764c310aa976ca +msgid "framework: z3c.form, formlib, deform" +msgstr "" + +#: ../addons.rst:123 +# afadbfca9b4b4d75ae4a28976662d1cd +msgid "ttw: Products.PloneFormGen" +msgstr "" + +#: ../addons.rst:125 +# bc6b9d124d294afaa05cc964c2a742e8 +msgid "Registration-form:" +msgstr "" + +#: ../addons.rst:127 +# e1d1687e67a8421fbdac27138c83633d +msgid "Add a object of the new type 'Form Folder' in the site-root. Call it \"Registration\"" +msgstr "" + +#: ../addons.rst:128 +# d8a6f7edc558475c88e2a02235c3712b +msgid "Save and view the result" +msgstr "" + +#: ../addons.rst:129 +# 7582fe6ee72a40b1ac5ad1fa7c92aad8 +msgid "Click in QuickEdit" +msgstr "" + +#: ../addons.rst:130 +# 1f9d533881a946b781938084a1fa7b58 +msgid "Remove field \"Subject\"" +msgstr "" + +#: ../addons.rst:131 +# d68888eacda24e719a777b42c23fa354 +msgid "Add fields for food-preference and shirt-size" +msgstr "" + +#: ../addons.rst:132 +# 2cae5be81c1a461b8019b05e0d7ce320 +msgid "Add a DataSave Adapter" +msgstr "" + +#: ../addons.rst:136 +# ed3103ea787149c08255a26403f016b3 +msgid "Add Photogallery with collective.plonetruegallery" +msgstr "" + +#: ../addons.rst:138 +# 38a7686b83024dcd90e6c004a88c7894 +msgid "To advertice the conference we want to show some photos showing past conferences and the city where conference is taking place in." +msgstr "" + +#: ../addons.rst:140 +# a4099a84155a48cd9d5bd73dac4ac318 +msgid "collective.plonetruegallery is a role model on how to write a Plone Extension." +msgstr "" + +#: ../addons.rst:142 +# a270fc9bec3e4b4fb62da1d361b161bf +msgid "Instead of creating custom content types for galleries, it integrates with the Plone functionality to choose different views for folderish content types." +msgstr "" + +#: ../addons.rst:144 +# f5833f4282054a8c99def66bf888b75b +msgid "https://pypi.python.org/pypi/collective.plonetruegallery" +msgstr "" + +#: ../addons.rst:146 +# 6c1fef2557944cada2daec028031fe02 +msgid "Install the addon: http://localhost:8080/Plone/prefs_install_products_form" +msgstr "" + +#: ../addons.rst:147 +# 4f581df745934e52aa5440e8f852ed11 +msgid "Enable the behavior ``Plone True Gallery`` on the type ``Folder``: http://localhost:8080/Plone/dexterity-types/Folder/@@behaviors" +msgstr "" + +#: ../addons.rst:148 +# 84321e1513d44a2585d9212b3f9aece0 +msgid "Add a folder /the-event/location" +msgstr "" + +#: ../addons.rst:149 +# 0463f45ed3504a12bcbd3231902e737f +msgid "Upload some fotos from http://lorempixel.com/600/400/city/" +msgstr "" + +#: ../addons.rst:150 +# 94090a65a1af4e2dbde6b0d548689124 +msgid "Enable the view ``galleryview``" +msgstr "" + +#: ../addons.rst:154 +# 2fe98249ae064d12987c6ab1c81fd79f +msgid "Internationalisation" +msgstr "" + +#: ../addons.rst:156 +# 5518a88e461d467b9ef8c21faf45be58 +msgid "Plone can run the same site in many different languages." +msgstr "" + +#: ../addons.rst:158 +# 2f3138dbea80436eb6e0bcfb478e7943 +msgid "We're not doing this with the conference-site since the lingua franca of the plone-community is english." +msgstr "" + +#: ../addons.rst:160 +# 7272b4da294c4a34bcf531f43f5321b7 +msgid "We would use http://pypi.python.org/pypi/plone.app.multilingual for this. It is the successor of Products.LinguaPlone (which only works with Archetypes)." +msgstr "" + +#: ../addons.rst:164 +# 08a250046961417c919c07f40320349f +msgid "Summary" +msgstr "" + +#: ../addons.rst:166 +# a2aa3127a8c948478dd8b08582b7bf78 +msgid "We are now able to customize and extend many parts of our website. We can even install extensions that add new functionality." +msgstr "" + +#: ../addons.rst:168 +# bfb1596948b543e698651206ab4619bc +msgid "But:" +msgstr "" + +#: ../addons.rst:170 +# 392863bf1aa54a76a25e4ae7b5dc1fa4 +msgid "Can we submit talks now?" +msgstr "" + +#: ../addons.rst:171 +# 0f58b69cc2984a589f0c6187c18c5a09 +msgid "Can we create lists with the most important properties of each tasks?" +msgstr "" + +#: ../addons.rst:172 +# 61c986edc6c54336922106716d7b9476 +msgid "Can we allow a jury to vote on talks?" +msgstr "" + +#: ../addons.rst:174 +# 2d074ec67aad4cdd96696841440533cf +msgid "We often have to work with structured data. Up to a degree we can do all this TTW, but at some point we reach barriers. In the next part of the training, we'll teach you, how to break through these barriers." +msgstr "" + diff --git a/_locales/es/LC_MESSAGES/addons.po b/_locales/es/LC_MESSAGES/addons.po new file mode 100644 index 000000000..7e3b33308 --- /dev/null +++ b/_locales/es/LC_MESSAGES/addons.po @@ -0,0 +1,553 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) The text and illustrations in this website are licensed by the Plone Foundation under a Creative Commons Attribution 4.0 International license. +# This file is distributed under the same license as the Mastering Plone package. +# +# Translators: +# Carlos J Morales G. , 2014 +# Carlos J Morales G. , 2014 +# Leonardo J. Caballero G. , 2014 +msgid "" +msgstr "" +"Project-Id-Version: Mastering Plone Training\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-07-16 08:09-0430\n" +"PO-Revision-Date: 2014-07-16 12:46+0000\n" +"Last-Translator: Leonardo J. Caballero G. \n" +"Language-Team: Spanish (http://www.transifex.com/projects/p/mastering-plone-training/language/es/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: es\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +# 77b58025b3fc49fc90685e42dacac7ce +#: ../addons.rst:2 +msgid "Extend Plone with Add-ons" +msgstr "Extiende Plone con Complementos" + +# 4359c4b3b0a646f1981df667beac4a3a +#: ../addons.rst:4 +msgid "" +"There are more than 2000 addons for Plone. We will cover only a handfull " +"today." +msgstr "Hay mas de 2000 Complementos para Plone. Cubriremos solamente una porción de ellos." + +# 66c523e1318c4c2d84f5cf48df5c7c11 +#: ../addons.rst:5 +msgid "Using them can saves a lot of time" +msgstr "Usándolos puedes ahorrarte mucho tiempo" + +# 817f9426cdbe476e8ddd0dfc5caaae5e +#: ../addons.rst:6 +msgid "The success of a project often depends on finding the right addon" +msgstr "El éxito del proyecto a veces depende en encontrar el complemento adecuado" + +# 0cbf88ea3f7d458a9d974fdd0d0e52ec +#: ../addons.rst:7 +msgid "Their use, usefulness, quality and complexity varies a lot" +msgstr "Su uso, utilidad, calidad y complejidad varia mucho" + +# f9cdec03b6de4fcbaba4360b67ebedb2 +#: ../addons.rst:11 +msgid "How to find addons" +msgstr "Como encontrar complementos" + +# 3e5efa80b353427cbe1d4fcd430a7f1f +#: ../addons.rst:13 +msgid "https://pypi.python.org/pypi - use the search form!" +msgstr "https://pypi.python.org/pypi - ¡Use el Formulario de Búsqueda!" + +# 4513eb4098124a84bd44000616e33239 +#: ../addons.rst:14 +msgid "https://github.com/collective >1200 repos" +msgstr "https://github.com/collective > 1200 repositorios" + +# bf7661b7b7a84a6b9d42086ab4ee661a +#: ../addons.rst:15 +msgid "https://github.com/plone >260 repos" +msgstr "https://github.com/plone > 260 repositorios" + +# 742ee14a9b944759a7e4877239d466cf +#: ../addons.rst:16 +msgid "http://news.gmane.org/gmane.comp.web.zope.plone.user" +msgstr "http://news.gmane.org/gmane.comp.web.zope.plone.user" + +# 2073228af2534d02ac5e1cd03836d27a +#: ../addons.rst:17 +msgid "google (e.g. `Plone+Slider `_)" +msgstr "google (por ejemplo `Plone+Slider `_)" + +# 44b928fa38b04b80a2d579ad3d643fc3 +#: ../addons.rst:18 +msgid "Check shortlist (Plone Paragon) that will come in 2014 on plone.org" +msgstr "Revisa la lista corta (Plone Paragon) que vendrá en el 2014 en plone.org" + +# 5199a166753e495099cf623a627a9e2f +#: ../addons.rst:19 +msgid "ask in irc and on the mailing list" +msgstr "Pregunta en el canal irc y la lista de correo" + +# 84fe0f9926bd4c01bd7d52ddde34a1ea +#: ../addons.rst:23 +msgid "" +"A talk on finding and managing addons: " +"http://www.youtube.com/watch?v=Sc6NkqaSjqw" +msgstr "Una conversación sobre encontrar y administrar complementos: http://www.youtube.com/watch?v=Sc6NkqaSjqw" + +# 554b30c8681244e6a536143b54107182 +#: ../addons.rst:27 +msgid "Some noteable addons" +msgstr "Algunos complementos notables" + +# 16e25707739940cd9218f172ffbdb708 +#: ../addons.rst:30 +msgid "" +"`Products.PloneFormGen " +"`_" +msgstr "`Products.PloneFormGen `_" + +# faec4eb14e824339aeb11b2285108ec7 +#: ../addons.rst:30 +msgid "A form generator" +msgstr "Un generador de formularios" + +# f445ec2850bc4fb49f3202c48f9bf0d6 +#: ../addons.rst:33 +msgid "" +"`collective.plonetruegallery " +"`_" +msgstr "`collective.plonetruegallery `_" + +# e8ea29be05444865bae23aa367e1085e +#: ../addons.rst:33 +msgid "Photo galleries with a huge selection of various js-libraries" +msgstr "Galerías de fotos con una gran selección de varios librerías javascript" + +# 5e175089ee0c43569ce85f06907644f8 +#: ../addons.rst:36 +msgid "" +"`collective.cover " +"`_" +msgstr "`collective.cover `_" + +# 8a059255065b4edc9f5fc8be56f41c32 +#: ../addons.rst:36 +msgid "UI to create complex landing-pages" +msgstr "Interfaz para crear paginas de inicios complejas" + +# c65edef34db148fc81b22bbb534dc916 +#: ../addons.rst:39 +msgid "`collective.geo `_" +msgstr "`collective.geo `_" + +# a2036b80cb8f458a97bbda229b91cd3c +#: ../addons.rst:39 +msgid "Flexible bundle of addons to georeference content and display in maps" +msgstr "Paquete flexible de complementos para georeferenciar contenido y mostrar mapas" + +# de4a41385fdf4266ae0fd418c5f5d0f4 +#: ../addons.rst:42 +msgid "" +"`collective.mailchimp `_" +msgstr "`collective.mailchimp `_" + +# a831c9ef7e01403992e2d6210301dfda +#: ../addons.rst:42 +msgid "Allows visitors to subcribe to mailchimp newsletters" +msgstr "Permite a los visitantes suscribirse a noticias Mailchimp" + +# 8a3bdbb45fd240fea1e431907ecaf973 +#: ../addons.rst:45 +msgid "" +"`eea.facetednavigation " +"`_" +msgstr "`eea.facetednavigation `_" + +# b298866dc64843c291725b1b6ed33485 +#: ../addons.rst:45 +msgid "Create faceted navigation and searches through the web." +msgstr "Crear la navegación facetada y búsquedas a través de la web." + +# dbe1d01d6fa8441db6ffce28690bc196 +#: ../addons.rst:48 +msgid "" +"`webcouturier.dropdownmenu " +"`_" +msgstr "`webcouturier.dropdownmenu `_" + +# 2d185be58b4248059cbd93d09d90e390 +#: ../addons.rst:48 +msgid "Turns global navigation into dropdowns" +msgstr "Convierte la navegación global en menú desplegables" + +# e6825aaa1c354d6780f8f76f190de910 +#: ../addons.rst:51 +msgid "" +"`collective.quickupload " +"`_" +msgstr "`collective.quickupload `_" + +# 3c967773f4fa44bd8bfc3d2166c3fbae +#: ../addons.rst:51 +msgid "Multi-file upload using drag&drop" +msgstr "Subida de múltiples archivos usando el concepto drag & drop" + +# 5fa8b08f89fd4816bb23845c65414338 +#: ../addons.rst:54 +msgid "`Products.Doormat `_" +msgstr "`Products.Doormat `_" + +# b79245797c414659a82adf1c8ee941f2 +#: ../addons.rst:54 +msgid "A flexible doormat" +msgstr "Un flexible pie de pagina basado en el patrón de diseño doormat" + +# b3c5aa07d3944278ba2d41b9925a624a +#: ../addons.rst:57 +msgid "" +"`collective.behavior.banner " +"`_" +msgstr "`collective.behavior.banner `_" + +# 8ab50455391744ea9fd681ee58886e97 +#: ../addons.rst:57 +msgid "Add decorative banners and sliders" +msgstr "Agrega banners decorativos y pasarelas" + +# ccaf85e29e474d09accf749e9cc3e4a4 +#: ../addons.rst:60 +msgid "" +"`plone.app.multilingual " +"`_" +msgstr "`plone.app.multilingual `_" + +# 7fff1778d4fa46228d34333343ed53b6 +#: ../addons.rst:60 +msgid "Allows multilingual sites by translating content" +msgstr "Permite sitios multilingues mediante la traducción de contenido" + +# 35a511db8722434ba596e944373a5aa4 +#: ../addons.rst:65 +msgid "`Plomino `_" +msgstr "`Plomino `_" + +# 5c3c7203c69247a9b33ced99b5b35cbc +#: ../addons.rst:63 +msgid "Powerful and flexible web-based application builder for Plone" +msgstr "Un poderoso y flexible constructor de aplicaciones basado en Web para Plone" + +# d7fbdc887dba49eb80bba68435b6a4e2 +#: ../addons.rst:68 +msgid "Installing Addons" +msgstr "Instalando complementos" + +# fcfc9a38f1d3480db3d2685907d146fc +#: ../addons.rst:70 +msgid "Installation is a two-step process." +msgstr "La instalación es un proceso de dos pasos." + +# 50cf6bcc9a48499193a7bd8b4f4a3348 +#: ../addons.rst:73 +msgid "Making the addons code available to Zope" +msgstr "Haciendo el código de los complementos disponibles para Zope" + +# 40ce9f190e37463d8bffc7a077b388bd +#: ../addons.rst:75 +msgid "" +"First, we must make the addons code available to Zope. This means, that Zope" +" can import the code. Buildout is responsible for this." +msgstr "Primero, debemos hacer el código de los complementos disponible para Zope, Buildout es responsable de esto." + +# e750e0aa7c024f428b76e07a6f94d9b4 +#: ../addons.rst:77 +msgid "Look at ``buildout.cfg`` file in ``/vagrant/buildout``." +msgstr "Busca el archivo ``buildout.cfg`` en ``/vagrant/buildout``." + +# eaa227d8b5684f96bc61d18a4f1850c6 +#: ../addons.rst:79 +msgid "" +"In the section ``[instance]`` there is a variable called ``eggs``, which has" +" multiple *eggs* as a value. Add the following eggs:" +msgstr "En la sección ``[instance]`` existe una variable llamada ``eggs``, la cual tiene múltiples *eggs* como valor. Agrega los siguientes eggs:" + +# 8f8286c52c884d4aa0d1bd88bd3d21f8 +#: ../addons.rst:81 +msgid "We already have added the addons that we will use now:" +msgstr "Ya hemos agregado los complementos que usaras ahora:" + +# 3924889e61ce45a1bfb30ee4d9ca8ccc +#: ../addons.rst:83 +msgid "``Products.PloneFormGen``" +msgstr "``Products.PloneFormGen``" + +# 3d886d46bb8c489883324f4732173b95 +#: ../addons.rst:84 +msgid "``collective.plonetruegallery``" +msgstr "``collective.plonetruegallery``" + +# 0b62a9f33a544afda75ed1889d3b3ca9 +#: ../addons.rst:86 +msgid "" +"Usually, one enters the eggs by adding one more line per egg into the " +"configuration. You must write the egg name indented, this way buildout " +"understands that the current line is part of the last variable and not a new" +" variable." +msgstr "Generalmente, uno ingresa los paquetes eggs agregando una linea adicional por paquete egg en la configuración, Debes escribir el nombre del paquete egg de forma indentada, así el buildout entiende que la linea actual es parte de la ultima variable y no una nueva variable." + +# c24d12ce1d2e4064984275219db20891 +#: ../addons.rst:88 +msgid "" +"If you add new addons here you will have to run buildout and restart the " +"site:" +msgstr "Si agregas nuevos complementos tendrás que ejecutar buildout y reiniciar el sitio:" + +# d94699058d87469b9cc34c2b72e398ed +#: ../addons.rst:95 +msgid "" +"Now the code is importable from within Plone and everything got registered " +"via ZCML." +msgstr "Ahora el código es importable dentro de Plone y todo ha quedado registrado vía ZCML." + +# 626c79f4313a4b45b8d97a381ef0954d +#: ../addons.rst:98 +msgid "Installing addons in your Plone Site" +msgstr "Instalando complementos en tu sitio de Plone" + +# ad4532f1e8044f2ab9cb32131c2181af +#: ../addons.rst:100 +msgid "" +"Your Plone-site has not yet been told to use the addon. For this, you have " +"to install the addons in your Plone Site." +msgstr "Tu sitio de Plone no ha sido especificado para usar el complemento. Para esto debes instalar los complementos en tu sitio de Plone." + +# 5543b3a4631b426dbc0b8599688a25ce +#: ../addons.rst:102 +msgid "" +"In your browser, go the control panel ``@@plone_control_panel``, and open " +"the ``Addons`` Panel. You will see that you can install the addons there." +msgstr "En su navegador Web, ve a panel de control ``@@plone_control_panel``, y abre el panel de ``Complementos``. Usted vera que puedes instalar los complementos desde allí." + +# 55d25c9765c2424d9527e9b8c69ad167 +#: ../addons.rst:104 +msgid "Install **PloneFormGen** and **Plone True Gallery** them now." +msgstr "Instala **PloneFormGen** y **Plone True Gallery** ahora." + +# 53549fb25bf8493ca59a1e31361c7da1 +#: ../addons.rst:106 +msgid "" +"This is what happens: The GenericSetup profile of the product gets loaded. " +"This does things like:" +msgstr "Esto es lo que sucede: el perfil GenericSetup del producto se ha cargado. esto hace cosas como:" + +# e3656bbf2a264935b1f32b3e41049e5c +#: ../addons.rst:108 +msgid "configuring new actions," +msgstr "Configurando nuevas acciones," + +# dd3c0cdd81b3460d93d676a8b6c3fdf3 +#: ../addons.rst:109 +msgid "registering new content types" +msgstr "Registrando nuevos tipos de contenido" + +# 52a0775f31144fec9c19a984dd7cdca7 +#: ../addons.rst:110 +msgid "registering css- and js-files" +msgstr "Registrando archivos css y javascripts" + +# c3d7802afcf445029a9764dcc4ee7180 +#: ../addons.rst:111 +msgid "creating some content/configuration objects in your Plone site." +msgstr "Creando algunos objetos contenidos / configuración en tu sitio de Plone." + +# 75b2e0ece010472484269eb93997088f +#: ../addons.rst:113 +msgid "Let' have a look at what we just installed." +msgstr "Observe lo que ha instalado." + +# de4e3278dcab4997814437008b78fc7b +#: ../addons.rst:117 +msgid "PloneFormGen" +msgstr "PloneFormGen" + +# a181acd69b3c4c86b340382f36a7a5ba +#: ../addons.rst:119 +msgid "Creating forms in Plone:" +msgstr "Creando formularios en Plone:" + +# c3e7a78504ce4caa909d762f66e66fda +#: ../addons.rst:121 +msgid "pure: html and python in a view" +msgstr "puro: html y python en una vista" + +# 391adca4637b4c69a2764c310aa976ca +#: ../addons.rst:122 +msgid "framework: z3c.form, formlib, deform" +msgstr "usando framework: z3c.form, formlib, deform" + +# afadbfca9b4b4d75ae4a28976662d1cd +#: ../addons.rst:123 +msgid "ttw: Products.PloneFormGen" +msgstr "a través de la web: Products.PloneFormGen" + +# bc6b9d124d294afaa05cc964c2a742e8 +#: ../addons.rst:125 +msgid "Registration-form:" +msgstr "Formulario de registro:" + +# e1d1687e67a8421fbdac27138c83633d +#: ../addons.rst:127 +msgid "" +"Add a object of the new type 'Form Folder' in the site-root. Call it " +"\"Registration\"" +msgstr "Agrega un objeto del nuevo tipo 'Form Folder' en el raíz del sitio llamado \"Registro\"" + +# d8a6f7edc558475c88e2a02235c3712b +#: ../addons.rst:128 +msgid "Save and view the result" +msgstr "Guarde y vea el resultado" + +# 7582fe6ee72a40b1ac5ad1fa7c92aad8 +#: ../addons.rst:129 +msgid "Click in QuickEdit" +msgstr "Haga clic en QuickEdit (para la edición rápida)" + +# 1f9d533881a946b781938084a1fa7b58 +#: ../addons.rst:130 +msgid "Remove field \"Subject\"" +msgstr "Remueva el campo \"Subject\"" + +# d68888eacda24e719a777b42c23fa354 +#: ../addons.rst:131 +msgid "Add fields for food-preference and shirt-size" +msgstr "Agrega campos para food-preference y shirt-size" + +# 2cae5be81c1a461b8019b05e0d7ce320 +#: ../addons.rst:132 +msgid "Add a DataSave Adapter" +msgstr "Agrega un adaptador DataSave" + +# ed3103ea787149c08255a26403f016b3 +#: ../addons.rst:136 +msgid "Add Photogallery with collective.plonetruegallery" +msgstr "Agrega galerías de fotos con collective.plonetruegallery" + +# 38a7686b83024dcd90e6c004a88c7894 +#: ../addons.rst:138 +msgid "" +"To advertice the conference we want to show some photos showing past " +"conferences and the city where conference is taking place in." +msgstr "Para promocionar la conferencia, se quiere mostrar algunas fotos mostrando conferencias pasadas y la ciudad donde la conferencia se esta realizando." + +# a4099a84155a48cd9d5bd73dac4ac318 +#: ../addons.rst:140 +msgid "" +"collective.plonetruegallery is a role model on how to write a Plone " +"Extension." +msgstr "collective.plonetruegallery es un modelo a seguir sobre cómo escribir una extensión de Plone." + +# a270fc9bec3e4b4fb62da1d361b161bf +#: ../addons.rst:142 +msgid "" +"Instead of creating custom content types for galleries, it integrates with " +"the Plone functionality to choose different views for folderish content " +"types." +msgstr "En vez de crear tipos de contenido personalizados para galerías, este se integra con la funcionalidad de Plone para elegir diferentes vistas de tipos de contenidos en carpeta." + +# f5833f4282054a8c99def66bf888b75b +#: ../addons.rst:144 +msgid "https://pypi.python.org/pypi/collective.plonetruegallery" +msgstr "https://pypi.python.org/pypi/collective.plonetruegallery" + +# 6c1fef2557944cada2daec028031fe02 +#: ../addons.rst:146 +msgid "" +"Install the addon: http://localhost:8080/Plone/prefs_install_products_form" +msgstr "Instala el complemento: http://localhost:8080/Plone/prefs_install_products_form" + +# 4f581df745934e52aa5440e8f852ed11 +#: ../addons.rst:147 +msgid "" +"Enable the behavior ``Plone True Gallery`` on the type ``Folder``: " +"http://localhost:8080/Plone/dexterity-types/Folder/@@behaviors" +msgstr "Habilite el comportamiento \"Plone True Gallery\" en el tipo \"Folder\": http://localhost:8080/Plone/dexterity-types/Folder/@@behaviors" + +# 84321e1513d44a2585d9212b3f9aece0 +#: ../addons.rst:148 +msgid "Add a folder /the-event/location" +msgstr "Agregue una carpeta /the-event/location" + +# 0463f45ed3504a12bcbd3231902e737f +#: ../addons.rst:149 +msgid "Upload some fotos from http://lorempixel.com/600/400/city/" +msgstr "Suba algunas fotos desde http://lorempixel.com/600/400/city/" + +# 94090a65a1af4e2dbde6b0d548689124 +#: ../addons.rst:150 +msgid "Enable the view ``galleryview``" +msgstr "Habilite la vista ``galleryview``" + +# 2fe98249ae064d12987c6ab1c81fd79f +#: ../addons.rst:154 +msgid "Internationalisation" +msgstr "Internacionalización" + +# 5518a88e461d467b9ef8c21faf45be58 +#: ../addons.rst:156 +msgid "Plone can run the same site in many different languages." +msgstr "Plone puede ejecutar el mismo sitio en múltiples lenguajes." + +# 2f3138dbea80436eb6e0bcfb478e7943 +#: ../addons.rst:158 +msgid "" +"We're not doing this with the conference-site since the lingua franca of the" +" plone-community is english." +msgstr "No estamos haciendo esto con el sitio de la conferencia desde que el lenguaje Franco de la comunidad Plone es el Ingles." + +# 7272b4da294c4a34bcf531f43f5321b7 +#: ../addons.rst:160 +msgid "" +"We would use http://pypi.python.org/pypi/plone.app.multilingual for this. It" +" is the successor of Products.LinguaPlone (which only works with " +"Archetypes)." +msgstr "Para esto debe usar http://pypi.python.org/pypi/plone.app.multilingual. Ese es el sucesor del Products.LinguaPlone (el cual solo usa Arquetipos)." + +# 08a250046961417c919c07f40320349f +#: ../addons.rst:164 +msgid "Summary" +msgstr "Resumen" + +# a2aa3127a8c948478dd8b08582b7bf78 +#: ../addons.rst:166 +msgid "" +"We are now able to customize and extend many parts of our website. We can " +"even install extensions that add new functionality." +msgstr "Ahora somos capaces de personalizar y ampliar muchas partes de nuestro sitio web. Incluso podemos instalar extensiones que añaden nuevas funcionalidades." + +# bfb1596948b543e698651206ab4619bc +#: ../addons.rst:168 +msgid "But:" +msgstr "Pero:" + +# 392863bf1aa54a76a25e4ae7b5dc1fa4 +#: ../addons.rst:170 +msgid "Can we submit talks now?" +msgstr "¿Podemos enviar Charlas ahora?" + +# 0f58b69cc2984a589f0c6187c18c5a09 +#: ../addons.rst:171 +msgid "Can we create lists with the most important properties of each tasks?" +msgstr "¿Podemos crear listas con las propiedades mas importantes de cada tarea?" + +# 61c986edc6c54336922106716d7b9476 +#: ../addons.rst:172 +msgid "Can we allow a jury to vote on talks?" +msgstr "¿Podemos permitir a un jurado votar en las Charlas?" + +# 2d074ec67aad4cdd96696841440533cf +#: ../addons.rst:174 +msgid "" +"We often have to work with structured data. Up to a degree we can do all " +"this TTW, but at some point we reach barriers. In the next part of the " +"training, we'll teach you, how to break through these barriers." +msgstr "Algunas veces trabajamos con data estructurada. Hasta un grado podemos hacer todo a través de la web, pero a algún punto nos encontramos con barreras, en la siguiente parte de nuestro entrenamiento, te enseñaremos como romper esas barreras." diff --git a/_static/custom.css b/_static/custom.css index 0e63d39e3..2664c5a16 100644 --- a/_static/custom.css +++ b/_static/custom.css @@ -1,79 +1,135 @@ +a, +a:visited { + color: #2980b9; +} +/* a:visited { + color: #297fb9d0; +} */ +a:hover{ + color: #176aa1; + text-decoration: underline; +} +.figure img { + box-shadow: 0 6px 24px 0 rgba(153,153,153,0.3); +} +.sidebar .figure img { + box-shadow: none; +} + +div.section { + margin-bottom: 6rem; +} + .wy-nav-content { - max-width: 1000px; - padding-left: 2em; - padding-right: 2em; + max-width: 1000px; + padding-left: 2em; + padding-right: 2em; +} + +.rst-content .sidebar { + clear: right; +} +.rst-content .sidebar img { + max-width: 50%; } -.rst-content .menuselection{ - background-color: #f9ebb3; - border: 1px solid #f0b37e; - border-radius: 3px; - padding: 1px 6px; +.rst-content .menuselection { + background-color: #f9ebb3; + border: 1px solid #f0b37e; + border-radius: 3px; + padding: 1px 6px; } -.rst-content .guilabel{ - border: 1px solid #777; - background-color: #cee3fb; - border-radius: 3px; - padding: 1px 6px; +.rst-content .guilabel { + border: 1px solid #777; + background-color: #cee3fb; + border-radius: 3px; + padding: 1px 6px; } + .rst-content .toggle { - background: none repeat scroll 0 0 #e7f2fa; - padding: 12px; - line-height: 24px; - margin-bottom: 24px; + background: none repeat scroll 0 0 #e7f2fa; + padding: 12px; + line-height: 24px; + margin-bottom: 24px; } .rst-content .toggle .admonition-title { - display: block; - clear: both; - cursor: pointer; + display: block; + clear: both; + cursor: pointer; } .rst-content .toggle .admonition-title:after { - content: " ▼"; + content: ' ▶'; } .rst-content .toggle .admonition-title.open:after { - content: " ▲"; + content: ' ▼'; } .rst-content .toggle p:last-child { - margin-bottom: 0; + margin-bottom: 0; +} +.rst-content code.literal, +.rst-content tt.literal, +.rst-content cite { + color: #8c1313; } -@media screen and (max-width: 1200px){ -.wy-nav-content { +/* improve contrast */ +.highlight .hll { + background-color: #ff9; +} + +.highlight { + background: #fff; +} + +@media screen and (max-width: 1200px) { + .wy-nav-content { max-width: 1100px !important; padding-left: 2em; padding-right: 2em; -} -.wy-body-for-nav{ - background: #fcfcfc -} -.wy-nav-top{ -display: block -} -.wy-nav-side{ -left: -300px -} -.wy-nav-side.shift{ -width: 85%; -left: 0 -} -.wy-nav-content-wrap{ -margin-left: 0 -} -.wy-nav-content-wrap .wy-nav-content{ -padding: 1.618em -} -.wy-nav-content-wrap.shift{ -position: fixed; -min-width: 100%; -left: 85%; -top: 0; -height: 100%; -overflow: hidden + } + .wy-body-for-nav { + background: #fcfcfc; + } + + .wy-nav-top { + display: block; + } + .wy-nav-side { + left: -300px; + } + .wy-nav-side.shift { + width: 85%; + left: 0; + } + .wy-nav-content-wrap { + margin-left: 0; + } + .wy-nav-content-wrap .wy-nav-content { + padding: 1.618em; + } + .wy-nav-content-wrap.shift { + position: fixed; + min-width: 100%; + left: 85%; + top: 0; + height: 100%; + overflow: hidden; + } } +.wy-side-nav-search a.icon-home, +.wy-side-nav-search a.icon-home:visited { + color: #fcfcfc; + background-color: unset; + text-decoration: none; } + +.wy-menu-vertical a, +.wy-menu-vertical a:visited { + color: #d9d9d9; +} \ No newline at end of file diff --git a/_static/forest-areas.csv b/_static/forest-areas.csv new file mode 100644 index 000000000..b9f36209d --- /dev/null +++ b/_static/forest-areas.csv @@ -0,0 +1,89 @@ +COUNTRY, CNRTY_CODE," CNRTY_AREA +2000 (in ha)"," FORES_AREA +2000 (in ha)"," PERCT_FOR +2000 (in %)"," NUM_PATCH +2000 (in #)"," AV_P_SIZE +2000 (in ha)"," NO_01 +(in #)"," HA_01 +(in ha)"," PERC_NO_01 +(in %)"," PERC_HA_01 +(in %)"," NO_02 +(in #)"," HA_02 +(in ha)"," PERC_NO_02 +(in %)"," PERC_HA_02 +(in %)"," NO_03 +(in #)"," HA_03 +(in ha)"," PERC_NO_03 +(in %)"," PERC_HA_03 +(in %)"," NO_04 +(in #)"," HA_04 +(in ha)"," PERC_NO_04 +(in %)"," PERC_HA_04 +(in %)"," NO_05 +(in #)"," HA_05 +(in ha)"," PERC_NO_05 +(in %)"," PERC_HA_05 +(in %)"," NO_06 +(in #)"," HA_06 +(in ha)"," PERC_NO_06 +(in %)"," PERC_HA_06 +(in %)"," NO_07 +(in #)"," HA_07 +(in ha)"," PERC_NO_07 +(in %)"," PERC_HA_07 +(in %)"," NO_08 +(in #)"," HA_08 +(in ha)"," PERC_NO_08 +(in %)"," PERC_HA_08 +(in %)"," NO_09 +(in #)"," HA_09 +(in ha)"," PERC_NO_09 +(in %)"," PERC_HA_09 +(in %)"," NO_10 +(in #)"," HA_10 +(in ha)"," PERC_NO_10 +(in %)"," PERC_HA_10 +(in %)"," NO_11 +(in #)"," HA_11 +(in ha)"," PERC_NO_11 +(in %)"," PERC_HA_11 +(in %)",Sum_No,Sum_Ha,Difference_No,Difference_Ha,Sum_Perc_No,Sum_Perc_Ha +Albania, AL,2843931,714908,25.14,1561,457.98,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,685,15202,43.88,2.13,301,21792,19.28,3.05,409,86018,26.2,12.03,107,99830,6.85,13.96,46,188351,2.95,26.35,12,245427,0.77,34.33,1,58288,0.06,8.15,1561,714908,0,0,100,100 +Austria, AT,8392752,3668819,43.71,4999,733.91,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3088,53001,61.77,1.44,776,55387,15.52,1.51,825,175246,16.5,4.78,208,192970,4.16,5.26,75,313630,1.5,8.55,20,388452,0.4,10.59,7,2490133,0.14,67.87,4999,3668819,0,0,100,100 +Belgium, BE,3061624,610386,19.94,1808,337.6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,836,23349,46.24,3.83,423,30180,23.4,4.94,439,88378,24.28,14.48,91,86777,5.03,14.22,14,51198,0.77,8.39,4,69017,0.22,11.31,1,261487,0.06,42.84,1808,610386,0,0,100,100 +Bosnia and Herzegovina, BA,5115657,2374203,46.41,2747,864.29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1594,34539,58.03,1.45,511,35913,18.6,1.51,518,102040,18.86,4.3,82,76919,2.99,3.24,30,138028,1.09,5.81,10,191663,0.36,8.07,2,1795101,0.07,75.61,2747,2374203,0,0,100,100 +Bulgaria, BG,11096842,3502166,31.56,4773,733.75,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1817,60602,38.07,1.73,1210,86302,25.35,2.46,1371,282738,28.72,8.07,273,256390,5.72,7.32,82,309771,1.72,8.85,13,239718,0.27,6.84,7,2266645,0.15,64.72,4773,3502166,0,0,100,100 +Croatia, HR,5649522,2041592,36.14,2899,704.24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1035,31557,35.7,1.55,698,50071,24.08,2.45,856,184401,29.53,9.03,227,222397,7.83,10.89,62,260831,2.14,12.78,19,469848,0.66,23.01,2,822487,0.07,40.29,2899,2041592,0,0,100,100 +Cyprus, CY,922794,149428,16.19,94,1589.66,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,728,22.34,0.49,23,1683,24.47,1.13,29,6564,30.85,4.39,9,8438,9.57,5.65,10,44299,10.64,29.65,1,14567,1.06,9.75,1,73149,1.06,48.95,94,149428,0,0,100,100 +Czech Republic, CZ,7887000,2611372,33.11,5462,478.1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2604,65925,47.67,2.52,1064,75131,19.48,2.88,1272,280347,23.29,10.74,367,349843,6.72,13.4,114,482569,2.09,18.48,32,645883,0.59,24.73,9,711674,0.16,27.25,5462,2611372,0,0,100,100 +Denmark, DK,4299357,388292,9.03,2377,163.35,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,945,31930,39.76,8.22,637,45450,26.8,11.71,649,133644,27.3,34.42,132,118056,5.55,30.4,13,49162,0.55,12.66,1,10050,0.04,2.59,0,0,0,0,2377,388292,0,0,100,100 +Estonia, EE,4533381,2112164,46.59,2353,897.65,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1135,32503,48.24,1.54,509,36103,21.63,1.71,514,108995,21.84,5.16,130,126480,5.52,5.99,46,180280,1.95,8.54,14,339889,0.59,16.09,5,1287914,0.21,60.98,2353,2112164,0,0,100,100 +Finland, FI,33756904,20881591,61.86,12520,1667.86,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7038,174415,56.21,0.84,2550,177480,20.37,0.85,2328,474930,18.59,2.27,446,400083,3.56,1.92,134,554284,1.07,2.65,20,389173,0.16,1.86,4,18711226,0.03,89.61,12520,20881591,0,0,100,100 +France, FR,54883157,14387536,26.21,39780,361.68,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20264,607501,50.94,4.22,8878,626988,22.32,4.36,8184,1694257,20.57,11.78,1789,1650753,4.5,11.47,535,2145827,1.34,14.91,100,1912765,0.25,13.29,30,5749445,0.08,39.96,39780,14387536,0,0,100,100 +Germany, DE,35738464,10830761,30.31,24660,439.2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13403,290501,54.35,2.68,4385,310686,17.78,2.87,4914,1044729,19.93,9.65,1392,1334757,5.64,12.32,455,1859394,1.85,17.17,84,1610769,0.34,14.87,27,4379925,0.11,40.44,24660,10830761,0,0,100,100 +Greece, EL,13160021,2642354,20.08,4135,639.02,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1640,44288,39.66,1.68,949,67918,22.95,2.57,1126,237854,27.23,9,298,278852,7.21,10.55,83,340266,2.01,12.88,33,745828,0.8,28.23,6,927348,0.15,35.1,4135,2642354,0,0,100,100 +Hungary, HU,9301289,1747998,18.79,5219,334.93,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2593,72377,49.68,4.14,1142,80832,21.88,4.62,1098,226354,21.04,12.95,271,258004,5.19,14.76,92,382673,1.76,21.89,17,345587,0.33,19.77,6,382171,0.11,21.86,5219,1747998,0,0,100,100 +Iceland, IS,10254261,53500,0.52,308,173.7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,3997,41.23,7.47,68,4832,22.08,9.03,89,18559,28.9,34.69,21,18834,6.82,35.2,3,7278,0.97,13.6,0,0,0,0,0,0,0,0,308,53500,0,0,100,100 +Ireland, IE,6980929,465024,6.66,4583,101.47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2490,72250,54.33,15.54,1043,72648,22.76,15.62,915,181074,19.97,38.94,124,106948,2.71,23,11,32104,0.24,6.9,0,0,0,0,0,0,0,0,4583,465024,0,0,100,100 +Italy, IT,30056205,7930704,26.39,11615,682.8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5204,142806,44.8,1.8,2739,194047,23.58,2.45,2839,594368,24.44,7.49,572,529740,4.92,6.68,193,786221,1.66,9.91,52,1027416,0.45,12.95,16,4656106,0.14,58.71,11615,7930704,0,0,100,100 +Kosovo, XK,1090703,434268,39.82,537,808.69,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,241,6397,44.88,1.47,137,9773,25.51,2.25,116,23844,21.6,5.49,26,26918,4.84,6.2,12,46698,2.23,10.75,1,11569,0.19,2.66,4,309069,0.74,71.17,537,434268,0,0,100,100 +Latvia, LV,6458281,2465566,38.18,6680,369.1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2981,85032,44.63,3.45,1605,113421,24.03,4.6,1587,330186,23.76,13.39,372,361922,5.57,14.68,104,427444,1.56,17.34,26,601474,0.39,24.39,5,546087,0.07,22.15,6680,2465566,0,0,100,100 +Liechtenstein, LI,16036,6890,42.97,15,459.33,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,170,73.33,2.47,2,141,13.33,2.05,1,326,6.67,4.73,0,0,0,0,1,6253,6.67,90.75,0,0,0,0,0,0,0,0,15,6890,0,0,100,100 +Lithuania, LT,6489866,1936982,29.85,5301,365.4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2453,71579,46.27,3.7,1119,79434,21.11,4.1,1248,266175,23.54,13.74,372,358242,7.02,18.49,88,339411,1.66,17.52,18,371767,0.34,19.19,3,450374,0.06,23.25,5301,1936982,0,0,100,100 +Luxembourg, LU,259571,94274,36.32,251,375.59,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,137,2836,54.58,3.01,40,2773,15.94,2.94,53,11699,21.12,12.41,16,15944,6.37,16.91,3,14446,1.2,15.32,2,46576,0.8,49.4,0,0,0,0,251,94274,0,0,100,100 +Malta, MT,31391,206,0.66,3,68.67,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,206,100,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,206,0,0,100,100 +Montenegro, ME,1386013,574951,41.48,693,829.66,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,286,8235,41.27,1.43,174,12530,25.11,2.18,164,34310,23.67,5.97,51,47023,7.36,8.18,15,48898,2.16,8.5,2,51873,0.29,9.02,1,372082,0.14,64.72,693,574951,0,0,100,100 +Netherlands, NL,3730163,317123,8.5,1368,231.82,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,634,18374,46.35,5.79,318,22790,23.25,7.19,315,67140,23.03,21.17,86,80995,6.29,25.54,13,39892,0.95,12.58,1,18560,0.07,5.85,1,69372,0.07,21.88,1368,317123,0,0,100,100 +North Macedonia, MK,2543990,825081,32.43,1326,622.23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,763,16070,57.54,1.95,238,16695,17.95,2.02,244,50993,18.4,6.18,50,53805,3.77,6.52,21,92423,1.58,11.2,6,138555,0.45,16.79,4,456540,0.3,55.33,1326,825081,0,0,100,100 +Norway, NO,32291934,10815836,33.49,10214,1058.92,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5214,122369,51.05,1.13,2016,142060,19.74,1.31,2091,431282,20.47,3.99,580,541475,5.68,5.01,221,894003,2.16,8.27,73,1589959,0.71,14.7,19,7094688,0.19,65.6,10214,10815836,0,0,100,100 +Poland, PL,31191688,9710718,31.13,16772,578.98,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6826,211758,40.7,2.18,3837,271457,22.88,2.8,4338,927114,25.86,9.55,1258,1189125,7.5,12.25,408,1694378,2.43,17.45,85,1728811,0.51,17.8,20,3688075,0.12,37.98,16772,9710718,0,0,100,100 +Portugal, PT,9184450,1921315,20.92,6649,288.96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2784,95080,41.87,4.95,1799,127321,27.06,6.63,1632,333498,24.55,17.36,337,304810,5.07,15.86,80,309547,1.2,16.11,14,314364,0.21,16.36,3,436695,0.05,22.73,6649,1921315,0,0,100,100 +Romania, RO,23836953,7170803,30.08,9263,774.13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4682,106918,50.55,1.49,1770,125476,19.11,1.75,2048,445735,22.11,6.22,562,540848,6.07,7.54,167,697617,1.8,9.73,30,671459,0.32,9.36,4,4582750,0.04,63.91,9263,7170803,0,0,100,100 +Serbia, RS,7754187,2314214,29.84,3972,582.63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1922,58580,48.39,2.53,948,66429,23.87,2.87,863,174221,21.73,7.53,171,156365,4.31,6.76,47,215906,1.18,9.33,17,370495,0.43,16.01,4,1272218,0.1,54.97,3972,2314214,0,0,100,100 +Slovakia, SK,4902520,2065338,42.13,1558,1325.63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,715,19761,45.89,0.96,321,22777,20.6,1.1,356,73943,22.85,3.58,107,108326,6.87,5.24,46,195062,2.95,9.44,9,241319,0.58,11.68,4,1404150,0.26,67.99,1558,2065338,0,0,100,100 +Slovenia, SI,2027650,1138778,56.16,1203,946.62,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,681,14994,56.61,1.32,240,16605,19.95,1.46,225,47673,18.7,4.19,39,35249,3.24,3.1,16,59484,1.33,5.22,1,10271,0.08,0.9,1,954502,0.08,83.82,1203,1138778,0,0,100,100 +Spain, ES,50578079,11037335,21.82,42009,262.74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29849,387793,71.05,3.51,4945,350901,11.77,3.18,5423,1152725,12.91,10.44,1297,1180094,3.09,10.69,387,1529191,0.92,13.85,89,1999418,0.21,18.12,19,4437213,0.05,40.2,42009,11037335,0,0,100,100 +Sweden, SE,44933864,56155852,58.21,16691,1567.06,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11830,174099,70.88,0.67,2229,157285,13.35,0.6,2041,419791,12.23,1.6,480,447595,2.88,1.71,94,361719,0.56,1.38,12,206928,0.07,0.79,5,24388435,0.03,93.24,16691,26155852,0,0,100,100 +Switzerland, CH,4127960,1178724,28.55,2292,514.28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1037,29320,45.24,2.49,415,29364,18.11,2.49,616,131297,26.88,11.14,165,156931,7.2,13.31,40,179605,1.75,15.24,16,338397,0.7,28.71,3,313810,0.13,26.62,2292,1178724,0,0,100,100 +Turkey, TR,77958666,11617424,14.9,17287,672.03,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5427,177710,31.39,1.53,4206,300606,24.33,2.59,5651,1222658,32.69,10.52,1442,1316553,8.34,11.33,426,1778523,2.46,15.31,107,2179952,0.62,18.76,28,4641422,0.16,39.95,17287,11617424,0,0,100,100 +United Kingdom, UK,24484397,2118587,8.65,12576,168.46,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5806,189055,46.17,8.92,3264,230883,25.95,10.9,2861,569762,22.75,26.89,515,475057,4.1,22.42,117,474146,0.93,22.38,13,179684,0.1,8.48,0,0,0,0,12576,2118587,0,0,100,100 diff --git a/_static/plone_training_config.zip b/_static/plone_training_config.zip index 2a9340835..a6c8a438f 100644 Binary files a/_static/plone_training_config.zip and b/_static/plone_training_config.zip differ diff --git a/_static/sample_export.zip b/_static/sample_export.zip new file mode 100644 index 000000000..74579fc45 Binary files /dev/null and b/_static/sample_export.zip differ diff --git a/_templates/page.html b/_templates/page.html index 35e79d84c..fd9494f5d 100644 --- a/_templates/page.html +++ b/_templates/page.html @@ -1,7 +1,5 @@ {% extends "!page.html" %} -{% set css_files = css_files + ["_static/custom.css"] %} - {% block footer %} +{% endblock %} \ No newline at end of file diff --git a/gatsby/buildingsourceplugins.rst b/gatsby/buildingsourceplugins.rst new file mode 100644 index 000000000..49ef7e8e1 --- /dev/null +++ b/gatsby/buildingsourceplugins.rst @@ -0,0 +1,205 @@ +Building Source Plugins +======================= + +In the previous section on source plugins we already covered what they are and how to use them. + +Now we will be going a bit in-depth here to understand how they work internally and how to get onto building one. + +Our final goal is to build a GatsbyJS source plugin that can query all the data from a Plone site. + +This requires the Plone site to have `plone.restapi `_ configured. + +.. note:: + + plone.restapi is a RESTful hypermedia API for Plone. + Read more about it in the `docs `__. + +Then this plugin can be used to generate a static site from a Plone site, containing pages, structure and all of its contents. + +Let us dive into understanding how to create nodes. + +Comparing Plone Site and GatsbyJS Site +-------------------------------------- + +A Plone site has different types of content objects including ``Document``, ``News Item``, ``Folder`` and so on. + +Each of these content objects has pages dedicated to them. + +``Folder`` content object natively has children, which are content objects inside of them. + +This way there is a page structure as well. + +.. note:: + + Plone even allows custom types. + Read more about this in the `docs `__. + +Each of these content objects can be compared to nodes in GatsbyJS. + +Similar to what we did in the "Dynamic Pages" section, pages can be created for each of these nodes. + +The plone.restapi gives us data of children in ``Folders`` along with content itself. + +This allows us to setup internal linking to ensure the structure as the Plone site. + +Navigation and breadcrumb data as well is provided by plone.restapi. + +These also can be made into nodes and directly used in GatsbyJS. + + +How It Works +------------ + +Before we get into using the plone.restapi, let us first understand how node creation works. + +Source plugins run on GatsbyJS build time to pull data from a source, cache it, create nodes and a lot more. + +To create nodes, we will be using ``exports.sourceNodes`` API in ``gatsby-node.js``. + +This is a lifecycle API similar to ``exports.createPages`` which we used earlier for dynamically creating pages. + +.. note:: + + Read more about ``sourceNodes`` API in the `docs `__. + +It works similar to page creation but has a couple actions and helpers to aid us in creating nodes specifically. + +Roughly, the main function for a source plugin in ``gatsby-node.js`` would look like: + +.. code-block:: jsx + + ... + exports.sourceNodes = async ( + { actions, cache, getNode, getNodes, store }, + { baseUrl } + ) => { + ... + +The first function parameter object with ``actions``, ``cache``, ``getNode``, are all passed in from GatsbyJS, while the second parameter object is passed in from plugin options (``gatsby-config.js``). + +For instance, the plugins part of ``gatsby-config.js`` in this case would look like: + +.. code-block:: javascript + + plugins: [ + { + resolve: 'gatsby-source-plone', + options: { + baseUrl: 'https://plonedemo.kitconcept.com/en', + }, + } + ] + + +.. note:: + + ``exports.sourceNodes`` is an ``async`` function. + This means that it works asynchronously and returns a promise. + It is usually used in combination with ``await`` for processes that requires pausing of execution of function including fetching of data or asynchronous processing. + The `MDN docs `_ has detailed information about its working. + +GatsbyJS Node +------------- + +To create a node we use the ``createNode`` action which is a part of the ``actions`` passed into all functions implementing the GatsbyJS API. + +.. note:: + GatsbyJS offers a whole list of actions creators wrapped with a dispatch as ``actions``. + Read more about them in the `GatsbyJS docs `_. + +The structure of any node would look like this at the base level: + +.. code-block:: javascript + + let node = { + sampleData: "Sample Data", + + id: "sampleId", + internal: { + type: "sampleType", + contentDigest: crypto + .createHash(`md5`) + .update(JSON.stringify(sampleData)) + .digest(`hex`), + mediaType: "text/html" + }, + parent: '', + children: [], + } + + +Note that each node needs to have a property called ``internal`` which is an object containing some information about the node for GatsbyJS to process. + +``type`` is a string which represents the type of this particular node, allowing nodes of the same type be queried in GraphQL with ``allTypeName``. + +.. note:: + + While ``type`` can be any string, ensure that it is unique and has no spaces or special characters which cannot be handled by GraphQL. + + +.. note:: + + Content digest ensures GatsbyJS does not do extra work if the data of the node has not changed and helps with caching. + ``crypto`` is an external library which we are using to create content digest. + You can install it by ``npm install --save crypto``. + + +Exercise +++++++++ + +We want to create a single GatsbyJS node using some sample data. + +You need to make sure it works by checking the result in GraphiQL. + +Hints: use any sample data and spread it to the node, but make sure it has all the fields that are mentioned above. + + +.. admonition:: Solution + :class: toggle + + In ``gatsby-node.js``: + + .. code-block:: javascript + + const crypto = require('crypto'); + + exports.sourceNodes = async ({ actions }) => { + const { createNode } = actions; + + const sampleData = { + eventData: "Plone Conf 2018", + } + + let testNode = { + ...sampleData, + id: "test", + internal: { + type: "event", + contentDigest: crypto + .createHash(`md5`) + .update(JSON.stringify(sampleData)) + .digest(`hex`), + mediaType: "text/html" + }, + } + + createNode(testNode); + return; + } + + Now in http://localhost:8000/___graphql, you can query it with: + + .. code-block:: text + + { + allEvent { + edges { + node { + id + eventData + } + } + } + } + + diff --git a/gatsby/conf.py b/gatsby/conf.py new file mode 100644 index 000000000..c77ba2fe6 --- /dev/null +++ b/gatsby/conf.py @@ -0,0 +1,366 @@ +# -*- coding: utf-8 -*- +# +# Documentation documentation build configuration file, created by +# sphinx-quickstart on Thu Aug 18 17:52:49 2016. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import sys, os +on_rtd = os.environ.get('READTHEDOCS', None) == 'True' + +if not on_rtd: + import sphinx_rtd_theme + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + html_theme = 'sphinx_rtd_theme' + +else: + html_theme = 'default' +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.intersphinx', + 'sphinx.ext.todo', + 'sphinx.ext.coverage', +] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['README.rst', '_*.rst', + 'CHANGES.rst', + 'LICENSE',] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# Custom CSS settings +#def setup(app): +# app.add_stylesheet("theme_overrides.css") + + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +# +# source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'GatsbyJS' +copyright = u'2018, Plone Community' +author = u'Plone Community' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +#version = u'0.0.1-alpha' +# The full version, including alpha/beta/rc tags. +#release = u'0.0.1-alpha' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# +# today = '' +# +# Else, today_fmt is used as the format for a strftime call. +# +# today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', 'README.rst'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +# +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +#html_theme = 'alabaster' +#html_theme = "sphinx_rtd_theme" +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +html_theme_options = { + 'collapse_navigation' : False, + 'sticky_navigation': False, +} + +#html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] +# Add any paths that contain custom themes here, relative to this directory. +# html_theme_path = [] +# The name for this set of Sphinx documents. +# " v documentation" by default. +# +html_title = u'GatsbyJS' + +# A shorter title for the navigation bar. Default is the same as html_title. +# +html_short_title = 'Building static websites with GatsbyJS.' + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# +#html_logo = '_theme/plone-invers.svg' + +# The name of an image file (relative to this directory) to use as a favicon of +# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# +# html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +# +# html_extra_path = [] + +# If not None, a 'Last updated on:' timestamp is inserted at every page +# bottom, using the given strftime format. +# The empty string is equivalent to '%b %d, %Y'. +# +# html_last_updated_fmt = None + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +# +# html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +# +# html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# +# html_additional_pages = {} + +# If false, no module index is generated. +# +# html_domain_indices = True + +# If false, no index is generated. +# +# html_use_index = True + +# If true, the index is split into individual pages for each letter. +# +# html_split_index = False + +# If true, links to the reST sources are added to the pages. +# +# html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +# +# html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# +#html_show_copyright = False + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh' +# +# html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# 'ja' uses this config value. +# 'zh' user can custom change `jieba` dictionary path. +# +# html_search_options = {'type': 'default'} + +# The name of a JavaScript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +# +# html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'PloneTraininig' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'PloneTraining.tex', u'PloneTraining Documentation', + u'Plone Community', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# +# latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +# +# latex_use_parts = False + +# If true, show page references after internal links. +# +# latex_show_pagerefs = False + +# If true, show URL addresses after external links. +# +# latex_show_urls = False + +# Documents to append as an appendix to all manuals. +# +# latex_appendices = [] + +# It false, will not define \strong, \code, itleref, \crossref ... but only +# \sphinxstrong, ..., \sphinxtitleref, ... To help avoid clash with user added +# packages. +# +# latex_keep_old_macro_names = True + +# If false, no module index is generated. +# +# latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'PloneTraining', u'PloneTraining Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +# +# man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'PloneTraining', u'PloneTraining Documentation', + author, 'Documentation', 'Plone Training.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +# +# texinfo_appendices = [] + +# If false, no module index is generated. +# +# texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# +# texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +# +# texinfo_no_detailmenu = False + + +# Example configuration for intersphinx: refer to the Python standard library. +#intersphinx_mapping = {'https://docs.python.org/': None} diff --git a/gatsby/copyingplonesite.rst b/gatsby/copyingplonesite.rst new file mode 100644 index 000000000..348f6003c --- /dev/null +++ b/gatsby/copyingplonesite.rst @@ -0,0 +1,249 @@ +Copying The Plone Site +====================== + +Now we have seen how the plugin and starter work together. + +The end goal of the plugin along with GatsbyJS is to generate a static site which is an exact copy of the Plone site it sourced data from. + +Once ``gatsby-source-plugin`` retrieves all the required data for us, the ``gatsby-starter-plone`` processes and uses this data to generate the static site. + +Internally what ``gatsby-starter-plone`` does in steps is: + +- Create pages for each content object and ensure tree structure by retaining parent and items relationships. +- Display HTML, images and files in content objects correctly. +- Handle navigation in the site with a Navbar and Breadcrumbs. + + +Page Creation +------------- + +``exports.createPages`` is the API used in ``gatsby-node.js`` for creating pages from nodes. + +To create pages for all nodes, first we query the list of all different types of nodes and use this list to create individual pages. + +To illustrate how this process works, let us create pages for all nodes of type ``PloneFolder``. + +Later we can move on to include all the other types. + +In ``gatsby-node.js``: + +.. code-block:: javascript + + const path = require('path'); + + exports.createPages = async ({ graphql, actions }) => { + const { createPage } = actions; + + // Get data via GraphQL + const result = await graphql(` + { + allPloneFolder { + edges { + node { + _path + } + } + } + } + `); + + // Create pages for each PloneFolder item + result.data.allPloneFolder.edges.forEach(({ node }) => { + createPage({ + path: node._path, + component: path.resolve('./src/templates/Folder.js'), + }); + }); + }; + +The ``_path`` property is helpful to create pages. +It is unique to all nodes. +Files and images are linked to the nodes in which they are present via the ``_path`` value. + +This backlinking will be explained in the later sections. + +Backlinking can be used to set the relative path of a node in the generated static site. +It can also get the required images and files. + +Handling Different Data Types +----------------------------- + +For generating pages for each content object, the same process as illustrated by the code above can be followed. +The only major change would be that we would be using a ``default.js`` template instead and separate components for each type. +This would internally check what type of node is being used for page creation and return the matching component. + +In ``gatsby-node.js`` query for all data types: + +.. code-block:: jsx + + exports.createPages = async ({ graphql, actions }) => { + const { createPage } = actions; + const result = await graphql(` + { + allPloneDocument { + edges { + node { + _path + } + } + } + allPloneEvent { + edges { + node { + _path + } + } + } + allPloneFolder { + edges { + node { + _path + } + } + } + allPloneNewsItem { + edges { + node { + _path + } + } + } + } + `); + [] + .concat( + result.data.allPloneDocument.edges, + result.data.allPloneEvent.edges, + result.data.allPloneFolder.edges, + result.data.allPloneNewsItem.edges + ) + .forEach(({ node }) => { + createPage({ + path: node._path, + component: path.resolve('./src/templates/default.js'), + }); + }); + } + + +The ``default.js`` template: + +.. code-block:: jsx + + const componentFor = data => { + if (data) { + if (data.ploneCollection) { + return ( + + ); + } else if (data.ploneDocument) { + return ( + + ); + } else if (data.ploneEvent) { + return ( + + ); + } else if (data.ploneFolder) { + return ( + + ); + } else if (data.ploneNewsItem) { + return ( + + ); + } else { + return null; + } + } else { + return null; + } + }; + + const DefaultLayout = ({ data }) => {componentFor(data)}; + + // Query for all the different types from GraphQL + // Fragments for each type are defined in their relevant components + export const query = graphql` + query DefaultTemplateQuery($path: String!) { + ploneCollection(_path: { eq: $path }) { + ...Collection + } + ploneDocument(_path: { eq: $path }) { + ...Document + } + ploneEvent(_path: { eq: $path }) { + ...Event + } + ploneFolder(_path: { eq: $path }) { + ...Folder + } + ploneNewsItem(_path: { eq: $path }) { + ...NewsItem + } + } + `; + +To understand what happens in the components, let us take the example of the ``Folder`` component: + +.. code-block:: jsx + + import React from 'react'; + import { graphql, Link } from 'gatsby'; + + const Folder = ({ data, title }) => ( + + ); + + export default Folder; + + export const query = graphql` + fragment Folder on PloneFolder { + _id + title + description + items { + _path + } + _path + } + `; + +Here, the fragment is used by ``default.js`` to get the relevant data of the ``Folder`` content object and is passed in to the Folder component as ``data``. + +.. note:: + Fragments are reusable GraphQL queries. + It also allows you to split up complex queries into smaller, easier to understand components. + + In our case, even though all data is queried in ``default.js`` template, we split up the queries by type and place them in the relevant component. + These fragments are included back in the template as required. + This helps in maintainability as all the parts of a component, including the query, are placed together. + +The ``Folder`` component now displays the title and description of the Folder itself and a list of child items. + +.. note:: + + With the ``Link`` component and ``_path`` we can directly link between GatsbyJS pages. + diff --git a/gatsby/data.rst b/gatsby/data.rst new file mode 100644 index 000000000..0739df123 --- /dev/null +++ b/gatsby/data.rst @@ -0,0 +1,177 @@ +Data +==== + +If we want, we could create entire sites only with static pages, but with GatsbyJS we can also get data from external sources and use it to dynamically generate pages. + +Data could be pulled from different sources: files (Markdown, CSV, JSON), databases, API, CMS. + +The GatsbyJS data layer lets you pull data from these (and any other source) directly into your page components with GraphQL. + +GraphQL +------- + +GraphQL is a query language developed by Facebook. +It allows a developer to create API endpoints that can be queried with a particular syntax that describes exactly what kind of data we need (only desired values) and it returns only that data. + +.. note:: + + For more detailed information, you could read the `official documentation `_. + And the `tutorial `_. + +GatsbyJS uses GraphQL to expose stored data in a common way, allowing page components to access the data and returning only the desired information. + +GatsbyJS uses GraphQL also to expose some common information (site metadata for example) and to show what plugins are installed. + +GraphQL has a powerful tool called `GraphiQL` that helps to inspect what data can be queried and to test the queries. + +If we inspect the console output when we start development server, we can see these lines: + +.. code-block:: console + + View GraphiQL, an in-browser IDE, to explore your site's data and schema + + http://localhost:8000/___graphql + + +Now let us try to open `http://localhost:8000/___graphql `_ and see how it works. + + .. image:: ./_static/graphiql.png + :scale: 50% + +There are three columns: + +- Query builder +- Results +- Schema explorer + +**Query builder** is where we are going to write our queries. +Queries (and responses) are JSON objects, and that object will be returned as a response, filled with required data. + +**Results** is the section where the response is shown after the query. + +**Schema explorer** is where to inspect the structure of the data that we can query. + +Site metadata +------------- + +There are different configuration files in a GatsbyJS project that allow us to customize different aspects of the site. + +There is a file called ``gatsby-config.js`` where we can set some site metadata that can be queried with GraphQL and used in pages. + +One metadata that we could set is the site title. + +If we look at the demo site, we could see that there is a header with some text. + +This is the site title, read from the metadata config (we will see later how to read it in a component). + +If we open ``gatsby-config.js``, we'll se something like this: + +.. literalinclude:: _snippets/gatsby-config.js + :language: none + :emphasize-lines: 2-4 + :lines: 1-5 + +``siteMetadata`` is the section that we need to focus on. +The value of ``title`` is exactly what we see in the header. + +If we try to go to GraphiQL page, we could try to access this information with the following query: + +.. code-block:: none + + query { + site { + siteMetadata { + title + } + } + } + +.. note:: + + ``query`` is a keyword that means that we are requesting data. + If we need to modify the data, we need to use ``mutation``. + +Now that we have seen how to query some data from GraphQL, let us see how to use that information in components. + +There are two ways to inject data into components depending on whether the component is a page component (``index.js`` file), or not (Layout component). + +Let us start with the first one. +We need to change our ``index.js`` page like this: + +.. literalinclude:: _snippets/index_graphql.js + :language: jsx + :emphasize-lines: 3,7,10,17-25 + +First of all, we imported a new module ``graphql``. +This is used on the bottom of the file to generate the query. Note the use of backticks around the query definition. + +Then we declare in `IndexPage` that we are using `data`, the results of the ``graphql`` query. + +When we add a GraphQL query in our page component, the result is passed to the component as a property called ``data``. +In that property, we have the result of the query (with the same data structure). + +.. note:: + + To see what information are in the ``data`` property, try to put a ``console.log(data)`` in the component. + + To do that, we need to change the returned value of the arrow function, because ``()`` automatically returns everything inside them, and we want to add some logic before returning the value. + + The change should be like this: + + .. code-block:: jsx + + export default ({ data }) => { + console.log(data); + return ( + //... +

This is the site title: {data.site.siteMetadata.title}

+ //... + ) + + } + +This method could be used in every page component, but if we break up our layout in several pieces (components), we need to use a different approach using a wrapper component provided by GatsbyJS called ``StaticQuery``. +This is very useful because we cannot expose a GraphQL query in components that are not page components. +With these "StaticQuery" components, we could avoid passing useless properties through the components hierarchy that are only needed by a certain leaf. + +.. note:: + + In ReactJS, passing props to too many levels is called `prop drilling `_. + It is always better to avoid it, if we can. + +If we look at the ``Layout`` component in ``components/layout.js`` file, we could see an example of ``StaticQuery`` to read the site title: + +.. code-block:: jsx + + import { StaticQuery, graphql } from 'gatsby' + //... + + const Layout = ({ children }) => ( + ( + //... +
+ //... + )} + /> + ) + +In this case, the query is an attribute of the ```` tag. + +.. note:: + + StaticQuery is different from standard components that we have seen before, because it uses a ReactJS pattern called `render props `_. + + This pattern is used when there are different components of the interface that need the same piece of code/logic and we do not want to duplicate the same code. + + A component that implements that pattern has some logic hidden inside (for example how to perform a GraphQL query). + It takes a function (as ``render`` property) that expose some data (the result of the query) and returns a React element that could use that data. diff --git a/gatsby/dynamicpages.rst b/gatsby/dynamicpages.rst new file mode 100644 index 000000000..edfc45df7 --- /dev/null +++ b/gatsby/dynamicpages.rst @@ -0,0 +1,129 @@ +Dynamic pages +============= + +In previous chapters, we learned how: + +- Create static pages +- Fetch data from external sources +- Query data and show it in pages + +We could potentially build our static websites just with that information. + +The only problem is that we need to manually create every single page that we need. + +The last missing part in building a static website with GatsbyJS is to programmatically generate these pages from data. + +As we have seen in the :doc:`pages` chapter, at build time GatsbyJS maps every page with an URL that is its filename. +If we want to programmatically generate static pages, we are not going to have different page components (one for each node), but only GraphQL nodes. +We need to provide some additional information in nodes to allow GatsbyJS to generate the correct pages and URLs. + +In particular we need to add a "slug" or "path" attribute to the node. + +.. note:: A lot of source plugins automatically add this information in nodes, like CMS plugins. + +The GatsbyJS building stack has a sequence of steps that perform different actions: + +- Read the configuration to load the list of plugins +- Initialize the cache (to avoid re-fetch untouched data) +- Pull the data and preprocess it in a GraphQL schema +- Create pages (from ``/pages`` folder or from plugins) +- Extract and run GraphQL queries and replace their values in pages +- Write out the pages as static HTML pages + +GatsbyJS provides a rich set of "lifecycle APIs" to hook into every step and perform some customizations. +In this chapter we are going to use two of these APIs, which are the most used in plugins: + +- ``onCreateNode``: called by GatsbyJS whenever a node is created or updated, so we can edit the current node before storing it into GraphQL +- ``createPages``: step that creates a page. + +To implement an API, we need to export a function with the same name of the API in a file called ``gatsby-node.js``. + +Let us start with the first one, and export a function called ``onCreateNode``: + +.. literalinclude:: _snippets/gatsby-node.js + :language: jsx + :lines: 1-3 + +This function is called whenever a node is created. + +If we restart the server now, we will see that in the console we will have the types of every node. +We want to add a slug only for nodes generated by the MarkdownRemark plugin. + +We need to filter them by type. +To generate the slug for this node, we could use a helper funcion from ``gatsby-source-filesystem`` that is made for this purpose: ``createFilePath``. + +.. note:: + + If you remember, Remark nodes are built on top of filesystem nodes. + +Finally we need to add the slug attribute to the node. +Nodes can be directly modified only by the plugins that created them. +Other plugins can add new fields to the nodes only with a specific function called ``createNodeField`` (for security reasons). + +And finally, our ``onCreateNode`` function will be similar to this: + +.. literalinclude:: _snippets/gatsby-node.js + :language: jsx + :lines: 5-19 + :lineno-match: + +If we restart the server and try to query the data, we will see the slug under the ``fields`` attribute. + +Now that we have all the information, we need to create pages. + +As mentioned in the introduction, to create a page we need to query data with GraphQL and then map the results into a page. + +To do this, we need to export the other mentioned function (``createPages``) in ``gatsby-node.js`` file: + +.. literalinclude:: _snippets/gatsby-node.js + :language: jsx + :lines: 21-49 + :lineno-match: + +What can we see here? + +First of all we perform a GraphQL query, and we iterate through the results to create a new page. + +The method ``createPage`` is a helper method that GatsbyJS uses to generate dynamic pages. + +It takes 3 parameters: + +``path``: the slug value. + +This is used to generate the URL where we can access the current page. + +``component``: the template used to populate a blog post page. + +It is similar to a page component (we will see it shortly). + +``context``: we can pass a list of variables that can be used by the queries into page components (not ``StaticQuery``) to fetch information about the current node. + +A this point we create the ``blog-post.js`` template file to end our setup: + +.. literalinclude:: _snippets/blog-post.js + :language: jsx + +This is similar to a simple page component, except for GraphQL query. +We need to fetch data for a specific node. +To do this, we can use the ``slug`` value to filter only desired node. + +.. note:: + + We can filter with almost every node attribute, but it is always better use uniques values like ``id`` or ``slug``. + +.. note:: + + ``dangerouslySetInnerHTML`` is a helper function of ReactJS that allows to insert some not-reactish HTML into a component. + +If we restart the server, we can now directly access the pages that were automatically created. + +.. note:: + + To easily get a list of generated URLs, try to access a random page like `http://localhost:8000/asdf `_. + The default ``NotFound`` page will offer alternative URLs. + +Last thing that we could do is to link them in our ``index.js`` page: + +.. literalinclude:: _snippets/index_posts.js + :language: jsx + :emphasize-lines: 13,20 diff --git a/gatsby/gatsbysourceplone.rst b/gatsby/gatsbysourceplone.rst new file mode 100644 index 000000000..e99a5b78d --- /dev/null +++ b/gatsby/gatsbysourceplone.rst @@ -0,0 +1,95 @@ +gatsby-source-plone +=================== + +With the previous sections on source nodes, retrieving data from ``plone.restapi``, and finally using the search traversal method, we have understood how our source-plugin works at base level. + +Great work! + +``gatsby-source-plone`` is basically this plugin with additional helpful features and functionality to handle all kinds of data, caching and so on in an optimal manner. + +First remove whatever code we have written in ``gatsby-node.js``, as our plugin will be taking care of all that internally. +Then install ``gatsby-source-plone`` with ``npm install gatsby-source-plone``. + +Before we can use the plugin, we need to configure it to be used with GatsbyJS. + +Configuration +------------- + +All of the settings for the ``gatsby-source-plone`` plugin is in the ``gatsby-node.js``: + +.. code-block:: javascript + + { + resolve: 'gatsby-source-plone', + options: { + baseUrl: 'https://plonedemo.kitconcept.com/en' + }, + }, + + +**baseUrl** is the Plone site from which data is to be sourced from. +It can be a Plone site root or a Plone folder to be used as root. + +**searchParams** although not used in the example, it is worth noting. +It is used to limit retrieved content objects by a search parameter. +This allows users to use and display only filtered content in the generated static site. +For examples and more detailed explanation refer to the `docs `_. + +**token** is the ``JWT`` (JSON Web Token) for ``plone.restapi``. +This is used in some Plone sites that require authentication to query data. +For configuring authentication with ``JWT`` and `dotenv `_, read the full `documentation `_ for a step by step reference. + +.. note:: + + https://plonedemo.kitconcept.com/en which was earlier used in the examples requires no authentication to query for data. + Hence we can skip the ``token`` setting here. + +Once configured with basic settings, all the data of the Plone Site specified will be available for query via GraphQL. + +To test the plugin you could use the sample configuration mentioned above. + + +Exercise +-------- + +Run the development server with ``gatsby develop`` and navigate to GraphiQL explorer at http://localhost:8000/___graphql. + +Explore different content object types and also take a look at the breadcrumbs data. + +Hints: Query all objects of a type with ``allPloneEvent``, ``allPloneNewsItem`` and so on. +Breadcrumbs data for every content node is available to us with ``allPloneBreadcrumbs``. + +.. admonition:: Solution + :class: toggle + + .. code-block:: text + + { + allPloneNewsItem { + edges { + node { + id + } + } + } + + allPloneEvent { + edges { + node { + id + } + } + } + + allPloneBreadcrumbs { + edges { + node { + id + } + } + } + } + + + + diff --git a/gatsby/gatsbystarterplone.rst b/gatsby/gatsbystarterplone.rst new file mode 100644 index 000000000..1d9a7af3a --- /dev/null +++ b/gatsby/gatsbystarterplone.rst @@ -0,0 +1,31 @@ +gatsby-starter-plone +==================== + +``gatsby-starter-plone`` comes with ``gatsby-source-plone`` already configured and setup with all the functionality and also includes some additional helpful features. + +This makes sure you do not spend too much time on the configuration and can focus directly on building your site. + +Let us try out the `gatsby-source-plone `_ plugin with our `gatsby-starter-plone `_ to instantly kickstart GatsbyJS development with Plone. + +With the GatsbyJS CLI installed, start up with: + +.. code-block:: console + + gatsby new gatsby-plone-training https://github.com/collective/gatsby-starter-plone + + +This will setup a GatsbyJS project in the ``gatsby-plone-training`` folder with ``gatsby-source-plone`` setup already, along with a couple of useful extra features. + +To see the starter along with the plugin in action, run the following commands and navigate to http://localhost:8000. + +.. code-block:: console + + cd gatsby-plone-training + gatsby develop + +Yes! We have a GatsbyJS site sourced from a Plone site up and running. + +Take time exploring the static site generated by GatsbyJS and compare it to the Plone site at https://plonedemo.kitconcept.com/en/. + +Notice that we have tried to keep them as similar as possible. + diff --git a/gatsby/howitworks.rst b/gatsby/howitworks.rst new file mode 100644 index 000000000..35bcde7ca --- /dev/null +++ b/gatsby/howitworks.rst @@ -0,0 +1,41 @@ +How it works +============ + +There are basically three steps: + +1) Fetch data +------------- +You can configure GatsbyJS to fetch data from different sources like headless CMSs, SaaS services, APIs, databases, your file system and more. + +This is done with ``source plugins``. + +The active GatsbyJS community has `several plugins `_ that can fetch data from various sources. + +2) Build +-------- +In this step there are three main technologies involved: GraphQL, React and Webpack. + +GraphQL is a query language used to create APIs where you can create queries that generates exactly the data that you need (and only the data that you need). +It is used to store and serve fetched data in a common and easily to access way. + +The second component is ReactJS: a JavaScript library that allows to create powerful and reusable interfaces. + +It works with a basic rule: everything is a component, and every interface is built with a set of components. +Components let you split the UI into independent, reusable pieces, and think about each piece in isolation. + +Conceptually, components are like JavaScript functions. They accept arbitrary inputs (called "props") and return React elements describing what should appear on the screen. + +In GatsbyJS all pages are React components that receive data (if needed) from GraphQL and display some information. + +It also is very flexible in its project structure allowing you to choose the way you want it to be, libraries you want to use, methods of styling and much more. + +The last component is Webpack: a module bundler. + +It is a tool that takes all the resources (pages, stylesheets, images and other dependencies), combines them together, and generates a set of static pages that will be the final GatsbyJS site. + +In development mode, it exposes the built site to a certain HTTP port (to see what we are developing) and rebuild it every time we create/edit/delete a file in the source code. + +3) Deploy +--------- +The output of GatsbyJS is a set of static resources: HTML, CSS and JavaScript files. +You can deploy them wherever you deploy static files (Amazon S3, Netlify, GitHub pages, Apache, Surge.sh, and so on). diff --git a/gatsby/index.rst b/gatsby/index.rst new file mode 100644 index 000000000..52103764a --- /dev/null +++ b/gatsby/index.rst @@ -0,0 +1,48 @@ +.. gatsby-label: + +========= +GatsbyJS +========= + +:About: Building blazing-fast static websites with GatsbyJS +:Level: All levels + +.. note:: + + This training is meant to be used in a course or read and worked through by an individual user. + Instructors should note that this makes it more discursive than it would be if it was only meant for classroom use. + + Many sections may be zipped through in a class, noting to students that the full text is available for review. + + +.. toctree:: + :hidden: + :maxdepth: 3 + :caption: GatsbyJS + + summary + whatisgatsby + howitworks + installing + pages + data + sourceplugins + transformerplugins + dynamicpages + buildingsourceplugins + plonerestapi + searchtraversal + gatsbysourceplone + gatsbystarterplone + copyingplonesite + richtext + navigation + +.. toctree:: + :hidden: + :maxdepth: 3 + :caption: Plone Trainings + :name: plone-trainings-gatsby-toc + + ../about/index + ../about/glossary diff --git a/gatsby/installing.rst b/gatsby/installing.rst new file mode 100644 index 000000000..57d40a5e2 --- /dev/null +++ b/gatsby/installing.rst @@ -0,0 +1,61 @@ +Installing The Development Environment +====================================== + +First, we need last LTS NodeJS version (8.12.0 at writing time). +We recommend to use nvm to install NodeJS instead of using your OS-based version. + +Install nvm on your system using the instructions and provided script at: + +https://github.com/nvm-sh/nvm#install-script + +Using nvm we will look up the latest lts version of NodeJS and install it + +.. code-block:: console + + nvm install --lts + nvm use --lts + +NodeJS is provided with npm, its package manager, we will use it to install the GatsbyJS CLI + +.. code-block:: console + + npm install --g gatsby-cli + +.. note:: ``-g`` means the CLI will be available globally in our nvm instance. + +When you are prompted to use either `yarn` or `npm` to install the GatsbyJS CLI, it's ok to use the default, `yarn`. + +Creating a new GatsbyJS site +============================ + +The CLI allows to initialize a project: + +.. code-block:: console + + gatsby new hello-world + +This command tells gatsby-cli to create a new GatsbyJS project with the name ``hello-world`` with a basic default file structure. + +There are several boilerplates created by the community that allows to bootstrap an application for different use-cases. + +These boilerplates are called "starters" and in the `offical site `_ you could +find a complete list of available starters. There are starters with some pre-configured themes (for example material-ui or bootstrap), support for authentication, and so on. + +There are also some starters that are specialized in integration with some external sources, such as a CMS like Plone or WordPress. +They create a boilerplate with all the configuration to fetch data from the external sources and give some helper methods to build the pages/interface with that specific data, such as the breadcrumbs or navigation. + +Data fetching part is usually managed by a different type of plugins called "source-plugins" that can retrieve data from a specific source. + +We will cover "source-plugins" in later chapters. + +.. note:: To create a new project with a starter, you need to append the github URL of the desired starter in the cli command: ``gatsby new [SITE_DIRECTORY] [URL_OF_STARTER_GITHUB_REPO]`` + +.. code-block:: console + + cd hello-world + gatsby develop + +This command starts a development server. +You will be able to see and interact with your new site in a development environment at http://localhost:8000. + +Now that we have a working installation, let us go deep inside GatsbyJS to see how it works and what are its main parts. diff --git a/gatsby/navigation.rst b/gatsby/navigation.rst new file mode 100644 index 000000000..694478b75 --- /dev/null +++ b/gatsby/navigation.rst @@ -0,0 +1,62 @@ +Navigation +========== + +We have covered page creation and displaying data. + +As the amount of the content and pages increases, navigation is important so that a user does not get lost deep in a site. + +``gatsby-source-plone`` provides Breadcrumb and root Navigation data, making this task fairly simple. + + +Breadcrumbs +----------- + +Since breadcrumbs depend on the page you are in, it needs to be dynamically created for each page. + +So the approach is to query it in each page as they are created and pass it on to the Breadcrumb component. + +.. code-block:: text + + ploneBreadcrumbs(_path: { eq: $path }) { + items { + _id + _path + title + } + } + + +Here ``items`` is an array of items where each one is a breadcrumb. + +This data can be appropriately styled and used in a breadcrumb bar. + + +Navigation +---------- + +This is the common topbar in all the views of the site. + +It allows quick jumping between root folders (depending on customization). + +Unlike breadcrumbs, we can use a static query here (which queries data initially and then just uses existing data). + +.. code-block:: jsx + + const NavBar = ({ active }) => ( + ( +