1
0
mirror of https://github.com/projekteuler/projekteuler.git synced 2026-01-27 02:28:50 +01:00

2 Commits

Author SHA1 Message Date
8e55afe9c2 Add logo to navbar 2019-02-08 20:57:08 +01:00
cad4973f6a Update favicon 2019-02-08 20:56:23 +01:00
103 changed files with 770 additions and 13998 deletions

View File

@@ -1,39 +0,0 @@
# See https://docs.docker.com/engine/reference/builder/#dockerignore-file for more about ignoring files.
# Ignore git directory.
/.git/
# Ignore bundler config.
/.bundle
# Ignore all default key files.
/config/master.key
/config/credentials/*.key
# Ignore all environment files.
/.env*
!/.env.example
# Ignore all logfiles and tempfiles.
/log/*
/tmp/*
!/log/.keep
!/tmp/.keep
# Ignore pidfiles, but keep the directory.
/tmp/pids/*
!/tmp/pids/
!/tmp/pids/.keep
# Ignore storage (uploaded files in development and any SQLite databases).
/storage/*
!/storage/.keep
/tmp/storage/*
!/tmp/storage/
!/tmp/storage/.keep
# Ignore assets.
/node_modules/
/app/assets/builds/*
!/app/assets/builds/.keep
/public/assets

9
.gitattributes vendored
View File

@@ -1,9 +0,0 @@
# See https://git-scm.com/docs/gitattributes for more about git attribute files.
# Mark the database schema as having been generated.
db/schema.rb linguist-generated
# Mark any vendored files as having been vendored.
vendor/* linguist-vendored
config/credentials/*.yml.enc diff=rails_credentials
config/credentials.yml.enc diff=rails_credentials

View File

@@ -1,7 +0,0 @@
version: 2
updates:
- package-ecosystem: bundler
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 10

View File

@@ -1,28 +0,0 @@
name: CI
on:
push:
branches: [$default-branch]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
ruby: ["3.0", "3.1", "3.2"]
steps:
- uses: actions/checkout@v3
- name: Set up Ruby ${{ matrix.ruby }}
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
- name: Set up Node
uses: actions/setup-node@v3
with:
node-version: "20"
- name: Install dependencies
run: bundle install --without production
- name: Run tests
run: bundle exec rake
env:
RAILS_ENV: test

View File

@@ -1,48 +0,0 @@
#
name: Create and publish a Docker image
# Configures this workflow to run every time a change is pushed to the branch called `release`.
on:
push:
branches: ["release"]
# Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds.
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
# There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu.
jobs:
build-and-push-image:
runs-on: ubuntu-latest
# Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job.
permissions:
contents: read
packages: write
#
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here.
- name: Log in to the Container registry
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels.
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
# This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages.
# It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository.
# It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step.
- name: Build and push Docker image
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

23
.gitignore vendored
View File

@@ -12,24 +12,13 @@
/db/*.sqlite3-journal
# Ignore all logfiles and tempfiles.
/log/*
/tmp/*
!/log/.keep
!/tmp/.keep
/log/*.log
/tmp
# Ignore pidfiles, but keep the directory.
/tmp/pids/*
!/tmp/pids/
!/tmp/pids/.keep
# Ignore storage (uploaded files in development and any SQLite databases).
/storage/*
!/storage/.keep
/tmp/storage/*
!/tmp/storage/
!/tmp/storage/.keep
/public/assets
# Ignore coverage data generated by coveralls
/coverage
# Ignore encrypted secrets key file.
config/secrets.yml.key
# Ignore master key for decrypting credentials and more.
/config/master.key

View File

@@ -1 +0,0 @@
ruby-3.2.2

12
.travis.yml Normal file
View File

@@ -0,0 +1,12 @@
dist: trusty
language: ruby
cache: bundler
rvm:
- 2.6
- 2.5
- 2.4
- 2.3
script:
- export RAILS_ENV=test
- bundle exec rake db:schema:load
- bundle exec rake test

View File

@@ -1,77 +0,0 @@
# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
ARG RUBY_VERSION=3.2.2
FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base
# Rails app lives here
WORKDIR /rails
# Set production environment
ENV RAILS_ENV="production" \
BUNDLE_DEPLOYMENT="1" \
BUNDLE_PATH="/usr/local/bundle" \
BUNDLE_WITHOUT="development"
# Throw-away build stage to reduce size of final image
FROM base as build
# Install packages needed to build gems and node modules
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential git libvips pkg-config curl node-gyp default-libmysqlclient-dev
# Install JavaScript dependencies
ARG NODE_VERSION=20.5.0
ARG YARN_VERSION=1.22.19
ENV PATH=/usr/local/node/bin:$PATH
RUN curl -sL https://github.com/nodenv/node-build/archive/master.tar.gz | tar xz -C /tmp/ && \
/tmp/node-build-master/bin/node-build "${NODE_VERSION}" /usr/local/node && \
npm install -g yarn@$YARN_VERSION && \
rm -rf /tmp/node-build-master
# Install application gems
COPY Gemfile Gemfile.lock ./
RUN bundle install && \
rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
bundle exec bootsnap precompile --gemfile
# Install node modules
#COPY package.json yarn.lock ./
#RUN yarn install --frozen-lockfile
# Copy application code
COPY . .
# Precompile bootsnap code for faster boot times
RUN bundle exec bootsnap precompile app/ lib/
# Precompiling assets for production without requiring secret RAILS_MASTER_KEY
RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile
# Final stage for app image
FROM base
LABEL org.opencontainers.image.source=https://github.com/projekteuler/projekteuler
LABEL org.opencontainers.image.description="Projekteuler production image"
LABEL org.opencontainers.image.licenses=MIT
# Install packages needed for deployment
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y curl node-gyp default-mysql-client libvips && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
# Copy built artifacts: gems, application
COPY --from=build /usr/local/bundle /usr/local/bundle
COPY --from=build /rails /rails
# Run and own only the runtime files as a non-root user for security
RUN useradd rails --create-home --shell /bin/bash && \
chown -R rails:rails db log tmp
USER rails:rails
# Entrypoint prepares the database.
ENTRYPOINT ["/rails/bin/docker-entrypoint"]
# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
CMD ["./bin/rails", "server"]

51
Gemfile
View File

@@ -2,59 +2,56 @@ source 'https://rubygems.org'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 7.1.1'
# Use Puma as the app server
gem 'puma', '~> 6.3'
gem 'rails', '5.2.2'
# Use sqlite3 as the database for Active Record
gem 'sqlite3', '~> 1.6.3'
gem 'sqlite3', '~> 1.3.13'
gem 'mysql2', '~> 0.5.5', group: :production
gem 'mysql2', '~> 0.5.2', group: :production
gem 'bootsnap', require: false
# Use SCSS for stylesheets
gem 'sassc-rails', '~> 2.1.2'
gem 'sassc-rails', '~> 2.1.0'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '~> 4.2.0'
gem 'uglifier', '~> 4.1.20'
# Use CoffeeScript for .js.coffee assets and views
gem 'coffee-rails', '~> 5.0.0'
gem 'coffee-rails', '~> 4.2.2'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# gem 'therubyracer', platforms: :ruby
gem 'rails-i18n', '~> 7.0.7'
gem 'rails-i18n', '~> 5.1.3'
gem 'rails-controller-testing'
gem 'webmock', group: :test
# Use jquery as the JavaScript library
gem 'jquery-rails', '~> 4.5.1'
gem 'jquery-rails', '~> 4.3.3'
# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
gem 'turbolinks', '~> 5.2.1'
gem 'turbolinks', '~> 5.2.0'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.11.3'
gem 'jbuilder', '~> 2.8.0'
# bundle exec rake doc:rails generates the API under doc/api.
gem 'sdoc', '~> 2.6.1', group: :doc
gem 'sdoc', '~> 1.0.0', group: :doc
gem 'web-console', '~> 4.2.0', group: :development
gem 'listen', '~> 3.8.0', group: :development
gem 'web-console', '~> 3.7.0', group: :development
gem 'bootstrap', '~> 5.2.3'
gem "bootstrap_form", "~> 5.2"
gem 'font-awesome-sass', '~> 6.4.0'
# Use Codacy for coverage
gem 'codacy-coverage', :require => false
# Use Diffy for showing translation diffs
gem 'diffy'
gem 'diff-lcs'
gem 'bootstrap-sass', '~> 3.4.0'
gem 'autoprefixer-rails', '~> 9.4.6'
gem 'will_paginate', '~> 3.3.1'
gem 'will_paginate-bootstrap4', '~> 0.2.2'
gem 'bh', '~> 1.3.6'
gem 'devise', '~> 4.8.0'
gem 'will_paginate', '~> 3.1.6'
gem 'will-paginate-i18n', '~> 0.1.15'
gem 'will_paginate-bootstrap', '~> 1.0.1'
gem 'devise', '~> 4.5.0'
gem 'devise-bootstrap-views', '~> 0.0.11'
gem 'omniauth'
gem 'omniauth-rails_csrf_protection'
gem 'omniauth-github'
gem 'codemirror-rails', '~> 5.16.0'
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'

View File

@@ -1,353 +1,274 @@
GEM
remote: https://rubygems.org/
specs:
actioncable (7.1.1)
actionpack (= 7.1.1)
activesupport (= 7.1.1)
actioncable (5.2.2)
actionpack (= 5.2.2)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
zeitwerk (~> 2.6)
actionmailbox (7.1.1)
actionpack (= 7.1.1)
activejob (= 7.1.1)
activerecord (= 7.1.1)
activestorage (= 7.1.1)
activesupport (= 7.1.1)
mail (>= 2.7.1)
net-imap
net-pop
net-smtp
actionmailer (7.1.1)
actionpack (= 7.1.1)
actionview (= 7.1.1)
activejob (= 7.1.1)
activesupport (= 7.1.1)
actionmailer (5.2.2)
actionpack (= 5.2.2)
actionview (= 5.2.2)
activejob (= 5.2.2)
mail (~> 2.5, >= 2.5.4)
net-imap
net-pop
net-smtp
rails-dom-testing (~> 2.2)
actionpack (7.1.1)
actionview (= 7.1.1)
activesupport (= 7.1.1)
nokogiri (>= 1.8.5)
rack (>= 2.2.4)
rack-session (>= 1.0.1)
rails-dom-testing (~> 2.0)
actionpack (5.2.2)
actionview (= 5.2.2)
activesupport (= 5.2.2)
rack (~> 2.0)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
actiontext (7.1.1)
actionpack (= 7.1.1)
activerecord (= 7.1.1)
activestorage (= 7.1.1)
activesupport (= 7.1.1)
globalid (>= 0.6.0)
nokogiri (>= 1.8.5)
actionview (7.1.1)
activesupport (= 7.1.1)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (5.2.2)
activesupport (= 5.2.2)
builder (~> 3.1)
erubi (~> 1.11)
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
activejob (7.1.1)
activesupport (= 7.1.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
activejob (5.2.2)
activesupport (= 5.2.2)
globalid (>= 0.3.6)
activemodel (7.1.1)
activesupport (= 7.1.1)
activerecord (7.1.1)
activemodel (= 7.1.1)
activesupport (= 7.1.1)
timeout (>= 0.4.0)
activestorage (7.1.1)
actionpack (= 7.1.1)
activejob (= 7.1.1)
activerecord (= 7.1.1)
activesupport (= 7.1.1)
marcel (~> 1.0)
activesupport (7.1.1)
base64
bigdecimal
activemodel (5.2.2)
activesupport (= 5.2.2)
activerecord (5.2.2)
activemodel (= 5.2.2)
activesupport (= 5.2.2)
arel (>= 9.0)
activestorage (5.2.2)
actionpack (= 5.2.2)
activerecord (= 5.2.2)
marcel (~> 0.3.1)
activesupport (5.2.2)
concurrent-ruby (~> 1.0, >= 1.0.2)
connection_pool (>= 2.2.5)
drb
i18n (>= 1.6, < 2)
minitest (>= 5.1)
mutex_m
tzinfo (~> 2.0)
addressable (2.8.4)
public_suffix (>= 2.0.2, < 6.0)
autoprefixer-rails (10.4.13.0)
execjs (~> 2)
base64 (0.1.1)
bcrypt (3.1.16)
bigdecimal (3.1.4)
bindex (0.8.1)
bootsnap (1.16.0)
msgpack (~> 1.2)
bootstrap (5.2.3)
autoprefixer-rails (>= 9.1.0)
popper_js (>= 2.11.6, < 3)
sassc-rails (>= 2.0.0)
bootstrap_form (5.2.3)
actionpack (>= 6.0)
activemodel (>= 6.0)
builder (3.2.4)
coffee-rails (5.0.0)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
arel (9.0.0)
autoprefixer-rails (9.4.6)
execjs
bcrypt (3.1.12)
bcrypt (3.1.12-x64-mingw32)
bcrypt (3.1.12-x86-mingw32)
bh (1.3.6)
actionpack
activesupport
bindex (0.5.0)
bootsnap (1.3.2)
msgpack (~> 1.0)
bootstrap-sass (3.4.0)
autoprefixer-rails (>= 5.2.1)
sassc (>= 2.0.0)
builder (3.2.3)
codacy-coverage (2.1.0)
simplecov
codemirror-rails (5.16.0)
railties (>= 3.0, < 6.0)
coffee-rails (4.2.2)
coffee-script (>= 2.2.0)
railties (>= 5.2.0)
railties (>= 4.0.0)
coffee-script (2.4.1)
coffee-script-source
execjs
coffee-script-source (1.12.2)
concurrent-ruby (1.2.2)
connection_pool (2.4.1)
crack (0.4.5)
rexml
crass (1.0.6)
date (3.3.3)
devise (4.8.1)
concurrent-ruby (1.1.4)
crass (1.0.4)
devise (4.5.0)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0)
railties (>= 4.1.0, < 6.0)
responders
warden (~> 1.2.3)
diff-lcs (1.5.0)
diffy (3.4.2)
drb (2.1.1)
ruby2_keywords
erubi (1.12.0)
execjs (2.8.1)
faraday (2.7.4)
faraday-net_http (>= 2.0, < 3.1)
ruby2_keywords (>= 0.0.4)
faraday-net_http (3.0.2)
ffi (1.15.5)
font-awesome-sass (6.4.0)
sassc (~> 2.0)
globalid (1.2.1)
activesupport (>= 6.1)
hashdiff (1.0.1)
hashie (5.0.0)
i18n (1.14.1)
devise-bootstrap-views (0.0.11)
docile (1.3.1)
erubi (1.8.0)
execjs (2.7.0)
faraday (0.15.4)
multipart-post (>= 1.2, < 3)
ffi (1.9.25)
ffi (1.9.25-x64-mingw32)
ffi (1.9.25-x86-mingw32)
globalid (0.4.2)
activesupport (>= 4.2.0)
hashie (3.6.0)
i18n (0.9.5)
concurrent-ruby (~> 1.0)
io-console (0.6.0)
irb (1.8.3)
rdoc
reline (>= 0.3.8)
jbuilder (2.11.5)
actionview (>= 5.0.0)
activesupport (>= 5.0.0)
jquery-rails (4.5.1)
jbuilder (2.8.0)
activesupport (>= 4.2.0)
multi_json (>= 1.2)
jquery-rails (4.3.3)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
jwt (2.7.0)
listen (3.8.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
loofah (2.21.4)
json (2.1.0)
jwt (2.1.0)
loofah (2.2.3)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
mail (2.8.1)
nokogiri (>= 1.5.9)
mail (2.7.1)
mini_mime (>= 0.1.1)
net-imap
net-pop
net-smtp
marcel (1.0.2)
mini_mime (1.1.5)
mini_portile2 (2.8.4)
minitest (5.20.0)
msgpack (1.6.0)
marcel (0.3.3)
mimemagic (~> 0.3.2)
method_source (0.9.2)
mimemagic (0.3.3)
mini_mime (1.0.1)
mini_portile2 (2.4.0)
minitest (5.11.3)
msgpack (1.2.6)
msgpack (1.2.6-x64-mingw32)
msgpack (1.2.6-x86-mingw32)
multi_json (1.13.1)
multi_xml (0.6.0)
mutex_m (0.1.2)
mysql2 (0.5.5)
net-imap (0.4.1)
date
net-protocol
net-pop (0.1.2)
net-protocol
net-protocol (0.2.1)
timeout
net-smtp (0.4.0)
net-protocol
nio4r (2.5.9)
nokogiri (1.15.4)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
oauth2 (2.0.9)
faraday (>= 0.17.3, < 3.0)
multipart-post (2.0.0)
mysql2 (0.5.2)
mysql2 (0.5.2-x64-mingw32)
mysql2 (0.5.2-x86-mingw32)
nio4r (2.3.1)
nokogiri (1.10.1)
mini_portile2 (~> 2.4.0)
nokogiri (1.10.1-x64-mingw32)
mini_portile2 (~> 2.4.0)
nokogiri (1.10.1-x86-mingw32)
mini_portile2 (~> 2.4.0)
oauth2 (1.4.1)
faraday (>= 0.8, < 0.16.0)
jwt (>= 1.0, < 3.0)
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (>= 1.2, < 4)
snaky_hash (~> 2.0)
version_gem (~> 1.1)
omniauth (2.1.1)
hashie (>= 3.4.6)
rack (>= 2.2.3)
rack-protection
omniauth-github (2.0.1)
omniauth (~> 2.0)
omniauth-oauth2 (~> 1.8)
omniauth-oauth2 (1.8.0)
oauth2 (>= 1.4, < 3)
omniauth (~> 2.0)
omniauth-rails_csrf_protection (1.0.1)
actionpack (>= 4.2)
omniauth (~> 2.0)
rack (>= 1.2, < 3)
omniauth (1.9.0)
hashie (>= 3.4.6, < 3.7.0)
rack (>= 1.6.2, < 3)
omniauth-github (1.3.0)
omniauth (~> 1.5)
omniauth-oauth2 (>= 1.4.0, < 2.0)
omniauth-oauth2 (1.6.0)
oauth2 (~> 1.1)
omniauth (~> 1.9)
orm_adapter (0.5.0)
popper_js (2.11.7)
psych (5.1.0)
stringio
public_suffix (5.0.1)
puma (6.3.0)
nio4r (~> 2.0)
racc (1.7.1)
rack (3.0.8)
rack-protection (3.0.6)
rack
rack-session (2.0.0)
rack (>= 3.0.0)
rack-test (2.1.0)
rack (>= 1.3)
rackup (2.1.0)
rack (>= 3)
webrick (~> 1.8)
rails (7.1.1)
actioncable (= 7.1.1)
actionmailbox (= 7.1.1)
actionmailer (= 7.1.1)
actionpack (= 7.1.1)
actiontext (= 7.1.1)
actionview (= 7.1.1)
activejob (= 7.1.1)
activemodel (= 7.1.1)
activerecord (= 7.1.1)
activestorage (= 7.1.1)
activesupport (= 7.1.1)
bundler (>= 1.15.0)
railties (= 7.1.1)
rails-controller-testing (1.0.5)
actionpack (>= 5.0.1.rc1)
actionview (>= 5.0.1.rc1)
activesupport (>= 5.0.1.rc1)
rails-dom-testing (2.2.0)
activesupport (>= 5.0.0)
minitest
rack (2.0.6)
rack-test (1.1.0)
rack (>= 1.0, < 3)
rails (5.2.2)
actioncable (= 5.2.2)
actionmailer (= 5.2.2)
actionpack (= 5.2.2)
actionview (= 5.2.2)
activejob (= 5.2.2)
activemodel (= 5.2.2)
activerecord (= 5.2.2)
activestorage (= 5.2.2)
activesupport (= 5.2.2)
bundler (>= 1.3.0)
railties (= 5.2.2)
sprockets-rails (>= 2.0.0)
rails-controller-testing (1.0.4)
actionpack (>= 5.0.1.x)
actionview (>= 5.0.1.x)
activesupport (>= 5.0.1.x)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.6.0)
loofah (~> 2.21)
nokogiri (~> 1.14)
rails-i18n (7.0.7)
rails-html-sanitizer (1.0.4)
loofah (~> 2.2, >= 2.2.2)
rails-i18n (5.1.3)
i18n (>= 0.7, < 2)
railties (>= 6.0.0, < 8)
railties (7.1.1)
actionpack (= 7.1.1)
activesupport (= 7.1.1)
irb
rackup (>= 1.0.0)
rake (>= 12.2)
thor (~> 1.0, >= 1.2.2)
zeitwerk (~> 2.6)
rake (13.0.6)
rb-fsevent (0.11.2)
rb-inotify (0.10.1)
ffi (~> 1.0)
rdoc (6.5.0)
psych (>= 4.0.0)
reline (0.3.9)
io-console (~> 0.5)
responders (3.0.1)
actionpack (>= 5.0)
railties (>= 5.0)
rexml (3.2.5)
ruby2_keywords (0.0.5)
sassc (2.4.0)
ffi (~> 1.9)
sassc-rails (2.1.2)
railties (>= 5.0, < 6)
railties (5.2.2)
actionpack (= 5.2.2)
activesupport (= 5.2.2)
method_source
rake (>= 0.8.7)
thor (>= 0.19.0, < 2.0)
rake (12.3.2)
rdoc (6.1.1)
responders (2.4.1)
actionpack (>= 4.2.0, < 6.0)
railties (>= 4.2.0, < 6.0)
sassc (2.0.0)
ffi (~> 1.9.6)
rake
sassc-rails (2.1.0)
railties (>= 4.0.0)
sassc (>= 2.0)
sprockets (> 3.0)
sprockets-rails
tilt
sdoc (2.6.1)
sdoc (1.0.0)
rdoc (>= 5.0)
snaky_hash (2.0.1)
hashie
version_gem (~> 1.1, >= 1.1.1)
sprockets (4.2.0)
simplecov (0.16.1)
docile (~> 1.1)
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.2)
sprockets (3.7.2)
concurrent-ruby (~> 1.0)
rack (>= 2.2.4, < 4)
sprockets-rails (3.4.2)
actionpack (>= 5.2)
activesupport (>= 5.2)
rack (> 1, < 3)
sprockets-rails (3.2.1)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
sqlite3 (1.6.3)
mini_portile2 (~> 2.8.0)
stringio (3.0.6)
thor (1.2.2)
tilt (2.1.0)
timeout (0.4.0)
turbolinks (5.2.1)
sqlite3 (1.3.13)
sqlite3 (1.3.13-x64-mingw32)
sqlite3 (1.3.13-x86-mingw32)
thor (0.19.4)
thread_safe (0.3.6)
tilt (2.0.9)
turbolinks (5.2.0)
turbolinks-source (~> 5.2)
turbolinks-source (5.2.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
uglifier (4.2.0)
tzinfo (1.2.5)
thread_safe (~> 0.1)
tzinfo-data (1.2018.9)
tzinfo (>= 1.0.0)
uglifier (4.1.20)
execjs (>= 0.3.0, < 3)
version_gem (1.1.2)
warden (1.2.9)
rack (>= 2.0.9)
web-console (4.2.0)
actionview (>= 6.0.0)
activemodel (>= 6.0.0)
warden (1.2.8)
rack (>= 2.0.6)
web-console (3.7.0)
actionview (>= 5.0)
activemodel (>= 5.0)
bindex (>= 0.4.0)
railties (>= 6.0.0)
webmock (3.18.1)
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
webrick (1.8.1)
websocket-driver (0.7.6)
railties (>= 5.0)
websocket-driver (0.7.0)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
will_paginate (3.3.1)
will_paginate-bootstrap4 (0.2.2)
will_paginate (~> 3.0, >= 3.0.0)
zeitwerk (2.6.12)
websocket-extensions (0.1.3)
will-paginate-i18n (0.1.15)
will_paginate (3.1.6)
will_paginate-bootstrap (1.0.1)
will_paginate (>= 3.0.3)
PLATFORMS
ruby
x64-mingw32
x86-mingw32
DEPENDENCIES
autoprefixer-rails (~> 9.4.6)
bh (~> 1.3.6)
bootsnap
bootstrap (~> 5.2.3)
bootstrap_form (~> 5.2)
coffee-rails (~> 5.0.0)
devise (~> 4.8.0)
diff-lcs
diffy
font-awesome-sass (~> 6.4.0)
jbuilder (~> 2.11.3)
jquery-rails (~> 4.5.1)
listen (~> 3.8.0)
mysql2 (~> 0.5.5)
bootstrap-sass (~> 3.4.0)
codacy-coverage
codemirror-rails (~> 5.16.0)
coffee-rails (~> 4.2.2)
devise (~> 4.5.0)
devise-bootstrap-views (~> 0.0.11)
jbuilder (~> 2.8.0)
jquery-rails (~> 4.3.3)
mysql2 (~> 0.5.2)
omniauth
omniauth-github
omniauth-rails_csrf_protection
puma (~> 6.3)
rails (~> 7.1.1)
rails (= 5.2.2)
rails-controller-testing
rails-i18n (~> 7.0.7)
sassc-rails (~> 2.1.2)
sdoc (~> 2.6.1)
sqlite3 (~> 1.6.3)
turbolinks (~> 5.2.1)
rails-i18n (~> 5.1.3)
sassc-rails (~> 2.1.0)
sdoc (~> 1.0.0)
sqlite3 (~> 1.3.13)
turbolinks (~> 5.2.0)
tzinfo-data
uglifier (~> 4.2.0)
web-console (~> 4.2.0)
webmock
will_paginate (~> 3.3.1)
will_paginate-bootstrap4 (~> 0.2.2)
uglifier (~> 4.1.20)
web-console (~> 3.7.0)
will-paginate-i18n (~> 0.1.15)
will_paginate (~> 3.1.6)
will_paginate-bootstrap (~> 1.0.1)
BUNDLED WITH
2.4.10
1.17.2

View File

@@ -1,63 +1,9 @@
# Projekt Euler
Projekt Euler
=============
![Build Status](https://github.com/projekteuler/projekteuler/workflows/CI/badge.svg)
[![Build Status](https://travis-ci.com/projekteuler/projekteuler.svg?branch=master)](https://travis-ci.org/projekteuler/projekteuler)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/68921bff5347435f8fff10c1d6872568)](https://www.codacy.com/app/projekteuler/projekteuler)
This is the Ruby on Rails web-app powering [projekteuler.de](https://projekteuler.de).
It allows visitors to view and suggest German translations of the maths puzzles found on [projecteuler.net](https://projecteuler.net).
This is a rails app for the german translation of [projecteuler.net](https://projecteuler.net).
## Getting started
1. Download this repository, e.g., with `git clone`.
2. Make sure [NodeJS >= 18](https://nodejs.org) is installed.
3. Navigate inside the repository folder.
4. Use bundler to install all required gems.
$ bundle install
5. Setup the database:
$ bin/rails db:setup
6. Start the server:
$ bin/rails server
7. Open `http://localhost:3000` in your browser. You should see the web app up and running!
8. Start playing with the web app. By default, the database will contain some users and translations. The user `admin` can review translations, while the user `translator` has submitted some translations.
You can login as any user by clicking the Login button and entering their name. This is simply a mock OAuth login; in production mode, GitHub is used for login.
9. If you ever want to reset the database to the original state, run `rails db:reset`.
## Contributing
Do you have a suggestion for an improvement for the web app? Please create an [issue](https://github.com/projekteuler/projekteuler/issues) for it.
Do you want to implement this improvement yourself? Follow these steps:
1. Fork this repository on GitHub.
2. Create a new branch for your improvement
3. Implement your improvement, and create tests for it if applicable.
4. Submit a pull request.
## Deployment
1. Make sure [NodeJS](https://nodejs.org) is installed.
2. Set up a MySQL database.
3. Copy all files from this repository.
4. Make sure the Rails environment is set to `production`.
5. Set up the following environment variables:
- `RAILS_MASTER_KEY`: The master key for decryption of the Rails credentials
- `DATABASE_NAME`: The name of the MySQL database
- `DATABASE_USERNAME`: The username for the MYSQL database
- `DATABASE_PASSWORD`: The password for the MYSQL database
- `DATABASE_HOST`: The host of the MYSQL database
- `DATABASE_PORT`: The port of the MYSQL database
- `GITHUB_CLIENT_ID`: The client ID of your GitHub OAuth App (that you will need to create)
- `GITHUB_CLIENT_SECRET`: The client secret of the GitHub OAuth App
6. Install all required gems with `bundle install`.
7. Load the database schema with `bin/rails db:schema:load`.
8. Precompile all assets with `bin/rails assets:precompile`.
9. Start the server, e.g., with `bin/rails server`.
Anytime you update the files, you should run `bin/rails db:migrate`, `bin/rails log:clear tmp:clear`, `bin/rails assets:precompile` and then restart the server.
## License
This project is released under the [MIT License](https://opensource.org/licenses/MIT).
Currently, it doesn't have a website, but when most of the current issues are fixed, it will be uploaded.

View File

@@ -1,4 +0,0 @@
//= link_tree ../images
//= link application.css
//= link application.js
//

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
app/assets/images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@@ -10,16 +10,15 @@
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require jquery3
//= require rails-ujs
//= require popper
//= require bootstrap-sprockets
//= require codemirror/codemirror
//= require codemirror/addon/display/placeholder
//= require codemirror/mode/xml
//= require codemirror/mode/css
//= require codemirror/mode/javascript
//= require codemirror/mode/htmlmixed
//= require mathjax-config
//= require init
//= require codemirror
//= require codemirror/addons/display/placeholder
//= require codemirror/modes/xml
//= require codemirror/modes/css
//= require codemirror/modes/javascript
//= require codemirror/modes/htmlmixed
//= require translations
//= require_tree .

View File

@@ -1,10 +0,0 @@
window.MathJax = {
jax: ["input/TeX", "output/HTML-CSS"],
tex2jax: {
inlineMath: [ ["$","$"], ["\\(","\\)"] ],
displayMath: [ ["$$","$$"], ["\\[","\\]"] ],
processEscapes: true,
ignoreClass: "mathjax_ignore|diff"
},
"HTML-CSS": { availableFonts: ["TeX"] }
};

View File

@@ -0,0 +1,2 @@
$(document).on 'turbolinks:load', ->
MathJax.Hub.Queue(["Typeset",MathJax.Hub]);

View File

@@ -1,4 +1,6 @@
window.App ||= {}
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
cm = null
@@ -11,13 +13,9 @@ loadCodeMirror = ->
mode: "text/html"
})
App.init = ->
MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
loadCodeMirror();
$(document).on "turbolinks:load", loadCodeMirror
$(document).on "turbolinks:load", ->
App.init()
$(document).on "click", '#translationTab button[data-bs-target="#preview"]', ->
$(document).on "click", '#translationNav a[href="#preview"]', ->
$('#preview .problem-content').html(cm.getValue())
MathJax.Hub.Queue(["Typeset",MathJax.Hub]);

View File

@@ -10,17 +10,17 @@
* defined in the other CSS/SCSS files in this directory. It is generally better to create a new
* file per style scope.
*
*= require codemirror/codemirror
*= require_self
*= require_tree .
*= require devise_bootstrap_views
*= require codemirror
*= require_self
*/
@import "bootstrap-sprockets";
@import "bootstrap";
@import "rails_bootstrap_forms";
@import "font-awesome";
.turbolinks-progress-bar {
background-color: $primary;
background-color: $brand-primary;
}
/* Sticky footer styles
-------------------------------------------------- */
@@ -38,101 +38,111 @@ body {
width: 100%;
/* Set the fixed height of the footer here */
height: 40px;
line-height: 40px;
background-color: $light;
background-color: #f5f5f5;
}
/* Custom style for navbar toggler due to CSP problems */
.navbar-toggler-icon {
background-image: none !important;
}
/* Style for buttons in the corner of problems/translations */
.problem-buttons {
position: relative;
display: block;
}
.problem-buttons .problem-buttons-inner {
position: absolute;
right: 0;
top: 0;
z-index: 10;
}
/* Style for links to previous and next problem */
.problem-prev {
float: left;
margin: 20px -30px 0;
}
.problem-next {
float: right;
margin: 20px -30px 0;
}
/* Style for translation diffs */
.diff {
overflow:auto;
margin-bottom: 20px;
ul{background:#fff;overflow:auto;font-size:13px;list-style:none;margin:0;padding:0;display:table;width:100%;}
del, ins{display:block;text-decoration:none;}
li {
padding:0;
display:table-row;
margin: 0;
height:1em;
ins {
background:#dfd;
color:#080;
strong{font-weight:normal;background:#9f9;}
}
del {
background:#fee;
color:#b00;
strong{font-weight:normal;background:#fcc;}
}
/* try 'whitespace:pre;' if you don't want lines to wrap */
del, ins, span {white-space:pre-wrap;font-family:courier;}
}
.container .text-muted {
margin: 10px 0;
}
/* Custom css for fixing styles within problem content */
.problem-content {
blockquote {
margin: 0px;
font-size: 14px;
border-left: medium none;
}
div {
margin: 0px 0px 10px;
}
table {
border-collapse: separate;
border-spacing: 2px;
}
td {
padding: 1px;
}
// Make info/note boxes styled like bootstrap info alerts
> .info, > .note {
@extend .alert;
@extend .alert-info;
margin-bottom: 0px;
> a {
@extend .alert-link;
}
}
dfn {
border-bottom: 1px dotted;
font-style: normal;
cursor: help;
}
.problem-content blockquote {
margin: 0px;
font-size: 14px;
border-left: medium none;
}
.problem-content div {
margin: 0px 0px 10px;
}
.problem-content table {
border-collapse: separate;
border-spacing: 2px;
}
.problem-content td {
padding: 1px;
}
/* Side notes for calling out things
-------------------------------------------------- */
/* Base styles (regardless of theme) */
.bs-callout, .problem-content > .info:first-child, .problem-content > .info:last-child{
margin: 20px 0;
padding: 15px 30px 15px 15px;
border-left: 5px solid #eee;
}
.bs-callout h1,
.bs-callout h2,
.bs-callout h3,
.bs-callout h4,
.bs-callout h5,
.bs-callout h6 {
margin-top: 0;
}
.bs-callout-danger h1,
.bs-callout-danger h2,
.bs-callout-danger h3,
.bs-callout-danger h4,
.bs-callout-danger h5,
.bs-callout-danger h6 {
color: #B94A48;
}
.bs-callout-warning h1,
.bs-callout-warning h2,
.bs-callout-warning h3,
.bs-callout-warning h4,
.bs-callout-warning h5,
.bs-callout-warning h6 {
color: #C09853;
}
.bs-callout-info h1,
.bs-callout-info h2,
.bs-callout-info h3,
.bs-callout-info h4,
.bs-callout-info h5,
.bs-callout-info h6 {
color: #3A87AD;
}
.bs-callout-success h1,
.bs-callout-success h2,
.bs-callout-success h3,
.bs-callout-success h4,
.bs-callout-success h5,
.bs-callout-success h6 {
color: #3C763D;
}
.bs-callout p:last-child {
margin-bottom: 0;
}
.bs-callout code,
.bs-callout .highlight {
background-color: #fff;
}
/* Themes for different contexts */
.bs-callout-danger {
background-color: #fcf2f2;
border-color: #dFb5b4;
}
.bs-callout-warning {
background-color: #fefbed;
border-color: #f1e7bc;
}
.bs-callout-info, .problem-content > .info:first-child, .problem-content > .info:last-child {
background-color: #f0f7fd;
border-color: #d0e3f0;
}
.bs-callout-success {
background-color: #dff0d8;
border-color: #d6e9c6;
}

View File

@@ -1,11 +1,16 @@
class Admin::DashboardController < AdminController
def index
@current_problem_count = Problem.count
@most_recent_pull = Problem.maximum(:pulled_at)
end
def pull_problems
PullProblemsJob.perform_later
redirect_to({:controller => 'admin/dashboard', :action => :index}, notice: t('.pull_problems_initiated'))
def update_problem_count
begin
new_problem_count = params[:problem_count].to_i
raise t('no_problem_count') unless new_problem_count
Problem.update_count(new_problem_count)
redirect_to({:controller => 'admin/dashboard', :action => :index}, notice: t('.success_message'))
rescue => e
redirect_to({:controller => 'admin/dashboard', :action => :index}, alert: t('.failure_message', error: e.message))
end
end
end

View File

@@ -1,3 +1,8 @@
class AdminController < ApplicationController
before_action :authenticate_admin!
before_action :authenticate!
def authenticate!
authenticate_user!
throw(:warden) unless current_user.admin?
end
end

View File

@@ -2,9 +2,4 @@ class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
def authenticate_admin!
authenticate_user!
throw(:warden) unless current_user.admin?
end
end

View File

@@ -7,6 +7,9 @@ class ProblemsController < ApplicationController
end
def show
unless @problem.is_translated?
render action: "untranslated"
end
end
private

View File

@@ -1,6 +1,5 @@
class TranslationsController < ApplicationController
before_action :set_problem, only: [:new, :create]
before_action :set_accept, only: [:create]
# GET /translations/new
def new
@@ -8,9 +7,6 @@ class TranslationsController < ApplicationController
if @problem.is_translated?
@translation.title = @problem.translation.title
@translation.content = @problem.translation.content
else
@translation.title = @problem.original_title
@translation.content = @problem.original_content
end
end
@@ -21,12 +17,7 @@ class TranslationsController < ApplicationController
@translation.author = current_user
end
if @translation.save
if @accept
@problem.set_translation(@translation)
redirect_to @problem, notice: t('translations.notice.successfully_created_and_accepted')
else
redirect_to @problem, notice: t('translations.notice.successfully_created')
end
redirect_to @problem, notice: t('translations.notice.successfully_created')
else
render :new
end
@@ -41,12 +32,4 @@ class TranslationsController < ApplicationController
def set_problem
@problem = Problem.find(params[:problem_id])
end
def set_accept
if user_signed_in? and current_user.admin?
@accept = params.fetch(:accept, false)
else
@accept = false
end
end
end

View File

@@ -4,7 +4,6 @@ class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def sign_in_with(provider_name)
@user = User.from_omniauth(request.env["omniauth.auth"])
@user.remember_me!
@user.remember_me = true
sign_in_and_redirect @user, event: :authentication
set_flash_message(:notice, :success, kind: provider_name) if is_navigational_format?
end

View File

@@ -7,8 +7,11 @@ module ApplicationHelper
capture do
flash.each do |msg_type, message|
concat(content_tag(:div, message, class: "alert #{bootstrap_class_for(msg_type)} alert-dismissible", role: 'alert') do
concat(content_tag(:button, class: 'close', data: { dismiss: 'alert' }) do
concat content_tag(:span, '&times;'.html_safe, 'aria-hidden' => true)
concat content_tag(:span, 'Close', class: 'sr-only')
end)
concat message
concat content_tag(:button, "", class: 'btn-close', data: { 'bs-dismiss': 'alert' }, 'aria-label': 'Close')
end)
end
nil
@@ -24,11 +27,4 @@ module ApplicationHelper
page_title + ' - ' + base_title
end
end
def nav_link_to(body, url)
content_tag(:li, class: 'nav-item') do
link_to body, url, class: current_page?(url) ? 'nav-link active': 'nav-link'
end
end
end

View File

@@ -1,21 +0,0 @@
require 'open-uri'
class PullProblemContentJob < ApplicationJob
queue_as :default
def perform(problem)
html = URI.open("https://projecteuler.net/minimal=#{problem.id}").read
html.strip!
# Linked problems
html.gsub!('<a href="problem=', '<a href="/problem=')
# Linked about pages
html.gsub!('<a href="about=', '<a href="/about=')
# Linked txt resources
html.gsub!('<a href="project/resources/', '<a href="https://projecteuler.net/project/resources/')
# Included images
html.gsub!('<img src="project/images/', '<img src="https://projecteuler.net/project/images/')
problem.update(original_content: html, pulled_at: Time.current())
end
end

View File

@@ -1,23 +0,0 @@
require 'csv'
require 'open-uri'
class PullProblemsJob < ApplicationJob
queue_as :default
PULL_URL = "https://projecteuler.net/minimal=problems;csv"
def perform
csv = CSV.parse(URI.open(PULL_URL), headers: :first_row)
csv.each do |row|
id = row["ID"].to_i
last_updated = Time.at(row["Updated"].to_i)
problem = Problem.where(id: id).first_or_create!
if problem.pulled_at.nil? or problem.pulled_at < last_updated
original_title = row["Description"]
problem.update(original_title: original_title)
# Don't update pulled_at yet until we also successfully pulled the original_content
PullProblemContentJob.perform_later problem
end
end
end
end

View File

@@ -1,14 +0,0 @@
class TranslationContentScrubber < Rails::Html::PermitScrubber
def initialize
super
self.tags = %w( strong em b i p code pre tt samp kbd var sub
sup dfn cite big small address hr br div span h1 h2 h3 h4 h5 h6 ul ol li dl dt dd abbr
acronym a img blockquote del ins table th tr td thead tbody tfoot u )
self.attributes = %w( href src width height alt cite datetime title class name xml:lang abbr style
align border cellpadding cellspacing colspan )
end
def skip_node?(node)
node.text?
end
end

View File

@@ -1,9 +1,7 @@
<% provide(:title, 'Copyright') %>
<div class="pb-2 mt-4 mb-2 border-bottom">
<h1>Copyright</h1>
</div>
<div class="alert alert-info" role="alert">Dieser Artikel dient gleichzeitig der Übersetzung der <a href="https://projecteuler.net/copyright">"Copyright Information" auf projecteuler.net</a> sowie der tatsächlich geltenden Copyright-Informationen für diese Seite.</div>
<div class="page-header"><h1>Copyright</h1></div>
<div class="bs-callout bs-callout-info">Dieser Artikel dient gleichzeitig der Übersetzung der <a href="https://projecteuler.net/copyright">"Copyright Information" auf projecteuler.net</a> sowie der tatsächlich geltenden Copyright-Informationen für diese Seite.</div>
<h2>Kann ich die Probleme woanders benutzen?</h2>
<p>Ja! Es ist nicht nur erlaubt, sondern beherzt, das Material zu teilen und frei zu benutzen - für nichtkommerzielle Zwecke. Aber bitte lesen Sie weiter...<br />
<br />
@@ -22,7 +20,7 @@
<p>Sie können zum Problem xxx mit der folgenden URI auf projecteuler.net verlinken:</p>
<pre>https://projecteuler.net/problem=xxx</pre>
<p>Ebenso können Sie zu der entsprechenden Übersetzung mit folgender URI verlinken:</p>
<pre>https://projekteuler.de/problems/xxx</pre>
<pre>http://projekteuler.de/problems/xxx</pre>
<h2>Kann ich genauere Informationen zum Copyright erhalten?</h2>
<p>Der Inhalt von projecteuler.net ist lizenziert unter einer Creative Commons Lizenz:<br />
Attribution-NonCommercial-ShareAlike 2.0 UK: England & Wales.</p>

View File

@@ -1,33 +1,34 @@
<div class="bg-light p-5 rounded">
<h1 class="display-4">Willkommen auf Projekt Euler!</h1>
<p>Diese Seite ist eine Übersetzung der englischen Rätsel-Webseite <a href="https://projecteuler.net/">projecteuler.net</a>.</p>
<p class="lead">
<%= link_to about_info_path, class: 'btn btn-primary btn-lg' do %>
Mehr erfahren &raquo;
<% end %>
<div class="jumbotron">
<div class="container">
<h1>Willkommen auf Projekt Euler!</h1>
<p>Diese Seite ist eine Übersetzung der englischen Rätsel-Webseite <a href="https://projecteuler.net/">projecteuler.net</a>.</p>
<p>
<%= link_to about_info_path, class: 'btn btn-primary btn-lg' do %>
Mehr erfahren &raquo;
<% end %>
</div>
</div>
<div class="row g-4 py-5 row-cols-1 row-cols-lg-3">
<div class="col d-flex align-items-start">
<div>
<div class="container">
<!-- Example row of columns -->
<div class="row">
<div class="col-md-4">
<h2>Ansehen</h2>
<p>Sehen Sie sich die mathematischen Probleme in deutscher Sprache an.</p>
<%= link_to problems_path, class: 'btn btn-primary' do %>
Zu den Problemen &raquo;
<% end %>
<p>
<%= link_to problems_path, class: 'btn btn-default' do %>
Zu den Problemen &raquo;
<% end %>
</p>
</div>
</div>
<div class="col d-flex align-items-start">
<div>
<div class="col-md-4">
<h2>Übersetzen</h2>
<p>Bisher wurden erst <%= Problem.translated_count %> der <%= Problem.count %> Probleme übersetzt. Helfen Sie mit, Übersetzungen zu erstellen und anzupassen!</p>
</div>
</div>
<div class="col d-flex align-items-start">
<div>
<div class="col-md-4">
<h2>Verbessern</h2>
<p>Vermissen Sie eine Funktion auf der Webseite, oder ist Ihnen ein Fehler aufgefallen? Dann helfen Sie beim Entwickeln der Webseite in Ruby on Rails!</p>
<a class="btn btn-primary" href="https://github.com/projekteuler/projekteuler" target="_blank">Projekt Euler auf GitHub &raquo;</a>
<p><a class="btn btn-default" href="https://github.com/projekteuler/projekteuler" target="_blank" role="button">Projekt Euler auf GitHub &raquo;</a></p>
</div>
</div>
</div>

View File

@@ -1,8 +1,8 @@
<% provide(:title, 'Über Project Euler') %>
<div class="pb-2 mt-4 mb-2 border-bottom">
<h1>Über Project Euler</h1>
</div>
<div class="page-header">
<h1>Über Project Euler</h1>
</div>
<h2>Was ist Project Euler?</h2>
<%= image_tag 'euler_main.jpg', alt: 'Leonhard Euler (1707-1783)', width: '150px', style: 'border:1px solid black;margin:10px;float:right' %>
<p>Project Euler ist eine Serie von herausfordernden mathematischen bzw. Programmier-Problemen, die mehr als nur mathematische Einblicke zum Lösen erfordern. Obwohl die Mathematik Ihnen helfen wird, auf elegante und effiziente Lösungswege zu kommen, ist der Gebrauch von Computer- und Programmierkenntnissen nötig, um den Großteil der Probleme zu lösen.<br /><br />Die Motivation für das Starten und die Instandhaltung von Project Euler ist die, dem Forschergeist eine Plattform bereitzustellen, die sich mit unbekannten Gebieten befasst, und neue Konzepte in einem spaßigen und freizeitlichen Kontext zu erlernen.</p>
@@ -18,4 +18,4 @@
</p>
<p>Aber wenn die Probleme nach einer Herausforderung klingen, dann können Sie sich die <%= link_to 'Probleme', problems_path %> ansehen, bevor Sie sich registrieren.
</p>
<blockquote class="blockquote"><p>&quot;Project Euler existiert zum Begeistern, Herausfordern und Entwickeln der Fähigkeiten und des Genusses von jedem mit einem Interesse für die faszinierende Welt der Mathematik.&quot;</p></blockquote>
<blockquote><p>&quot;Project Euler existiert zum Begeistern, Herausfordern und Entwickeln der Fähigkeiten und des Genusses von jedem mit einem Interesse für die faszinierende Welt der Mathematik.&quot;</p></blockquote>

View File

@@ -1,8 +1,6 @@
<% provide(:title, 'Impressum') %>
<div class="pb-2 mt-4 mb-2 border-bottom">
<h1>Impressum</h1>
</div>
<div class="page-header"><h1>Impressum</h1></div>
<p>Angaben gemäß § 5 TMG:<br/><br/></p>
<p>Philipp Fischbeck<br />
Großbeerenstraße 48<br />
@@ -10,8 +8,6 @@
</p>
<h2>Kontakt:</h2>
<p>E-Mail: projekteuler@gmail.com</p>
<p><strong>Haftung für Inhalte</strong></p> <p>Die Inhalte unserer Seiten wurden mit größter Sorgfalt erstellt. Für die Richtigkeit, Vollständigkeit und Aktualität der Inhalte können wir jedoch keine Gewähr übernehmen. Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG für eigene Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach §§ 8 bis 10 TMG sind wir als Diensteanbieter jedoch nicht verpflichtet, übermittelte oder gespeicherte fremde Informationen zu überwachen oder nach Umständen zu forschen, die auf eine rechtswidrige Tätigkeit hinweisen. Verpflichtungen zur Entfernung oder Sperrung der Nutzung von Informationen nach den allgemeinen Gesetzen bleiben hiervon unberührt. Eine diesbezügliche Haftung ist jedoch erst ab dem Zeitpunkt der Kenntnis einer konkreten Rechtsverletzung möglich. Bei Bekanntwerden von entsprechenden Rechtsverletzungen werden wir diese Inhalte umgehend entfernen.</p>
<p><strong>Haftung für Links</strong></p> <p>Unser Angebot enthält Links zu externen Webseiten Dritter, auf deren Inhalte wir keinen Einfluss haben. Deshalb können wir für diese fremden Inhalte auch keine Gewähr übernehmen. Für die Inhalte der verlinkten Seiten ist stets der jeweilige Anbieter oder Betreiber der Seiten verantwortlich. Die verlinkten Seiten wurden zum Zeitpunkt der Verlinkung auf mögliche Rechtsverstöße überprüft. Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht erkennbar. Eine permanente inhaltliche Kontrolle der verlinkten Seiten ist jedoch ohne konkrete Anhaltspunkte einer Rechtsverletzung nicht zumutbar. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Links umgehend entfernen.</p>
<p><strong>Kontaktdaten</strong></p>
<p>Der Nutzung von im Rahmen der Impressumspflicht veröffentlichten Kontaktdaten durch Dritte zur Übersendung von nicht ausdrücklich angeforderter Werbung und Informationsmaterialien wird hiermit ausdrücklich widersprochen. Die Betreiber der Seiten behalten sich ausdrücklich rechtliche Schritte im Falle der unverlangten Zusendung von Werbeinformationen, etwa durch Spam-Mails, vor.</p><p> </p>
<h2>Haftungsausschluss:</h2>
<p><strong>Haftung für Inhalte</strong></p> <p>Die Inhalte unserer Seiten wurden mit größter Sorgfalt erstellt. Für die Richtigkeit, Vollständigkeit und Aktualität der Inhalte können wir jedoch keine Gewähr übernehmen. Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG für eigene Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach §§ 8 bis 10 TMG sind wir als Diensteanbieter jedoch nicht verpflichtet, übermittelte oder gespeicherte fremde Informationen zu überwachen oder nach Umständen zu forschen, die auf eine rechtswidrige Tätigkeit hinweisen. Verpflichtungen zur Entfernung oder Sperrung der Nutzung von Informationen nach den allgemeinen Gesetzen bleiben hiervon unberührt. Eine diesbezügliche Haftung ist jedoch erst ab dem Zeitpunkt der Kenntnis einer konkreten Rechtsverletzung möglich. Bei Bekanntwerden von entsprechenden Rechtsverletzungen werden wir diese Inhalte umgehend entfernen.</p> <p><strong>Haftung für Links</strong></p> <p>Unser Angebot enthält Links zu externen Webseiten Dritter, auf deren Inhalte wir keinen Einfluss haben. Deshalb können wir für diese fremden Inhalte auch keine Gewähr übernehmen. Für die Inhalte der verlinkten Seiten ist stets der jeweilige Anbieter oder Betreiber der Seiten verantwortlich. Die verlinkten Seiten wurden zum Zeitpunkt der Verlinkung auf mögliche Rechtsverstöße überprüft. Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht erkennbar. Eine permanente inhaltliche Kontrolle der verlinkten Seiten ist jedoch ohne konkrete Anhaltspunkte einer Rechtsverletzung nicht zumutbar. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Links umgehend entfernen.</p> <p><strong>Urheberrecht</strong></p> <p>Die durch die Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen Urheberrecht. Die Vervielfältigung, Bearbeitung, Verbreitung und jede Art der Verwertung außerhalb der Grenzen des Urheberrechtes bedürfen der schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers. Downloads und Kopien dieser Seite sind nur für den privaten, nicht kommerziellen Gebrauch gestattet. Soweit die Inhalte auf dieser Seite nicht vom Betreiber erstellt wurden, werden die Urheberrechte Dritter beachtet. Insbesondere werden Inhalte Dritter als solche gekennzeichnet. Sollten Sie trotzdem auf eine Urheberrechtsverletzung aufmerksam werden, bitten wir um einen entsprechenden Hinweis. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Inhalte umgehend entfernen.</p> <p><strong>Datenschutz</strong></p> <p>Die Nutzung unserer Webseite ist in der Regel ohne Angabe personenbezogener Daten möglich. Soweit auf unseren Seiten personenbezogene Daten (beispielsweise Name, Anschrift oder eMail-Adressen) erhoben werden, erfolgt dies, soweit möglich, stets auf freiwilliger Basis. Diese Daten werden ohne Ihre ausdrückliche Zustimmung nicht an Dritte weitergegeben. </p> <p>Wir weisen darauf hin, dass die Datenübertragung im Internet (z.B. bei der Kommunikation per E-Mail) Sicherheitslücken aufweisen kann. Ein lückenloser Schutz der Daten vor dem Zugriff durch Dritte ist nicht möglich. </p> <p>Der Nutzung von im Rahmen der Impressumspflicht veröffentlichten Kontaktdaten durch Dritte zur Übersendung von nicht ausdrücklich angeforderter Werbung und Informationsmaterialien wird hiermit ausdrücklich widersprochen. Die Betreiber der Seiten behalten sich ausdrücklich rechtliche Schritte im Falle der unverlangten Zusendung von Werbeinformationen, etwa durch Spam-Mails, vor.</p><p> </p>
<p><i>Quellverweis: <a href="http://www.e-recht24.de/muster-disclaimer.htm" target="_blank">eRecht24 Disclaimer</a></i></p>

View File

@@ -1,49 +0,0 @@
<% provide(:title, 'Datenschutz') %>
<div class="pb-2 mt-4 mb-2 border-bottom">
<h1>Datenschutz</h1>
</div>
<p>Diese Datenschutz-Information gilt für die Datenverarbeitung durch:<br /></p>
<p>Philipp Fischbeck<br />
Großbeerenstraße 48<br />
14482 Potsdam<br />
E-Mail: projekteuler@gmail.com<br />
</p>
<p>Die Bestellung eines betrieblichen Datenschutzbeauftragten ist nicht erforderlich.</p>
<h2>Erhebung und Verarbeitung personenbezogener Daten</h2>
<p><strong>Besuch der Webseite</strong></p>
Bei Besuch dieser Webseite werden zwangsweise folgende Daten übertragen:
<ul>
<li>Aufgerufene URL</li>
<li>IP-Adresse des aufrufenden Geräts (mit dem letzten Byte anonymisiert)</li>
<li>Datum und Uhrzeit des Aufrufs</li>
<li>Webseite, von der aus der Zugriff erfolgt</li>
<li>Verwendeter Browser und Betriebssystem</li>
</ul>
<p>Die genannten Daten werden durch mich verarbeitet, um einen Verbindungsaufbau zur Webseite zu gewährleisten und die Funktionalität der Webseite zu gewährleisten. Die Rechtsgrundlage für diese Verarbeitung ist Art.6 Abs.1 S.1 lit.f DSGVO. Die Daten werden nicht dazu verwendet, Rückschlüsse auf die Person zu ziehen.</p>
<p>Die oben beschriebenen Daten werden höchstens 24 Stunden gespeichert und anschließend gelöscht.</p>
<p><strong>Anmeldung über GitHub</strong></p>
<p>Wenn sich der Besucher über ein GitHub-Konto anmeldet, so wird in einer Datenbank ein Eintrag für diesen Nutzer angelegt. In dem Eintrag wird eine Referenznummer auf das GitHub-Konto, der Anzeigename sowie das Datum des letzten Logins gespeichert. Zusätzlich werden Informationen gespeichert, die dem Besucher ein Fortsetzen der letzten Sitzung ermöglicht.</p>
<p><strong>Einstellen von Übersetzungen</strong></p>
<p>Bei der Einstellung von Übersetzungen wird neben dem Inhalt der Übersetzung auch Datum und Uhrzeit des Absendens gespeichert. Ist der Besucher über GitHub angemeldet, so wird zusätzlich eine Referenz auf den entsprechenden Eintrag des Nutzers in der Datenbank gespeichert.</p>
<p><strong>Nutzung der Kontaktadresse</strong></p>
<p>Besucher haben die Möglichkeit, mich über die angegebene Kontaktadresse zu erreichen. Sämtliche Angaben sind freiwillig. Die Datenverarbeitung für die Kontaktaufnahme erfolgt nach Art.6 Abs.1 S.1 lit.a DSGVO auf Grundlage der freiwilligen Einwilligung des Besuchers.</p>
<h2>Betroffenenrechte</h2>
Sie haben das Recht auf
<ul>
<li>Auskunft über die bei uns über Sie gespeicherten Daten und ihre Verarbeitung (Art. 15 DSGVO),</li>
<li>Berichtigung unrichtiger personenbezogener Daten (Art. 16 DSGVO),</li>
<li>Löschung Ihrer bei uns gespeicherten Daten (Art. 17 DSGVO),</li>
<li>Einschränkung der Datenverarbeitung, sofern wir Ihre Daten aufgrund gesetzlicher Pflichten noch nicht löschen dürfen (Art. 18 DSGVO),</li>
<li>Widerspruch gegen die Verarbeitung Ihrer Daten bei uns (Art. 21 DSGVO) und</li>
<li>Datenübertragbarkeit, sofern Sie in die Datenverarbeitung eingewilligt haben oder einen Vertrag mit uns abgeschlossen haben (Art. 20 DSGVO).</li>
</ul>
Wenden Sie sich für Anfragen an die oben genannte E-Mail-Adresse.

View File

@@ -1,6 +1,6 @@
<%= provide(:title, 'Über römische Zahlen') %>
<div class="pb-2 mt-4 mb-2 border-bottom">
<div class="page-header">
<h1>Über... römische Zahlen</h1>
</div>
<h3>Wie liest und schreibt man römische Zahlen?</h3>

View File

@@ -1,12 +1,9 @@
<% provide(:title, t('.administration')) %>
<div class="pb-2 mt-4 mb-2 border-bottom">
<h1><%= t('.administration') %></h1>
</div>
<%= link_to t('.view_translations'), admin_translations_path, class: 'btn btn-primary' %>
<p>
<%= t('.number_of_problems') %>: <%= @current_problem_count %><br/>
<% if @most_recent_pull.present? %>
<%= t('.time_since_last_pull') %>: <%= time_ago_in_words @most_recent_pull %>
<% end %>
</p>
<%= button_to t('.pull_problems'), '/admin/pull_problems', method: :post, class: 'btn btn-warning' %>
<h1><%= t('.administration') %></h1>
<%= link_to t('.view_translations'), admin_translations_path, class: 'btn btn-default' %>
<h1><%= t('.update_problem_count') %></h1>
<%= form_tag '/admin/update_problem_count', method: :post, class: 'form-inline' do %>
<%= number_field_tag 'problem_count', @current_problem_count, min: @current_problem_count, class: 'form-control' %>
<%= submit_tag t('.update'), class: 'btn btn-warning' %>
<% end %>

View File

@@ -1 +1 @@
<%= will_paginate @translations, renderer: WillPaginate::ActionView::BootstrapLinkRenderer %>
<%= will_paginate @translations, renderer: BootstrapPagination::Rails %>

View File

@@ -1,8 +1,6 @@
<% provide(:title, Translation.model_name.human(count: 2)) %>
<div class="pb-2 mt-4 mb-2 border-bottom">
<h1><%= Translation.model_name.human(count: 2) %></h1>
</div>
<h1><%= Translation.model_name.human(count: 2) %></h1>
<%= render 'translation_pagination' %>
<table class="table table-striped table-bordered">

View File

@@ -1,47 +1,31 @@
<% provide(:title, t('problems.show.problem_subtitle', id: @translation.problem_id)) %>
<div class="pb-2 mt-4 mb-2">
<h1><%= @translation.title %></h1>
</div>
<div class="card mb-3">
<div class="card-header">
<%= t 'problems.show.problem_subtitle', id: @translation.problem_id %>
</div>
<% if @translation.pending? %>
<div class="problem-buttons">
<div class="btn-group problem-buttons-inner">
<%= link_to admin_translation_decline_path(@translation), method: :post, class: 'btn btn-danger btn-sm' do %>
<%= icon('fas', 'times') %> <%= t '.decline_translation' %>
<% end %>
<%= link_to admin_translation_accept_path(@translation), method: :post, class: 'btn btn-success btn-sm' do %>
<%= icon('fas', 'check') %> <%= t '.accept_translation' %>
<% end %>
</div>
</div>
<% end %>
<div class="card-body problem-content">
<%= sanitize @translation.content, scrubber: TranslationContentScrubber.new %>
</div>
<div class="card-footer text-muted">
<div class="page-header">
<p class="text-muted">
<%= render 'shared/authors', authors: Array(@translation.author) %>
</div>
</p>
<h1><%= @translation.title %> <small><%= t 'problems.show.problem_subtitle', id: @translation.problem_id %></small></h1>
</div>
<% if @translation.problem.is_translated? %>
<% if @translation.title != @translation.problem.title %>
<h3><%= t 'activerecord.attributes.translation.title' %></h3>
<p><%= t '.changed_title_html', old: @translation.problem.title, new: @translation.title %></p>
<% end %>
<h3><%= t 'activerecord.attributes.translation.content' %></h3>
<%= raw Diffy::Diff.new(@translation.problem.content, @translation.content, allow_empty_diff: false).to_s(:html) %>
<div class="alert alert-warning" role="alert"><%= t('.already_translated') %> <%= link_to t('.visit_current_translation'), @translation.problem, target: '_blank', class: 'alert-link' %></div>
<% else %>
<h2><%= t 'activerecord.attributes.translation.content' %></h2>
<%= raw Diffy::Diff.new(@translation.content, @translation.content, allow_empty_diff: false).to_s(:html) %>
<div class="alert alert-info" role="alert"><%= t('.is_new_translation') %></div>
<% end %>
<% if @translation.pending? %>
<%= link_to admin_translation_decline_path(@translation), method: :post, class: 'btn btn-default btn-sm pull-right' do %>
<%= icon :remove %> <%= t '.decline_translation' %>
<% end %>
<%= link_to admin_translation_accept_path(@translation), method: :post, class: 'btn btn-default btn-sm pull-right' do %>
<%= icon :ok %> <%= t '.accept_translation' %>
<% end %>
<% end %>
<%= panel do %>
<div class="panel-body problem-content">
<%= sanitize @translation.content %>
</div>
<% end %>
<div class="text-center">
<%= link_to t('problems.show.view_original_problem'), @translation.problem.original_url, target: '_blank' %>
</div>

View File

@@ -1,10 +1,5 @@
<footer class="footer">
<div class="container text-center">
<span class="text-muted">
<%= link_to t('application.legal'), about_legal_path %>
| <%= link_to t('application.privacy'), about_privacy_path %>
| <%= link_to t('application.copyright'), about_copyright_path %>
| <%= t('application.bootstrap_html')%>
</span>
<div class="container">
<p class="text-muted text-center"><%= link_to t('application.copyright'), about_copyright_path %> | <%= t('application.bootstrap_html')%></p>
</div>
</footer>

View File

@@ -1,46 +1,38 @@
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<%= link_to root_path, class: 'navbar-brand' do %>
<%= image_tag "favicon.ico", alt: "", width: 24, height: 24, class: "d-inline-block align-text-top" %> <%= t('application.site_title') %>
<% end %>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon">
<%= icon('fas', 'bars') %>
</span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto">
<%= nav_link_to t('application.info'), about_info_path %>
<%= nav_link_to Problem.model_name.human(count: 2), problems_path %>
<% if user_signed_in? and current_user.admin? %>
<%= nav_link_to t('admin.dashboard.index.administration'), admin_dashboard_index_path %>
<%= link_to admin_translations_path, class: 'nav-link' do %>
<%= t('admin.dashboard.index.translations') %> <span class="badge bg-secondary"><%= Translation.pending.count %></span>
<% end %>
<% end %>
</ul>
<% if user_signed_in? %>
<span class="navbar-text"><%= t 'application.logged_in_as_html', name: current_user.name %>
<% if current_user.admin? %>
<b><%= icon('fas', 'star') %></b>
<% end %>
</span>
<ul class="navbar-nav">
<li class="nav-item">
<%= link_to t('application.sign_out'), destroy_user_session_path, method: :delete, class: 'nav-link' %>
</li>
</ul>
<% else %>
<ul class="navbar-nav">
<li class="nav-item">
<% if Rails.env.development? %>
<%= link_to t('application.sign_in_with_github'), user_developer_omniauth_authorize_path, method: :post, class: 'nav-link' %>
<% else %>
<%= link_to t('application.sign_in_with_github'), user_github_omniauth_authorize_path, method: :post, class: 'nav-link' %>
<% end %>
</li>
</ul>
<%= navbar position: :static do %>
<%= vertical do %>
<%= link_to root_path, style:'display:flex;align-items:center' do %>
<%= image_tag 'logo.png', height: '35px' %>
<p class="navbar-text"><%= t('application.site_title') %></p>
<% end %>
</div>
</div>
</nav>
<% end %>
<%= horizontal do %>
<%= nav class: 'navbar-left' do %>
<%= link_to t('application.info'), about_info_path %>
<%= link_to Problem.model_name.human(count: 2), problems_path %>
<% if user_signed_in? and current_user.admin? %>
<%= link_to t('admin.dashboard.index.administration'), admin_dashboard_index_path %>
<%= link_to admin_translations_path do %>
<%= t('admin.dashboard.index.translations') %> <span class="badge"><%= Translation.pending.count %></span>
<% end %>
<% end %>
<% end %>
<%= nav class: 'navbar-right' do %>
<%= link_to t('application.legal'), about_legal_path %>
<% if user_signed_in? %>
<span class="navbar-text">Eingeloggt als <b>
<%= current_user.name %>
<% if current_user.admin? %>
<%= icon :star %>
<% end %>
</b></span>
<%= link_to(t('application.sign_out'), destroy_user_session_path, method: :delete) %>
<% else %>
<% if Rails.env.development? %>
<%= link_to(t('application.sign_in'), user_developer_omniauth_authorize_path) %>
<% else %>
<%= link_to(t('application.sign_in'), user_github_omniauth_authorize_path) %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>

View File

@@ -5,15 +5,28 @@
<%= favicon_link_tag %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS_HTML-full,Safe', 'data-turbolinks-track' => true %>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
jax: ["input/TeX", "output/HTML-CSS"],
tex2jax: {
inlineMath: [ ["$","$"], ["\\(","\\)"] ],
displayMath: [ ["$$","$$"], ["\\[","\\]"] ],
processEscapes: true
},
"HTML-CSS": { availableFonts: ["TeX"] }
});
</script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS_HTML' async></script>
<%= csrf_meta_tags %>
</head>
<body>
<main role="main">
<%= render 'layouts/header' %>
<div class="container mt-3 mb-3">
<div class="container">
<%= flash_messages %>
<%= yield %>
<div class="row">
<%= yield %>
</div>
</div>
</main>

View File

@@ -1 +1 @@
<%= will_paginate @problems, renderer: WillPaginate::ActionView::BootstrapLinkRenderer %>
<%= will_paginate @problems, renderer: BootstrapPagination::Rails %>

View File

@@ -1,15 +1,9 @@
<% provide(:title, Problem.model_name.human(count: 2)) %>
<div class="pb-2 mt-4 mb-2 border-bottom">
<h1><%= Problem.model_name.human(count: 2) %></h1>
</div>
<div class="page-header"><h1><%= Problem.model_name.human(count: 2) %></h1></div>
<p><%= t('problems.index.translated_count', translated: Problem.translated_count, total: Problem.count) %></p>
<div class="progress mb-3">
<div class="progress-bar progress-bar-striped bg-primary" role="progressbar" style="width: <%= @translated_percentage %>%" aria-valuenow="<%= @translated_percentage %>>" aria-valuemin="0" aria-valuemax="100">
<%= @translated_percentage %>%
</div>
</div>
<%= progress_bar percentage: @translated_percentage, label: true, striped: true %>
<%= render 'problem_pagination' %>
<table class="table table-striped table-bordered">
@@ -28,10 +22,12 @@
<% if problem.is_translated? %>
<%= link_to problem.title, problem %>
<% else %>
<%= link_to problem do %>
<i><%= problem.original_title %> <%= t 'problems.not_translated_yet' %></i>
<% end %>
<i><%= t 'problems.not_yet_translated' %></i>
<%= link_to new_problem_translation_path(problem), class: 'btn btn-default btn-xs' do %>
<%= icon :pencil %> <%= t '.suggest_translation' %>
<% end %>
<% end %>
</td>
</tr>
<% end %>

View File

@@ -1,51 +1,19 @@
<% provide(:title, t('problems.show.problem_subtitle', id: @problem.id)) %>
<div class="pb-2 mt-4 mb-2">
<h1>
<% if @problem.is_translated? %>
<%= @problem.title %>
<% else %>
<i><%= @problem.original_title %> <%= t 'problems.not_translated_yet' %></i>
<% end %>
</h1>
<div class="page-header">
<p class="text-muted">
<%= render 'shared/authors', authors: @problem.authors, has_anonymous_author: @problem.has_anonymous_author? %>
</p>
<h1><%= @problem.title %> <small><%= t '.problem_subtitle', id: @problem.id %></small></h1>
</div>
<% if Problem.exists?(@problem.id-1) %>
<%= link_to problem_path(@problem.id-1), title: t('problems.show.problem_subtitle', id: @problem.id-1), class: 'problem-prev' do %>
<%= icon('fas', 'chevron-left') %>
<% end %>
<%= link_to new_problem_translation_path(@problem), class: 'btn btn-default btn-sm pull-right' do %>
<%= icon :pencil %> <%= t '.improve_translation' %>
<% end %>
<% if Problem.exists?(@problem.id+1) %>
<%= link_to problem_path(@problem.id+1), title: t('problems.show.problem_subtitle', id: @problem.id+1), class: 'problem-next' do %>
<%= icon('fas', 'chevron-right') %>
<% end %>
<% end %>
<div class="card mb-3">
<div class="card-header">
<%= t '.problem_subtitle', id: @problem.id %>
</div>
<div class="problem-buttons">
<%= link_to new_problem_translation_path(@problem), class: 'problem-buttons-inner btn btn-primary btn-sm' do %>
<%= icon('fas', 'edit') %>
<% if @problem.is_translated? %>
<%= t '.improve_translation' %>
<% else %>
<%= t '.suggest_translation' %>
<% end %>
<% end %>
</div>
<div class="card-body problem-content">
<% if @problem.is_translated? %>
<%= sanitize @problem.content, scrubber: TranslationContentScrubber.new %>
<% else %>
<%= sanitize @problem.original_content, scrubber: TranslationContentScrubber.new %>
<% end %>
</div>
<% if @problem.is_translated? %>
<div class="card-footer text-muted">
<%= render 'shared/authors', authors: @problem.authors, has_anonymous_author: @problem.has_anonymous_author? %>
<%= panel do %>
<div class="panel-body problem-content">
<%= sanitize @problem.content %>
</div>
<% end %>
</div>
<% end %>
<div class="text-center">
<%= link_to t('.view_original_problem'), @problem.original_url, target: '_blank' %>
</div>

View File

@@ -0,0 +1,10 @@
<% provide(:title, t('problems.show.problem_subtitle', id: @problem.id)) %>
<div class="page-header">
<h1><%= t 'problems.show.problem_subtitle', id: @problem.id %></h1>
</div>
<%= t 'problems.not_yet_translated' %>
<%= link_to new_problem_translation_path(@problem), class: 'btn btn-default btn-xs' do %>
<%= icon :pencil %> <%= t 'problems.index.suggest_translation' %>
<% end %>

View File

@@ -1,5 +1,5 @@
<% if authors.empty? %>
Diese Übersetzung wurde anonym erstellt.
Diese Übersetung wurde anonym erstellt.
<% else %>
Diese Übersetzung wurde von
<% if local_assigns[:has_anonymous_author] %>

View File

@@ -1,23 +1,17 @@
<%= bootstrap_form_for [@problem, @translation], layout: :basic do |f| %>
<%= form_for [@problem, @translation], layout: :basic do |f| %>
<%= f.text_field :title %>
<ul class="nav nav-tabs" id="translationTab" role="tablist">
<li class="nav-item">
<button class="nav-link active" id="source-tab" data-bs-toggle="tab" data-bs-target="#source" type="button" role="tab" aria-controls="source" aria-selected="true"><%= t('.source_code') %></button>
</li>
<li class="nav-item">
<button class="nav-link" id="preview-tab" data-bs-toggle="tab" data-bs-target="#preview" type="button" role="tab" aria-controls="preview" aria-selected="false"><%= t('.preview') %></button>
</li>
</ul>
<div class="tab-content" id="translationTabContent">
<div class="tab-pane show active" id="source" role="tabpanel" aria-labelledby="source-tab">
<%= nav id: 'translationNav' do %>
<%= link_to t('.source_code'), '#source', data: {toggle: 'tab'} %>
<%= link_to t('.preview'), '#preview', data: {toggle: 'tab'} %>
<% end %>
<div class="tab-content">
<div class="tab-pane active" id="source">
<%= f.text_area :content, placeholder: t('.translation_source_explanation') %>
</div>
<div class="tab-pane" id="preview" role="tabpanel" aria-labelledby="preview-tab">
<div class="card mb-3">
<div class="card-body problem-content">
</div>
<%= panel class: 'tab-pane', id: 'preview' do %>
<div class="panel-body problem-content">
</div>
</div>
<% end %>
</div>
<div class="alert alert-info">
<%= t '.copyright_warning_html' %>
@@ -25,8 +19,5 @@
<%= t '.not_logged_in_warning' %>
<% end %>
</div>
<%= f.primary %>
<% if user_signed_in? and current_user.admin? %>
<%= f.button t('.save_and_accept'), type: :submit, name: "accept", value: true, class: "btn btn-success" %>
<% end %>
<%= f.submit %>
<% end %>

View File

@@ -1,15 +1,11 @@
<div class="card mb-3">
<div class="card-header">
Hinweise zur Erstellung von Übersetzungen
</div>
<div class='card-body'>
<%= panel heading: 'Hinweise zur Erstellung von Übersetzungen', context: :info do %>
<div class='panel-body'>
<ul>
<li>Als Basis für jede Übersetzung dient der <%= link_to "Text von projecteuler.net", @problem.original_url, target: '_blank' %>.</li>
<li>Der Originaltitel und Text im untenstehenden Formular sind zu übersetzen.</li>
<li>Der HTML-Quelltext in seiner Struktur sollte im Allgemeinen unverändert bleiben.</li>
<li>Zurzeit müssen Sie den HTML-Quellcode noch manuell von projecteuler.net holen. In Zukunft soll dies automatisch passieren.</li>
<li>Die Sie-Form benutzen.</li>
<li>Der HTML-Quellcode sollte im Allgemeinen unverändert bleiben.</li>
<li>Querverweise zu anderen Problemen sollten in der Form <code>/problem=??</code> erfolgen.</li>
<li>Wenn Grafiken oder Dateien verwendet werden, sollte die URL <code>https://projecteuler.net/...</code> verwendet werden.</li>
<li>Die Sie-Form benutzen.</li>
</ul>
</div>
</div>
<% end %>

2
bin/bundle Executable file → Normal file
View File

@@ -1,3 +1,3 @@
#!/usr/bin/env ruby
#!/usr/bin/env ruby.exe
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
load Gem.bin_path('bundler', 'bundle')

View File

@@ -1,8 +0,0 @@
#!/bin/bash -e
# If running the rails server then create or migrate existing database
if [ "${*}" == "./bin/rails server" ]; then
./bin/rails db:prepare
fi
exec "${@}"

8
bin/rails Executable file → Normal file
View File

@@ -1,4 +1,4 @@
#!/usr/bin/env ruby
APP_PATH = File.expand_path("../config/application", __dir__)
require_relative "../config/boot"
require "rails/commands"
#!/usr/bin/env ruby.exe
APP_PATH = File.expand_path('../config/application', __dir__)
require_relative '../config/boot'
require 'rails/commands'

6
bin/rake Executable file → Normal file
View File

@@ -1,4 +1,4 @@
#!/usr/bin/env ruby
require_relative "../config/boot"
require "rake"
#!/usr/bin/env ruby.exe
require_relative '../config/boot'
require 'rake'
Rake.application.run

31
bin/setup Executable file → Normal file
View File

@@ -1,33 +1,36 @@
#!/usr/bin/env ruby
require "fileutils"
#!/usr/bin/env ruby.exe
require 'fileutils'
include FileUtils
# path to your application root.
APP_ROOT = File.expand_path("..", __dir__)
APP_ROOT = File.expand_path('..', __dir__)
def system!(*args)
system(*args) || abort("\n== Command #{args} failed ==")
end
FileUtils.chdir APP_ROOT do
# This script is a way to set up or update your development environment automatically.
# This script is idempotent, so that you can run it at any time and get an expectable outcome.
chdir APP_ROOT do
# This script is a starting point to setup your application.
# Add necessary setup steps to this file.
puts "== Installing dependencies =="
system! "gem install bundler --conservative"
system("bundle check") || system!("bundle install")
puts '== Installing dependencies =='
system! 'gem install bundler --conservative'
system('bundle check') || system!('bundle install')
# Install JavaScript dependencies if using Yarn
# system('bin/yarn')
# puts "\n== Copying sample files =="
# unless File.exist?("config/database.yml")
# FileUtils.cp "config/database.yml.sample", "config/database.yml"
# unless File.exist?('config/database.yml')
# cp 'config/database.yml.sample', 'config/database.yml'
# end
puts "\n== Preparing database =="
system! "bin/rails db:prepare"
system! 'bin/rails db:setup'
puts "\n== Removing old logs and tempfiles =="
system! "bin/rails log:clear tmp:clear"
system! 'bin/rails log:clear tmp:clear'
puts "\n== Restarting application server =="
system! "bin/rails restart"
system! 'bin/rails restart'
end

2
bin/update Executable file → Normal file
View File

@@ -1,4 +1,4 @@
#!/usr/bin/env ruby
#!/usr/bin/env ruby.exe
require 'fileutils'
include FileUtils

14
bin/yarn Executable file → Normal file
View File

@@ -1,15 +1,9 @@
#!/usr/bin/env ruby
#!/usr/bin/env ruby.exe
APP_ROOT = File.expand_path('..', __dir__)
Dir.chdir(APP_ROOT) do
yarn = ENV["PATH"].split(File::PATH_SEPARATOR).
select { |dir| File.expand_path(dir) != __dir__ }.
product(["yarn", "yarn.exe"]).
map { |dir, file| File.expand_path(file, dir) }.
find { |file| File.executable?(file) }
if yarn
exec yarn, *ARGV
else
begin
exec "yarnpkg", *ARGV
rescue Errno::ENOENT
$stderr.puts "Yarn executable was not detected in the system."
$stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
exit 1

View File

@@ -1,6 +1,4 @@
# This file is used by Rack-based servers to start the application.
require_relative "config/environment"
require ::File.expand_path('../config/environment', __FILE__)
run Rails.application
Rails.application.load_server

View File

@@ -1,6 +1,6 @@
require_relative "boot"
require_relative 'boot'
require "rails/all"
require 'rails/all'
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
@@ -9,26 +9,16 @@ Bundler.require(*Rails.groups)
module Projekteuler
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 7.0
config.load_defaults 5.2
# Configuration for the application, engines, and railties goes here.
#
# These settings can be overridden in specific environments using the files
# in config/environments, which are processed later.
config.action_dispatch.default_headers = {
'X-Frame-Options' => 'DENY',
'X-XSS-Protection' => '1; mode=block',
'X-Content-Type-Options' => 'nosniff',
'X-Download-Options' => 'noopen',
'X-Permitted-Cross-Domain-Policies' => 'none',
'Referrer-Policy' => 'strict-origin-when-cross-origin'
}
# Settings in config/environments/* take precedence over those specified here.
# Application configuration can go into files in config/initializers
# -- all .rb files in that directory are automatically loaded after loading
# the framework and any gems in your application.
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
config.time_zone = "Berlin"
# config.eager_load_paths << Rails.root.join("extras")
# config.time_zone = 'Central Time (US & Canada)'
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s]

View File

@@ -1,4 +1,4 @@
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
require "bundler/setup" # Set up gems listed in the Gemfile.
require "bootsnap/setup" # Speed up boot time by caching expensive operations.
require 'bundler/setup' # Set up gems listed in the Gemfile.
require 'bootsnap/setup' # Speed up boot time by caching expensive operations.

View File

@@ -2,7 +2,7 @@ development:
adapter: async
test:
adapter: test
adapter: async
production:
adapter: redis

View File

@@ -1 +1 @@
9lygNbYe2bQDZCR1eyyL6+txjBYkoqBE+qPBYeh/xEFj8uOh4sQ/B+EU3VrY1+djm7ZDTVmPeGtbxAkU5I9fSy/YADTON3m5U5WkNft+UnP/gMOkCqe72ceBBmM/HOJFEFcJ8EesCkWVaZPya8+4Q75lF0g1ke1pwxE8Y534lAkG4E9sEaiM+JTwMqNQoqPyCdhAetZd+suWm5vfbqhC/Im7G0axmxATWTd3AUcDP7PUgeuoJ/B/fI4YVlq9rsa938TIfWSDHzfHV5MSyTzwlv+e4Y0TkiJ40dUddIDEk/zZODDhe5YoImgqqgCjgmcUQKmRMKLGbvhACaIIbML+zuodwwJrtQiJRTppwou57+cUGJJ043gjW57f8JSifU9W8cckP8dhYlECuyAPmlLIYuZP0D0=--5k58Qs//NZVKi7uK--00UCCSNXZAl0g8RCUy6qwA==
fmujPxH4j3Pge1kfEi/+pTVW7yA6/X3pBWwuLTIRhchpJokcEie/lbUNlpGOhzGUeOaNZpdEWbB+DVh7r8VUf9FaTMZwyA8u7ipB6Kt7FxrmyqGF4Sb3N54JdREq5KetMCR209VR5URghVnTv6fWMNY/CnfmoAhIi6z40ARP//wSgSQIYlTSsIF/LWdaI9Zn6v3eJ4KSs53EeHyIUal5E67QnvPESwWLvZ6BrKh6GO67xfjAKnoWU4YK+bkFeffubRSKqbb9fAHZLiEVD0glOAeibuJzLAZZa5worvQQgJLZnS1syWCDIz4U6PN4/ZBfrxq8Y+TpBXCEu/5JWrr6ARqbQy8Qnte+IL5EYY65Z70vyI9fcpVYiyKtvUQOsOypf/UxMjahg0MSddZlAiY3+ufyA1Sw9s7BCClaaNtOCtRM/thwNRdn3kNh2S/9YuodVSu5PV/V6DDX9BSo/FZeTbntBSsFnIe5NWwyEaC7jn1zp0FXeAT1N7beUpYcIwWXl7roGATq5J+eSycSAydj5TSPpy6pe0JV--zgHjFhqIX9PMSptP--a4kSt219OHlMrnkVTQFQVA==

View File

@@ -27,5 +27,5 @@ production:
database: <%= ENV['DATABASE_NAME'] %>
username: <%= ENV['DATABASE_USERNAME'] %>
password: <%= ENV['DATABASE_PASSWORD'] %>
host: <%= ENV['DATABASE_HOST'] %>
port: <%= ENV['DATABASE_PORT'] %>
host: 127.0.0.1
port: 3306

View File

@@ -1,19 +1,5 @@
# Load the Rails application.
require_relative "application"
# Replace when upgrading to Rails 7.1
# See https://github.com/rails/rails/issues/32947#issuecomment-1356391185
class Rails::Application
def secret_key_base
if Rails.env.development? || Rails.env.test? || ENV["SECRET_KEY_BASE_DUMMY"]
secrets.secret_key_base ||= generate_development_secret
else
validate_secret_key_base(
ENV["SECRET_KEY_BASE"] || credentials.secret_key_base || secrets.secret_key_base
)
end
end
end
require_relative 'application'
# Initialize the Rails application.
Rails.application.initialize!

View File

@@ -1,10 +1,8 @@
require "active_support/core_ext/integer/time"
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# In the development environment your application's code is reloaded any time
# it changes. This slows down response time but is perfect for development
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
config.cache_classes = false
@@ -14,18 +12,14 @@ Rails.application.configure do
# Show full error reports.
config.consider_all_requests_local = true
# Enable server timing
config.server_timing = true
# Enable/disable caching. By default caching is disabled.
# Run rails dev:cache to toggle caching.
if Rails.root.join("tmp/caching-dev.txt").exist?
if Rails.root.join('tmp', 'caching-dev.txt').exist?
config.action_controller.perform_caching = true
config.action_controller.enable_fragment_cache_logging = true
config.cache_store = :memory_store
config.public_file_server.headers = {
"Cache-Control" => "public, max-age=#{2.days.to_i}"
'Cache-Control' => "public, max-age=#{2.days.to_i}"
}
else
config.action_controller.perform_caching = false
@@ -33,7 +27,7 @@ Rails.application.configure do
config.cache_store = :null_store
end
# Store uploaded files on the local file system (see config/storage.yml for options).
# Store uploaded files on the local file system (see config/storage.yml for options)
config.active_storage.service = :local
# Don't care if the mailer can't send.
@@ -44,27 +38,24 @@ Rails.application.configure do
# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
# Raise exceptions for disallowed deprecations.
config.active_support.disallowed_deprecation = :raise
# Tell Active Support which deprecation messages to disallow.
config.active_support.disallowed_deprecation_warnings = []
# Raise an error on page load if there are pending migrations.
config.active_record.migration_error = :page_load
# Highlight code that triggered database queries in logs.
config.active_record.verbose_query_logs = true
# Debug mode disables concatenation and preprocessing of assets.
# This option may cause significant delays in view rendering with a large
# number of complex assets.
config.assets.debug = true
# Suppress logger output for asset requests.
config.assets.quiet = true
# Raises error for missing translations.
config.i18n.raise_on_missing_translations = true
# Raises error for missing translations
config.action_view.raise_on_missing_translations = true
# Annotate rendered view with file names.
# config.action_view.annotate_rendered_view_with_filenames = true
# Uncomment if you wish to allow Action Cable access from any origin.
# config.action_cable.disable_request_forgery_protection = true
# Use an evented file watcher to asynchronously detect changes in source code,
# routes, locales, etc. This feature depends on the listen gem.
# config.file_watcher = ActiveSupport::EventedFileUpdateChecker
end

View File

@@ -1,5 +1,3 @@
require "active_support/core_ext/integer/time"
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
@@ -18,39 +16,42 @@ Rails.application.configure do
# Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
# or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
config.require_master_key = false
config.require_master_key = true
# Disable serving static files from the `/public` folder by default since
# Apache or NGINX already handles this.
config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present?
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
# Compress CSS using a preprocessor.
# Compress JavaScripts and CSS.
config.assets.js_compressor = :uglifier
# config.assets.css_compressor = :sass
# Do not fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = false
# `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
# config.asset_host = "http://assets.example.com"
# config.action_controller.asset_host = 'http://assets.example.com'
# Specifies the header that your server uses for sending files.
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache
# config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX
# config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
# Store uploaded files on the local file system (see config/storage.yml for options).
# Store uploaded files on the local file system (see config/storage.yml for options)
config.active_storage.service = :local
# Mount Action Cable outside main process or domain.
# Mount Action Cable outside main process or domain
# config.action_cable.mount_path = nil
# config.action_cable.url = "wss://example.com/cable"
# config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ]
# config.action_cable.url = 'wss://example.com/cable'
# config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
config.force_ssl = true
# config.force_ssl = true
# Include generic and useful information about system operation, but avoid logging too much
# information to avoid inadvertent exposure of personally identifiable information (PII).
config.log_level = :info
# Use the lowest log level to ensure availability of diagnostic information
# when problems arise.
config.log_level = :debug
# Prepend all log lines with the following tags.
config.log_tags = [ :request_id ]
@@ -58,9 +59,9 @@ Rails.application.configure do
# Use a different cache store in production.
# config.cache_store = :mem_cache_store
# Use a real queuing backend for Active Job (and separate queues per environment).
# Use a real queuing backend for Active Job (and separate queues per environment)
# config.active_job.queue_adapter = :resque
# config.active_job.queue_name_prefix = "projekteuler_production"
# config.active_job.queue_name_prefix = "projekteuler_#{Rails.env}"
config.action_mailer.perform_caching = false
@@ -72,15 +73,15 @@ Rails.application.configure do
# the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = true
# Log deprecations.
config.active_support.report_deprecations = true
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
# Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new
# Use a different logger for distributed setups.
# require "syslog/logger"
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name")
# require 'syslog/logger'
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
if ENV["RAILS_LOG_TO_STDOUT"].present?
logger = ActiveSupport::Logger.new(STDOUT)

View File

@@ -1,31 +1,26 @@
require "active_support/core_ext/integer/time"
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# Turn false under Spring and add config.action_view.cache_template_loading = true.
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
config.cache_classes = true
# Eager loading loads your whole application. When running a single test locally,
# this probably isn't necessary. It's a good idea to do in a continuous integration
# system, or in some way before deploying your code.
config.eager_load = ENV["CI"].present?
# Do not eager load code on boot. This avoids loading your whole application
# just for the purpose of running a single test. If you are using a tool that
# preloads Rails for running tests, you may have to set it to true.
config.eager_load = false
# Configure public file server for tests with Cache-Control for performance.
config.public_file_server.enabled = true
config.public_file_server.headers = {
"Cache-Control" => "public, max-age=#{1.hour.to_i}"
'Cache-Control' => "public, max-age=#{1.hour.to_i}"
}
# Show full error reports and disable caching.
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
config.cache_store = :null_store
# Raise exceptions instead of rendering exception templates.
config.action_dispatch.show_exceptions = false
@@ -33,7 +28,7 @@ Rails.application.configure do
# Disable request forgery protection in test environment.
config.action_controller.allow_forgery_protection = false
# Store uploaded files on the local file system in a temporary directory.
# Store uploaded files on the local file system in a temporary directory
config.active_storage.service = :test
config.action_mailer.perform_caching = false
@@ -46,15 +41,6 @@ Rails.application.configure do
# Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr
# Raise exceptions for disallowed deprecations.
config.active_support.disallowed_deprecation = :raise
# Tell Active Support which deprecation messages to disallow.
config.active_support.disallowed_deprecation_warnings = []
# Raises error for missing translations.
config.i18n.raise_on_missing_translations = true
# Annotate rendered view with file names.
# config.action_view.annotate_rendered_view_with_filenames = true
# Raises error for missing translations
config.action_view.raise_on_missing_translations = true
end

View File

@@ -1,10 +1,12 @@
# Be sure to restart your server when you modify this file.
# Version of your assets, change this if you want to expire all your assets.
Rails.application.config.assets.version = "1.0"
Rails.application.config.assets.version = '1.0'
# Add additional assets to the asset load path.
# Rails.application.config.assets.paths << Emoji.images_path
# Add Yarn node_modules folder to the asset load path.
Rails.application.config.assets.paths << Rails.root.join('node_modules')
# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in the app/assets

View File

@@ -1,8 +1,7 @@
# Be sure to restart your server when you modify this file.
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
# Rails.backtrace_cleaner.add_silencer { |line| /my_noisy_library/.match?(line) }
# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code
# by setting BACKTRACE=1 before calling your invocation, like "BACKTRACE=1 ./bin/rails runner 'MyClass.perform'".
Rails.backtrace_cleaner.remove_silencers! if ENV["BACKTRACE"]
# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
# Rails.backtrace_cleaner.remove_silencers!

View File

@@ -4,24 +4,22 @@
# For further information see the following documentation
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
Rails.application.configure do
config.content_security_policy do |policy|
policy.default_src :none
policy.font_src :self, "https://cdnjs.cloudflare.com"
policy.img_src :self, "https://cdnjs.cloudflare.com", "https://projecteuler.net"
policy.object_src :none
policy.script_src :self, "https://cdnjs.cloudflare.com"
policy.style_src :self, :unsafe_inline
policy.connect_src :self
# Specify URI for violation reports
# policy.report_uri "/csp-violation-report-endpoint"
end
# Rails.application.config.content_security_policy do |policy|
# policy.default_src :self, :https
# policy.font_src :self, :https, :data
# policy.img_src :self, :https, :data
# policy.object_src :none
# policy.script_src :self, :https
# policy.style_src :self, :https
# Generate session nonces for permitted importmap and inline scripts
config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s }
config.content_security_policy_nonce_directives = %w(script-src)
# # Specify URI for violation reports
# # policy.report_uri "/csp-violation-report-endpoint"
# end
# Report CSP violations to a specified URI. See:
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
# config.content_security_policy_report_only = true
end
# If you are using UJS then enable automatic nonce generation
# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
# Report CSP violations to a specified URI
# For further information see the following documentation:
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
# Rails.application.config.content_security_policy_report_only = true

View File

@@ -126,17 +126,17 @@ Devise.setup do |config|
# ==> Configuration for :rememberable
# The time the user will be remembered without asking for credentials again.
config.remember_for = 2.weeks
# config.remember_for = 2.weeks
# Invalidates all the remember me tokens when the user signs out.
config.expire_all_remember_me_on_sign_out = true
# If true, extends the user's remember period when remembered via cookie.
config.extend_remember_period = true
# config.extend_remember_period = false
# Options to be passed to the created cookie. For instance, you can set
# secure: true in order to force SSL only cookies.
config.rememberable_options = { secure: Rails.env.production? }
# config.rememberable_options = {}
# ==> Configuration for :validatable
# Range for password length.
@@ -237,7 +237,7 @@ Devise.setup do |config|
config.omniauth :developer, fields: [:name], uid_field: :name
end
if Rails.env.production?
config.omniauth :github, ENV['GITHUB_CLIENT_ID'], ENV['GITHUB_CLIENT_SECRET'], scope: ''
config.omniauth :github, Rails.application.credentials.github[:client_id], Rails.application.credentials.github[:client_secret], scope: ''
end
if Rails.env.test?
config.omniauth :github, '', '', scope: ''

View File

@@ -1,6 +1,4 @@
# Be sure to restart your server when you modify this file.
# Configure sensitive parameters which will be filtered from the log file.
Rails.application.config.filter_parameters += [
:passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn
]
Rails.application.config.filter_parameters += [:password]

View File

@@ -4,13 +4,13 @@
# are locale specific, and you may define rules for as many different
# locales as you wish. All of these examples are active by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.plural /^(ox)$/i, "\\1en"
# inflect.singular /^(ox)en/i, "\\1"
# inflect.irregular "person", "people"
# inflect.plural /^(ox)$/i, '\1en'
# inflect.singular /^(ox)en/i, '\1'
# inflect.irregular 'person', 'people'
# inflect.uncountable %w( fish sheep )
# end
# These inflection rules are supported but not enabled by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.acronym "RESTful"
# inflect.acronym 'RESTful'
# end

View File

@@ -0,0 +1,14 @@
# Be sure to restart your server when you modify this file.
#
# This file contains migration options to ease your Rails 5.1 upgrade.
#
# Once upgraded flip defaults one by one to migrate to the new default.
#
# Read the Guide for Upgrading Ruby on Rails for more info on each option.
# Make `form_with` generate non-remote forms.
Rails.application.config.action_view.form_with_generates_remote_forms = false
# Unknown asset fallback will return the path passed in when the given
# asset is not present in the asset pipeline.
# Rails.application.config.assets.unknown_asset_fallback = false

View File

@@ -1,11 +0,0 @@
# Define an application-wide HTTP permissions policy. For further
# information see https://developers.google.com/web/updates/2018/06/feature-policy
#
Rails.application.config.permissions_policy do |f|
f.camera :none
f.gyroscope :none
f.microphone :none
f.usb :none
f.fullscreen :self
f.payment :none
end

View File

@@ -5,11 +5,12 @@ de:
administration: "Administration"
translations: "Übersetzungen"
view_translations: "Übersetzungen anschauen"
pull_problems: "Probleme aktualisieren"
number_of_problems: "Anzahl Probleme"
time_since_last_pull: "Zeit seit letzter erfolgreicher Aktualisierung"
pull_problems:
pull_problems_initiated: "Das Aktualisieren der Probleme wurde angestoßen."
update_problem_count: "Problem-Anzahl aktualisieren"
update: "Aktualisieren"
update_problem_count:
success_message: "Problem-Anzahl wurde erfolgreich aktualisiert!"
failure_message: "Problem-Anzahl konnte nicht aktualisiert werden! Grund: %{error}"
no_problem_count: "Keine Problem-Anzahl gegeben!"
translations:
index:
anonymous: "Anonym"
@@ -20,7 +21,6 @@ de:
visit_current_translation: "Aktuelle Übersetzung anschauen"
already_translated: "Dieses Problem wurde bereits übersetzt."
is_new_translation: "Dieses Problem hat bisher keine Übersetzung."
changed_title_html: "Neuer Titel: <code>%{new}</code> statt <code>%{old}</code>"
accept:
success_message: "Übersetzung wurde erfolgreich akzeptiert!"
decline:

View File

@@ -6,13 +6,11 @@ de:
updated_at: Aktualisiert
application:
site_title: "Projekt Euler"
sign_in_with_github: 'Mit GitHub anmelden'
logged_in_as_html: "Angemeldet als <b>%{name}</b>"
sign_out: 'Abmelden'
sign_in: 'Einloggen'
sign_out: 'Ausloggen'
info: "Info"
privacy: "Datenschutz"
legal: "Impressum"
copyright: "Copyright"
copyright: "Copyright-Informationen"
bootstrap_html: 'Entworfen mit <a href="http://getbootstrap.com/">Bootstrap</a>'
helpers:
submit:

View File

@@ -2,11 +2,11 @@
de:
problems:
not_translated_yet: "(noch nicht übersetzt)"
not_yet_translated: Dieses Problem wurde noch nicht übersetzt.
index:
suggest_translation: Übersetzung vorschlagen
translated_count: "Übersetzte Probleme: %{translated} von %{total}"
show:
improve_translation: Übersetzung verbessern
problem_subtitle: Problem %{id}
view_original_problem: Dieses Problem auf projecteuler.net
suggest_translation: Übersetzung vorschlagen
view_original_problem: Dieses Problem auf projecteuler.net

View File

@@ -8,9 +8,7 @@ de:
translation_source_explanation: Hier kommt der HTML-Quelltext der Übersetzung hin.
copyright_warning_html: Sie erklären sich einverstanden, dass die Übersetzung unter der Creative Commons Lizenz <a class="alert-link" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.de" target="_blank">CC BY-NC-SA 4.0</a> veröffentlicht wird.
not_logged_in_warning: Wenn Sie wollen, dass die Übersetzung Ihnen zugeordnet werden kann, müssen Sie sich einloggen (oben rechts), andernfalls ist sie anonym.
save_and_accept: Übersetzung direkt setzen
new:
new_translation: Neue Übersetzung für Problem %{id}
notice:
successfully_created: Der Übersetzungsvorschlag wurde eingereicht. Ein Organisator wird sich Ihren Vorschlag so bald wie möglich anschauen.
successfully_created_and_accepted: Die Übersetzung wurde erfolgreich erstellt und akzeptiert.
successfully_created: Der Übersetzungsvorschlag wurde eingereicht. Ein Organisator wird sich Ihren Vorschlag so bald wie möglich anschauen.

View File

@@ -1,5 +1,5 @@
Rails.application.routes.draw do
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
@@ -11,7 +11,6 @@ Rails.application.routes.draw do
get 'about/info'
get 'about/copyright'
get 'about/legal'
get 'about/privacy'
get 'about/roman_numerals'
@@ -32,7 +31,7 @@ Rails.application.routes.draw do
namespace :admin do
get '', to: 'dashboard#index', as: 'dashboard_index'
post '/pull_problems', to: 'dashboard#pull_problems', as: 'dashboard_pull_problems'
post '/update_problem_count', to: 'dashboard#update_problem_count', as: 'dashboard_update_problem_count'
resources :translations, only: [:index] do
get '', to: 'translations#show', as: ''
post 'accept', to: 'translations#accept'

View File

@@ -1,5 +0,0 @@
class AddRememberTokenToUsers < ActiveRecord::Migration[5.2]
def change
add_column :users, :remember_token, :string
end
end

View File

@@ -1,7 +0,0 @@
class AddOriginalDataToProblems < ActiveRecord::Migration[6.0]
def change
add_column :problems, :pulled_at, :datetime
add_column :problems, :original_title, :string
add_column :problems, :original_content, :text
end
end

View File

@@ -2,23 +2,20 @@
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# This file is the source Rails uses to define your schema when running `rails
# db:schema:load`. When creating a new database, `rails db:schema:load` tends to
# be faster and is potentially less error prone than running all of your
# migrations from scratch. Old migrations may fail to apply correctly if those
# migrations use external dependencies or application code.
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2020_05_01_095104) do
ActiveRecord::Schema.define(version: 2019_02_04_164033) do
create_table "problems", force: :cascade do |t|
t.datetime "created_at"
t.datetime "updated_at"
t.integer "translation_id"
t.datetime "pulled_at"
t.string "original_title"
t.text "original_content"
t.index ["translation_id"], name: "index_problems_on_translation_id"
end
@@ -42,7 +39,6 @@ ActiveRecord::Schema.define(version: 2020_05_01_095104) do
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "name"
t.string "remember_token"
end
end

View File

@@ -10,27 +10,13 @@ Translation.delete_all
Problem.delete_all
User.delete_all
admin = User.create!(
provider: :developer,
uid: "admin",
name: "admin",
role: :admin
)
translator = User.create!(
provider: :developer,
uid: "translator",
name: "translator",
role: :user
)
for i in 1..60 do
for i in 1..20 do
Problem.create!(id: i)
end
for i in 1..10 do
translation = Translation.create!(
author: translator,
problem: Problem.find(i),
title: "Problem Nummer #{i}",
content: %Q(<p>Das hier ist der Inhalt von <b>Problem #{i}</b>.
@@ -44,6 +30,19 @@ for i in 1..10 do
end
User.create!(
provider: :developer,
uid: "admin",
name: "admin",
role: 1
)
User.create!(
provider: :developer,
uid: "translator",
name: "translator"
)
p "Created #{Problem.count} problems"
p "Created #{Translation.count} translations"
p "Created #{User.count} users"

View File

@@ -2,7 +2,6 @@ require 'test_helper'
class Admin::DashboardControllerTest < ActionDispatch::IntegrationTest
include Devise::Test::IntegrationHelpers
include ActiveJob::TestHelper
setup do
end
@@ -19,14 +18,18 @@ class Admin::DashboardControllerTest < ActionDispatch::IntegrationTest
assert_response :success
end
test "should update problems" do
WebMock.stub_request(:get, "https://projecteuler.net/minimal=problems;csv").to_return(body: "")
test "should post new problem count" do
login_admin
assert_enqueued_jobs 1, only: PullProblemsJob do
post admin_dashboard_pull_problems_url
end
post admin_dashboard_update_problem_count_url(problem_count: 15)
assert_redirected_to admin_dashboard_index_url
assert_equal 15, Problem.count
end
test "should fail incorrect problem count" do
login_admin
post admin_dashboard_update_problem_count_url(problem_count: 2)
assert_redirected_to admin_dashboard_index_url
assert_equal 3, Problem.count
end
end

View File

@@ -7,8 +7,6 @@ class Admin::TranslationsControllerTest < ActionDispatch::IntegrationTest
login_admin
@translation = translations(:translation_one)
@translation_alternative = translations(:translation_two_alternative)
@translation_outdated = translations(:translation_two_outdated)
@translation_declined = translations(:translation_two_declined)
end
test "should get index" do
get admin_translations_url
@@ -16,26 +14,11 @@ class Admin::TranslationsControllerTest < ActionDispatch::IntegrationTest
assert_not_nil assigns(:translations)
end
test "should show current_translation" do
test "should show translation" do
get admin_translation_url(translation_id: @translation)
assert_response :success
end
test "should show alternative_translation" do
get admin_translation_url(translation_id: @translation_alternative)
assert_response :success
end
test "should show outdated_translation" do
get admin_translation_url(translation_id: @translation_outdated)
assert_response :success
end
test "should show declined_translation" do
get admin_translation_url(translation_id: @translation_declined)
assert_response :success
end
test "should accept translation" do
post admin_translation_accept_path(@translation_alternative)
assert_redirected_to problem_path(2)

View File

@@ -22,12 +22,4 @@ class ProblemsControllerTest < ActionDispatch::IntegrationTest
assert_redirected_to problem_path(id: 2)
end
test "should contain HTML styles in translation content" do
get problem_url(id: 4)
assert_response :success
assert_select ".problem-content" do
assert_select "b", 1
assert_select 'p[style="text-align:center;"]', 1
end
end
end

View File

@@ -40,28 +40,6 @@ class TranslationsControllerTest < ActionDispatch::IntegrationTest
assert_equal users(:translator), Translation.last.author
end
test "should create and accept translation from admin" do
login_admin
assert_difference('Translation.count') do
post problem_translations_url(problem_id: 1, translation: @update, accept: true)
end
assert_redirected_to problem_path(id: 1)
assert_equal users(:admin), Translation.last.author
assert_equal Problem.find(1).translation, Translation.last
end
test "should create but not accept translation from normal user" do
login_translator
assert_difference('Translation.count') do
post problem_translations_url(problem_id: 1, translation: @update, accept: true)
end
assert_redirected_to problem_path(id: 1)
assert_equal users(:translator), Translation.last.author
assert_not_equal Problem.find(1).translation, Translation.last
end
test "should not create incorrect translation" do
assert_no_difference('Translation.count') do
post problem_translations_url(problem_id: 1, translation: @incorrect)

View File

@@ -11,7 +11,3 @@ two:
three:
id: 3
four:
id: 4
translation: translation_with_html

View File

@@ -17,22 +17,3 @@ translation_two_alternative:
title: Second title
content: The changed content for the second problem
status: 0
translation_two_outdated:
problem_id: 2
title: Second title
content: The old content for the second problem
status: 2
translation_two_declined:
problem_id: 2
title: Second title
content: The content for the second problem with typo
status: 3
translation_with_html:
problem_id: 4
title: Some title
content: 'p>This is some <b>custom</b> text.</p><p style="text-align:center;">This is centered.</p>'
status: 1

View File

@@ -8,6 +8,6 @@ class ApplicationHelperTest < ActionView::TestCase
test "bootstrap flash messages should work" do
flash[:error] = "Error"
assert_equal "<div class=\"alert alert-danger alert-dismissible\" role=\"alert\">Error<button class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button></div>", flash_messages
assert_equal "<div class=\"alert alert-danger alert-dismissible\" role=\"alert\"><button class=\"close\" data-dismiss=\"alert\"><span aria-hidden=\"true\">&times;</span><span class=\"sr-only\">Close</span></button>Error</div>", flash_messages
end
end

View File

@@ -4,11 +4,11 @@ class TranslatorFlowTest < ActionDispatch::IntegrationTest
test "can view a problem" do
get '/problems/1'
assert_response :success
assert_select "h1", "First title"
assert_select "h1", "First title Problem 1"
end
test "can login via github" do
post '/users/auth/github'
get '/users/auth/github'
assert_response :redirect
follow_redirect!
follow_redirect!

View File

@@ -1,15 +0,0 @@
require 'test_helper'
class PullProblemContentJobTest < ActiveJob::TestCase
test "should update problem count and titles" do
stub = WebMock.stub_request(:get, "https://projecteuler.net/minimal=3").
to_return(body: "\n<p><a href=\"problem=5\">test</a></p>")
PullProblemContentJob.perform_now problems(:three)
assert_requested stub
assert_equal '<p><a href="/problem=5">test</a></p>', Problem.find(3).original_content
assert_in_delta Time.current, Problem.find(3).pulled_at, 5
end
end

View File

@@ -1,27 +0,0 @@
require 'test_helper'
require 'csv'
class PullProblemsJobTest < ActiveJob::TestCase
test "should update problem count and titles" do
csv_string = CSV.generate do |csv|
csv << ["ID", "Description", "Published", "Updated", "Solved By"]
csv << [1, "Title of problem 1", 4.days.ago.to_i, 2.days.ago.to_i, 123]
csv << [2, "Title of problem 2", 4.days.ago.to_i, 2.days.ago.to_i, 123]
csv << [3, "Title of problem 3", 4.days.ago.to_i, 2.days.ago.to_i, 123]
csv << [4, "Title of problem 4", 4.days.ago.to_i, 2.days.ago.to_i, 123]
csv << [5, "Title of problem 5", 4.days.ago.to_i, 2.days.ago.to_i, 123]
end
stub = WebMock.stub_request(:get, "https://projecteuler.net/minimal=problems;csv").
to_return(body: csv_string)
problems(:two).update(pulled_at: 3.days.ago)
problems(:three).update(pulled_at: 1.day.ago)
assert_enqueued_jobs(4, only: PullProblemContentJob) do
PullProblemsJob.perform_now
end
assert_requested stub
assert_equal 5, Problem.count
assert_equal "Title of problem 2", Problem.find(2).original_title
end
end

View File

@@ -26,7 +26,7 @@ class ProblemTest < ActiveSupport::TestCase
end
test "should return correct number of translated problems" do
assert_equal 3, Problem.translated_count
assert_equal 2, Problem.translated_count
end
test "should allow for problem count updating" do
@@ -44,7 +44,7 @@ class ProblemTest < ActiveSupport::TestCase
assert_raises ArgumentError do
Problem.update_count(1)
end
assert_equal 4, Problem.count()
assert_equal 3, Problem.count()
assert_equal "First title", Problem.find(1).title
end
end

View File

@@ -1,4 +1,6 @@
require 'webmock/minitest'
require 'codacy-coverage'
Codacy::Reporter.start
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
@@ -8,8 +10,6 @@ class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
WebMock.disable_net_connect!
# Add more helper methods to be used by all tests here...
end

View File

@@ -1,63 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
CodeMirror.defineOption("placeholder", "", function(cm, val, old) {
var prev = old && old != CodeMirror.Init;
if (val && !prev) {
cm.on("blur", onBlur);
cm.on("change", onChange);
cm.on("swapDoc", onChange);
onChange(cm);
} else if (!val && prev) {
cm.off("blur", onBlur);
cm.off("change", onChange);
cm.off("swapDoc", onChange);
clearPlaceholder(cm);
var wrapper = cm.getWrapperElement();
wrapper.className = wrapper.className.replace(" CodeMirror-empty", "");
}
if (val && !cm.hasFocus()) onBlur(cm);
});
function clearPlaceholder(cm) {
if (cm.state.placeholder) {
cm.state.placeholder.parentNode.removeChild(cm.state.placeholder);
cm.state.placeholder = null;
}
}
function setPlaceholder(cm) {
clearPlaceholder(cm);
var elt = cm.state.placeholder = document.createElement("pre");
elt.style.cssText = "height: 0; overflow: visible";
elt.style.direction = cm.getOption("direction");
elt.className = "CodeMirror-placeholder CodeMirror-line-like";
var placeHolder = cm.getOption("placeholder")
if (typeof placeHolder == "string") placeHolder = document.createTextNode(placeHolder)
elt.appendChild(placeHolder)
cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild);
}
function onBlur(cm) {
if (isEmpty(cm)) setPlaceholder(cm);
}
function onChange(cm) {
var wrapper = cm.getWrapperElement(), empty = isEmpty(cm);
wrapper.className = wrapper.className.replace(" CodeMirror-empty", "") + (empty ? " CodeMirror-empty" : "");
if (empty) setPlaceholder(cm);
else clearPlaceholder(cm);
}
function isEmpty(cm) {
return (cm.lineCount() === 1) && (cm.getLine(0) === "");
}
});

View File

@@ -1,349 +0,0 @@
/* BASICS */
.CodeMirror {
/* Set height, width, borders, and global font properties here */
font-family: monospace;
height: 300px;
color: black;
direction: ltr;
}
/* PADDING */
.CodeMirror-lines {
padding: 4px 0; /* Vertical padding around content */
}
.CodeMirror pre.CodeMirror-line,
.CodeMirror pre.CodeMirror-line-like {
padding: 0 4px; /* Horizontal padding of content */
}
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
background-color: white; /* The little square between H and V scrollbars */
}
/* GUTTER */
.CodeMirror-gutters {
border-right: 1px solid #ddd;
background-color: #f7f7f7;
white-space: nowrap;
}
.CodeMirror-linenumbers {}
.CodeMirror-linenumber {
padding: 0 3px 0 5px;
min-width: 20px;
text-align: right;
color: #999;
white-space: nowrap;
}
.CodeMirror-guttermarker { color: black; }
.CodeMirror-guttermarker-subtle { color: #999; }
/* CURSOR */
.CodeMirror-cursor {
border-left: 1px solid black;
border-right: none;
width: 0;
}
/* Shown when moving in bi-directional text */
.CodeMirror div.CodeMirror-secondarycursor {
border-left: 1px solid silver;
}
.cm-fat-cursor .CodeMirror-cursor {
width: auto;
border: 0 !important;
background: #7e7;
}
.cm-fat-cursor div.CodeMirror-cursors {
z-index: 1;
}
.cm-fat-cursor-mark {
background-color: rgba(20, 255, 20, 0.5);
-webkit-animation: blink 1.06s steps(1) infinite;
-moz-animation: blink 1.06s steps(1) infinite;
animation: blink 1.06s steps(1) infinite;
}
.cm-animate-fat-cursor {
width: auto;
border: 0;
-webkit-animation: blink 1.06s steps(1) infinite;
-moz-animation: blink 1.06s steps(1) infinite;
animation: blink 1.06s steps(1) infinite;
background-color: #7e7;
}
@-moz-keyframes blink {
0% {}
50% { background-color: transparent; }
100% {}
}
@-webkit-keyframes blink {
0% {}
50% { background-color: transparent; }
100% {}
}
@keyframes blink {
0% {}
50% { background-color: transparent; }
100% {}
}
/* Can style cursor different in overwrite (non-insert) mode */
.CodeMirror-overwrite .CodeMirror-cursor {}
.cm-tab { display: inline-block; text-decoration: inherit; }
.CodeMirror-rulers {
position: absolute;
left: 0; right: 0; top: -50px; bottom: 0;
overflow: hidden;
}
.CodeMirror-ruler {
border-left: 1px solid #ccc;
top: 0; bottom: 0;
position: absolute;
}
/* DEFAULT THEME */
.cm-s-default .cm-header {color: blue;}
.cm-s-default .cm-quote {color: #090;}
.cm-negative {color: #d44;}
.cm-positive {color: #292;}
.cm-header, .cm-strong {font-weight: bold;}
.cm-em {font-style: italic;}
.cm-link {text-decoration: underline;}
.cm-strikethrough {text-decoration: line-through;}
.cm-s-default .cm-keyword {color: #708;}
.cm-s-default .cm-atom {color: #219;}
.cm-s-default .cm-number {color: #164;}
.cm-s-default .cm-def {color: #00f;}
.cm-s-default .cm-variable,
.cm-s-default .cm-punctuation,
.cm-s-default .cm-property,
.cm-s-default .cm-operator {}
.cm-s-default .cm-variable-2 {color: #05a;}
.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}
.cm-s-default .cm-comment {color: #a50;}
.cm-s-default .cm-string {color: #a11;}
.cm-s-default .cm-string-2 {color: #f50;}
.cm-s-default .cm-meta {color: #555;}
.cm-s-default .cm-qualifier {color: #555;}
.cm-s-default .cm-builtin {color: #30a;}
.cm-s-default .cm-bracket {color: #997;}
.cm-s-default .cm-tag {color: #170;}
.cm-s-default .cm-attribute {color: #00c;}
.cm-s-default .cm-hr {color: #999;}
.cm-s-default .cm-link {color: #00c;}
.cm-s-default .cm-error {color: #f00;}
.cm-invalidchar {color: #f00;}
.CodeMirror-composing { border-bottom: 2px solid; }
/* Default styles for common addons */
div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
.CodeMirror-activeline-background {background: #e8f2ff;}
/* STOP */
/* The rest of this file contains styles related to the mechanics of
the editor. You probably shouldn't touch them. */
.CodeMirror {
position: relative;
overflow: hidden;
background: white;
}
.CodeMirror-scroll {
overflow: scroll !important; /* Things will break if this is overridden */
/* 30px is the magic margin used to hide the element's real scrollbars */
/* See overflow: hidden in .CodeMirror */
margin-bottom: -30px; margin-right: -30px;
padding-bottom: 30px;
height: 100%;
outline: none; /* Prevent dragging from highlighting the element */
position: relative;
}
.CodeMirror-sizer {
position: relative;
border-right: 30px solid transparent;
}
/* The fake, visible scrollbars. Used to force redraw during scrolling
before actual scrolling happens, thus preventing shaking and
flickering artifacts. */
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
position: absolute;
z-index: 6;
display: none;
}
.CodeMirror-vscrollbar {
right: 0; top: 0;
overflow-x: hidden;
overflow-y: scroll;
}
.CodeMirror-hscrollbar {
bottom: 0; left: 0;
overflow-y: hidden;
overflow-x: scroll;
}
.CodeMirror-scrollbar-filler {
right: 0; bottom: 0;
}
.CodeMirror-gutter-filler {
left: 0; bottom: 0;
}
.CodeMirror-gutters {
position: absolute; left: 0; top: 0;
min-height: 100%;
z-index: 3;
}
.CodeMirror-gutter {
white-space: normal;
height: 100%;
display: inline-block;
vertical-align: top;
margin-bottom: -30px;
}
.CodeMirror-gutter-wrapper {
position: absolute;
z-index: 4;
background: none !important;
border: none !important;
}
.CodeMirror-gutter-background {
position: absolute;
top: 0; bottom: 0;
z-index: 4;
}
.CodeMirror-gutter-elt {
position: absolute;
cursor: default;
z-index: 4;
}
.CodeMirror-gutter-wrapper ::selection { background-color: transparent }
.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
.CodeMirror-lines {
cursor: text;
min-height: 1px; /* prevents collapsing before first draw */
}
.CodeMirror pre.CodeMirror-line,
.CodeMirror pre.CodeMirror-line-like {
/* Reset some styles that the rest of the page might have set */
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
border-width: 0;
background: transparent;
font-family: inherit;
font-size: inherit;
margin: 0;
white-space: pre;
word-wrap: normal;
line-height: inherit;
color: inherit;
z-index: 2;
position: relative;
overflow: visible;
-webkit-tap-highlight-color: transparent;
-webkit-font-variant-ligatures: contextual;
font-variant-ligatures: contextual;
}
.CodeMirror-wrap pre.CodeMirror-line,
.CodeMirror-wrap pre.CodeMirror-line-like {
word-wrap: break-word;
white-space: pre-wrap;
word-break: normal;
}
.CodeMirror-linebackground {
position: absolute;
left: 0; right: 0; top: 0; bottom: 0;
z-index: 0;
}
.CodeMirror-linewidget {
position: relative;
z-index: 2;
padding: 0.1px; /* Force widget margins to stay inside of the container */
}
.CodeMirror-widget {}
.CodeMirror-rtl pre { direction: rtl; }
.CodeMirror-code {
outline: none;
}
/* Force content-box sizing for the elements where we expect it */
.CodeMirror-scroll,
.CodeMirror-sizer,
.CodeMirror-gutter,
.CodeMirror-gutters,
.CodeMirror-linenumber {
-moz-box-sizing: content-box;
box-sizing: content-box;
}
.CodeMirror-measure {
position: absolute;
width: 100%;
height: 0;
overflow: hidden;
visibility: hidden;
}
.CodeMirror-cursor {
position: absolute;
pointer-events: none;
}
.CodeMirror-measure pre { position: static; }
div.CodeMirror-cursors {
visibility: hidden;
position: relative;
z-index: 3;
}
div.CodeMirror-dragcursors {
visibility: visible;
}
.CodeMirror-focused div.CodeMirror-cursors {
visibility: visible;
}
.CodeMirror-selected { background: #d9d9d9; }
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
.CodeMirror-crosshair { cursor: crosshair; }
.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
.cm-searching {
background-color: #ffa;
background-color: rgba(255, 255, 0, .4);
}
/* Used to force a border model for a node */
.cm-force-border { padding-right: .1px; }
@media print {
/* Hide the cursor when printing */
.CodeMirror div.CodeMirror-cursors {
visibility: hidden;
}
}
/* See issue #2901 */
.cm-tab-wrap-hack:after { content: ''; }
/* Help users use markselection to safely style text background */
span.CodeMirror-selectedtext { background: none; }

File diff suppressed because it is too large Load Diff

View File

@@ -1,831 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineMode("css", function(config, parserConfig) {
var inline = parserConfig.inline
if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css");
var indentUnit = config.indentUnit,
tokenHooks = parserConfig.tokenHooks,
documentTypes = parserConfig.documentTypes || {},
mediaTypes = parserConfig.mediaTypes || {},
mediaFeatures = parserConfig.mediaFeatures || {},
mediaValueKeywords = parserConfig.mediaValueKeywords || {},
propertyKeywords = parserConfig.propertyKeywords || {},
nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {},
fontProperties = parserConfig.fontProperties || {},
counterDescriptors = parserConfig.counterDescriptors || {},
colorKeywords = parserConfig.colorKeywords || {},
valueKeywords = parserConfig.valueKeywords || {},
allowNested = parserConfig.allowNested,
lineComment = parserConfig.lineComment,
supportsAtComponent = parserConfig.supportsAtComponent === true;
var type, override;
function ret(style, tp) { type = tp; return style; }
// Tokenizers
function tokenBase(stream, state) {
var ch = stream.next();
if (tokenHooks[ch]) {
var result = tokenHooks[ch](stream, state);
if (result !== false) return result;
}
if (ch == "@") {
stream.eatWhile(/[\w\\\-]/);
return ret("def", stream.current());
} else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) {
return ret(null, "compare");
} else if (ch == "\"" || ch == "'") {
state.tokenize = tokenString(ch);
return state.tokenize(stream, state);
} else if (ch == "#") {
stream.eatWhile(/[\w\\\-]/);
return ret("atom", "hash");
} else if (ch == "!") {
stream.match(/^\s*\w*/);
return ret("keyword", "important");
} else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) {
stream.eatWhile(/[\w.%]/);
return ret("number", "unit");
} else if (ch === "-") {
if (/[\d.]/.test(stream.peek())) {
stream.eatWhile(/[\w.%]/);
return ret("number", "unit");
} else if (stream.match(/^-[\w\\\-]*/)) {
stream.eatWhile(/[\w\\\-]/);
if (stream.match(/^\s*:/, false))
return ret("variable-2", "variable-definition");
return ret("variable-2", "variable");
} else if (stream.match(/^\w+-/)) {
return ret("meta", "meta");
}
} else if (/[,+>*\/]/.test(ch)) {
return ret(null, "select-op");
} else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
return ret("qualifier", "qualifier");
} else if (/[:;{}\[\]\(\)]/.test(ch)) {
return ret(null, ch);
} else if (stream.match(/[\w-.]+(?=\()/)) {
if (/^(url(-prefix)?|domain|regexp)$/.test(stream.current().toLowerCase())) {
state.tokenize = tokenParenthesized;
}
return ret("variable callee", "variable");
} else if (/[\w\\\-]/.test(ch)) {
stream.eatWhile(/[\w\\\-]/);
return ret("property", "word");
} else {
return ret(null, null);
}
}
function tokenString(quote) {
return function(stream, state) {
var escaped = false, ch;
while ((ch = stream.next()) != null) {
if (ch == quote && !escaped) {
if (quote == ")") stream.backUp(1);
break;
}
escaped = !escaped && ch == "\\";
}
if (ch == quote || !escaped && quote != ")") state.tokenize = null;
return ret("string", "string");
};
}
function tokenParenthesized(stream, state) {
stream.next(); // Must be '('
if (!stream.match(/\s*[\"\')]/, false))
state.tokenize = tokenString(")");
else
state.tokenize = null;
return ret(null, "(");
}
// Context management
function Context(type, indent, prev) {
this.type = type;
this.indent = indent;
this.prev = prev;
}
function pushContext(state, stream, type, indent) {
state.context = new Context(type, stream.indentation() + (indent === false ? 0 : indentUnit), state.context);
return type;
}
function popContext(state) {
if (state.context.prev)
state.context = state.context.prev;
return state.context.type;
}
function pass(type, stream, state) {
return states[state.context.type](type, stream, state);
}
function popAndPass(type, stream, state, n) {
for (var i = n || 1; i > 0; i--)
state.context = state.context.prev;
return pass(type, stream, state);
}
// Parser
function wordAsValue(stream) {
var word = stream.current().toLowerCase();
if (valueKeywords.hasOwnProperty(word))
override = "atom";
else if (colorKeywords.hasOwnProperty(word))
override = "keyword";
else
override = "variable";
}
var states = {};
states.top = function(type, stream, state) {
if (type == "{") {
return pushContext(state, stream, "block");
} else if (type == "}" && state.context.prev) {
return popContext(state);
} else if (supportsAtComponent && /@component/i.test(type)) {
return pushContext(state, stream, "atComponentBlock");
} else if (/^@(-moz-)?document$/i.test(type)) {
return pushContext(state, stream, "documentTypes");
} else if (/^@(media|supports|(-moz-)?document|import)$/i.test(type)) {
return pushContext(state, stream, "atBlock");
} else if (/^@(font-face|counter-style)/i.test(type)) {
state.stateArg = type;
return "restricted_atBlock_before";
} else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/i.test(type)) {
return "keyframes";
} else if (type && type.charAt(0) == "@") {
return pushContext(state, stream, "at");
} else if (type == "hash") {
override = "builtin";
} else if (type == "word") {
override = "tag";
} else if (type == "variable-definition") {
return "maybeprop";
} else if (type == "interpolation") {
return pushContext(state, stream, "interpolation");
} else if (type == ":") {
return "pseudo";
} else if (allowNested && type == "(") {
return pushContext(state, stream, "parens");
}
return state.context.type;
};
states.block = function(type, stream, state) {
if (type == "word") {
var word = stream.current().toLowerCase();
if (propertyKeywords.hasOwnProperty(word)) {
override = "property";
return "maybeprop";
} else if (nonStandardPropertyKeywords.hasOwnProperty(word)) {
override = "string-2";
return "maybeprop";
} else if (allowNested) {
override = stream.match(/^\s*:(?:\s|$)/, false) ? "property" : "tag";
return "block";
} else {
override += " error";
return "maybeprop";
}
} else if (type == "meta") {
return "block";
} else if (!allowNested && (type == "hash" || type == "qualifier")) {
override = "error";
return "block";
} else {
return states.top(type, stream, state);
}
};
states.maybeprop = function(type, stream, state) {
if (type == ":") return pushContext(state, stream, "prop");
return pass(type, stream, state);
};
states.prop = function(type, stream, state) {
if (type == ";") return popContext(state);
if (type == "{" && allowNested) return pushContext(state, stream, "propBlock");
if (type == "}" || type == "{") return popAndPass(type, stream, state);
if (type == "(") return pushContext(state, stream, "parens");
if (type == "hash" && !/^#([0-9a-fA-f]{3,4}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/.test(stream.current())) {
override += " error";
} else if (type == "word") {
wordAsValue(stream);
} else if (type == "interpolation") {
return pushContext(state, stream, "interpolation");
}
return "prop";
};
states.propBlock = function(type, _stream, state) {
if (type == "}") return popContext(state);
if (type == "word") { override = "property"; return "maybeprop"; }
return state.context.type;
};
states.parens = function(type, stream, state) {
if (type == "{" || type == "}") return popAndPass(type, stream, state);
if (type == ")") return popContext(state);
if (type == "(") return pushContext(state, stream, "parens");
if (type == "interpolation") return pushContext(state, stream, "interpolation");
if (type == "word") wordAsValue(stream);
return "parens";
};
states.pseudo = function(type, stream, state) {
if (type == "meta") return "pseudo";
if (type == "word") {
override = "variable-3";
return state.context.type;
}
return pass(type, stream, state);
};
states.documentTypes = function(type, stream, state) {
if (type == "word" && documentTypes.hasOwnProperty(stream.current())) {
override = "tag";
return state.context.type;
} else {
return states.atBlock(type, stream, state);
}
};
states.atBlock = function(type, stream, state) {
if (type == "(") return pushContext(state, stream, "atBlock_parens");
if (type == "}" || type == ";") return popAndPass(type, stream, state);
if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top");
if (type == "interpolation") return pushContext(state, stream, "interpolation");
if (type == "word") {
var word = stream.current().toLowerCase();
if (word == "only" || word == "not" || word == "and" || word == "or")
override = "keyword";
else if (mediaTypes.hasOwnProperty(word))
override = "attribute";
else if (mediaFeatures.hasOwnProperty(word))
override = "property";
else if (mediaValueKeywords.hasOwnProperty(word))
override = "keyword";
else if (propertyKeywords.hasOwnProperty(word))
override = "property";
else if (nonStandardPropertyKeywords.hasOwnProperty(word))
override = "string-2";
else if (valueKeywords.hasOwnProperty(word))
override = "atom";
else if (colorKeywords.hasOwnProperty(word))
override = "keyword";
else
override = "error";
}
return state.context.type;
};
states.atComponentBlock = function(type, stream, state) {
if (type == "}")
return popAndPass(type, stream, state);
if (type == "{")
return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top", false);
if (type == "word")
override = "error";
return state.context.type;
};
states.atBlock_parens = function(type, stream, state) {
if (type == ")") return popContext(state);
if (type == "{" || type == "}") return popAndPass(type, stream, state, 2);
return states.atBlock(type, stream, state);
};
states.restricted_atBlock_before = function(type, stream, state) {
if (type == "{")
return pushContext(state, stream, "restricted_atBlock");
if (type == "word" && state.stateArg == "@counter-style") {
override = "variable";
return "restricted_atBlock_before";
}
return pass(type, stream, state);
};
states.restricted_atBlock = function(type, stream, state) {
if (type == "}") {
state.stateArg = null;
return popContext(state);
}
if (type == "word") {
if ((state.stateArg == "@font-face" && !fontProperties.hasOwnProperty(stream.current().toLowerCase())) ||
(state.stateArg == "@counter-style" && !counterDescriptors.hasOwnProperty(stream.current().toLowerCase())))
override = "error";
else
override = "property";
return "maybeprop";
}
return "restricted_atBlock";
};
states.keyframes = function(type, stream, state) {
if (type == "word") { override = "variable"; return "keyframes"; }
if (type == "{") return pushContext(state, stream, "top");
return pass(type, stream, state);
};
states.at = function(type, stream, state) {
if (type == ";") return popContext(state);
if (type == "{" || type == "}") return popAndPass(type, stream, state);
if (type == "word") override = "tag";
else if (type == "hash") override = "builtin";
return "at";
};
states.interpolation = function(type, stream, state) {
if (type == "}") return popContext(state);
if (type == "{" || type == ";") return popAndPass(type, stream, state);
if (type == "word") override = "variable";
else if (type != "variable" && type != "(" && type != ")") override = "error";
return "interpolation";
};
return {
startState: function(base) {
return {tokenize: null,
state: inline ? "block" : "top",
stateArg: null,
context: new Context(inline ? "block" : "top", base || 0, null)};
},
token: function(stream, state) {
if (!state.tokenize && stream.eatSpace()) return null;
var style = (state.tokenize || tokenBase)(stream, state);
if (style && typeof style == "object") {
type = style[1];
style = style[0];
}
override = style;
if (type != "comment")
state.state = states[state.state](type, stream, state);
return override;
},
indent: function(state, textAfter) {
var cx = state.context, ch = textAfter && textAfter.charAt(0);
var indent = cx.indent;
if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev;
if (cx.prev) {
if (ch == "}" && (cx.type == "block" || cx.type == "top" ||
cx.type == "interpolation" || cx.type == "restricted_atBlock")) {
// Resume indentation from parent context.
cx = cx.prev;
indent = cx.indent;
} else if (ch == ")" && (cx.type == "parens" || cx.type == "atBlock_parens") ||
ch == "{" && (cx.type == "at" || cx.type == "atBlock")) {
// Dedent relative to current context.
indent = Math.max(0, cx.indent - indentUnit);
}
}
return indent;
},
electricChars: "}",
blockCommentStart: "/*",
blockCommentEnd: "*/",
blockCommentContinue: " * ",
lineComment: lineComment,
fold: "brace"
};
});
function keySet(array) {
var keys = {};
for (var i = 0; i < array.length; ++i) {
keys[array[i].toLowerCase()] = true;
}
return keys;
}
var documentTypes_ = [
"domain", "regexp", "url", "url-prefix"
], documentTypes = keySet(documentTypes_);
var mediaTypes_ = [
"all", "aural", "braille", "handheld", "print", "projection", "screen",
"tty", "tv", "embossed"
], mediaTypes = keySet(mediaTypes_);
var mediaFeatures_ = [
"width", "min-width", "max-width", "height", "min-height", "max-height",
"device-width", "min-device-width", "max-device-width", "device-height",
"min-device-height", "max-device-height", "aspect-ratio",
"min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio",
"min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color",
"max-color", "color-index", "min-color-index", "max-color-index",
"monochrome", "min-monochrome", "max-monochrome", "resolution",
"min-resolution", "max-resolution", "scan", "grid", "orientation",
"device-pixel-ratio", "min-device-pixel-ratio", "max-device-pixel-ratio",
"pointer", "any-pointer", "hover", "any-hover"
], mediaFeatures = keySet(mediaFeatures_);
var mediaValueKeywords_ = [
"landscape", "portrait", "none", "coarse", "fine", "on-demand", "hover",
"interlace", "progressive"
], mediaValueKeywords = keySet(mediaValueKeywords_);
var propertyKeywords_ = [
"align-content", "align-items", "align-self", "alignment-adjust",
"alignment-baseline", "anchor-point", "animation", "animation-delay",
"animation-direction", "animation-duration", "animation-fill-mode",
"animation-iteration-count", "animation-name", "animation-play-state",
"animation-timing-function", "appearance", "azimuth", "backface-visibility",
"background", "background-attachment", "background-blend-mode", "background-clip",
"background-color", "background-image", "background-origin", "background-position",
"background-repeat", "background-size", "baseline-shift", "binding",
"bleed", "bookmark-label", "bookmark-level", "bookmark-state",
"bookmark-target", "border", "border-bottom", "border-bottom-color",
"border-bottom-left-radius", "border-bottom-right-radius",
"border-bottom-style", "border-bottom-width", "border-collapse",
"border-color", "border-image", "border-image-outset",
"border-image-repeat", "border-image-slice", "border-image-source",
"border-image-width", "border-left", "border-left-color",
"border-left-style", "border-left-width", "border-radius", "border-right",
"border-right-color", "border-right-style", "border-right-width",
"border-spacing", "border-style", "border-top", "border-top-color",
"border-top-left-radius", "border-top-right-radius", "border-top-style",
"border-top-width", "border-width", "bottom", "box-decoration-break",
"box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
"caption-side", "caret-color", "clear", "clip", "color", "color-profile", "column-count",
"column-fill", "column-gap", "column-rule", "column-rule-color",
"column-rule-style", "column-rule-width", "column-span", "column-width",
"columns", "content", "counter-increment", "counter-reset", "crop", "cue",
"cue-after", "cue-before", "cursor", "direction", "display",
"dominant-baseline", "drop-initial-after-adjust",
"drop-initial-after-align", "drop-initial-before-adjust",
"drop-initial-before-align", "drop-initial-size", "drop-initial-value",
"elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis",
"flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap",
"float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings",
"font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust",
"font-stretch", "font-style", "font-synthesis", "font-variant",
"font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
"font-variant-ligatures", "font-variant-numeric", "font-variant-position",
"font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow",
"grid-auto-rows", "grid-column", "grid-column-end", "grid-column-gap",
"grid-column-start", "grid-gap", "grid-row", "grid-row-end", "grid-row-gap",
"grid-row-start", "grid-template", "grid-template-areas", "grid-template-columns",
"grid-template-rows", "hanging-punctuation", "height", "hyphens",
"icon", "image-orientation", "image-rendering", "image-resolution",
"inline-box-align", "justify-content", "justify-items", "justify-self", "left", "letter-spacing",
"line-break", "line-height", "line-stacking", "line-stacking-ruby",
"line-stacking-shift", "line-stacking-strategy", "list-style",
"list-style-image", "list-style-position", "list-style-type", "margin",
"margin-bottom", "margin-left", "margin-right", "margin-top",
"marks", "marquee-direction", "marquee-loop",
"marquee-play-count", "marquee-speed", "marquee-style", "max-height",
"max-width", "min-height", "min-width", "mix-blend-mode", "move-to", "nav-down", "nav-index",
"nav-left", "nav-right", "nav-up", "object-fit", "object-position",
"opacity", "order", "orphans", "outline",
"outline-color", "outline-offset", "outline-style", "outline-width",
"overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y",
"padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
"page", "page-break-after", "page-break-before", "page-break-inside",
"page-policy", "pause", "pause-after", "pause-before", "perspective",
"perspective-origin", "pitch", "pitch-range", "place-content", "place-items", "place-self", "play-during", "position",
"presentation-level", "punctuation-trim", "quotes", "region-break-after",
"region-break-before", "region-break-inside", "region-fragment",
"rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness",
"right", "rotation", "rotation-point", "ruby-align", "ruby-overhang",
"ruby-position", "ruby-span", "shape-image-threshold", "shape-inside", "shape-margin",
"shape-outside", "size", "speak", "speak-as", "speak-header",
"speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set",
"tab-size", "table-layout", "target", "target-name", "target-new",
"target-position", "text-align", "text-align-last", "text-decoration",
"text-decoration-color", "text-decoration-line", "text-decoration-skip",
"text-decoration-style", "text-emphasis", "text-emphasis-color",
"text-emphasis-position", "text-emphasis-style", "text-height",
"text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow",
"text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position",
"text-wrap", "top", "transform", "transform-origin", "transform-style",
"transition", "transition-delay", "transition-duration",
"transition-property", "transition-timing-function", "unicode-bidi",
"user-select", "vertical-align", "visibility", "voice-balance", "voice-duration",
"voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
"voice-volume", "volume", "white-space", "widows", "width", "will-change", "word-break",
"word-spacing", "word-wrap", "z-index",
// SVG-specific
"clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
"flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events",
"color-interpolation", "color-interpolation-filters",
"color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering",
"marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke",
"stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin",
"stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering",
"baseline-shift", "dominant-baseline", "glyph-orientation-horizontal",
"glyph-orientation-vertical", "text-anchor", "writing-mode"
], propertyKeywords = keySet(propertyKeywords_);
var nonStandardPropertyKeywords_ = [
"scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color",
"scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color",
"scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside",
"searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button",
"searchfield-results-decoration", "zoom"
], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_);
var fontProperties_ = [
"font-family", "src", "unicode-range", "font-variant", "font-feature-settings",
"font-stretch", "font-weight", "font-style"
], fontProperties = keySet(fontProperties_);
var counterDescriptors_ = [
"additive-symbols", "fallback", "negative", "pad", "prefix", "range",
"speak-as", "suffix", "symbols", "system"
], counterDescriptors = keySet(counterDescriptors_);
var colorKeywords_ = [
"aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
"bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
"burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue",
"cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod",
"darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen",
"darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
"darkslateblue", "darkslategray", "darkturquoise", "darkviolet",
"deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick",
"floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite",
"gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew",
"hotpink", "indianred", "indigo", "ivory", "khaki", "lavender",
"lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral",
"lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink",
"lightsalmon", "lightseagreen", "lightskyblue", "lightslategray",
"lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta",
"maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple",
"mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
"mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
"navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered",
"orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred",
"papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue",
"purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown",
"salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue",
"slateblue", "slategray", "snow", "springgreen", "steelblue", "tan",
"teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white",
"whitesmoke", "yellow", "yellowgreen"
], colorKeywords = keySet(colorKeywords_);
var valueKeywords_ = [
"above", "absolute", "activeborder", "additive", "activecaption", "afar",
"after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate",
"always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
"arabic-indic", "armenian", "asterisks", "attr", "auto", "auto-flow", "avoid", "avoid-column", "avoid-page",
"avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary",
"bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
"both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel",
"buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "cambodian",
"capitalize", "caps-lock-indicator", "caption", "captiontext", "caret",
"cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch",
"cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
"col-resize", "collapse", "color", "color-burn", "color-dodge", "column", "column-reverse",
"compact", "condensed", "contain", "content", "contents",
"content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop",
"cross", "crosshair", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal",
"decimal-leading-zero", "default", "default-button", "dense", "destination-atop",
"destination-in", "destination-out", "destination-over", "devanagari", "difference",
"disc", "discard", "disclosure-closed", "disclosure-open", "document",
"dot-dash", "dot-dot-dash",
"dotted", "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out",
"element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede",
"ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er",
"ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er",
"ethiopic-halehame-aa-et", "ethiopic-halehame-am-et",
"ethiopic-halehame-gez", "ethiopic-halehame-om-et",
"ethiopic-halehame-sid-et", "ethiopic-halehame-so-et",
"ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig",
"ethiopic-numeric", "ew-resize", "exclusion", "expanded", "extends", "extra-condensed",
"extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes",
"forwards", "from", "geometricPrecision", "georgian", "graytext", "grid", "groove",
"gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hard-light", "hebrew",
"help", "hidden", "hide", "higher", "highlight", "highlighttext",
"hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "hue", "icon", "ignore",
"inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
"infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
"inline-block", "inline-flex", "inline-grid", "inline-table", "inset", "inside", "intrinsic", "invert",
"italic", "japanese-formal", "japanese-informal", "justify", "kannada",
"katakana", "katakana-iroha", "keep-all", "khmer",
"korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal",
"landscape", "lao", "large", "larger", "left", "level", "lighter", "lighten",
"line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem",
"local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
"lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian",
"lower-roman", "lowercase", "ltr", "luminosity", "malayalam", "match", "matrix", "matrix3d",
"media-controls-background", "media-current-time-display",
"media-fullscreen-button", "media-mute-button", "media-play-button",
"media-return-to-realtime-button", "media-rewind-button",
"media-seek-back-button", "media-seek-forward-button", "media-slider",
"media-sliderthumb", "media-time-remaining-display", "media-volume-slider",
"media-volume-slider-container", "media-volume-sliderthumb", "medium",
"menu", "menulist", "menulist-button", "menulist-text",
"menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic",
"mix", "mongolian", "monospace", "move", "multiple", "multiply", "myanmar", "n-resize",
"narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
"no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
"ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "opacity", "open-quote",
"optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
"outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
"painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter",
"pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d",
"progress", "push-button", "radial-gradient", "radio", "read-only",
"read-write", "read-write-plaintext-only", "rectangle", "region",
"relative", "repeat", "repeating-linear-gradient",
"repeating-radial-gradient", "repeat-x", "repeat-y", "reset", "reverse",
"rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY",
"rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running",
"s-resize", "sans-serif", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen",
"scroll", "scrollbar", "scroll-position", "se-resize", "searchfield",
"searchfield-cancel-button", "searchfield-decoration",
"searchfield-results-button", "searchfield-results-decoration", "self-start", "self-end",
"semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
"simp-chinese-formal", "simp-chinese-informal", "single",
"skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal",
"slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
"small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "somali",
"source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "space-evenly", "spell-out", "square",
"square-button", "start", "static", "status-bar", "stretch", "stroke", "sub",
"subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "system-ui", "table",
"table-caption", "table-cell", "table-column", "table-column-group",
"table-footer-group", "table-header-group", "table-row", "table-row-group",
"tamil",
"telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai",
"thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
"threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
"tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
"trad-chinese-formal", "trad-chinese-informal", "transform",
"translate", "translate3d", "translateX", "translateY", "translateZ",
"transparent", "ultra-condensed", "ultra-expanded", "underline", "unset", "up",
"upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
"upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
"var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
"visibleStroke", "visual", "w-resize", "wait", "wave", "wider",
"window", "windowframe", "windowtext", "words", "wrap", "wrap-reverse", "x-large", "x-small", "xor",
"xx-large", "xx-small"
], valueKeywords = keySet(valueKeywords_);
var allWords = documentTypes_.concat(mediaTypes_).concat(mediaFeatures_).concat(mediaValueKeywords_)
.concat(propertyKeywords_).concat(nonStandardPropertyKeywords_).concat(colorKeywords_)
.concat(valueKeywords_);
CodeMirror.registerHelper("hintWords", "css", allWords);
function tokenCComment(stream, state) {
var maybeEnd = false, ch;
while ((ch = stream.next()) != null) {
if (maybeEnd && ch == "/") {
state.tokenize = null;
break;
}
maybeEnd = (ch == "*");
}
return ["comment", "comment"];
}
CodeMirror.defineMIME("text/css", {
documentTypes: documentTypes,
mediaTypes: mediaTypes,
mediaFeatures: mediaFeatures,
mediaValueKeywords: mediaValueKeywords,
propertyKeywords: propertyKeywords,
nonStandardPropertyKeywords: nonStandardPropertyKeywords,
fontProperties: fontProperties,
counterDescriptors: counterDescriptors,
colorKeywords: colorKeywords,
valueKeywords: valueKeywords,
tokenHooks: {
"/": function(stream, state) {
if (!stream.eat("*")) return false;
state.tokenize = tokenCComment;
return tokenCComment(stream, state);
}
},
name: "css"
});
CodeMirror.defineMIME("text/x-scss", {
mediaTypes: mediaTypes,
mediaFeatures: mediaFeatures,
mediaValueKeywords: mediaValueKeywords,
propertyKeywords: propertyKeywords,
nonStandardPropertyKeywords: nonStandardPropertyKeywords,
colorKeywords: colorKeywords,
valueKeywords: valueKeywords,
fontProperties: fontProperties,
allowNested: true,
lineComment: "//",
tokenHooks: {
"/": function(stream, state) {
if (stream.eat("/")) {
stream.skipToEnd();
return ["comment", "comment"];
} else if (stream.eat("*")) {
state.tokenize = tokenCComment;
return tokenCComment(stream, state);
} else {
return ["operator", "operator"];
}
},
":": function(stream) {
if (stream.match(/\s*\{/, false))
return [null, null]
return false;
},
"$": function(stream) {
stream.match(/^[\w-]+/);
if (stream.match(/^\s*:/, false))
return ["variable-2", "variable-definition"];
return ["variable-2", "variable"];
},
"#": function(stream) {
if (!stream.eat("{")) return false;
return [null, "interpolation"];
}
},
name: "css",
helperType: "scss"
});
CodeMirror.defineMIME("text/x-less", {
mediaTypes: mediaTypes,
mediaFeatures: mediaFeatures,
mediaValueKeywords: mediaValueKeywords,
propertyKeywords: propertyKeywords,
nonStandardPropertyKeywords: nonStandardPropertyKeywords,
colorKeywords: colorKeywords,
valueKeywords: valueKeywords,
fontProperties: fontProperties,
allowNested: true,
lineComment: "//",
tokenHooks: {
"/": function(stream, state) {
if (stream.eat("/")) {
stream.skipToEnd();
return ["comment", "comment"];
} else if (stream.eat("*")) {
state.tokenize = tokenCComment;
return tokenCComment(stream, state);
} else {
return ["operator", "operator"];
}
},
"@": function(stream) {
if (stream.eat("{")) return [null, "interpolation"];
if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/i, false)) return false;
stream.eatWhile(/[\w\\\-]/);
if (stream.match(/^\s*:/, false))
return ["variable-2", "variable-definition"];
return ["variable-2", "variable"];
},
"&": function() {
return ["atom", "atom"];
}
},
name: "css",
helperType: "less"
});
CodeMirror.defineMIME("text/x-gss", {
documentTypes: documentTypes,
mediaTypes: mediaTypes,
mediaFeatures: mediaFeatures,
propertyKeywords: propertyKeywords,
nonStandardPropertyKeywords: nonStandardPropertyKeywords,
fontProperties: fontProperties,
counterDescriptors: counterDescriptors,
colorKeywords: colorKeywords,
valueKeywords: valueKeywords,
supportsAtComponent: true,
tokenHooks: {
"/": function(stream, state) {
if (!stream.eat("*")) return false;
state.tokenize = tokenCComment;
return tokenCComment(stream, state);
}
},
name: "css",
helperType: "gss"
});
});

Some files were not shown because too many files have changed in this diff Show More