From e22ba227a694b8426e69dbce640c5b0e4f39f574 Mon Sep 17 00:00:00 2001 From: Sam Stephenson Date: Wed, 7 Feb 2018 12:43:36 -0600 Subject: Initial commit --- .gitattributes | 2 + .gitignore | 2 + Gemfile | 8 +++ Gemfile.lock | 135 +++++++++++++++++++++++++++++++++++++ LICENSE | 21 ++++++ README.md | 1 + activetext.gemspec | 20 ++++++ app/javascript/activetext/index.js | 1 + app/models/active_text/document.rb | 4 ++ lib/active_text.rb | 5 ++ lib/active_text/engine.rb | 7 ++ package.json | 20 ++++++ test/test_helper.rb | 4 ++ yarn.lock | 7 ++ 14 files changed, 237 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 Gemfile create mode 100644 Gemfile.lock create mode 100644 LICENSE create mode 100644 README.md create mode 100644 activetext.gemspec create mode 100644 app/javascript/activetext/index.js create mode 100644 app/models/active_text/document.rb create mode 100644 lib/active_text.rb create mode 100644 lib/active_text/engine.rb create mode 100644 package.json create mode 100644 test/test_helper.rb create mode 100644 yarn.lock diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..dfe0770424 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..4d64059f69 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/node_modules + diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000000..7a50773bb3 --- /dev/null +++ b/Gemfile @@ -0,0 +1,8 @@ +source "https://rubygems.org" + +git_source(:github) { |repo_path| "https://github.com/#{repo_path}.git" } + +gemspec + +gem "rails", github: "rails/rails" +gem "rake" diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000000..d6f040c0e8 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,135 @@ +GIT + remote: https://github.com/rails/rails.git + revision: c5d431e469505ec4438f9fd37530dd9c79c8a872 + specs: + actioncable (6.0.0.alpha) + actionpack (= 6.0.0.alpha) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailer (6.0.0.alpha) + actionpack (= 6.0.0.alpha) + actionview (= 6.0.0.alpha) + activejob (= 6.0.0.alpha) + mail (~> 2.5, >= 2.5.4) + rails-dom-testing (~> 2.0) + actionpack (6.0.0.alpha) + actionview (= 6.0.0.alpha) + activesupport (= 6.0.0.alpha) + rack (~> 2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.0.2) + actionview (6.0.0.alpha) + activesupport (= 6.0.0.alpha) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.0.3) + activejob (6.0.0.alpha) + activesupport (= 6.0.0.alpha) + globalid (>= 0.3.6) + activemodel (6.0.0.alpha) + activesupport (= 6.0.0.alpha) + activerecord (6.0.0.alpha) + activemodel (= 6.0.0.alpha) + activesupport (= 6.0.0.alpha) + arel (>= 9.0) + activestorage (6.0.0.alpha) + actionpack (= 6.0.0.alpha) + activerecord (= 6.0.0.alpha) + marcel (~> 0.3.1) + activesupport (6.0.0.alpha) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (~> 0.7) + minitest (~> 5.1) + tzinfo (~> 1.1) + rails (6.0.0.alpha) + actioncable (= 6.0.0.alpha) + actionmailer (= 6.0.0.alpha) + actionpack (= 6.0.0.alpha) + actionview (= 6.0.0.alpha) + activejob (= 6.0.0.alpha) + activemodel (= 6.0.0.alpha) + activerecord (= 6.0.0.alpha) + activestorage (= 6.0.0.alpha) + activesupport (= 6.0.0.alpha) + bundler (>= 1.3.0) + railties (= 6.0.0.alpha) + sprockets-rails (>= 2.0.0) + railties (6.0.0.alpha) + actionpack (= 6.0.0.alpha) + activesupport (= 6.0.0.alpha) + method_source + rake (>= 0.8.7) + thor (>= 0.18.1, < 2.0) + +PATH + remote: . + specs: + activetext (0.1) + activerecord (>= 5.2.0) + activestorage (>= 5.2.0) + rails (>= 5.2.0) + +GEM + remote: https://rubygems.org/ + specs: + arel (9.0.0) + builder (3.2.3) + concurrent-ruby (1.0.5) + crass (1.0.3) + erubi (1.7.0) + globalid (0.4.1) + activesupport (>= 4.2.0) + i18n (0.9.3) + concurrent-ruby (~> 1.0) + loofah (2.1.1) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.0) + mini_mime (>= 0.1.1) + marcel (0.3.1) + mimemagic (~> 0.3.2) + method_source (0.9.0) + mimemagic (0.3.2) + mini_mime (1.0.0) + mini_portile2 (2.3.0) + minitest (5.11.3) + nio4r (2.2.0) + nokogiri (1.8.2) + mini_portile2 (~> 2.3.0) + rack (2.0.4) + rack-test (0.8.2) + rack (>= 1.0, < 3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.0.3) + loofah (~> 2.0) + rake (12.3.0) + sprockets (3.7.1) + concurrent-ruby (~> 1.0) + rack (> 1, < 3) + sprockets-rails (3.2.1) + actionpack (>= 4.0) + activesupport (>= 4.0) + sprockets (>= 3.0.0) + thor (0.20.0) + thread_safe (0.3.6) + tzinfo (1.2.5) + thread_safe (~> 0.1) + websocket-driver (0.7.0) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.3) + +PLATFORMS + ruby + +DEPENDENCIES + activetext! + bundler (~> 1.15) + rails! + rake + +BUNDLED WITH + 1.16.1 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..4a5fe6361d --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Basecamp, LLC + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000000..07e2238c34 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# activetext diff --git a/activetext.gemspec b/activetext.gemspec new file mode 100644 index 0000000000..9f5e611f2f --- /dev/null +++ b/activetext.gemspec @@ -0,0 +1,20 @@ +Gem::Specification.new do |s| + s.name = "activetext" + s.version = "0.1" + s.authors = ["Javan Makhmali", "Sam Stephenson"] + s.email = ["javan@javan.us", "sstephenson@gmail.com"] + s.summary = "Edit and display rich text in Rails applications" + s.homepage = "https://github.com/basecamp/activetext" + s.license = "MIT" + + s.required_ruby_version = ">= 2.2.2" + + s.add_dependency "rails", ">= 5.2.0" + s.add_dependency "activerecord", ">= 5.2.0" + s.add_dependency "activestorage", ">= 5.2.0" + + s.add_development_dependency "bundler", "~> 1.15" + + s.files = `git ls-files`.split("\n") + s.test_files = `git ls-files -- test/*`.split("\n") +end diff --git a/app/javascript/activetext/index.js b/app/javascript/activetext/index.js new file mode 100644 index 0000000000..c77ed0ab26 --- /dev/null +++ b/app/javascript/activetext/index.js @@ -0,0 +1 @@ +import * as Trix from "trix" diff --git a/app/models/active_text/document.rb b/app/models/active_text/document.rb new file mode 100644 index 0000000000..74b1ddc746 --- /dev/null +++ b/app/models/active_text/document.rb @@ -0,0 +1,4 @@ +module ActiveText + class Document < ActiveRecord::Base + end +end diff --git a/lib/active_text.rb b/lib/active_text.rb new file mode 100644 index 0000000000..e6384020f1 --- /dev/null +++ b/lib/active_text.rb @@ -0,0 +1,5 @@ +require "active_record" +require "active_text/engine" + +module ActiveText +end diff --git a/lib/active_text/engine.rb b/lib/active_text/engine.rb new file mode 100644 index 0000000000..28383672f4 --- /dev/null +++ b/lib/active_text/engine.rb @@ -0,0 +1,7 @@ +require "rails/engine" + +module ActiveText + class Engine < Rails::Engine + config.eager_load_namespaces << ActiveText + end +end diff --git a/package.json b/package.json new file mode 100644 index 0000000000..7f0c79a054 --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "name": "activetext", + "version": "0.1", + "description": "Edit and display rich text in Rails applications", + "main": "app/javascript/activetext/index.js", + "files": [ + "app/javascript/activetext/*.js" + ], + "repository": "https://github.com/basecamp/activetext", + "author": "Basecamp, LLC", + "contributors": [ + "Javan Makhmali ", + "Sam Stephenson " + ], + "license": "MIT", + "dependencies": { + "trix": "^0.11.1" + }, + "private": true +} diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000000..7ea27bb507 --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,4 @@ +require "bundler/setup" +require "active_support" +require "active_support/test_case" +require "active_support/testing/autorun" diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000000..fbaef41eaa --- /dev/null +++ b/yarn.lock @@ -0,0 +1,7 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +trix@^0.11.1: + version "0.11.1" + resolved "https://registry.yarnpkg.com/trix/-/trix-0.11.1.tgz#ffe54f2757c2c2385b8424fd5c5d2ab712a09acc" -- cgit v1.2.3 From 68d350ddacedf604717f0d1074d7624fa57757c2 Mon Sep 17 00:00:00 2001 From: Sam Stephenson Date: Wed, 7 Feb 2018 18:26:19 -0600 Subject: Initial import from BC3 RichText --- Gemfile.lock | 1 + activetext.gemspec | 1 + lib/active_text.rb | 27 ++++++ lib/active_text/attachable.rb | 24 +++++ lib/active_text/attachables/content_attachment.rb | 36 ++++++++ lib/active_text/attachables/missing_attachable.rb | 11 +++ lib/active_text/attachables/remote_image.rb | 44 ++++++++++ lib/active_text/attachment.rb | 101 ++++++++++++++++++++++ lib/active_text/attachments/caching.rb | 14 +++ lib/active_text/attachments/minification.rb | 15 ++++ lib/active_text/attachments/trix_conversion.rb | 32 +++++++ lib/active_text/content.rb | 80 +++++++++++++++++ lib/active_text/fragment.rb | 55 ++++++++++++ lib/active_text/html_conversion.rb | 22 +++++ lib/active_text/plain_text_conversion.rb | 79 +++++++++++++++++ lib/active_text/serialization.rb | 32 +++++++ lib/active_text/trix_attachment.rb | 89 +++++++++++++++++++ 17 files changed, 663 insertions(+) create mode 100644 lib/active_text/attachable.rb create mode 100644 lib/active_text/attachables/content_attachment.rb create mode 100644 lib/active_text/attachables/missing_attachable.rb create mode 100644 lib/active_text/attachables/remote_image.rb create mode 100644 lib/active_text/attachment.rb create mode 100644 lib/active_text/attachments/caching.rb create mode 100644 lib/active_text/attachments/minification.rb create mode 100644 lib/active_text/attachments/trix_conversion.rb create mode 100644 lib/active_text/content.rb create mode 100644 lib/active_text/fragment.rb create mode 100644 lib/active_text/html_conversion.rb create mode 100644 lib/active_text/plain_text_conversion.rb create mode 100644 lib/active_text/serialization.rb create mode 100644 lib/active_text/trix_attachment.rb diff --git a/Gemfile.lock b/Gemfile.lock index d6f040c0e8..ce010a91c0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -69,6 +69,7 @@ PATH activetext (0.1) activerecord (>= 5.2.0) activestorage (>= 5.2.0) + nokogiri rails (>= 5.2.0) GEM diff --git a/activetext.gemspec b/activetext.gemspec index 9f5e611f2f..1a43fdb688 100644 --- a/activetext.gemspec +++ b/activetext.gemspec @@ -12,6 +12,7 @@ Gem::Specification.new do |s| s.add_dependency "rails", ">= 5.2.0" s.add_dependency "activerecord", ">= 5.2.0" s.add_dependency "activestorage", ">= 5.2.0" + s.add_dependency "nokogiri" s.add_development_dependency "bundler", "~> 1.15" diff --git a/lib/active_text.rb b/lib/active_text.rb index e6384020f1..e9dfaeefe4 100644 --- a/lib/active_text.rb +++ b/lib/active_text.rb @@ -1,5 +1,32 @@ require "active_record" require "active_text/engine" +require "nokogiri" module ActiveText + extend ActiveSupport::Autoload + + autoload :Attachable + autoload :Attachment + autoload :Content + autoload :Fragment + autoload :HtmlConversion + autoload :PlainTextConversion + autoload :Serialization + autoload :TrixAttachment + + module Attachables + extend ActiveSupport::Autoload + + autoload :ContentAttachment + autoload :MissingAttachable + autoload :RemoteImage + end + + module Attachments + extend ActiveSupport::Autoload + + autoload :Caching + autoload :Minification + autoload :TrixConversion + end end diff --git a/lib/active_text/attachable.rb b/lib/active_text/attachable.rb new file mode 100644 index 0000000000..445ee30605 --- /dev/null +++ b/lib/active_text/attachable.rb @@ -0,0 +1,24 @@ +module ActiveText + module Attachable + class << self + def from_node(node) + if attachable = attachable_from_sgid(node["sgid"]) + attachable + elsif attachable = ActiveText::Attachables::ContentAttachment.from_node(node) + attachable + elsif attachable = ActiveText::Attachables::RemoteImage.from_node(node) + attachable + else + ActiveText::Attachables::MissingAttachable + end + end + + private + def attachable_from_sgid(sgid) + ::Attachable.from_attachable_sgid(sgid) + rescue ActiveRecord::RecordNotFound + nil + end + end + end +end diff --git a/lib/active_text/attachables/content_attachment.rb b/lib/active_text/attachables/content_attachment.rb new file mode 100644 index 0000000000..316d7e304a --- /dev/null +++ b/lib/active_text/attachables/content_attachment.rb @@ -0,0 +1,36 @@ +module ActiveText + module Attachables + class ContentAttachment + include ActiveModel::Model + + def self.from_node(node) + if node["content-type"] + if matches = node["content-type"].match(/vnd\.rubyonrails\.(.+)\.html/) + attachment = new(name: matches[1]) + attachment if attachment.valid? + end + end + end + + attr_accessor :name + validates_inclusion_of :name, in: %w( horizontal-rule ) + + def attachable_plain_text_representation(caption) + case name + when "horizontal-rule" + " ┄ " + else + " " + end + end + + def to_partial_path + "active_text/attachables/content_attachment" + end + + def to_trix_content_attachment_partial_path + "active_text/attachables/content_attachments/#{name.underscore}" + end + end + end +end diff --git a/lib/active_text/attachables/missing_attachable.rb b/lib/active_text/attachables/missing_attachable.rb new file mode 100644 index 0000000000..94a095ce09 --- /dev/null +++ b/lib/active_text/attachables/missing_attachable.rb @@ -0,0 +1,11 @@ +module ActiveText + module Attachables + module MissingAttachable + extend ActiveModel::Naming + + def self.to_partial_path + "active_text/attachables/missing_attachable" + end + end + end +end diff --git a/lib/active_text/attachables/remote_image.rb b/lib/active_text/attachables/remote_image.rb new file mode 100644 index 0000000000..0624b5564d --- /dev/null +++ b/lib/active_text/attachables/remote_image.rb @@ -0,0 +1,44 @@ +module ActiveText + module Attachables + class RemoteImage + extend ActiveModel::Naming + + class << self + def from_node(node) + if node["url"] && content_type_is_image?(node["content-type"]) + new(attributes_from_node(node)) + end + end + + private + def content_type_is_image?(content_type) + content_type.to_s =~ /^image(\/.+|$)/ + end + + def attributes_from_node(node) + { url: node["url"], + content_type: node["content-type"], + width: node["width"], + height: node["height"] } + end + end + + attr_reader :url, :content_type, :width, :height + + def initialize(attributes = {}) + @url = attributes[:url] + @content_type = attributes[:content_type] + @width = attributes[:width] + @height = attributes[:height] + end + + def attachable_plain_text_representation(caption) + "[#{caption || "Image"}]" + end + + def to_partial_path + "active_text/attachables/remote_image" + end + end + end +end diff --git a/lib/active_text/attachment.rb b/lib/active_text/attachment.rb new file mode 100644 index 0000000000..870390f63e --- /dev/null +++ b/lib/active_text/attachment.rb @@ -0,0 +1,101 @@ +module ActiveText + class Attachment + include Attachments::TrixConversion, Attachments::Minification, Attachments::Caching + + TAG_NAME = "active-text-attachment" + SELECTOR = TAG_NAME + ATTRIBUTES = %w( sgid content-type url href filename filesize width height previewable caption ) + + class << self + def fragment_by_canonicalizing_attachments(content) + fragment_by_minifying_attachments(fragment_by_converting_trix_attachments(content)) + end + + def from_node(node, attachable = nil) + new(node, attachable || ActiveText::Attachable.from_node(node)) + end + + def from_attachables(attachables) + Array(attachables).map { |attachable| from_attachable(attachable) }.compact + end + + def from_attachable(attachable, attributes = {}) + if node = node_from_attributes(attachable.to_active_text_attributes(attributes)) + new(node, attachable) + end + end + + def from_attributes(attributes, attachable = nil) + if node = node_from_attributes(attributes) + from_node(node, attachable) + end + end + + private + def node_from_attributes(attributes) + if attributes = process_attributes(attributes).presence + ActiveText::HtmlConversion.create_element(TAG_NAME, attributes) + end + end + + def process_attributes(attributes) + attributes.transform_keys { |key| key.to_s.underscore.dasherize }.slice(*ATTRIBUTES) + end + end + + attr_reader :node, :attachable + + delegate :to_param, to: :attachable + delegate_missing_to :attachable + + def initialize(node, attachable) + @node = node + @attachable = attachable + end + + def caption + node_attributes["caption"].presence + end + + def full_attributes + node_attributes.merge(attachable_attributes).merge(sgid_attributes) + end + + def with_full_attributes + self.class.from_attributes(full_attributes, attachable) + end + + def to_plain_text + if respond_to?(:attachable_plain_text_representation) + attachable_plain_text_representation(caption) + else + caption.to_s + end + end + + def to_html + HtmlConversion.node_to_html(node) + end + + def to_s + to_html + end + + def inspect + "#<#{self.class.name} attachable=#{attachable.inspect}>" + end + + private + def node_attributes + @node_attributes ||= ATTRIBUTES.map { |name| [ name.underscore, node[name] ] }.to_h.compact + end + + def attachable_attributes + @attachable_attributes ||= (attachable.try(:to_active_text_attributes) || {}).stringify_keys + end + + def sgid_attributes + @sgid_attributes ||= node_attributes.slice("sgid").presence || attachable_attributes.slice("sgid") + end + end +end diff --git a/lib/active_text/attachments/caching.rb b/lib/active_text/attachments/caching.rb new file mode 100644 index 0000000000..b0194170e1 --- /dev/null +++ b/lib/active_text/attachments/caching.rb @@ -0,0 +1,14 @@ +module ActiveText + module Attachments + module Caching + def cache_key(*args) + [self.class.name, cache_digest, *attachable.cache_key(*args)].join("/") + end + + private + def cache_digest + Digest::SHA256.hexdigest(node.to_s) + end + end + end +end diff --git a/lib/active_text/attachments/minification.rb b/lib/active_text/attachments/minification.rb new file mode 100644 index 0000000000..b33822862f --- /dev/null +++ b/lib/active_text/attachments/minification.rb @@ -0,0 +1,15 @@ +module ActiveText + module Attachments + module Minification + extend ActiveSupport::Concern + + class_methods do + def fragment_by_minifying_attachments(content) + Fragment.wrap(content).replace(ActiveText::Attachment::SELECTOR) do |node| + node.tap { |node| node.inner_html = "" } + end + end + end + end + end +end diff --git a/lib/active_text/attachments/trix_conversion.rb b/lib/active_text/attachments/trix_conversion.rb new file mode 100644 index 0000000000..25eada6709 --- /dev/null +++ b/lib/active_text/attachments/trix_conversion.rb @@ -0,0 +1,32 @@ +module ActiveText + module Attachments + module TrixConversion + extend ActiveSupport::Concern + + class_methods do + def fragment_by_converting_trix_attachments(content) + Fragment.wrap(content).replace(TrixAttachment::SELECTOR) do |node| + from_trix_attachment(TrixAttachment.new(node)) + end + end + + def from_trix_attachment(trix_attachment) + from_attributes(trix_attachment.attributes) + end + end + + def to_trix_attachment(content = trix_attachment_content) + attributes = full_attributes.dup + attributes["content"] = content if content + TrixAttachment.from_attributes(attributes) + end + + private + def trix_attachment_content + if partial_path = attachable.try(:to_trix_content_attachment_partial_path) + ApplicationRenderer.render(partial: partial_path, object: self, as: model_name.element) + end + end + end + end +end diff --git a/lib/active_text/content.rb b/lib/active_text/content.rb new file mode 100644 index 0000000000..0154cea17e --- /dev/null +++ b/lib/active_text/content.rb @@ -0,0 +1,80 @@ +module ActiveText + class Content + include Serialization + + attr_reader :fragment + + delegate :blank?, :empty?, :present?, to: :to_s + + def initialize(content = nil) + @fragment = ActiveText::Attachment.fragment_by_canonicalizing_attachments(content) + end + + def links + @links ||= fragment.find_all("a[href]").map { |a| a["href"] }.uniq + end + + def attachments + @attachments ||= attachment_nodes.map do |node| + attachment_for_node(node) + end + end + + def attachables + @attachables ||= attachment_nodes.map do |node| + ActiveText::Attachable.from_node(node) + end + end + + def append_attachables(attachables) + attachments = ActiveText::Attachment.from_attachables(attachables) + self.class.new([self.to_s.presence, *attachments].compact.join("\n")) + end + + def render_attachments(**options, &block) + fragment.replace(ActiveText::Attachment::SELECTOR) do |node| + block.call(attachment_for_node(node, **options)) + end + end + + def to_plain_text + render_attachments(with_full_attributes: false, &:to_plain_text).to_plain_text + end + + def to_trix_html + render_attachments(&:to_trix_attachment).to_html + end + + def to_html + fragment.to_html + end + + def to_s + to_html + end + + def as_json(*) + to_html + end + + def inspect + "#<#{self.class.name} #{to_s.truncate(25).inspect}>" + end + + def ==(other) + if other.is_a?(self.class) + to_s == other.to_s + end + end + + private + def attachment_nodes + @attachment_nodes ||= fragment.find_all(ActiveText::Attachment::SELECTOR) + end + + def attachment_for_node(node, with_full_attributes: true) + attachment = ActiveText::Attachment.from_node(node) + with_full_attributes ? attachment.with_full_attributes : attachment + end + end +end diff --git a/lib/active_text/fragment.rb b/lib/active_text/fragment.rb new file mode 100644 index 0000000000..9e0af6f57a --- /dev/null +++ b/lib/active_text/fragment.rb @@ -0,0 +1,55 @@ +module ActiveText + class Fragment + class << self + def wrap(fragment_or_html) + case fragment_or_html + when self + fragment_or_html + when Nokogiri::HTML::DocumentFragment + new(fragment_or_html) + else + from_html(fragment_or_html) + end + end + + def from_html(html) + new(ActiveText::HtmlConversion.fragment_for_html(html.to_s.strip)) + end + end + + attr_reader :source + + def initialize(source) + @source = source + end + + def find_all(selector) + source.css(selector) + end + + def update + yield source = self.source.clone + self.class.new(source) + end + + def replace(selector) + update do |source| + source.css(selector).each do |node| + node.replace(yield(node).to_s) + end + end + end + + def to_plain_text + @plain_text ||= PlainTextConversion.node_to_plain_text(source) + end + + def to_html + @html ||= HtmlConversion.node_to_html(source) + end + + def to_s + to_html + end + end +end diff --git a/lib/active_text/html_conversion.rb b/lib/active_text/html_conversion.rb new file mode 100644 index 0000000000..7c35e5cf94 --- /dev/null +++ b/lib/active_text/html_conversion.rb @@ -0,0 +1,22 @@ +module ActiveText + module HtmlConversion + extend self + + def node_to_html(node) + node.to_html(save_with: Nokogiri::XML::Node::SaveOptions::AS_HTML) + end + + def fragment_for_html(html) + document.fragment(html) + end + + def create_element(tag_name, attributes = {}) + document.create_element(tag_name, attributes) + end + + private + def document + Nokogiri::HTML::Document.new.tap { |doc| doc.encoding = "UTF-8" } + end + end +end diff --git a/lib/active_text/plain_text_conversion.rb b/lib/active_text/plain_text_conversion.rb new file mode 100644 index 0000000000..3e5f3b8654 --- /dev/null +++ b/lib/active_text/plain_text_conversion.rb @@ -0,0 +1,79 @@ +module ActiveText + module PlainTextConversion + extend self + + def node_to_plain_text(node) + remove_trailing_newlines(plain_text_for_node(node)) + end + + private + def plain_text_for_node(node, index = 0) + if respond_to?(plain_text_method_for_node(node), true) + send(plain_text_method_for_node(node), node, index) + else + plain_text_for_node_children(node) + end + end + + def plain_text_for_node_children(node) + node.children.each_with_index.map do |node, index| + plain_text_for_node(node, index) + end.compact.join("") + end + + def plain_text_method_for_node(node) + :"plain_text_for_#{node.name}_node" + end + + def plain_text_for_block(node, index = 0) + "#{remove_trailing_newlines(plain_text_for_node_children(node))}\n\n" + end + + %i[ p ul ol ].each do |element| + alias_method :"plain_text_for_#{element}_node", :plain_text_for_block + end + + def plain_text_for_br_node(node, index) + "\n" + end + + def plain_text_for_text_node(node, index) + remove_trailing_newlines(node.text) + end + + def plain_text_for_div_node(node, index) + "#{remove_trailing_newlines(plain_text_for_node_children(node))}\n" + end + + def plain_text_for_figcaption_node(node, index) + "[#{remove_trailing_newlines(plain_text_for_node_children(node))}]" + end + + def plain_text_for_blockquote_node(node, index) + text = plain_text_for_block(node) + text.sub(/\A(\s*)(.+?)(\s*)\Z/m, '\1“\2”\3') + end + + def plain_text_for_li_node(node, index) + bullet = bullet_for_li_node(node, index) + text = remove_trailing_newlines(plain_text_for_node_children(node)) + "#{bullet} #{text}\n" + end + + def remove_trailing_newlines(text) + text.chomp("") + end + + def bullet_for_li_node(node, index) + if list_node_name_for_li_node(node) == "ol" + "#{index + 1}." + else + "•" + end + end + + def list_node_name_for_li_node(node) + node.ancestors.lazy.map(&:name).grep(/^[uo]l$/).first + end + end +end diff --git a/lib/active_text/serialization.rb b/lib/active_text/serialization.rb new file mode 100644 index 0000000000..46ebeba1aa --- /dev/null +++ b/lib/active_text/serialization.rb @@ -0,0 +1,32 @@ +module ActiveText + module Serialization + extend ActiveSupport::Concern + + class_methods do + def load(content) + new(content) if content + end + + def dump(content) + case content + when nil + nil + when self + content.to_html + else + new(content).to_html + end + end + end + + # Marshal compatibility + + class_methods do + alias_method :_load, :load + end + + def _dump(*) + self.class.dump(self) + end + end +end diff --git a/lib/active_text/trix_attachment.rb b/lib/active_text/trix_attachment.rb new file mode 100644 index 0000000000..19add53414 --- /dev/null +++ b/lib/active_text/trix_attachment.rb @@ -0,0 +1,89 @@ +module ActiveText + class TrixAttachment + TAG_NAME = "figure" + SELECTOR = "[data-trix-attachment]" + + ATTRIBUTES = %w( sgid contentType url href filename filesize width height previewable content caption ) + ATTRIBUTE_TYPES = { + "previewable" => ->(value) { value.to_s == "true" }, + "filesize" => ->(value) { Integer(value.to_s) rescue value }, + "width" => ->(value) { Integer(value.to_s) rescue nil }, + "height" => ->(value) { Integer(value.to_s) rescue nil }, + :default => ->(value) { value.to_s } + } + + class << self + def from_attributes(attributes) + attributes = process_attributes(attributes) + + trix_attachment_attributes = attributes.except("caption") + trix_attributes = attributes.slice("caption") + + node = ActiveText::HtmlConversion.create_element(TAG_NAME) + node["data-trix-attachment"] = JSON.generate(trix_attachment_attributes) + node["data-trix-attributes"] = JSON.generate(trix_attributes) if trix_attributes.any? + + new(node) + end + + private + def process_attributes(attributes) + typecast_attribute_values(transform_attribute_keys(attributes)) + end + + def transform_attribute_keys(attributes) + attributes.transform_keys { |key| key.to_s.underscore.camelize(:lower) } + end + + def typecast_attribute_values(attributes) + attributes.map do |key, value| + typecast = ATTRIBUTE_TYPES[key] || ATTRIBUTE_TYPES[:default] + [key, typecast.call(value)] + end.to_h + end + end + + attr_reader :node + + def initialize(node) + @node = node + end + + def attributes + @attributes ||= attachment_attributes.merge(composed_attributes).slice(*ATTRIBUTES) + end + + def to_html + ActiveText::HtmlConversion.node_to_html(node) + end + + def to_s + to_html + end + + private + def attachment_attributes + read_json_object_attribute("data-trix-attachment") + end + + def composed_attributes + read_json_object_attribute("data-trix-attributes") + end + + def read_json_object_attribute(name) + read_json_attribute(name) || {} + end + + def read_json_attribute(name) + if value = node[name] + begin + JSON.parse(value) + rescue => e + Rails.logger.error "[#{self.class.name}] Couldn't parse JSON #{value} from NODE #{node.inspect}" + Rails.logger.error "[#{self.class.name}] Failed with #{e.class}: #{e.backtrace}" + nil + end + end + end + end +end -- cgit v1.2.3 From 38e1f12d79ec3313e42643e52f2d10cb5fbd5d5d Mon Sep 17 00:00:00 2001 From: Sam Stephenson Date: Thu, 8 Feb 2018 11:01:46 -0600 Subject: Add dummy app --- Gemfile | 4 - Gemfile.lock | 111 ++++++++++----------- Rakefile | 27 +++++ activetext.gemspec | 13 ++- bin/test | 5 + lib/active_text/attachments/minification.rb | 2 +- lib/active_text/engine.rb | 1 + lib/active_text/plain_text_conversion.rb | 4 +- lib/active_text/version.rb | 3 + test/dummy/.ruby-version | 1 + test/dummy/Rakefile | 6 ++ test/dummy/app/assets/config/manifest.js | 3 + test/dummy/app/assets/images/.keep | 0 test/dummy/app/assets/javascripts/application.js | 14 +++ test/dummy/app/assets/javascripts/cable.js | 13 +++ test/dummy/app/assets/javascripts/channels/.keep | 0 test/dummy/app/assets/stylesheets/application.css | 15 +++ .../app/channels/application_cable/channel.rb | 4 + .../app/channels/application_cable/connection.rb | 4 + .../app/controllers/application_controller.rb | 2 + test/dummy/app/controllers/concerns/.keep | 0 test/dummy/app/helpers/application_helper.rb | 2 + test/dummy/app/jobs/application_job.rb | 2 + test/dummy/app/mailers/application_mailer.rb | 4 + test/dummy/app/models/application_record.rb | 3 + test/dummy/app/models/concerns/.keep | 0 test/dummy/app/views/layouts/application.html.erb | 14 +++ test/dummy/app/views/layouts/mailer.html.erb | 13 +++ test/dummy/app/views/layouts/mailer.text.erb | 1 + test/dummy/bin/bundle | 3 + test/dummy/bin/rails | 4 + test/dummy/bin/rake | 4 + test/dummy/bin/setup | 36 +++++++ test/dummy/bin/update | 31 ++++++ test/dummy/bin/yarn | 11 ++ test/dummy/config.ru | 5 + test/dummy/config/application.rb | 19 ++++ test/dummy/config/boot.rb | 5 + test/dummy/config/cable.yml | 10 ++ test/dummy/config/database.yml | 25 +++++ test/dummy/config/environment.rb | 5 + test/dummy/config/environments/development.rb | 61 +++++++++++ test/dummy/config/environments/production.rb | 94 +++++++++++++++++ test/dummy/config/environments/test.rb | 46 +++++++++ .../application_controller_renderer.rb | 8 ++ test/dummy/config/initializers/assets.rb | 14 +++ .../config/initializers/backtrace_silencers.rb | 7 ++ .../config/initializers/content_security_policy.rb | 22 ++++ .../config/initializers/cookies_serializer.rb | 5 + .../initializers/filter_parameter_logging.rb | 4 + test/dummy/config/initializers/inflections.rb | 16 +++ test/dummy/config/initializers/mime_types.rb | 4 + test/dummy/config/initializers/wrap_parameters.rb | 14 +++ test/dummy/config/locales/en.yml | 33 ++++++ test/dummy/config/puma.rb | 34 +++++++ test/dummy/config/routes.rb | 3 + test/dummy/config/spring.rb | 6 ++ test/dummy/config/storage.yml | 35 +++++++ test/dummy/db/test.sqlite3 | 0 test/dummy/lib/assets/.keep | 0 test/dummy/log/.keep | 0 test/dummy/log/test.log | 20 ++++ test/dummy/package.json | 5 + test/dummy/public/404.html | 67 +++++++++++++ test/dummy/public/422.html | 67 +++++++++++++ test/dummy/public/500.html | 66 ++++++++++++ test/dummy/public/apple-touch-icon-precomposed.png | 0 test/dummy/public/apple-touch-icon.png | 0 test/dummy/public/favicon.ico | 0 test/dummy/storage/.keep | 0 test/dummy/tmp/.keep | 0 test/dummy/tmp/storage/.keep | 0 test/test_helper.rb | 25 ++++- test/unit/content_test.rb | 10 ++ 74 files changed, 1021 insertions(+), 74 deletions(-) create mode 100644 Rakefile create mode 100755 bin/test create mode 100644 lib/active_text/version.rb create mode 100644 test/dummy/.ruby-version create mode 100644 test/dummy/Rakefile create mode 100644 test/dummy/app/assets/config/manifest.js create mode 100644 test/dummy/app/assets/images/.keep create mode 100644 test/dummy/app/assets/javascripts/application.js create mode 100644 test/dummy/app/assets/javascripts/cable.js create mode 100644 test/dummy/app/assets/javascripts/channels/.keep create mode 100644 test/dummy/app/assets/stylesheets/application.css create mode 100644 test/dummy/app/channels/application_cable/channel.rb create mode 100644 test/dummy/app/channels/application_cable/connection.rb create mode 100644 test/dummy/app/controllers/application_controller.rb create mode 100644 test/dummy/app/controllers/concerns/.keep create mode 100644 test/dummy/app/helpers/application_helper.rb create mode 100644 test/dummy/app/jobs/application_job.rb create mode 100644 test/dummy/app/mailers/application_mailer.rb create mode 100644 test/dummy/app/models/application_record.rb create mode 100644 test/dummy/app/models/concerns/.keep create mode 100644 test/dummy/app/views/layouts/application.html.erb create mode 100644 test/dummy/app/views/layouts/mailer.html.erb create mode 100644 test/dummy/app/views/layouts/mailer.text.erb create mode 100755 test/dummy/bin/bundle create mode 100755 test/dummy/bin/rails create mode 100755 test/dummy/bin/rake create mode 100755 test/dummy/bin/setup create mode 100755 test/dummy/bin/update create mode 100755 test/dummy/bin/yarn create mode 100644 test/dummy/config.ru create mode 100644 test/dummy/config/application.rb create mode 100644 test/dummy/config/boot.rb create mode 100644 test/dummy/config/cable.yml create mode 100644 test/dummy/config/database.yml create mode 100644 test/dummy/config/environment.rb create mode 100644 test/dummy/config/environments/development.rb create mode 100644 test/dummy/config/environments/production.rb create mode 100644 test/dummy/config/environments/test.rb create mode 100644 test/dummy/config/initializers/application_controller_renderer.rb create mode 100644 test/dummy/config/initializers/assets.rb create mode 100644 test/dummy/config/initializers/backtrace_silencers.rb create mode 100644 test/dummy/config/initializers/content_security_policy.rb create mode 100644 test/dummy/config/initializers/cookies_serializer.rb create mode 100644 test/dummy/config/initializers/filter_parameter_logging.rb create mode 100644 test/dummy/config/initializers/inflections.rb create mode 100644 test/dummy/config/initializers/mime_types.rb create mode 100644 test/dummy/config/initializers/wrap_parameters.rb create mode 100644 test/dummy/config/locales/en.yml create mode 100644 test/dummy/config/puma.rb create mode 100644 test/dummy/config/routes.rb create mode 100644 test/dummy/config/spring.rb create mode 100644 test/dummy/config/storage.yml create mode 100644 test/dummy/db/test.sqlite3 create mode 100644 test/dummy/lib/assets/.keep create mode 100644 test/dummy/log/.keep create mode 100644 test/dummy/log/test.log create mode 100644 test/dummy/package.json create mode 100644 test/dummy/public/404.html create mode 100644 test/dummy/public/422.html create mode 100644 test/dummy/public/500.html create mode 100644 test/dummy/public/apple-touch-icon-precomposed.png create mode 100644 test/dummy/public/apple-touch-icon.png create mode 100644 test/dummy/public/favicon.ico create mode 100644 test/dummy/storage/.keep create mode 100644 test/dummy/tmp/.keep create mode 100644 test/dummy/tmp/storage/.keep create mode 100644 test/unit/content_test.rb diff --git a/Gemfile b/Gemfile index 7a50773bb3..9b78acc762 100644 --- a/Gemfile +++ b/Gemfile @@ -1,8 +1,4 @@ source "https://rubygems.org" - git_source(:github) { |repo_path| "https://github.com/#{repo_path}.git" } gemspec - -gem "rails", github: "rails/rails" -gem "rake" diff --git a/Gemfile.lock b/Gemfile.lock index ce010a91c0..e6db9609d9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,80 +1,54 @@ -GIT - remote: https://github.com/rails/rails.git - revision: c5d431e469505ec4438f9fd37530dd9c79c8a872 +PATH + remote: . + specs: + activetext (0.1.0) + nokogiri + rails (>= 5.2.0.rc1) + +GEM + remote: https://rubygems.org/ specs: - actioncable (6.0.0.alpha) - actionpack (= 6.0.0.alpha) + actioncable (5.2.0.rc1) + actionpack (= 5.2.0.rc1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailer (6.0.0.alpha) - actionpack (= 6.0.0.alpha) - actionview (= 6.0.0.alpha) - activejob (= 6.0.0.alpha) + actionmailer (5.2.0.rc1) + actionpack (= 5.2.0.rc1) + actionview (= 5.2.0.rc1) + activejob (= 5.2.0.rc1) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.0.0.alpha) - actionview (= 6.0.0.alpha) - activesupport (= 6.0.0.alpha) + actionpack (5.2.0.rc1) + actionview (= 5.2.0.rc1) + activesupport (= 5.2.0.rc1) rack (~> 2.0) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (6.0.0.alpha) - activesupport (= 6.0.0.alpha) + actionview (5.2.0.rc1) + activesupport (= 5.2.0.rc1) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (6.0.0.alpha) - activesupport (= 6.0.0.alpha) + activejob (5.2.0.rc1) + activesupport (= 5.2.0.rc1) globalid (>= 0.3.6) - activemodel (6.0.0.alpha) - activesupport (= 6.0.0.alpha) - activerecord (6.0.0.alpha) - activemodel (= 6.0.0.alpha) - activesupport (= 6.0.0.alpha) + activemodel (5.2.0.rc1) + activesupport (= 5.2.0.rc1) + activerecord (5.2.0.rc1) + activemodel (= 5.2.0.rc1) + activesupport (= 5.2.0.rc1) arel (>= 9.0) - activestorage (6.0.0.alpha) - actionpack (= 6.0.0.alpha) - activerecord (= 6.0.0.alpha) + activestorage (5.2.0.rc1) + actionpack (= 5.2.0.rc1) + activerecord (= 5.2.0.rc1) marcel (~> 0.3.1) - activesupport (6.0.0.alpha) + activesupport (5.2.0.rc1) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (~> 0.7) minitest (~> 5.1) tzinfo (~> 1.1) - rails (6.0.0.alpha) - actioncable (= 6.0.0.alpha) - actionmailer (= 6.0.0.alpha) - actionpack (= 6.0.0.alpha) - actionview (= 6.0.0.alpha) - activejob (= 6.0.0.alpha) - activemodel (= 6.0.0.alpha) - activerecord (= 6.0.0.alpha) - activestorage (= 6.0.0.alpha) - activesupport (= 6.0.0.alpha) - bundler (>= 1.3.0) - railties (= 6.0.0.alpha) - sprockets-rails (>= 2.0.0) - railties (6.0.0.alpha) - actionpack (= 6.0.0.alpha) - activesupport (= 6.0.0.alpha) - method_source - rake (>= 0.8.7) - thor (>= 0.18.1, < 2.0) - -PATH - remote: . - specs: - activetext (0.1) - activerecord (>= 5.2.0) - activestorage (>= 5.2.0) - nokogiri - rails (>= 5.2.0) - -GEM - remote: https://rubygems.org/ - specs: arel (9.0.0) builder (3.2.3) concurrent-ruby (1.0.5) @@ -102,11 +76,30 @@ GEM rack (2.0.4) rack-test (0.8.2) rack (>= 1.0, < 3) + rails (5.2.0.rc1) + actioncable (= 5.2.0.rc1) + actionmailer (= 5.2.0.rc1) + actionpack (= 5.2.0.rc1) + actionview (= 5.2.0.rc1) + activejob (= 5.2.0.rc1) + activemodel (= 5.2.0.rc1) + activerecord (= 5.2.0.rc1) + activestorage (= 5.2.0.rc1) + activesupport (= 5.2.0.rc1) + bundler (>= 1.3.0) + railties (= 5.2.0.rc1) + sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) rails-html-sanitizer (1.0.3) loofah (~> 2.0) + railties (5.2.0.rc1) + actionpack (= 5.2.0.rc1) + activesupport (= 5.2.0.rc1) + method_source + rake (>= 0.8.7) + thor (>= 0.18.1, < 2.0) rake (12.3.0) sprockets (3.7.1) concurrent-ruby (~> 1.0) @@ -115,6 +108,7 @@ GEM actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) + sqlite3 (1.3.13) thor (0.20.0) thread_safe (0.3.6) tzinfo (1.2.5) @@ -129,8 +123,7 @@ PLATFORMS DEPENDENCIES activetext! bundler (~> 1.15) - rails! - rake + sqlite3 BUNDLED WITH 1.16.1 diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000000..f6c2a1304c --- /dev/null +++ b/Rakefile @@ -0,0 +1,27 @@ +begin + require 'bundler/setup' +rescue LoadError + puts 'You must `gem install bundler` and `bundle install` to run rake tasks' +end + +require 'rdoc/task' + +RDoc::Task.new(:rdoc) do |rdoc| + rdoc.rdoc_dir = 'rdoc' + rdoc.title = 'Active Text' + rdoc.options << '--line-numbers' + rdoc.rdoc_files.include('README.md') + rdoc.rdoc_files.include('lib/**/*.rb') +end + +require 'bundler/gem_tasks' + +require 'rake/testtask' + +Rake::TestTask.new(:test) do |t| + t.libs << 'test' + t.pattern = 'test/**/*_test.rb' + t.verbose = false +end + +task default: :test diff --git a/activetext.gemspec b/activetext.gemspec index 1a43fdb688..511fd76bd1 100644 --- a/activetext.gemspec +++ b/activetext.gemspec @@ -1,6 +1,12 @@ +$:.push File.expand_path("lib", __dir__) + +# Maintain your gem's version: +require "active_text/version" + +# Describe your gem and declare its dependencies: Gem::Specification.new do |s| s.name = "activetext" - s.version = "0.1" + s.version = ActiveText::VERSION s.authors = ["Javan Makhmali", "Sam Stephenson"] s.email = ["javan@javan.us", "sstephenson@gmail.com"] s.summary = "Edit and display rich text in Rails applications" @@ -9,12 +15,11 @@ Gem::Specification.new do |s| s.required_ruby_version = ">= 2.2.2" - s.add_dependency "rails", ">= 5.2.0" - s.add_dependency "activerecord", ">= 5.2.0" - s.add_dependency "activestorage", ">= 5.2.0" + s.add_dependency "rails", ">= 5.2.0.rc1" s.add_dependency "nokogiri" s.add_development_dependency "bundler", "~> 1.15" + s.add_development_dependency "sqlite3" s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- test/*`.split("\n") diff --git a/bin/test b/bin/test new file mode 100755 index 0000000000..5516a12bcd --- /dev/null +++ b/bin/test @@ -0,0 +1,5 @@ +#!/usr/bin/env ruby +$: << File.expand_path("../test", __dir__) + +require "bundler/setup" +require "rails/plugin/test" diff --git a/lib/active_text/attachments/minification.rb b/lib/active_text/attachments/minification.rb index b33822862f..aa25875aae 100644 --- a/lib/active_text/attachments/minification.rb +++ b/lib/active_text/attachments/minification.rb @@ -6,7 +6,7 @@ module ActiveText class_methods do def fragment_by_minifying_attachments(content) Fragment.wrap(content).replace(ActiveText::Attachment::SELECTOR) do |node| - node.tap { |node| node.inner_html = "" } + node.tap { |n| n.inner_html = "" } end end end diff --git a/lib/active_text/engine.rb b/lib/active_text/engine.rb index 28383672f4..d9dfff6122 100644 --- a/lib/active_text/engine.rb +++ b/lib/active_text/engine.rb @@ -2,6 +2,7 @@ require "rails/engine" module ActiveText class Engine < Rails::Engine + isolate_namespace ActiveText config.eager_load_namespaces << ActiveText end end diff --git a/lib/active_text/plain_text_conversion.rb b/lib/active_text/plain_text_conversion.rb index 3e5f3b8654..ecd598e192 100644 --- a/lib/active_text/plain_text_conversion.rb +++ b/lib/active_text/plain_text_conversion.rb @@ -16,8 +16,8 @@ module ActiveText end def plain_text_for_node_children(node) - node.children.each_with_index.map do |node, index| - plain_text_for_node(node, index) + node.children.each_with_index.map do |child, index| + plain_text_for_node(child, index) end.compact.join("") end diff --git a/lib/active_text/version.rb b/lib/active_text/version.rb new file mode 100644 index 0000000000..29b47f7eab --- /dev/null +++ b/lib/active_text/version.rb @@ -0,0 +1,3 @@ +module ActiveText + VERSION = '0.1.0' +end diff --git a/test/dummy/.ruby-version b/test/dummy/.ruby-version new file mode 100644 index 0000000000..58073ef8d7 --- /dev/null +++ b/test/dummy/.ruby-version @@ -0,0 +1 @@ +2.4.1 \ No newline at end of file diff --git a/test/dummy/Rakefile b/test/dummy/Rakefile new file mode 100644 index 0000000000..e85f913914 --- /dev/null +++ b/test/dummy/Rakefile @@ -0,0 +1,6 @@ +# Add your own tasks in files placed in lib/tasks ending in .rake, +# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. + +require_relative 'config/application' + +Rails.application.load_tasks diff --git a/test/dummy/app/assets/config/manifest.js b/test/dummy/app/assets/config/manifest.js new file mode 100644 index 0000000000..b16e53d6d5 --- /dev/null +++ b/test/dummy/app/assets/config/manifest.js @@ -0,0 +1,3 @@ +//= link_tree ../images +//= link_directory ../javascripts .js +//= link_directory ../stylesheets .css diff --git a/test/dummy/app/assets/images/.keep b/test/dummy/app/assets/images/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/dummy/app/assets/javascripts/application.js b/test/dummy/app/assets/javascripts/application.js new file mode 100644 index 0000000000..e914de7396 --- /dev/null +++ b/test/dummy/app/assets/javascripts/application.js @@ -0,0 +1,14 @@ +// This is a manifest file that'll be compiled into application.js, which will include all the files +// listed below. +// +// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, +// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. +// +// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the +// compiled file. JavaScript code in this file should be added after the last require_* statement. +// +// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details +// about supported directives. +// +//= require activestorage +//= require_tree . diff --git a/test/dummy/app/assets/javascripts/cable.js b/test/dummy/app/assets/javascripts/cable.js new file mode 100644 index 0000000000..739aa5f022 --- /dev/null +++ b/test/dummy/app/assets/javascripts/cable.js @@ -0,0 +1,13 @@ +// Action Cable provides the framework to deal with WebSockets in Rails. +// You can generate new channels where WebSocket features live using the `rails generate channel` command. +// +//= require action_cable +//= require_self +//= require_tree ./channels + +(function() { + this.App || (this.App = {}); + + App.cable = ActionCable.createConsumer(); + +}).call(this); diff --git a/test/dummy/app/assets/javascripts/channels/.keep b/test/dummy/app/assets/javascripts/channels/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/dummy/app/assets/stylesheets/application.css b/test/dummy/app/assets/stylesheets/application.css new file mode 100644 index 0000000000..0ebd7fe829 --- /dev/null +++ b/test/dummy/app/assets/stylesheets/application.css @@ -0,0 +1,15 @@ +/* + * This is a manifest file that'll be compiled into application.css, which will include all the files + * listed below. + * + * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, + * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. + * + * You're free to add application-wide styles to this file and they'll appear at the bottom of the + * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS + * files in this directory. Styles in this file should be added after the last require_* statement. + * It is generally better to create a new file per style scope. + * + *= require_tree . + *= require_self + */ diff --git a/test/dummy/app/channels/application_cable/channel.rb b/test/dummy/app/channels/application_cable/channel.rb new file mode 100644 index 0000000000..d672697283 --- /dev/null +++ b/test/dummy/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/test/dummy/app/channels/application_cable/connection.rb b/test/dummy/app/channels/application_cable/connection.rb new file mode 100644 index 0000000000..0ff5442f47 --- /dev/null +++ b/test/dummy/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/test/dummy/app/controllers/application_controller.rb b/test/dummy/app/controllers/application_controller.rb new file mode 100644 index 0000000000..09705d12ab --- /dev/null +++ b/test/dummy/app/controllers/application_controller.rb @@ -0,0 +1,2 @@ +class ApplicationController < ActionController::Base +end diff --git a/test/dummy/app/controllers/concerns/.keep b/test/dummy/app/controllers/concerns/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/dummy/app/helpers/application_helper.rb b/test/dummy/app/helpers/application_helper.rb new file mode 100644 index 0000000000..de6be7945c --- /dev/null +++ b/test/dummy/app/helpers/application_helper.rb @@ -0,0 +1,2 @@ +module ApplicationHelper +end diff --git a/test/dummy/app/jobs/application_job.rb b/test/dummy/app/jobs/application_job.rb new file mode 100644 index 0000000000..a009ace51c --- /dev/null +++ b/test/dummy/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/test/dummy/app/mailers/application_mailer.rb b/test/dummy/app/mailers/application_mailer.rb new file mode 100644 index 0000000000..286b2239d1 --- /dev/null +++ b/test/dummy/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: 'from@example.com' + layout 'mailer' +end diff --git a/test/dummy/app/models/application_record.rb b/test/dummy/app/models/application_record.rb new file mode 100644 index 0000000000..10a4cba84d --- /dev/null +++ b/test/dummy/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + self.abstract_class = true +end diff --git a/test/dummy/app/models/concerns/.keep b/test/dummy/app/models/concerns/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/dummy/app/views/layouts/application.html.erb b/test/dummy/app/views/layouts/application.html.erb new file mode 100644 index 0000000000..a6eb0174b7 --- /dev/null +++ b/test/dummy/app/views/layouts/application.html.erb @@ -0,0 +1,14 @@ + + + + Dummy + <%= csrf_meta_tags %> + + <%= stylesheet_link_tag 'application', media: 'all' %> + <%= javascript_include_tag 'application' %> + + + + <%= yield %> + + diff --git a/test/dummy/app/views/layouts/mailer.html.erb b/test/dummy/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000000..cbd34d2e9d --- /dev/null +++ b/test/dummy/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/test/dummy/app/views/layouts/mailer.text.erb b/test/dummy/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000000..37f0bddbd7 --- /dev/null +++ b/test/dummy/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/test/dummy/bin/bundle b/test/dummy/bin/bundle new file mode 100755 index 0000000000..f19acf5b5c --- /dev/null +++ b/test/dummy/bin/bundle @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) +load Gem.bin_path('bundler', 'bundle') diff --git a/test/dummy/bin/rails b/test/dummy/bin/rails new file mode 100755 index 0000000000..0739660237 --- /dev/null +++ b/test/dummy/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path('../config/application', __dir__) +require_relative '../config/boot' +require 'rails/commands' diff --git a/test/dummy/bin/rake b/test/dummy/bin/rake new file mode 100755 index 0000000000..17240489f6 --- /dev/null +++ b/test/dummy/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative '../config/boot' +require 'rake' +Rake.application.run diff --git a/test/dummy/bin/setup b/test/dummy/bin/setup new file mode 100755 index 0000000000..94fd4d7977 --- /dev/null +++ b/test/dummy/bin/setup @@ -0,0 +1,36 @@ +#!/usr/bin/env ruby +require 'fileutils' +include FileUtils + +# path to your application root. +APP_ROOT = File.expand_path('..', __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +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') + + # Install JavaScript dependencies if using Yarn + # system('bin/yarn') + + # puts "\n== Copying sample files ==" + # unless File.exist?('config/database.yml') + # cp 'config/database.yml.sample', 'config/database.yml' + # end + + puts "\n== Preparing database ==" + system! 'bin/rails db:setup' + + puts "\n== Removing old logs and tempfiles ==" + system! 'bin/rails log:clear tmp:clear' + + puts "\n== Restarting application server ==" + system! 'bin/rails restart' +end diff --git a/test/dummy/bin/update b/test/dummy/bin/update new file mode 100755 index 0000000000..58bfaed518 --- /dev/null +++ b/test/dummy/bin/update @@ -0,0 +1,31 @@ +#!/usr/bin/env ruby +require 'fileutils' +include FileUtils + +# path to your application root. +APP_ROOT = File.expand_path('..', __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +chdir APP_ROOT do + # This script is a way to update your development environment automatically. + # Add necessary update steps to this file. + + 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== Updating database ==" + system! 'bin/rails db:migrate' + + puts "\n== Removing old logs and tempfiles ==" + system! 'bin/rails log:clear tmp:clear' + + puts "\n== Restarting application server ==" + system! 'bin/rails restart' +end diff --git a/test/dummy/bin/yarn b/test/dummy/bin/yarn new file mode 100755 index 0000000000..460dd565b4 --- /dev/null +++ b/test/dummy/bin/yarn @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby +APP_ROOT = File.expand_path('..', __dir__) +Dir.chdir(APP_ROOT) do + 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 + end +end diff --git a/test/dummy/config.ru b/test/dummy/config.ru new file mode 100644 index 0000000000..f7ba0b527b --- /dev/null +++ b/test/dummy/config.ru @@ -0,0 +1,5 @@ +# This file is used by Rack-based servers to start the application. + +require_relative 'config/environment' + +run Rails.application diff --git a/test/dummy/config/application.rb b/test/dummy/config/application.rb new file mode 100644 index 0000000000..7f41fce8d0 --- /dev/null +++ b/test/dummy/config/application.rb @@ -0,0 +1,19 @@ +require_relative 'boot' + +require 'rails/all' + +Bundler.require(*Rails.groups) +require "active_text" + +module Dummy + class Application < Rails::Application + # Initialize configuration defaults for originally generated Rails version. + config.load_defaults 5.2 + + # 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. + end +end + diff --git a/test/dummy/config/boot.rb b/test/dummy/config/boot.rb new file mode 100644 index 0000000000..c9aef85d40 --- /dev/null +++ b/test/dummy/config/boot.rb @@ -0,0 +1,5 @@ +# Set up gems listed in the Gemfile. +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__) + +require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) +$LOAD_PATH.unshift File.expand_path('../../../lib', __dir__) diff --git a/test/dummy/config/cable.yml b/test/dummy/config/cable.yml new file mode 100644 index 0000000000..1cd0f8363e --- /dev/null +++ b/test/dummy/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: async + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: dummy_production diff --git a/test/dummy/config/database.yml b/test/dummy/config/database.yml new file mode 100644 index 0000000000..0d02f24980 --- /dev/null +++ b/test/dummy/config/database.yml @@ -0,0 +1,25 @@ +# SQLite version 3.x +# gem install sqlite3 +# +# Ensure the SQLite 3 gem is defined in your Gemfile +# gem 'sqlite3' +# +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/test/dummy/config/environment.rb b/test/dummy/config/environment.rb new file mode 100644 index 0000000000..426333bb46 --- /dev/null +++ b/test/dummy/config/environment.rb @@ -0,0 +1,5 @@ +# Load the Rails application. +require_relative 'application' + +# Initialize the Rails application. +Rails.application.initialize! diff --git a/test/dummy/config/environments/development.rb b/test/dummy/config/environments/development.rb new file mode 100644 index 0000000000..366e75ad77 --- /dev/null +++ b/test/dummy/config/environments/development.rb @@ -0,0 +1,61 @@ +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 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 + + # Do not eager load code on boot. + config.eager_load = false + + # Show full error reports. + config.consider_all_requests_local = 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? + config.action_controller.perform_caching = true + + config.cache_store = :memory_store + config.public_file_server.headers = { + 'Cache-Control' => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + + # 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. + config.action_mailer.raise_delivery_errors = false + + config.action_mailer.perform_caching = false + + # Print deprecation notices to the Rails logger. + config.active_support.deprecation = :log + + # 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.action_view.raise_on_missing_translations = 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 diff --git a/test/dummy/config/environments/production.rb b/test/dummy/config/environments/production.rb new file mode 100644 index 0000000000..9ea5ad2784 --- /dev/null +++ b/test/dummy/config/environments/production.rb @@ -0,0 +1,94 @@ +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + config.action_controller.perform_caching = true + + # 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 = 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? + + # 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.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 + + # 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 + # 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.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # 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 ] + + # 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) + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "dummy_#{Rails.env}" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = 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') + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/test/dummy/config/environments/test.rb b/test/dummy/config/environments/test.rb new file mode 100644 index 0000000000..0a38fd3ce9 --- /dev/null +++ b/test/dummy/config/environments/test.rb @@ -0,0 +1,46 @@ +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # 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 + + # 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}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # 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 + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raises error for missing translations + # config.action_view.raise_on_missing_translations = true +end diff --git a/test/dummy/config/initializers/application_controller_renderer.rb b/test/dummy/config/initializers/application_controller_renderer.rb new file mode 100644 index 0000000000..89d2efab2b --- /dev/null +++ b/test/dummy/config/initializers/application_controller_renderer.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# ActiveSupport::Reloader.to_prepare do +# ApplicationController.renderer.defaults.merge!( +# http_host: 'example.org', +# https: false +# ) +# end diff --git a/test/dummy/config/initializers/assets.rb b/test/dummy/config/initializers/assets.rb new file mode 100644 index 0000000000..4b828e80cb --- /dev/null +++ b/test/dummy/config/initializers/assets.rb @@ -0,0 +1,14 @@ +# 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' + +# 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 +# folder are already added. +# Rails.application.config.assets.precompile += %w( admin.js admin.css ) diff --git a/test/dummy/config/initializers/backtrace_silencers.rb b/test/dummy/config/initializers/backtrace_silencers.rb new file mode 100644 index 0000000000..59385cdf37 --- /dev/null +++ b/test/dummy/config/initializers/backtrace_silencers.rb @@ -0,0 +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| 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. +# Rails.backtrace_cleaner.remove_silencers! diff --git a/test/dummy/config/initializers/content_security_policy.rb b/test/dummy/config/initializers/content_security_policy.rb new file mode 100644 index 0000000000..edde7f42b8 --- /dev/null +++ b/test/dummy/config/initializers/content_security_policy.rb @@ -0,0 +1,22 @@ +# Be sure to restart your server when you modify this file. + +# Define an application-wide content security policy +# For further information see the following documentation +# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy + +# 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, :unsafe_inline + +# # Specify URI for violation reports +# # policy.report_uri "/csp-violation-report-endpoint" +# end + +# 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 diff --git a/test/dummy/config/initializers/cookies_serializer.rb b/test/dummy/config/initializers/cookies_serializer.rb new file mode 100644 index 0000000000..5a6a32d371 --- /dev/null +++ b/test/dummy/config/initializers/cookies_serializer.rb @@ -0,0 +1,5 @@ +# Be sure to restart your server when you modify this file. + +# Specify a serializer for the signed and encrypted cookie jars. +# Valid options are :json, :marshal, and :hybrid. +Rails.application.config.action_dispatch.cookies_serializer = :json diff --git a/test/dummy/config/initializers/filter_parameter_logging.rb b/test/dummy/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000000..4a994e1e7b --- /dev/null +++ b/test/dummy/config/initializers/filter_parameter_logging.rb @@ -0,0 +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 += [:password] diff --git a/test/dummy/config/initializers/inflections.rb b/test/dummy/config/initializers/inflections.rb new file mode 100644 index 0000000000..ac033bf9dc --- /dev/null +++ b/test/dummy/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# 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.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym 'RESTful' +# end diff --git a/test/dummy/config/initializers/mime_types.rb b/test/dummy/config/initializers/mime_types.rb new file mode 100644 index 0000000000..dc1899682b --- /dev/null +++ b/test/dummy/config/initializers/mime_types.rb @@ -0,0 +1,4 @@ +# Be sure to restart your server when you modify this file. + +# Add new mime types for use in respond_to blocks: +# Mime::Type.register "text/richtext", :rtf diff --git a/test/dummy/config/initializers/wrap_parameters.rb b/test/dummy/config/initializers/wrap_parameters.rb new file mode 100644 index 0000000000..bbfc3961bf --- /dev/null +++ b/test/dummy/config/initializers/wrap_parameters.rb @@ -0,0 +1,14 @@ +# Be sure to restart your server when you modify this file. + +# This file contains settings for ActionController::ParamsWrapper which +# is enabled by default. + +# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. +ActiveSupport.on_load(:action_controller) do + wrap_parameters format: [:json] +end + +# To enable root element in JSON for ActiveRecord objects. +# ActiveSupport.on_load(:active_record) do +# self.include_root_in_json = true +# end diff --git a/test/dummy/config/locales/en.yml b/test/dummy/config/locales/en.yml new file mode 100644 index 0000000000..decc5a8573 --- /dev/null +++ b/test/dummy/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t 'hello' +# +# In views, this is aliased to just `t`: +# +# <%= t('hello') %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# 'true': 'foo' +# +# To learn more, please read the Rails Internationalization guide +# available at http://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/test/dummy/config/puma.rb b/test/dummy/config/puma.rb new file mode 100644 index 0000000000..a5eccf816b --- /dev/null +++ b/test/dummy/config/puma.rb @@ -0,0 +1,34 @@ +# Puma can serve each request in a thread from an internal thread pool. +# The `threads` method setting takes two numbers: a minimum and maximum. +# Any libraries that use thread pools should be configured to match +# the maximum value specified for Puma. Default is set to 5 threads for minimum +# and maximum; this matches the default thread size of Active Record. +# +threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +threads threads_count, threads_count + +# Specifies the `port` that Puma will listen on to receive requests; default is 3000. +# +port ENV.fetch("PORT") { 3000 } + +# Specifies the `environment` that Puma will run in. +# +environment ENV.fetch("RAILS_ENV") { "development" } + +# Specifies the number of `workers` to boot in clustered mode. +# Workers are forked webserver processes. If using threads and workers together +# the concurrency of the application would be max `threads` * `workers`. +# Workers do not work on JRuby or Windows (both of which do not support +# processes). +# +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } + +# Use the `preload_app!` method when specifying a `workers` number. +# This directive tells Puma to first boot the application and load code +# before forking the application. This takes advantage of Copy On Write +# process behavior so workers use less memory. +# +# preload_app! + +# Allow puma to be restarted by `rails restart` command. +plugin :tmp_restart diff --git a/test/dummy/config/routes.rb b/test/dummy/config/routes.rb new file mode 100644 index 0000000000..787824f888 --- /dev/null +++ b/test/dummy/config/routes.rb @@ -0,0 +1,3 @@ +Rails.application.routes.draw do + # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html +end diff --git a/test/dummy/config/spring.rb b/test/dummy/config/spring.rb new file mode 100644 index 0000000000..9fa7863f99 --- /dev/null +++ b/test/dummy/config/spring.rb @@ -0,0 +1,6 @@ +%w[ + .ruby-version + .rbenv-vars + tmp/restart.txt + tmp/caching-dev.txt +].each { |path| Spring.watch(path) } diff --git a/test/dummy/config/storage.yml b/test/dummy/config/storage.yml new file mode 100644 index 0000000000..53e562e0fc --- /dev/null +++ b/test/dummy/config/storage.yml @@ -0,0 +1,35 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket + +# Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# path: your_azure_storage_path +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/test/dummy/db/test.sqlite3 b/test/dummy/db/test.sqlite3 new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/dummy/lib/assets/.keep b/test/dummy/lib/assets/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/dummy/log/.keep b/test/dummy/log/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/dummy/log/test.log b/test/dummy/log/test.log new file mode 100644 index 0000000000..fdb06fb70a --- /dev/null +++ b/test/dummy/log/test.log @@ -0,0 +1,20 @@ +  (0.1ms) begin transaction +----------------------------------- +ActiveText::ContentTest: test_truth +----------------------------------- +  (0.0ms) rollback transaction +  (0.1ms) begin transaction +--------------------------------------------------- +ActiveText::ContentTest: test_plain_text_conversion +--------------------------------------------------- +  (0.0ms) rollback transaction +  (0.1ms) begin transaction +--------------------------------------------------- +ActiveText::ContentTest: test_plain_text_conversion +--------------------------------------------------- +  (0.1ms) rollback transaction +  (0.1ms) begin transaction +--------------------------------------------------- +ActiveText::ContentTest: test_plain_text_conversion +--------------------------------------------------- +  (0.0ms) rollback transaction diff --git a/test/dummy/package.json b/test/dummy/package.json new file mode 100644 index 0000000000..caa2d7bb3f --- /dev/null +++ b/test/dummy/package.json @@ -0,0 +1,5 @@ +{ + "name": "dummy", + "private": true, + "dependencies": {} +} diff --git a/test/dummy/public/404.html b/test/dummy/public/404.html new file mode 100644 index 0000000000..2be3af26fc --- /dev/null +++ b/test/dummy/public/404.html @@ -0,0 +1,67 @@ + + + + The page you were looking for doesn't exist (404) + + + + + + +
+
+

The page you were looking for doesn't exist.

+

You may have mistyped the address or the page may have moved.

+
+

If you are the application owner check the logs for more information.

+
+ + diff --git a/test/dummy/public/422.html b/test/dummy/public/422.html new file mode 100644 index 0000000000..c08eac0d1d --- /dev/null +++ b/test/dummy/public/422.html @@ -0,0 +1,67 @@ + + + + The change you wanted was rejected (422) + + + + + + +
+
+

The change you wanted was rejected.

+

Maybe you tried to change something you didn't have access to.

+
+

If you are the application owner check the logs for more information.

+
+ + diff --git a/test/dummy/public/500.html b/test/dummy/public/500.html new file mode 100644 index 0000000000..78a030af22 --- /dev/null +++ b/test/dummy/public/500.html @@ -0,0 +1,66 @@ + + + + We're sorry, but something went wrong (500) + + + + + + +
+
+

We're sorry, but something went wrong.

+
+

If you are the application owner check the logs for more information.

+
+ + diff --git a/test/dummy/public/apple-touch-icon-precomposed.png b/test/dummy/public/apple-touch-icon-precomposed.png new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/dummy/public/apple-touch-icon.png b/test/dummy/public/apple-touch-icon.png new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/dummy/public/favicon.ico b/test/dummy/public/favicon.ico new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/dummy/storage/.keep b/test/dummy/storage/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/dummy/tmp/.keep b/test/dummy/tmp/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/dummy/tmp/storage/.keep b/test/dummy/tmp/storage/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/test_helper.rb b/test/test_helper.rb index 7ea27bb507..94fec6b8be 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,4 +1,21 @@ -require "bundler/setup" -require "active_support" -require "active_support/test_case" -require "active_support/testing/autorun" +# Configure Rails Environment +ENV["RAILS_ENV"] = "test" + +require_relative "../test/dummy/config/environment" +ActiveRecord::Migrator.migrations_paths = [File.expand_path("../test/dummy/db/migrate", __dir__)] +require "rails/test_help" + +# Filter out Minitest backtrace while allowing backtrace from other libraries +# to be shown. +Minitest.backtrace_filter = Minitest::BacktraceFilter.new + +require "rails/test_unit/reporter" +Rails::TestUnitReporter.executable = 'bin/test' + +# Load fixtures from the engine +if ActiveSupport::TestCase.respond_to?(:fixture_path=) + ActiveSupport::TestCase.fixture_path = File.expand_path("fixtures", __dir__) + ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path + ActiveSupport::TestCase.file_fixture_path = ActiveSupport::TestCase.fixture_path + "/files" + ActiveSupport::TestCase.fixtures :all +end diff --git a/test/unit/content_test.rb b/test/unit/content_test.rb new file mode 100644 index 0000000000..48ba731597 --- /dev/null +++ b/test/unit/content_test.rb @@ -0,0 +1,10 @@ +require_relative '../test_helper' + +module ActiveText + class ContentTest < ActiveSupport::TestCase + test "plain text conversion" do + content = ActiveText::Content.new("

Hello world

") + assert "Hello world", content.to_plain_text + end + end +end -- cgit v1.2.3 From 5012d645daa65ef776d27eb973b3278302c36cad Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Thu, 8 Feb 2018 15:48:45 -0500 Subject: Add initial ActiveRecord extension: `active_text_attribute` --- lib/active_text.rb | 1 + lib/active_text/attribute.rb | 11 +++++++++++ lib/active_text/engine.rb | 6 ++++++ 3 files changed, 18 insertions(+) create mode 100644 lib/active_text/attribute.rb diff --git a/lib/active_text.rb b/lib/active_text.rb index e9dfaeefe4..1981abc4c6 100644 --- a/lib/active_text.rb +++ b/lib/active_text.rb @@ -7,6 +7,7 @@ module ActiveText autoload :Attachable autoload :Attachment + autoload :Attribute autoload :Content autoload :Fragment autoload :HtmlConversion diff --git a/lib/active_text/attribute.rb b/lib/active_text/attribute.rb new file mode 100644 index 0000000000..577adde83a --- /dev/null +++ b/lib/active_text/attribute.rb @@ -0,0 +1,11 @@ +module ActiveText + module Attribute + extend ActiveSupport::Concern + + class_methods do + def active_text_attribute(attribute_name) + serialize(attribute_name, ActiveText::Content) + end + end + end +end diff --git a/lib/active_text/engine.rb b/lib/active_text/engine.rb index d9dfff6122..3f076ab321 100644 --- a/lib/active_text/engine.rb +++ b/lib/active_text/engine.rb @@ -4,5 +4,11 @@ module ActiveText class Engine < Rails::Engine isolate_namespace ActiveText config.eager_load_namespaces << ActiveText + + initializer "active_text.attribute" do + ActiveSupport.on_load(:active_record) do + include ActiveText::Attribute + end + end end end -- cgit v1.2.3 From d8fd858c9cba69c04e6934f438d045dad2717e90 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Thu, 8 Feb 2018 16:02:16 -0500 Subject: Tests: Add Message scaffolding --- .gitignore | 13 +++- .ruby-version | 1 + test/dummy/.ruby-version | 1 - test/dummy/app/assets/javascripts/messages.js | 2 + test/dummy/app/assets/stylesheets/messages.css | 4 ++ test/dummy/app/assets/stylesheets/scaffold.css | 80 ++++++++++++++++++++++ test/dummy/app/controllers/messages_controller.rb | 58 ++++++++++++++++ test/dummy/app/helpers/messages_helper.rb | 2 + test/dummy/app/models/message.rb | 3 + test/dummy/app/views/messages/_form.html.erb | 27 ++++++++ test/dummy/app/views/messages/edit.html.erb | 6 ++ test/dummy/app/views/messages/index.html.erb | 29 ++++++++ test/dummy/app/views/messages/new.html.erb | 5 ++ test/dummy/app/views/messages/show.html.erb | 14 ++++ test/dummy/config/routes.rb | 1 + .../db/migrate/20180208205311_create_messages.rb | 10 +++ test/dummy/db/schema.rb | 22 ++++++ test/dummy/db/test.sqlite3 | 0 test/dummy/log/test.log | 20 ------ test/unit/content_test.rb | 4 +- 20 files changed, 277 insertions(+), 25 deletions(-) create mode 100644 .ruby-version delete mode 100644 test/dummy/.ruby-version create mode 100644 test/dummy/app/assets/javascripts/messages.js create mode 100644 test/dummy/app/assets/stylesheets/messages.css create mode 100644 test/dummy/app/assets/stylesheets/scaffold.css create mode 100644 test/dummy/app/controllers/messages_controller.rb create mode 100644 test/dummy/app/helpers/messages_helper.rb create mode 100644 test/dummy/app/models/message.rb create mode 100644 test/dummy/app/views/messages/_form.html.erb create mode 100644 test/dummy/app/views/messages/edit.html.erb create mode 100644 test/dummy/app/views/messages/index.html.erb create mode 100644 test/dummy/app/views/messages/new.html.erb create mode 100644 test/dummy/app/views/messages/show.html.erb create mode 100644 test/dummy/db/migrate/20180208205311_create_messages.rb create mode 100644 test/dummy/db/schema.rb delete mode 100644 test/dummy/db/test.sqlite3 delete mode 100644 test/dummy/log/test.log diff --git a/.gitignore b/.gitignore index 4d64059f69..0aec2551f0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,11 @@ -/node_modules - +.bundle/ +log/*.log +node_modules/ +pkg/ +test/dummy/db/*.sqlite3 +test/dummy/db/*.sqlite3-journal +test/dummy/log/*.log +test/dummy/node_modules/ +test/dummy/yarn-error.log +test/dummy/storage/ +test/dummy/tmp/ diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000000..437459cd94 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +2.5.0 diff --git a/test/dummy/.ruby-version b/test/dummy/.ruby-version deleted file mode 100644 index 58073ef8d7..0000000000 --- a/test/dummy/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -2.4.1 \ No newline at end of file diff --git a/test/dummy/app/assets/javascripts/messages.js b/test/dummy/app/assets/javascripts/messages.js new file mode 100644 index 0000000000..dee720facd --- /dev/null +++ b/test/dummy/app/assets/javascripts/messages.js @@ -0,0 +1,2 @@ +// Place all the behaviors and hooks related to the matching controller here. +// All this logic will automatically be available in application.js. diff --git a/test/dummy/app/assets/stylesheets/messages.css b/test/dummy/app/assets/stylesheets/messages.css new file mode 100644 index 0000000000..afad32db02 --- /dev/null +++ b/test/dummy/app/assets/stylesheets/messages.css @@ -0,0 +1,4 @@ +/* + Place all the styles related to the matching controller here. + They will automatically be included in application.css. +*/ diff --git a/test/dummy/app/assets/stylesheets/scaffold.css b/test/dummy/app/assets/stylesheets/scaffold.css new file mode 100644 index 0000000000..cd4f3de38d --- /dev/null +++ b/test/dummy/app/assets/stylesheets/scaffold.css @@ -0,0 +1,80 @@ +body { + background-color: #fff; + color: #333; + margin: 33px; +} + +body, p, ol, ul, td { + font-family: verdana, arial, helvetica, sans-serif; + font-size: 13px; + line-height: 18px; +} + +pre { + background-color: #eee; + padding: 10px; + font-size: 11px; +} + +a { + color: #000; +} + +a:visited { + color: #666; +} + +a:hover { + color: #fff; + background-color: #000; +} + +th { + padding-bottom: 5px; +} + +td { + padding: 0 5px 7px; +} + +div.field, +div.actions { + margin-bottom: 10px; +} + +#notice { + color: green; +} + +.field_with_errors { + padding: 2px; + background-color: red; + display: table; +} + +#error_explanation { + width: 450px; + border: 2px solid red; + padding: 7px 7px 0; + margin-bottom: 20px; + background-color: #f0f0f0; +} + +#error_explanation h2 { + text-align: left; + font-weight: bold; + padding: 5px 5px 5px 15px; + font-size: 12px; + margin: -7px -7px 0; + background-color: #c00; + color: #fff; +} + +#error_explanation ul li { + font-size: 12px; + list-style: square; +} + +label { + display: block; +} diff --git a/test/dummy/app/controllers/messages_controller.rb b/test/dummy/app/controllers/messages_controller.rb new file mode 100644 index 0000000000..81c79a2d1e --- /dev/null +++ b/test/dummy/app/controllers/messages_controller.rb @@ -0,0 +1,58 @@ +class MessagesController < ApplicationController + before_action :set_message, only: [:show, :edit, :update, :destroy] + + # GET /messages + def index + @messages = Message.all + end + + # GET /messages/1 + def show + end + + # GET /messages/new + def new + @message = Message.new + end + + # GET /messages/1/edit + def edit + end + + # POST /messages + def create + @message = Message.new(message_params) + + if @message.save + redirect_to @message, notice: 'Message was successfully created.' + else + render :new + end + end + + # PATCH/PUT /messages/1 + def update + if @message.update(message_params) + redirect_to @message, notice: 'Message was successfully updated.' + else + render :edit + end + end + + # DELETE /messages/1 + def destroy + @message.destroy + redirect_to messages_url, notice: 'Message was successfully destroyed.' + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_message + @message = Message.find(params[:id]) + end + + # Only allow a trusted parameter "white list" through. + def message_params + params.require(:message).permit(:subject, :content) + end +end diff --git a/test/dummy/app/helpers/messages_helper.rb b/test/dummy/app/helpers/messages_helper.rb new file mode 100644 index 0000000000..f1bca9f6ca --- /dev/null +++ b/test/dummy/app/helpers/messages_helper.rb @@ -0,0 +1,2 @@ +module MessagesHelper +end diff --git a/test/dummy/app/models/message.rb b/test/dummy/app/models/message.rb new file mode 100644 index 0000000000..bb0ae59ad7 --- /dev/null +++ b/test/dummy/app/models/message.rb @@ -0,0 +1,3 @@ +class Message < ApplicationRecord + active_text_attribute :content +end diff --git a/test/dummy/app/views/messages/_form.html.erb b/test/dummy/app/views/messages/_form.html.erb new file mode 100644 index 0000000000..6f9ba7899c --- /dev/null +++ b/test/dummy/app/views/messages/_form.html.erb @@ -0,0 +1,27 @@ +<%= form_with(model: message, local: true) do |form| %> + <% if message.errors.any? %> +
+

<%= pluralize(message.errors.count, "error") %> prohibited this message from being saved:

+ +
    + <% message.errors.full_messages.each do |message| %> +
  • <%= message %>
  • + <% end %> +
+
+ <% end %> + +
+ <%= form.label :subject %> + <%= form.text_field :subject %> +
+ +
+ <%= form.label :content %> + <%= form.text_area :content %> +
+ +
+ <%= form.submit %> +
+<% end %> diff --git a/test/dummy/app/views/messages/edit.html.erb b/test/dummy/app/views/messages/edit.html.erb new file mode 100644 index 0000000000..90ad68c788 --- /dev/null +++ b/test/dummy/app/views/messages/edit.html.erb @@ -0,0 +1,6 @@ +

Editing Message

+ +<%= render 'form', message: @message %> + +<%= link_to 'Show', @message %> | +<%= link_to 'Back', messages_path %> diff --git a/test/dummy/app/views/messages/index.html.erb b/test/dummy/app/views/messages/index.html.erb new file mode 100644 index 0000000000..a8c97468c6 --- /dev/null +++ b/test/dummy/app/views/messages/index.html.erb @@ -0,0 +1,29 @@ +

<%= notice %>

+ +

Messages

+ + + + + + + + + + + + <% @messages.each do |message| %> + + + + + + + + <% end %> + +
SubjectContent
<%= message.subject %><%= message.content %><%= link_to 'Show', message %><%= link_to 'Edit', edit_message_path(message) %><%= link_to 'Destroy', message, method: :delete, data: { confirm: 'Are you sure?' } %>
+ +
+ +<%= link_to 'New Message', new_message_path %> diff --git a/test/dummy/app/views/messages/new.html.erb b/test/dummy/app/views/messages/new.html.erb new file mode 100644 index 0000000000..6cbd3b8ffe --- /dev/null +++ b/test/dummy/app/views/messages/new.html.erb @@ -0,0 +1,5 @@ +

New Message

+ +<%= render 'form', message: @message %> + +<%= link_to 'Back', messages_path %> diff --git a/test/dummy/app/views/messages/show.html.erb b/test/dummy/app/views/messages/show.html.erb new file mode 100644 index 0000000000..837b11ef1d --- /dev/null +++ b/test/dummy/app/views/messages/show.html.erb @@ -0,0 +1,14 @@ +

<%= notice %>

+ +

+ Subject: + <%= @message.subject %> +

+ +

+ Content: + <%= @message.content %> +

+ +<%= link_to 'Edit', edit_message_path(@message) %> | +<%= link_to 'Back', messages_path %> diff --git a/test/dummy/config/routes.rb b/test/dummy/config/routes.rb index 787824f888..30b05169b3 100644 --- a/test/dummy/config/routes.rb +++ b/test/dummy/config/routes.rb @@ -1,3 +1,4 @@ Rails.application.routes.draw do + resources :messages # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html end diff --git a/test/dummy/db/migrate/20180208205311_create_messages.rb b/test/dummy/db/migrate/20180208205311_create_messages.rb new file mode 100644 index 0000000000..6817d5933f --- /dev/null +++ b/test/dummy/db/migrate/20180208205311_create_messages.rb @@ -0,0 +1,10 @@ +class CreateMessages < ActiveRecord::Migration[5.2] + def change + create_table :messages do |t| + t.string :subject + t.text :content + + t.timestamps + end + end +end diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb new file mode 100644 index 0000000000..21d6c8d847 --- /dev/null +++ b/test/dummy/db/schema.rb @@ -0,0 +1,22 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# 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: 2018_02_08_205311) do + + create_table "messages", force: :cascade do |t| + t.string "subject" + t.text "content" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + +end diff --git a/test/dummy/db/test.sqlite3 b/test/dummy/db/test.sqlite3 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/test/dummy/log/test.log b/test/dummy/log/test.log deleted file mode 100644 index fdb06fb70a..0000000000 --- a/test/dummy/log/test.log +++ /dev/null @@ -1,20 +0,0 @@ -  (0.1ms) begin transaction ------------------------------------ -ActiveText::ContentTest: test_truth ------------------------------------ -  (0.0ms) rollback transaction -  (0.1ms) begin transaction ---------------------------------------------------- -ActiveText::ContentTest: test_plain_text_conversion ---------------------------------------------------- -  (0.0ms) rollback transaction -  (0.1ms) begin transaction ---------------------------------------------------- -ActiveText::ContentTest: test_plain_text_conversion ---------------------------------------------------- -  (0.1ms) rollback transaction -  (0.1ms) begin transaction ---------------------------------------------------- -ActiveText::ContentTest: test_plain_text_conversion ---------------------------------------------------- -  (0.0ms) rollback transaction diff --git a/test/unit/content_test.rb b/test/unit/content_test.rb index 48ba731597..5299ae3f8f 100644 --- a/test/unit/content_test.rb +++ b/test/unit/content_test.rb @@ -3,8 +3,8 @@ require_relative '../test_helper' module ActiveText class ContentTest < ActiveSupport::TestCase test "plain text conversion" do - content = ActiveText::Content.new("

Hello world

") - assert "Hello world", content.to_plain_text + message = Message.create!(subject: "Greetings", content: "

Hello world

") + assert_equal "Hello world", message.content.to_plain_text end end end -- cgit v1.2.3 From 63add5acc4a9bd84907bf6bf17de307792336539 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Mon, 12 Feb 2018 10:16:49 -0500 Subject: Extract BC3's rich_text_field helper --- app/helpers/active_text/tag_helper.rb | 46 ++++++++++++++++++++++++++++ lib/active_text/engine.rb | 8 +++++ test/dummy/app/views/messages/_form.html.erb | 2 +- 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 app/helpers/active_text/tag_helper.rb diff --git a/app/helpers/active_text/tag_helper.rb b/app/helpers/active_text/tag_helper.rb new file mode 100644 index 0000000000..c2ec7e5e8f --- /dev/null +++ b/app/helpers/active_text/tag_helper.rb @@ -0,0 +1,46 @@ +module ActiveText + module TagHelper + cattr_accessor(:id, instance_accessor: false) { 0 } + + def active_text_field_tag(name, value = nil, options = {}) + options = options.symbolize_keys + options[:input] ||= "trix_input_#{ActiveText::TagHelper.id += 1}" + + editor_tag = content_tag("trix-editor", "", options) + input_tag = hidden_field_tag(name, value, id: options[:input]) + + editor_tag + input_tag + end + end +end + +module ActionView::Helpers + class Tags::ActiveText < Tags::Base + include ActiveText::TagHelper + + delegate :dom_id, to: ActionView::RecordIdentifier + + def render + options = @options.stringify_keys + add_default_name_and_id(options) + options["input"] ||= dom_id(object, [options["id"], :trix_input].compact.join("_")) + active_text_field_tag(options.delete("name"), editable_value, options) + end + + def editable_value + value.try(:to_trix_html) + end + end + + module FormHelper + def active_text_field(object_name, method, options = {}) + Tags::ActiveText.new(object_name, method, self, options).render + end + end + + class FormBuilder + def active_text_field(method, options = {}) + @template.active_text_field(@object_name, method, objectify_options(options)) + end + end +end diff --git a/lib/active_text/engine.rb b/lib/active_text/engine.rb index 3f076ab321..5b16acab04 100644 --- a/lib/active_text/engine.rb +++ b/lib/active_text/engine.rb @@ -10,5 +10,13 @@ module ActiveText include ActiveText::Attribute end end + + # FIXME: Aren't helpers supposed to load automatically? + # https://github.com/rails/rails/issues/26627 ? + initializer "active_text.helper" do + ActiveSupport.on_load(:action_controller_base) do + helper ActiveText::TagHelper + end + end end end diff --git a/test/dummy/app/views/messages/_form.html.erb b/test/dummy/app/views/messages/_form.html.erb index 6f9ba7899c..6ead526229 100644 --- a/test/dummy/app/views/messages/_form.html.erb +++ b/test/dummy/app/views/messages/_form.html.erb @@ -18,7 +18,7 @@
<%= form.label :content %> - <%= form.text_area :content %> + <%= form.active_text_field :content %>
-- cgit v1.2.3 From 2f13b3c9fe21debec4bd9afe4601125f4fe29ce2 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Mon, 12 Feb 2018 10:34:29 -0500 Subject: Pull activetext.js into dummy app with webpacker --- .gitignore | 1 + Gemfile.lock | 7 + activetext.gemspec | 1 + bin/webpack | 29 + bin/webpack-dev-server | 29 + test/dummy/.babelrc | 18 + test/dummy/.postcssrc.yml | 3 + test/dummy/app/assets/javascripts/application.js | 14 - test/dummy/app/assets/javascripts/cable.js | 13 - test/dummy/app/assets/javascripts/channels/.keep | 0 test/dummy/app/assets/javascripts/messages.js | 2 - test/dummy/app/assets/stylesheets/application.css | 1 + test/dummy/app/javascript/packs/application.js | 1 + test/dummy/app/views/layouts/application.html.erb | 4 +- test/dummy/app/views/messages/show.html.erb | 2 +- test/dummy/config/environments/development.rb | 2 + test/dummy/config/environments/production.rb | 2 + test/dummy/config/webpack/development.js | 3 + test/dummy/config/webpack/environment.js | 3 + test/dummy/config/webpack/production.js | 3 + test/dummy/config/webpack/test.js | 3 + test/dummy/config/webpacker.yml | 65 + test/dummy/package.json | 8 +- test/dummy/yarn.lock | 6066 +++++++++++++++++++++ 24 files changed, 6247 insertions(+), 33 deletions(-) create mode 100755 bin/webpack create mode 100755 bin/webpack-dev-server create mode 100644 test/dummy/.babelrc create mode 100644 test/dummy/.postcssrc.yml delete mode 100644 test/dummy/app/assets/javascripts/application.js delete mode 100644 test/dummy/app/assets/javascripts/cable.js delete mode 100644 test/dummy/app/assets/javascripts/channels/.keep delete mode 100644 test/dummy/app/assets/javascripts/messages.js create mode 100644 test/dummy/app/javascript/packs/application.js create mode 100644 test/dummy/config/webpack/development.js create mode 100644 test/dummy/config/webpack/environment.js create mode 100644 test/dummy/config/webpack/production.js create mode 100644 test/dummy/config/webpack/test.js create mode 100644 test/dummy/config/webpacker.yml create mode 100644 test/dummy/yarn.lock diff --git a/.gitignore b/.gitignore index 0aec2551f0..d1654bd7a4 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ test/dummy/db/*.sqlite3 test/dummy/db/*.sqlite3-journal test/dummy/log/*.log test/dummy/node_modules/ +test/dummy/public/ test/dummy/yarn-error.log test/dummy/storage/ test/dummy/tmp/ diff --git a/Gemfile.lock b/Gemfile.lock index e6db9609d9..e693ad5c38 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -74,6 +74,8 @@ GEM nokogiri (1.8.2) mini_portile2 (~> 2.3.0) rack (2.0.4) + rack-proxy (0.6.3) + rack rack-test (0.8.2) rack (>= 1.0, < 3) rails (5.2.0.rc1) @@ -113,6 +115,10 @@ GEM thread_safe (0.3.6) tzinfo (1.2.5) thread_safe (~> 0.1) + webpacker (3.2.2) + activesupport (>= 4.2) + rack-proxy (>= 0.6.1) + railties (>= 4.2) websocket-driver (0.7.0) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.3) @@ -124,6 +130,7 @@ DEPENDENCIES activetext! bundler (~> 1.15) sqlite3 + webpacker (~> 3.2.2) BUNDLED WITH 1.16.1 diff --git a/activetext.gemspec b/activetext.gemspec index 511fd76bd1..6c0fea16c6 100644 --- a/activetext.gemspec +++ b/activetext.gemspec @@ -20,6 +20,7 @@ Gem::Specification.new do |s| s.add_development_dependency "bundler", "~> 1.15" s.add_development_dependency "sqlite3" + s.add_development_dependency "webpacker", "~> 3.2.2" s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- test/*`.split("\n") diff --git a/bin/webpack b/bin/webpack new file mode 100755 index 0000000000..917c5096f5 --- /dev/null +++ b/bin/webpack @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'webpack' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +bundle_binstub = File.expand_path("../bundle", __FILE__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 150) =~ /This file was generated by Bundler/ + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("webpacker", "webpack") diff --git a/bin/webpack-dev-server b/bin/webpack-dev-server new file mode 100755 index 0000000000..bf2bf34edc --- /dev/null +++ b/bin/webpack-dev-server @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'webpack-dev-server' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +bundle_binstub = File.expand_path("../bundle", __FILE__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 150) =~ /This file was generated by Bundler/ + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("webpacker", "webpack-dev-server") diff --git a/test/dummy/.babelrc b/test/dummy/.babelrc new file mode 100644 index 0000000000..ded31c0d80 --- /dev/null +++ b/test/dummy/.babelrc @@ -0,0 +1,18 @@ +{ + "presets": [ + ["env", { + "modules": false, + "targets": { + "browsers": "> 1%", + "uglify": true + }, + "useBuiltIns": true + }] + ], + + "plugins": [ + "syntax-dynamic-import", + "transform-object-rest-spread", + ["transform-class-properties", { "spec": true }] + ] +} diff --git a/test/dummy/.postcssrc.yml b/test/dummy/.postcssrc.yml new file mode 100644 index 0000000000..150dac3c6c --- /dev/null +++ b/test/dummy/.postcssrc.yml @@ -0,0 +1,3 @@ +plugins: + postcss-import: {} + postcss-cssnext: {} diff --git a/test/dummy/app/assets/javascripts/application.js b/test/dummy/app/assets/javascripts/application.js deleted file mode 100644 index e914de7396..0000000000 --- a/test/dummy/app/assets/javascripts/application.js +++ /dev/null @@ -1,14 +0,0 @@ -// This is a manifest file that'll be compiled into application.js, which will include all the files -// listed below. -// -// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, -// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. -// -// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the -// compiled file. JavaScript code in this file should be added after the last require_* statement. -// -// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details -// about supported directives. -// -//= require activestorage -//= require_tree . diff --git a/test/dummy/app/assets/javascripts/cable.js b/test/dummy/app/assets/javascripts/cable.js deleted file mode 100644 index 739aa5f022..0000000000 --- a/test/dummy/app/assets/javascripts/cable.js +++ /dev/null @@ -1,13 +0,0 @@ -// Action Cable provides the framework to deal with WebSockets in Rails. -// You can generate new channels where WebSocket features live using the `rails generate channel` command. -// -//= require action_cable -//= require_self -//= require_tree ./channels - -(function() { - this.App || (this.App = {}); - - App.cable = ActionCable.createConsumer(); - -}).call(this); diff --git a/test/dummy/app/assets/javascripts/channels/.keep b/test/dummy/app/assets/javascripts/channels/.keep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/test/dummy/app/assets/javascripts/messages.js b/test/dummy/app/assets/javascripts/messages.js deleted file mode 100644 index dee720facd..0000000000 --- a/test/dummy/app/assets/javascripts/messages.js +++ /dev/null @@ -1,2 +0,0 @@ -// Place all the behaviors and hooks related to the matching controller here. -// All this logic will automatically be available in application.js. diff --git a/test/dummy/app/assets/stylesheets/application.css b/test/dummy/app/assets/stylesheets/application.css index 0ebd7fe829..e4b10eb997 100644 --- a/test/dummy/app/assets/stylesheets/application.css +++ b/test/dummy/app/assets/stylesheets/application.css @@ -10,6 +10,7 @@ * files in this directory. Styles in this file should be added after the last require_* statement. * It is generally better to create a new file per style scope. * + *= require trix/dist/trix.css *= require_tree . *= require_self */ diff --git a/test/dummy/app/javascript/packs/application.js b/test/dummy/app/javascript/packs/application.js new file mode 100644 index 0000000000..f12ff2fdc3 --- /dev/null +++ b/test/dummy/app/javascript/packs/application.js @@ -0,0 +1 @@ +import "activetext" diff --git a/test/dummy/app/views/layouts/application.html.erb b/test/dummy/app/views/layouts/application.html.erb index a6eb0174b7..f221f512b7 100644 --- a/test/dummy/app/views/layouts/application.html.erb +++ b/test/dummy/app/views/layouts/application.html.erb @@ -4,8 +4,8 @@ Dummy <%= csrf_meta_tags %> - <%= stylesheet_link_tag 'application', media: 'all' %> - <%= javascript_include_tag 'application' %> + <%= stylesheet_link_tag 'application', media: 'all' %> + <%= javascript_pack_tag 'application' %> diff --git a/test/dummy/app/views/messages/show.html.erb b/test/dummy/app/views/messages/show.html.erb index 837b11ef1d..feec71cb93 100644 --- a/test/dummy/app/views/messages/show.html.erb +++ b/test/dummy/app/views/messages/show.html.erb @@ -7,7 +7,7 @@

Content: - <%= @message.content %> + <%= raw @message.content %>

<%= link_to 'Edit', edit_message_path(@message) %> | diff --git a/test/dummy/config/environments/development.rb b/test/dummy/config/environments/development.rb index 366e75ad77..42768bf68c 100644 --- a/test/dummy/config/environments/development.rb +++ b/test/dummy/config/environments/development.rb @@ -1,4 +1,6 @@ Rails.application.configure do + # Verifies that versions and hashed value of the package contents in the project's package.json + config.webpacker.check_yarn_integrity = true # Settings specified here will take precedence over those in config/application.rb. # In the development environment your application's code is reloaded on diff --git a/test/dummy/config/environments/production.rb b/test/dummy/config/environments/production.rb index 9ea5ad2784..2aaa79f620 100644 --- a/test/dummy/config/environments/production.rb +++ b/test/dummy/config/environments/production.rb @@ -1,4 +1,6 @@ Rails.application.configure do + # Verifies that versions and hashed value of the package contents in the project's package.json + config.webpacker.check_yarn_integrity = false # Settings specified here will take precedence over those in config/application.rb. # Code is not reloaded between requests. diff --git a/test/dummy/config/webpack/development.js b/test/dummy/config/webpack/development.js new file mode 100644 index 0000000000..81269f6513 --- /dev/null +++ b/test/dummy/config/webpack/development.js @@ -0,0 +1,3 @@ +const environment = require('./environment') + +module.exports = environment.toWebpackConfig() diff --git a/test/dummy/config/webpack/environment.js b/test/dummy/config/webpack/environment.js new file mode 100644 index 0000000000..d16d9af743 --- /dev/null +++ b/test/dummy/config/webpack/environment.js @@ -0,0 +1,3 @@ +const { environment } = require('@rails/webpacker') + +module.exports = environment diff --git a/test/dummy/config/webpack/production.js b/test/dummy/config/webpack/production.js new file mode 100644 index 0000000000..81269f6513 --- /dev/null +++ b/test/dummy/config/webpack/production.js @@ -0,0 +1,3 @@ +const environment = require('./environment') + +module.exports = environment.toWebpackConfig() diff --git a/test/dummy/config/webpack/test.js b/test/dummy/config/webpack/test.js new file mode 100644 index 0000000000..81269f6513 --- /dev/null +++ b/test/dummy/config/webpack/test.js @@ -0,0 +1,3 @@ +const environment = require('./environment') + +module.exports = environment.toWebpackConfig() diff --git a/test/dummy/config/webpacker.yml b/test/dummy/config/webpacker.yml new file mode 100644 index 0000000000..d3f24e1b4b --- /dev/null +++ b/test/dummy/config/webpacker.yml @@ -0,0 +1,65 @@ +# Note: You must restart bin/webpack-dev-server for changes to take effect + +default: &default + source_path: app/javascript + source_entry_path: packs + public_output_path: packs + cache_path: tmp/cache/webpacker + + # Additional paths webpack should lookup modules + # ['app/assets', 'engine/foo/app/assets'] + resolved_paths: [] + + # Reload manifest.json on all requests so we reload latest compiled packs + cache_manifest: false + + extensions: + - .js + - .sass + - .scss + - .css + - .png + - .svg + - .gif + - .jpeg + - .jpg + +development: + <<: *default + compile: true + + # Reference: https://webpack.js.org/configuration/dev-server/ + dev_server: + https: false + host: localhost + port: 3035 + public: localhost:3035 + hmr: false + # Inline should be set to true if using HMR + inline: true + overlay: true + compress: true + disable_host_check: true + use_local_ip: false + quiet: false + headers: + 'Access-Control-Allow-Origin': '*' + watch_options: + ignored: /node_modules/ + + +test: + <<: *default + compile: true + + # Compile test packs to a separate directory + public_output_path: packs-test + +production: + <<: *default + + # Production depends on precompilation of packs prior to booting for performance. + compile: false + + # Cache manifest.json for performance + cache_manifest: true diff --git a/test/dummy/package.json b/test/dummy/package.json index caa2d7bb3f..59fdfb8a60 100644 --- a/test/dummy/package.json +++ b/test/dummy/package.json @@ -1,5 +1,11 @@ { "name": "dummy", "private": true, - "dependencies": {} + "dependencies": { + "@rails/webpacker": "^3.2.2", + "activetext": "file:../.." + }, + "devDependencies": { + "webpack-dev-server": "^2.11.1" + } } diff --git a/test/dummy/yarn.lock b/test/dummy/yarn.lock new file mode 100644 index 0000000000..3b1f47bf41 --- /dev/null +++ b/test/dummy/yarn.lock @@ -0,0 +1,6066 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@rails/webpacker@^3.2.2": + version "3.2.2" + resolved "https://registry.yarnpkg.com/@rails/webpacker/-/webpacker-3.2.2.tgz#6d60e1cf729dc2ccc52053c9b6b8d30c9a48a297" + dependencies: + babel-core "^6.26.0" + babel-loader "^7.1.2" + babel-plugin-syntax-dynamic-import "^6.18.0" + babel-plugin-transform-class-properties "^6.24.1" + babel-plugin-transform-object-rest-spread "^6.26.0" + babel-polyfill "^6.26.0" + babel-preset-env "^1.6.1" + case-sensitive-paths-webpack-plugin "^2.1.1" + compression-webpack-plugin "^1.1.6" + css-loader "^0.28.9" + extract-text-webpack-plugin "^3.0.2" + file-loader "^1.1.6" + glob "^7.1.2" + js-yaml "^3.10.0" + node-sass "^4.7.2" + path-complete-extname "^0.1.0" + postcss-cssnext "^3.1.0" + postcss-import "^11.0.0" + postcss-loader "^2.1.0" + sass-loader "^6.0.6" + style-loader "^0.20.1" + uglifyjs-webpack-plugin "^1.1.8" + webpack "^3.10.0" + webpack-manifest-plugin "^1.3.2" + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + +accepts@~1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.4.tgz#86246758c7dd6d21a6474ff084a4740ec05eb21f" + dependencies: + mime-types "~2.1.16" + negotiator "0.6.1" + +acorn-dynamic-import@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4" + dependencies: + acorn "^4.0.3" + +acorn@^4.0.3: + version "4.0.13" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" + +acorn@^5.0.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.4.1.tgz#fdc58d9d17f4a4e98d102ded826a9b9759125102" + +"activetext@file:../..": + version "0.1" + dependencies: + trix "^0.11.1" + +ajv-keywords@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" + +ajv-keywords@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.1.0.tgz#ac2b27939c543e95d2c06e7f7f5c27be4aa543be" + +ajv@^4.9.1: + version "4.11.8" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + +ajv@^5.0.0, ajv@^5.1.0: + version "5.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + +ajv@^6.1.0: + version "6.1.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.1.1.tgz#978d597fbc2b7d0e5a5c3ddeb149a682f2abfa0e" + dependencies: + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + +align-text@^0.1.1, align-text@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + dependencies: + kind-of "^3.0.2" + longest "^1.0.1" + repeat-string "^1.5.2" + +alphanum-sort@^1.0.1, alphanum-sort@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" + +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + +ansi-html@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +ansi-styles@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88" + dependencies: + color-convert "^1.9.0" + +anymatch@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" + dependencies: + micromatch "^2.1.5" + normalize-path "^2.0.0" + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +aproba@^1.0.3, aproba@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + +are-we-there-yet@~1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +argparse@^1.0.7: + version "1.0.9" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + +arr-flatten@^1.0.1, arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + +array-find-index@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + +array-flatten@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.1.tgz#426bb9da84090c1838d812c8150af20a8331e296" + +array-includes@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.7.0" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + +asn1.js@^4.0.0: + version "4.9.2" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.2.tgz#8117ef4f7ed87cd8f89044b5bff97ac243a16c9a" + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + +assert@^1.1.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + dependencies: + util "0.10.3" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +async-foreach@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" + +async@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + +async@^2.1.2, async@^2.1.5, async@^2.4.1: + version "2.6.0" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4" + dependencies: + lodash "^4.14.0" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +atob@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.0.3.tgz#19c7a760473774468f20b2d2d03372ad7d4cbf5d" + +autoprefixer@^6.3.1: + version "6.7.7" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014" + dependencies: + browserslist "^1.7.6" + caniuse-db "^1.0.30000634" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + postcss "^5.2.16" + postcss-value-parser "^3.2.3" + +autoprefixer@^7.1.1: + version "7.2.6" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-7.2.6.tgz#256672f86f7c735da849c4f07d008abb056067dc" + dependencies: + browserslist "^2.11.3" + caniuse-lite "^1.0.30000805" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + postcss "^6.0.17" + postcss-value-parser "^3.2.3" + +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + +aws4@^1.2.1, aws4@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" + +babel-code-frame@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + +babel-core@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8" + dependencies: + babel-code-frame "^6.26.0" + babel-generator "^6.26.0" + babel-helpers "^6.24.1" + babel-messages "^6.23.0" + babel-register "^6.26.0" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + convert-source-map "^1.5.0" + debug "^2.6.8" + json5 "^0.5.1" + lodash "^4.17.4" + minimatch "^3.0.4" + path-is-absolute "^1.0.1" + private "^0.1.7" + slash "^1.0.0" + source-map "^0.5.6" + +babel-generator@^6.26.0: + version "6.26.1" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" + dependencies: + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.17.4" + source-map "^0.5.7" + trim-right "^1.0.1" + +babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" + dependencies: + babel-helper-explode-assignable-expression "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-call-delegate@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-define-map@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-explode-assignable-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-function-name@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" + dependencies: + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-get-function-arity@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-hoist-variables@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-optimise-call-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-regex@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" + dependencies: + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-remap-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-replace-supers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" + dependencies: + babel-helper-optimise-call-expression "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helpers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-loader@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.1.2.tgz#f6cbe122710f1aa2af4d881c6d5b54358ca24126" + dependencies: + find-cache-dir "^1.0.0" + loader-utils "^1.0.2" + mkdirp "^0.5.1" + +babel-messages@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-check-es2015-constants@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-syntax-async-functions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + +babel-plugin-syntax-class-properties@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" + +babel-plugin-syntax-dynamic-import@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" + +babel-plugin-syntax-exponentiation-operator@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + +babel-plugin-syntax-object-rest-spread@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" + +babel-plugin-syntax-trailing-function-commas@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + +babel-plugin-transform-async-to-generator@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-class-properties@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" + dependencies: + babel-helper-function-name "^6.24.1" + babel-plugin-syntax-class-properties "^6.8.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-arrow-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoping@^6.23.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" + dependencies: + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-plugin-transform-es2015-classes@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" + dependencies: + babel-helper-define-map "^6.24.1" + babel-helper-function-name "^6.24.1" + babel-helper-optimise-call-expression "^6.24.1" + babel-helper-replace-supers "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-computed-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-destructuring@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-for-of@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-function-name@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz#0d8394029b7dc6abe1a97ef181e00758dd2e5d8a" + dependencies: + babel-plugin-transform-strict-mode "^6.24.1" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-types "^6.26.0" + +babel-plugin-transform-es2015-modules-systemjs@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-umd@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-object-super@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" + dependencies: + babel-helper-replace-supers "^6.24.1" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-parameters@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" + dependencies: + babel-helper-call-delegate "^6.24.1" + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-shorthand-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-spread@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-sticky-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-template-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-unicode-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-exponentiation-operator@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" + dependencies: + babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" + babel-plugin-syntax-exponentiation-operator "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-object-rest-spread@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" + dependencies: + babel-plugin-syntax-object-rest-spread "^6.8.0" + babel-runtime "^6.26.0" + +babel-plugin-transform-regenerator@^6.22.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" + dependencies: + regenerator-transform "^0.10.0" + +babel-plugin-transform-strict-mode@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-polyfill@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" + dependencies: + babel-runtime "^6.26.0" + core-js "^2.5.0" + regenerator-runtime "^0.10.5" + +babel-preset-env@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.6.1.tgz#a18b564cc9b9afdf4aae57ae3c1b0d99188e6f48" + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-to-generator "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.23.0" + babel-plugin-transform-es2015-classes "^6.23.0" + babel-plugin-transform-es2015-computed-properties "^6.22.0" + babel-plugin-transform-es2015-destructuring "^6.23.0" + babel-plugin-transform-es2015-duplicate-keys "^6.22.0" + babel-plugin-transform-es2015-for-of "^6.23.0" + babel-plugin-transform-es2015-function-name "^6.22.0" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-plugin-transform-es2015-modules-commonjs "^6.23.0" + babel-plugin-transform-es2015-modules-systemjs "^6.23.0" + babel-plugin-transform-es2015-modules-umd "^6.23.0" + babel-plugin-transform-es2015-object-super "^6.22.0" + babel-plugin-transform-es2015-parameters "^6.23.0" + babel-plugin-transform-es2015-shorthand-properties "^6.22.0" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.22.0" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.23.0" + babel-plugin-transform-es2015-unicode-regex "^6.22.0" + babel-plugin-transform-exponentiation-operator "^6.22.0" + babel-plugin-transform-regenerator "^6.22.0" + browserslist "^2.1.2" + invariant "^2.2.2" + semver "^5.3.0" + +babel-register@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" + dependencies: + babel-core "^6.26.0" + babel-runtime "^6.26.0" + core-js "^2.5.0" + home-or-tmp "^2.0.0" + lodash "^4.17.4" + mkdirp "^0.5.1" + source-map-support "^0.4.15" + +babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babel-template@^6.24.1, babel-template@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + dependencies: + babel-runtime "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + lodash "^4.17.4" + +babel-traverse@^6.24.1, babel-traverse@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + dependencies: + babel-code-frame "^6.26.0" + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + debug "^2.6.8" + globals "^9.18.0" + invariant "^2.2.2" + lodash "^4.17.4" + +babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + dependencies: + babel-runtime "^6.26.0" + esutils "^2.0.2" + lodash "^4.17.4" + to-fast-properties "^1.0.3" + +babylon@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + +balanced-match@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.1.0.tgz#b504bd05869b39259dd0c5efc35d843176dccc4a" + +balanced-match@^0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +base64-js@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886" + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + +bcrypt-pbkdf@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" + dependencies: + tweetnacl "^0.14.3" + +big.js@^3.1.3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" + +binary-extensions@^1.0.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + +bluebird@^3.5.0: + version "3.5.1" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + +body-parser@1.18.2: + version "1.18.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" + dependencies: + bytes "3.0.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.1" + http-errors "~1.6.2" + iconv-lite "0.4.19" + on-finished "~2.3.0" + qs "6.5.1" + raw-body "2.3.2" + type-is "~1.6.15" + +bonjour@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" + dependencies: + array-flatten "^2.1.0" + deep-equal "^1.0.1" + dns-equal "^1.0.0" + dns-txt "^2.0.2" + multicast-dns "^6.0.1" + multicast-dns-service-types "^1.1.0" + +boom@2.x.x: + version "2.10.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + +boom@4.x.x: + version "4.3.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31" + dependencies: + hoek "4.x.x" + +boom@5.x.x: + version "5.2.0" + resolved "https://registry.yarnpkg.com/boom/-/boom-5.2.0.tgz#5dd9da6ee3a5f302077436290cb717d3f4a54e02" + dependencies: + hoek "4.x.x" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +braces@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.0.tgz#a46941cb5fb492156b3d6a656e06c35364e3e66e" + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + define-property "^1.0.0" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.1.1" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.1.1.tgz#38b7ab55edb806ff2dcda1a7f1620773a477c49f" + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a" + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd" + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + +browserify-rsa@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + dependencies: + bn.js "^4.1.1" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.2" + elliptic "^6.0.0" + inherits "^2.0.1" + parse-asn1 "^5.0.0" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + dependencies: + pako "~1.0.5" + +browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6: + version "1.7.7" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9" + dependencies: + caniuse-db "^1.0.30000639" + electron-to-chromium "^1.2.7" + +browserslist@^2.0.0, browserslist@^2.1.2, browserslist@^2.11.3: + version "2.11.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.11.3.tgz#fe36167aed1bbcde4827ebfe71347a2cc70b99b2" + dependencies: + caniuse-lite "^1.0.30000792" + electron-to-chromium "^1.3.30" + +buffer-indexof@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + +buffer@^4.3.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +builtin-modules@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + +cacache@^10.0.1: + version "10.0.2" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.2.tgz#105a93a162bbedf3a25da42e1939ed99ffb145f8" + dependencies: + bluebird "^3.5.0" + chownr "^1.0.1" + glob "^7.1.2" + graceful-fs "^4.1.11" + lru-cache "^4.1.1" + mississippi "^1.3.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.1" + ssri "^5.0.0" + unique-filename "^1.1.0" + y18n "^3.2.1" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +camelcase-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + dependencies: + camelcase "^2.0.0" + map-obj "^1.0.0" + +camelcase@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + +camelcase@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + +camelcase@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + +caniuse-api@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c" + dependencies: + browserslist "^1.3.6" + caniuse-db "^1.0.30000529" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" + +caniuse-api@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-2.0.0.tgz#b1ddb5a5966b16f48dc4998444d4bbc6c7d9d834" + dependencies: + browserslist "^2.0.0" + caniuse-lite "^1.0.0" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" + +caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639: + version "1.0.30000808" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000808.tgz#30dfd83009d5704f02dffb37725068ed12a366bb" + +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000792, caniuse-lite@^1.0.30000805: + version "1.0.30000808" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000808.tgz#7d759b5518529ea08b6705a19e70dbf401628ffc" + +case-sensitive-paths-webpack-plugin@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.1.1.tgz#3d29ced8c1f124bf6f53846fb3f5894731fdc909" + +caseless@~0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + +center-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + dependencies: + align-text "^0.1.3" + lazy-cache "^1.0.3" + +chalk@^1.1.1, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.0.1, chalk@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.1.tgz#523fe2678aec7b04e8041909292fe8b17059b796" + dependencies: + ansi-styles "^3.2.0" + escape-string-regexp "^1.0.5" + supports-color "^5.2.0" + +chokidar@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +chokidar@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.1.tgz#6e67e9998fe10e8f651e975ca62460456ff8e297" + dependencies: + anymatch "^2.0.0" + async-each "^1.0.0" + braces "^2.3.0" + glob-parent "^3.1.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^2.1.1" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + upath "1.0.0" + optionalDependencies: + fsevents "^1.0.0" + +chownr@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +clap@^1.0.9: + version "1.2.3" + resolved "https://registry.yarnpkg.com/clap/-/clap-1.2.3.tgz#4f36745b32008492557f46412d66d50cb99bce51" + dependencies: + chalk "^1.1.3" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +cliui@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + dependencies: + center-align "^0.1.1" + right-align "^0.1.1" + wordwrap "0.0.2" + +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + +clone-deep@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-0.3.0.tgz#348c61ae9cdbe0edfe053d91ff4cc521d790ede8" + dependencies: + for-own "^1.0.0" + is-plain-object "^2.0.1" + kind-of "^3.2.2" + shallow-clone "^0.1.2" + +clone@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.3.tgz#298d7e2231660f40c003c2ed3140decf3f53085f" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +coa@~1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.4.tgz#a9ef153660d6a86a8bdec0289a5c684d217432fd" + dependencies: + q "^1.1.2" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.3.0, color-convert@^1.8.2, color-convert@^1.9.0, color-convert@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" + dependencies: + color-name "^1.1.1" + +color-name@^1.0.0, color-name@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + +color-string@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991" + dependencies: + color-name "^1.0.0" + +color-string@^1.4.0, color-string@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.2.tgz#26e45814bc3c9a7cbd6751648a41434514a773a9" + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^0.11.0: + version "0.11.4" + resolved "https://registry.yarnpkg.com/color/-/color-0.11.4.tgz#6d7b5c74fb65e841cd48792ad1ed5e07b904d764" + dependencies: + clone "^1.0.2" + color-convert "^1.3.0" + color-string "^0.3.0" + +color@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/color/-/color-1.0.3.tgz#e48e832d85f14ef694fb468811c2d5cfe729b55d" + dependencies: + color-convert "^1.8.2" + color-string "^1.4.0" + +color@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color/-/color-2.0.1.tgz#e4ed78a3c4603d0891eba5430b04b86314f4c839" + dependencies: + color-convert "^1.9.1" + color-string "^1.5.2" + +colormin@^1.0.5: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colormin/-/colormin-1.1.2.tgz#ea2f7420a72b96881a38aae59ec124a6f7298133" + dependencies: + color "^0.11.0" + css-color-names "0.0.4" + has "^1.0.1" + +colors@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" + +combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" + dependencies: + delayed-stream "~1.0.0" + +commander@^2.9.0, commander@~2.14.1: + version "2.14.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa" + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + +component-emitter@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + +compressible@~2.0.11: + version "2.0.12" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.12.tgz#c59a5c99db76767e9876500e271ef63b3493bd66" + dependencies: + mime-db ">= 1.30.0 < 2" + +compression-webpack-plugin@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/compression-webpack-plugin/-/compression-webpack-plugin-1.1.6.tgz#450808fe143b4c5216a14f0c315c47bec3d83cec" + dependencies: + async "^2.4.1" + cacache "^10.0.1" + find-cache-dir "^1.0.0" + serialize-javascript "^1.4.0" + webpack-sources "^1.0.1" + +compression@^1.5.2: + version "1.7.1" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.1.tgz#eff2603efc2e22cf86f35d2eb93589f9875373db" + dependencies: + accepts "~1.3.4" + bytes "3.0.0" + compressible "~2.0.11" + debug "2.6.9" + on-headers "~1.0.1" + safe-buffer "5.1.1" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" + dependencies: + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +connect-history-api-fallback@^1.3.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz#b06873934bc5e344fef611a196a6faae0aee015a" + +console-browserify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + dependencies: + date-now "^0.1.4" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + +convert-source-map@^1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + +copy-concurrently@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + dependencies: + aproba "^1.1.1" + fs-write-stream-atomic "^1.0.8" + iferr "^0.1.5" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.0" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + +core-js@^2.4.0, core-js@^2.5.0: + version "2.5.3" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e" + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cosmiconfig@^2.1.0, cosmiconfig@^2.1.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-2.2.2.tgz#6173cebd56fac042c1f4390edf7af6c07c7cb892" + dependencies: + is-directory "^0.3.1" + js-yaml "^3.4.3" + minimist "^1.2.0" + object-assign "^4.1.0" + os-homedir "^1.0.1" + parse-json "^2.2.0" + require-from-string "^1.1.0" + +create-ecdh@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d" + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-hash@^1.1.0, create-hash@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd" + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + ripemd160 "^2.0.0" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: + version "1.1.6" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06" + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982" + dependencies: + lru-cache "^4.0.1" + which "^1.2.9" + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" + +cryptiles@3.x.x: + version "3.1.2" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe" + dependencies: + boom "5.x.x" + +crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +css-color-function@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/css-color-function/-/css-color-function-1.3.3.tgz#8ed24c2c0205073339fafa004bc8c141fccb282e" + dependencies: + balanced-match "0.1.0" + color "^0.11.0" + debug "^3.1.0" + rgb "~0.1.0" + +css-color-names@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" + +css-loader@^0.28.9: + version "0.28.9" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.9.tgz#68064b85f4e271d7ce4c48a58300928e535d1c95" + dependencies: + babel-code-frame "^6.26.0" + css-selector-tokenizer "^0.7.0" + cssnano "^3.10.0" + icss-utils "^2.1.0" + loader-utils "^1.0.2" + lodash.camelcase "^4.3.0" + object-assign "^4.1.1" + postcss "^5.0.6" + postcss-modules-extract-imports "^1.2.0" + postcss-modules-local-by-default "^1.2.0" + postcss-modules-scope "^1.1.0" + postcss-modules-values "^1.3.0" + postcss-value-parser "^3.3.0" + source-list-map "^2.0.0" + +css-selector-tokenizer@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz#e6988474ae8c953477bf5e7efecfceccd9cf4c86" + dependencies: + cssesc "^0.1.0" + fastparse "^1.1.1" + regexpu-core "^1.0.0" + +css-unit-converter@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/css-unit-converter/-/css-unit-converter-1.1.1.tgz#d9b9281adcfd8ced935bdbaba83786897f64e996" + +cssesc@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4" + +cssnano@^3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.10.0.tgz#4f38f6cea2b9b17fa01490f23f1dc68ea65c1c38" + dependencies: + autoprefixer "^6.3.1" + decamelize "^1.1.2" + defined "^1.0.0" + has "^1.0.1" + object-assign "^4.0.1" + postcss "^5.0.14" + postcss-calc "^5.2.0" + postcss-colormin "^2.1.8" + postcss-convert-values "^2.3.4" + postcss-discard-comments "^2.0.4" + postcss-discard-duplicates "^2.0.1" + postcss-discard-empty "^2.0.1" + postcss-discard-overridden "^0.1.1" + postcss-discard-unused "^2.2.1" + postcss-filter-plugins "^2.0.0" + postcss-merge-idents "^2.1.5" + postcss-merge-longhand "^2.0.1" + postcss-merge-rules "^2.0.3" + postcss-minify-font-values "^1.0.2" + postcss-minify-gradients "^1.0.1" + postcss-minify-params "^1.0.4" + postcss-minify-selectors "^2.0.4" + postcss-normalize-charset "^1.1.0" + postcss-normalize-url "^3.0.7" + postcss-ordered-values "^2.1.0" + postcss-reduce-idents "^2.2.2" + postcss-reduce-initial "^1.0.0" + postcss-reduce-transforms "^1.0.3" + postcss-svgo "^2.1.1" + postcss-unique-selectors "^2.0.2" + postcss-value-parser "^3.2.3" + postcss-zindex "^2.0.1" + +csso@~2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/csso/-/csso-2.3.2.tgz#ddd52c587033f49e94b71fc55569f252e8ff5f85" + dependencies: + clap "^1.0.9" + source-map "^0.5.3" + +currently-unhandled@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + dependencies: + array-find-index "^1.0.1" + +cyclist@~0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" + +d@1: + version "1.0.0" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" + dependencies: + es5-ext "^0.10.9" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +date-now@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + +debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + dependencies: + ms "2.0.0" + +debug@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + dependencies: + ms "2.0.0" + +decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + +deep-equal@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + +deep-extend@~0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" + +define-properties@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" + dependencies: + foreach "^2.0.5" + object-keys "^1.0.8" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + dependencies: + is-descriptor "^1.0.0" + +defined@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + +del@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/del/-/del-3.0.0.tgz#53ecf699ffcbcb39637691ab13baf160819766e5" + dependencies: + globby "^6.1.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + p-map "^1.1.1" + pify "^3.0.0" + rimraf "^2.2.8" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +depd@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" + +depd@~1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + +des.js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + dependencies: + repeating "^2.0.0" + +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + +detect-node@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.3.tgz#a2033c09cc8e158d37748fbde7507832bd6ce127" + +diffie-hellman@^5.0.0: + version "5.0.2" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e" + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dns-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + +dns-packet@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.1.tgz#12aa426981075be500b910eedcd0b47dd7deda5a" + dependencies: + ip "^1.1.0" + safe-buffer "^5.0.1" + +dns-txt@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" + dependencies: + buffer-indexof "^1.0.0" + +domain-browser@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + +duplexify@^3.4.2, duplexify@^3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.3.tgz#8b5818800df92fd0125b27ab896491912858243e" + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.30: + version "1.3.33" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.33.tgz#bf00703d62a7c65238136578c352d6c5c042a545" + +elliptic@^6.0.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + +encodeurl@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + dependencies: + once "^1.4.0" + +enhanced-resolve@^3.4.0: + version "3.4.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e" + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.4.0" + object-assign "^4.0.1" + tapable "^0.2.7" + +errno@^0.1.3, errno@^0.1.4: + version "0.1.6" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.6.tgz#c386ce8a6283f14fc09563b71560908c9bf53026" + dependencies: + prr "~1.0.1" + +error-ex@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.7.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.10.0.tgz#1ecb36c197842a00d8ee4c2dfd8646bb97d60864" + dependencies: + es-to-primitive "^1.1.1" + function-bind "^1.1.1" + has "^1.0.1" + is-callable "^1.1.3" + is-regex "^1.0.4" + +es-to-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" + dependencies: + is-callable "^1.1.1" + is-date-object "^1.0.1" + is-symbol "^1.0.1" + +es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: + version "0.10.38" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.38.tgz#fa7d40d65bbc9bb8a67e1d3f9cc656a00530eed3" + dependencies: + es6-iterator "~2.0.3" + es6-symbol "~3.1.1" + +es6-iterator@^2.0.1, es6-iterator@~2.0.1, es6-iterator@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-map@^0.1.3: + version "0.1.5" + resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" + dependencies: + d "1" + es5-ext "~0.10.14" + es6-iterator "~2.0.1" + es6-set "~0.1.5" + es6-symbol "~3.1.1" + event-emitter "~0.3.5" + +es6-set@~0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" + dependencies: + d "1" + es5-ext "~0.10.14" + es6-iterator "~2.0.1" + es6-symbol "3.1.1" + event-emitter "~0.3.5" + +es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" + dependencies: + d "1" + es5-ext "~0.10.14" + +es6-weak-map@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" + dependencies: + d "1" + es5-ext "^0.10.14" + es6-iterator "^2.0.1" + es6-symbol "^3.1.1" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +escope@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" + dependencies: + es6-map "^0.1.3" + es6-weak-map "^2.0.1" + esrecurse "^4.1.0" + estraverse "^4.1.1" + +esprima@^2.6.0: + version "2.7.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + +esprima@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" + +esrecurse@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163" + dependencies: + estraverse "^4.1.0" + object-assign "^4.0.1" + +estraverse@^4.1.0, estraverse@^4.1.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + +event-emitter@~0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + dependencies: + d "1" + es5-ext "~0.10.14" + +eventemitter3@1.x.x: + version "1.2.0" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" + +events@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + +eventsource@0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-0.1.6.tgz#0acede849ed7dd1ccc32c811bb11b944d4f29232" + dependencies: + original ">=0.0.5" + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + +express@^4.16.2: + version "4.16.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.16.2.tgz#e35c6dfe2d64b7dca0a5cd4f21781be3299e076c" + dependencies: + accepts "~1.3.4" + array-flatten "1.1.1" + body-parser "1.18.2" + content-disposition "0.5.2" + content-type "~1.0.4" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.1" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.1.0" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.2" + path-to-regexp "0.1.7" + proxy-addr "~2.0.2" + qs "6.5.1" + range-parser "~1.2.0" + safe-buffer "5.1.1" + send "0.16.1" + serve-static "1.13.1" + setprototypeof "1.1.0" + statuses "~1.3.1" + type-is "~1.6.15" + utils-merge "1.0.1" + vary "~1.1.2" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@~3.0.0, extend@~3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + +extglob@^2.0.2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extract-text-webpack-plugin@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extract-text-webpack-plugin/-/extract-text-webpack-plugin-3.0.2.tgz#5f043eaa02f9750a9258b78c0a6e0dc1408fb2f7" + dependencies: + async "^2.4.1" + loader-utils "^1.1.0" + schema-utils "^0.3.0" + webpack-sources "^1.0.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + +fast-deep-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + +fastparse@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8" + +faye-websocket@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + dependencies: + websocket-driver ">=0.5.1" + +faye-websocket@~0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.1.tgz#f0efe18c4f56e4f40afc7e06c719fd5ee6188f38" + dependencies: + websocket-driver ">=0.5.1" + +file-loader@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-1.1.6.tgz#7b9a8f2c58f00a77fddf49e940f7ac978a3ea0e8" + dependencies: + loader-utils "^1.0.2" + schema-utils "^0.3.0" + +filename-regex@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + +fill-range@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^1.1.3" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +finalhandler@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" + dependencies: + debug "2.6.9" + encodeurl "~1.0.1" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.2" + statuses "~1.3.1" + unpipe "~1.0.0" + +find-cache-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" + dependencies: + commondir "^1.0.1" + make-dir "^1.0.0" + pkg-dir "^2.0.0" + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +find-up@^2.0.0, find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + dependencies: + locate-path "^2.0.0" + +flatten@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" + +flush-write-stream@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.2.tgz#c81b90d8746766f1a609a46809946c45dd8ae417" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.4" + +for-in@^0.1.3: + version "0.1.8" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" + +for-in@^1.0.1, for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + +for-own@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + dependencies: + for-in "^1.0.1" + +for-own@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b" + dependencies: + for-in "^1.0.1" + +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~2.1.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +form-data@~2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.1.tgz#6fb94fbd71885306d73d15cc497fe4cc4ecd44bf" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + +from2@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-extra@^0.30.0: + version "0.30.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + klaw "^1.0.0" + path-is-absolute "^1.0.0" + rimraf "^2.2.8" + +fs-write-stream-atomic@^1.0.8: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8" + dependencies: + nan "^2.3.0" + node-pre-gyp "^0.6.39" + +fstream-ignore@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + dependencies: + fstream "^1.0.0" + inherits "2" + minimatch "^3.0.0" + +fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: + version "1.0.11" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +function-bind@^1.0.2, function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +gaze@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.2.tgz#847224677adb8870d679257ed3388fdb61e40105" + dependencies: + globule "^1.0.0" + +generate-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" + +generate-object-property@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + dependencies: + is-property "^1.0.0" + +get-caller-file@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" + +get-stdin@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob@^6.0.4: + version "6.0.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.2, glob@~7.1.1: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^9.18.0: + version "9.18.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + +globby@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" + dependencies: + array-union "^1.0.1" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +globule@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.0.tgz#1dc49c6822dd9e8a2fa00ba2a295006e8664bd09" + dependencies: + glob "~7.1.1" + lodash "~4.17.4" + minimatch "~3.0.2" + +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +handle-thing@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4" + +har-schema@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + +har-validator@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" + dependencies: + chalk "^1.1.1" + commander "^2.9.0" + is-my-json-valid "^2.12.4" + pinkie-promise "^2.0.0" + +har-validator@~4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" + dependencies: + ajv "^4.9.1" + har-schema "^1.0.5" + +har-validator@~5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" + dependencies: + ajv "^5.1.0" + har-schema "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + +has-flag@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" + dependencies: + function-bind "^1.0.2" + +hash-base@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1" + dependencies: + inherits "^2.0.1" + +hash-base@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.0" + +hawk@3.1.3, hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + +hawk@~6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" + dependencies: + boom "4.x.x" + cryptiles "3.x.x" + hoek "4.x.x" + sntp "2.x.x" + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +hoek@2.x.x: + version "2.16.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + +hoek@4.x.x: + version "4.2.0" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + +hosted-git-info@^2.1.4: + version "2.5.0" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +html-comment-regex@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e" + +html-entities@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" + +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + +http-errors@1.6.2, http-errors@~1.6.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" + dependencies: + depd "1.1.1" + inherits "2.0.3" + setprototypeof "1.0.3" + statuses ">= 1.3.1 < 2" + +http-parser-js@>=0.4.0: + version "0.4.10" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.10.tgz#92c9c1374c35085f75db359ec56cc257cbb93fa4" + +http-proxy-middleware@~0.17.4: + version "0.17.4" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.17.4.tgz#642e8848851d66f09d4f124912846dbaeb41b833" + dependencies: + http-proxy "^1.16.2" + is-glob "^3.1.0" + lodash "^4.17.2" + micromatch "^2.3.11" + +http-proxy@^1.16.2: + version "1.16.2" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742" + dependencies: + eventemitter3 "1.x.x" + requires-port "1.x.x" + +http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + +iconv-lite@0.4.19: + version "0.4.19" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" + +icss-replace-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" + +icss-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-2.1.0.tgz#83f0a0ec378bf3246178b6c2ad9136f135b1c962" + dependencies: + postcss "^6.0.1" + +ieee754@^1.1.4: + version "1.1.8" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" + +iferr@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + +import-local@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-1.0.0.tgz#5e4ffdc03f4fe6c009c6729beb29631c2f8227bc" + dependencies: + pkg-dir "^2.0.0" + resolve-cwd "^2.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +in-publish@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51" + +indent-string@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + dependencies: + repeating "^2.0.0" + +indexes-of@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + +ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + +internal-ip@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-1.2.0.tgz#ae9fbf93b984878785d50a8de1b356956058cf5c" + dependencies: + meow "^3.3.0" + +interpret@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" + +invariant@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" + dependencies: + loose-envify "^1.0.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + +ip@^1.1.0, ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + +ipaddr.js@1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.5.2.tgz#d4b505bde9946987ccf0fc58d9010ff9607e3fa0" + +is-absolute-url@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + dependencies: + kind-of "^6.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + +is-arrayish@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.1.tgz#c2dfc386abaa0c3e33c48db3fe87059e69065efd" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.0.2, is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + +is-builtin-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + dependencies: + builtin-modules "^1.0.0" + +is-callable@^1.1.1, is-callable@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-directory@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" + +is-dotfile@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" + dependencies: + is-extglob "^2.1.1" + +is-my-json-valid@^2.12.4: + version "2.17.1" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.17.1.tgz#3da98914a70a22f0a8563ef1511a246c6fc55471" + dependencies: + generate-function "^2.0.0" + generate-object-property "^1.1.0" + jsonpointer "^4.0.0" + xtend "^4.0.0" + +is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + dependencies: + kind-of "^3.0.2" + +is-odd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-1.0.0.tgz#3b8a932eb028b3775c39bb09e91767accdb69088" + dependencies: + is-number "^3.0.0" + +is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + +is-path-in-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" + dependencies: + is-path-inside "^1.0.0" + +is-path-inside@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" + dependencies: + path-is-inside "^1.0.1" + +is-plain-obj@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + dependencies: + isobject "^3.0.1" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + +is-property@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + +is-regex@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + dependencies: + has "^1.0.1" + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-svg@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.1.0.tgz#cf61090da0d9efbcab8722deba6f032208dbb0e9" + dependencies: + html-comment-regex "^1.1.0" + +is-symbol@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + +isnumeric@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/isnumeric/-/isnumeric-0.2.0.tgz#a2347ba360de19e33d0ffd590fddf7755cbf2e64" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +js-base64@^2.1.8, js-base64@^2.1.9: + version "2.4.3" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.3.tgz#2e545ec2b0f2957f41356510205214e98fad6582" + +js-tokens@^3.0.0, js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + +js-yaml@^3.10.0, js-yaml@^3.4.3: + version "3.10.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@~3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" + dependencies: + argparse "^1.0.7" + esprima "^2.6.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + +json-loader@^0.5.4: + version "0.5.7" + resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.7.tgz#dca14a70235ff82f0ac9a3abeb60d337a365185d" + +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +json3@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" + +json5@^0.5.0, json5@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + +jsonfile@^2.1.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + +jsonpointer@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +killable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.0.tgz#da8b84bd47de5395878f95d64d02f2449fe05e6b" + +kind-of@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-2.0.1.tgz#018ec7a4ce7e3a86cb9141be519d24c8faa981b5" + dependencies: + is-buffer "^1.0.2" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0, kind-of@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0, kind-of@^5.0.2: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + +klaw@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + optionalDependencies: + graceful-fs "^4.1.9" + +lazy-cache@^0.2.3: + version "0.2.7" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-0.2.7.tgz#7feddf2dcb6edb77d11ef1d117ab5ffdf0ab1b65" + +lazy-cache@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + +lazy-cache@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-2.0.2.tgz#b9190a4f913354694840859f8a8f7084d8822264" + dependencies: + set-getter "^0.1.0" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + dependencies: + invert-kv "^1.0.0" + +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + +loader-runner@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" + +loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" + dependencies: + big.js "^3.1.3" + emojis-list "^2.0.0" + json5 "^0.5.0" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +lodash._reinterpolate@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + +lodash.assign@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + +lodash.clonedeep@^4.3.2: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + +lodash.mergewith@^4.6.0: + version "4.6.1" + resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927" + +lodash.tail@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664" + +lodash.template@^4.2.4: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" + dependencies: + lodash._reinterpolate "~3.0.0" + lodash.templatesettings "^4.0.0" + +lodash.templatesettings@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" + dependencies: + lodash._reinterpolate "~3.0.0" + +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + +lodash@3.x: + version "3.10.1" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" + +"lodash@>=3.5 <5", lodash@^4.0.0, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.4, lodash@~4.17.4: + version "4.17.5" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" + +loglevel@^1.4.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.1.tgz#e0fc95133b6ef276cdc8887cdaf24aa6f156f8fa" + +longest@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + +loose-envify@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + dependencies: + js-tokens "^3.0.0" + +loud-rejection@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + dependencies: + currently-unhandled "^0.4.1" + signal-exit "^3.0.0" + +lru-cache@^4.0.1, lru-cache@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55" + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +macaddress@^0.2.8: + version "0.2.8" + resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12" + +make-dir@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.1.0.tgz#19b4369fe48c116f53c2af95ad102c0e39e85d51" + dependencies: + pify "^3.0.0" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + +map-obj@^1.0.0, map-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + dependencies: + object-visit "^1.0.0" + +math-expression-evaluator@^1.2.14: + version "1.2.17" + resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz#de819fdbcd84dccd8fae59c6aeb79615b9d266ac" + +md5.js@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +mem@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" + dependencies: + mimic-fn "^1.0.0" + +memory-fs@^0.4.0, memory-fs@~0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +meow@^3.3.0, meow@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + dependencies: + camelcase-keys "^2.0.0" + decamelize "^1.1.2" + loud-rejection "^1.0.0" + map-obj "^1.0.1" + minimist "^1.1.3" + normalize-package-data "^2.3.4" + object-assign "^4.0.1" + read-pkg-up "^1.0.1" + redent "^1.0.0" + trim-newlines "^1.0.0" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + +micromatch@^2.1.5, micromatch@^2.3.11: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +micromatch@^3.1.4: + version "3.1.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.5.tgz#d05e168c206472dfbca985bfef4f57797b4cd4ba" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.0" + define-property "^1.0.0" + extend-shallow "^2.0.1" + extglob "^2.0.2" + fragment-cache "^0.2.1" + kind-of "^6.0.0" + nanomatch "^1.2.5" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +"mime-db@>= 1.30.0 < 2": + version "1.32.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.32.0.tgz#485b3848b01a3cda5f968b4882c0771e58e09414" + +mime-db@~1.30.0: + version "1.30.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" + +mime-types@^2.1.12, mime-types@~2.1.15, mime-types@~2.1.16, mime-types@~2.1.17, mime-types@~2.1.7: + version "2.1.17" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" + dependencies: + mime-db "~1.30.0" + +mime@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + +mime@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + +minimalistic-assert@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@^1.1.3, minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +mississippi@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-1.3.1.tgz#2a8bb465e86550ac8b36a7b6f45599171d78671e" + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^1.0.0" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mixin-deep@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mixin-object@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mixin-object/-/mixin-object-2.0.1.tgz#4fb949441dab182540f1fe035ba60e1947a5e57e" + dependencies: + for-in "^0.1.3" + is-extendable "^0.1.1" + +mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +move-concurrently@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + dependencies: + aproba "^1.1.1" + copy-concurrently "^1.0.0" + fs-write-stream-atomic "^1.0.8" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.3" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +multicast-dns-service-types@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" + +multicast-dns@^6.0.1: + version "6.2.3" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229" + dependencies: + dns-packet "^1.3.1" + thunky "^1.0.2" + +nan@^2.3.0, nan@^2.3.2: + version "2.8.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a" + +nanomatch@^1.2.5: + version "1.2.7" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.7.tgz#53cd4aa109ff68b7f869591fdc9d10daeeea3e79" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^1.0.0" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + is-odd "^1.0.0" + kind-of "^5.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + +node-forge@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.1.tgz#9da611ea08982f4b94206b3beb4cc9665f20c300" + +node-gyp@^3.3.1: + version "3.6.2" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.6.2.tgz#9bfbe54562286284838e750eac05295853fa1c60" + dependencies: + fstream "^1.0.0" + glob "^7.0.3" + graceful-fs "^4.1.2" + minimatch "^3.0.2" + mkdirp "^0.5.0" + nopt "2 || 3" + npmlog "0 || 1 || 2 || 3 || 4" + osenv "0" + request "2" + rimraf "2" + semver "~5.3.0" + tar "^2.0.0" + which "1" + +node-libs-browser@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df" + dependencies: + assert "^1.1.1" + browserify-zlib "^0.2.0" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^1.0.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "0.0.0" + process "^0.11.10" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.3.3" + stream-browserify "^2.0.1" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.10.3" + vm-browserify "0.0.4" + +node-pre-gyp@^0.6.39: + version "0.6.39" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649" + dependencies: + detect-libc "^1.0.2" + hawk "3.1.3" + mkdirp "^0.5.1" + nopt "^4.0.1" + npmlog "^4.0.2" + rc "^1.1.7" + request "2.81.0" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^2.2.1" + tar-pack "^3.4.0" + +node-sass@^4.7.2: + version "4.7.2" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.7.2.tgz#9366778ba1469eb01438a9e8592f4262bcb6794e" + dependencies: + async-foreach "^0.1.3" + chalk "^1.1.1" + cross-spawn "^3.0.0" + gaze "^1.0.0" + get-stdin "^4.0.1" + glob "^7.0.3" + in-publish "^2.0.0" + lodash.assign "^4.2.0" + lodash.clonedeep "^4.3.2" + lodash.mergewith "^4.6.0" + meow "^3.7.0" + mkdirp "^0.5.1" + nan "^2.3.2" + node-gyp "^3.3.1" + npmlog "^4.0.0" + request "~2.79.0" + sass-graph "^2.2.4" + stdout-stream "^1.4.0" + "true-case-path" "^1.0.2" + +"nopt@2 || 3": + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + dependencies: + abbrev "1" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: + version "2.4.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + +normalize-url@^1.4.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c" + dependencies: + object-assign "^4.0.1" + prepend-http "^1.0.0" + query-string "^4.1.0" + sort-keys "^1.0.0" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + dependencies: + path-key "^2.0.0" + +"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +oauth-sign@~0.8.1, oauth-sign@~0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-keys@^1.0.8: + version "1.0.11" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + dependencies: + isobject "^3.0.0" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + dependencies: + isobject "^3.0.1" + +obuf@^1.0.0, obuf@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.1.tgz#104124b6c602c6796881a042541d36db43a5264e" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + +once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +onecolor@^3.0.4: + version "3.0.5" + resolved "https://registry.yarnpkg.com/onecolor/-/onecolor-3.0.5.tgz#36eff32201379efdf1180fb445e51a8e2425f9f6" + +opn@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.2.0.tgz#71fdf934d6827d676cecbea1531f95d354641225" + dependencies: + is-wsl "^1.1.0" + +original@>=0.0.5: + version "1.0.0" + resolved "https://registry.yarnpkg.com/original/-/original-1.0.0.tgz#9147f93fa1696d04be61e01bd50baeaca656bd3b" + dependencies: + url-parse "1.0.x" + +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + +os-homedir@^1.0.0, os-homedir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + dependencies: + lcid "^1.0.0" + +os-locale@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" + dependencies: + execa "^0.7.0" + lcid "^1.0.0" + mem "^1.1.0" + +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +osenv@0, osenv@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + +p-limit@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.2.0.tgz#0e92b6bedcb59f022c13d0f1949dc82d15909f1c" + dependencies: + p-try "^1.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + dependencies: + p-limit "^1.1.0" + +p-map@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + +pako@~1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" + +parallel-transform@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06" + dependencies: + cyclist "~0.2.2" + inherits "^2.0.3" + readable-stream "^2.1.5" + +parse-asn1@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712" + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + dependencies: + error-ex "^1.2.0" + +parseurl@~1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + +path-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" + +path-complete-extname@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/path-complete-extname/-/path-complete-extname-0.1.0.tgz#c454702669f31452f8193aa6168915fa31692f4a" + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + dependencies: + pinkie-promise "^2.0.0" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + +path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-is-inside@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + +path-key@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + +path-parse@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + dependencies: + pify "^2.0.0" + +pbkdf2@^3.0.3: + version "3.0.14" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.14.tgz#a35e13c64799b06ce15320f459c230e68e73bade" + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +performance-now@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + +pify@^2.0.0, pify@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +pixrem@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pixrem/-/pixrem-4.0.1.tgz#2da4a1de6ec4423c5fc3794e930b81d4490ec686" + dependencies: + browserslist "^2.0.0" + postcss "^6.0.0" + reduce-css-calc "^1.2.7" + +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + dependencies: + find-up "^2.1.0" + +pleeease-filters@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/pleeease-filters/-/pleeease-filters-4.0.0.tgz#6632b2fb05648d2758d865384fbced79e1ccaec7" + dependencies: + onecolor "^3.0.4" + postcss "^6.0.1" + +portfinder@^1.0.9: + version "1.0.13" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" + dependencies: + async "^1.5.2" + debug "^2.2.0" + mkdirp "0.5.x" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + +postcss-apply@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/postcss-apply/-/postcss-apply-0.8.0.tgz#14e544bbb5cb6f1c1e048857965d79ae066b1343" + dependencies: + babel-runtime "^6.23.0" + balanced-match "^0.4.2" + postcss "^6.0.0" + +postcss-attribute-case-insensitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-2.0.0.tgz#94dc422c8f90997f16bd33a3654bbbec084963b4" + dependencies: + postcss "^6.0.0" + postcss-selector-parser "^2.2.3" + +postcss-calc@^5.2.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e" + dependencies: + postcss "^5.0.2" + postcss-message-helpers "^2.0.0" + reduce-css-calc "^1.2.6" + +postcss-calc@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-6.0.1.tgz#3d24171bbf6e7629d422a436ebfe6dd9511f4330" + dependencies: + css-unit-converter "^1.1.1" + postcss "^6.0.0" + postcss-selector-parser "^2.2.2" + reduce-css-calc "^2.0.0" + +postcss-color-function@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-color-function/-/postcss-color-function-4.0.1.tgz#402b3f2cebc3f6947e618fb6be3654fbecef6444" + dependencies: + css-color-function "~1.3.3" + postcss "^6.0.1" + postcss-message-helpers "^2.0.0" + postcss-value-parser "^3.3.0" + +postcss-color-gray@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/postcss-color-gray/-/postcss-color-gray-4.1.0.tgz#e5581ed57eaa826fb652ca11b1e2b7b136a9f9df" + dependencies: + color "^2.0.1" + postcss "^6.0.14" + postcss-message-helpers "^2.0.0" + reduce-function-call "^1.0.2" + +postcss-color-hex-alpha@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-color-hex-alpha/-/postcss-color-hex-alpha-3.0.0.tgz#1e53e6c8acb237955e8fd08b7ecdb1b8b8309f95" + dependencies: + color "^1.0.3" + postcss "^6.0.1" + postcss-message-helpers "^2.0.0" + +postcss-color-hsl@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-color-hsl/-/postcss-color-hsl-2.0.0.tgz#12703666fa310430e3f30a454dac1386317d5844" + dependencies: + postcss "^6.0.1" + postcss-value-parser "^3.3.0" + units-css "^0.4.0" + +postcss-color-hwb@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-color-hwb/-/postcss-color-hwb-3.0.0.tgz#3402b19ef4d8497540c1fb5072be9863ca95571e" + dependencies: + color "^1.0.3" + postcss "^6.0.1" + postcss-message-helpers "^2.0.0" + reduce-function-call "^1.0.2" + +postcss-color-rebeccapurple@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-3.0.0.tgz#eebaf03d363b4300b96792bd3081c19ed66513d3" + dependencies: + postcss "^6.0.1" + postcss-value-parser "^3.3.0" + +postcss-color-rgb@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-color-rgb/-/postcss-color-rgb-2.0.0.tgz#14539c8a7131494b482e0dd1cc265ff6514b5263" + dependencies: + postcss "^6.0.1" + postcss-value-parser "^3.3.0" + +postcss-color-rgba-fallback@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-color-rgba-fallback/-/postcss-color-rgba-fallback-3.0.0.tgz#37d5c9353a07a09270912a82606bb42a0d702c04" + dependencies: + postcss "^6.0.6" + postcss-value-parser "^3.3.0" + rgb-hex "^2.1.0" + +postcss-colormin@^2.1.8: + version "2.2.2" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-2.2.2.tgz#6631417d5f0e909a3d7ec26b24c8a8d1e4f96e4b" + dependencies: + colormin "^1.0.5" + postcss "^5.0.13" + postcss-value-parser "^3.2.3" + +postcss-convert-values@^2.3.4: + version "2.6.1" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz#bbd8593c5c1fd2e3d1c322bb925dcae8dae4d62d" + dependencies: + postcss "^5.0.11" + postcss-value-parser "^3.1.2" + +postcss-cssnext@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/postcss-cssnext/-/postcss-cssnext-3.1.0.tgz#927dc29341a938254cde38ea60a923b9dfedead9" + dependencies: + autoprefixer "^7.1.1" + caniuse-api "^2.0.0" + chalk "^2.0.1" + pixrem "^4.0.0" + pleeease-filters "^4.0.0" + postcss "^6.0.5" + postcss-apply "^0.8.0" + postcss-attribute-case-insensitive "^2.0.0" + postcss-calc "^6.0.0" + postcss-color-function "^4.0.0" + postcss-color-gray "^4.0.0" + postcss-color-hex-alpha "^3.0.0" + postcss-color-hsl "^2.0.0" + postcss-color-hwb "^3.0.0" + postcss-color-rebeccapurple "^3.0.0" + postcss-color-rgb "^2.0.0" + postcss-color-rgba-fallback "^3.0.0" + postcss-custom-media "^6.0.0" + postcss-custom-properties "^6.1.0" + postcss-custom-selectors "^4.0.1" + postcss-font-family-system-ui "^3.0.0" + postcss-font-variant "^3.0.0" + postcss-image-set-polyfill "^0.3.5" + postcss-initial "^2.0.0" + postcss-media-minmax "^3.0.0" + postcss-nesting "^4.0.1" + postcss-pseudo-class-any-link "^4.0.0" + postcss-pseudoelements "^5.0.0" + postcss-replace-overflow-wrap "^2.0.0" + postcss-selector-matches "^3.0.1" + postcss-selector-not "^3.0.1" + +postcss-custom-media@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-6.0.0.tgz#be532784110ecb295044fb5395a18006eb21a737" + dependencies: + postcss "^6.0.1" + +postcss-custom-properties@^6.1.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-6.2.0.tgz#5d929a7f06e9b84e0f11334194c0ba9a30acfbe9" + dependencies: + balanced-match "^1.0.0" + postcss "^6.0.13" + +postcss-custom-selectors@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-4.0.1.tgz#781382f94c52e727ef5ca4776ea2adf49a611382" + dependencies: + postcss "^6.0.1" + postcss-selector-matches "^3.0.0" + +postcss-discard-comments@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz#befe89fafd5b3dace5ccce51b76b81514be00e3d" + dependencies: + postcss "^5.0.14" + +postcss-discard-duplicates@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz#b9abf27b88ac188158a5eb12abcae20263b91932" + dependencies: + postcss "^5.0.4" + +postcss-discard-empty@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz#d2b4bd9d5ced5ebd8dcade7640c7d7cd7f4f92b5" + dependencies: + postcss "^5.0.14" + +postcss-discard-overridden@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz#8b1eaf554f686fb288cd874c55667b0aa3668d58" + dependencies: + postcss "^5.0.16" + +postcss-discard-unused@^2.2.1: + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz#bce30b2cc591ffc634322b5fb3464b6d934f4433" + dependencies: + postcss "^5.0.14" + uniqs "^2.0.0" + +postcss-filter-plugins@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz#6d85862534d735ac420e4a85806e1f5d4286d84c" + dependencies: + postcss "^5.0.4" + uniqid "^4.0.0" + +postcss-font-family-system-ui@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-font-family-system-ui/-/postcss-font-family-system-ui-3.0.0.tgz#675fe7a9e029669f05f8dba2e44c2225ede80623" + dependencies: + postcss "^6.0" + +postcss-font-variant@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-font-variant/-/postcss-font-variant-3.0.0.tgz#08ccc88f6050ba82ed8ef2cc76c0c6a6b41f183e" + dependencies: + postcss "^6.0.1" + +postcss-image-set-polyfill@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/postcss-image-set-polyfill/-/postcss-image-set-polyfill-0.3.5.tgz#0f193413700cf1f82bd39066ef016d65a4a18181" + dependencies: + postcss "^6.0.1" + postcss-media-query-parser "^0.2.3" + +postcss-import@^11.0.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-11.1.0.tgz#55c9362c9192994ec68865d224419df1db2981f0" + dependencies: + postcss "^6.0.1" + postcss-value-parser "^3.2.3" + read-cache "^1.0.0" + resolve "^1.1.7" + +postcss-initial@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-initial/-/postcss-initial-2.0.0.tgz#72715f7336e0bb79351d99ee65c4a253a8441ba4" + dependencies: + lodash.template "^4.2.4" + postcss "^6.0.1" + +postcss-load-config@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-1.2.0.tgz#539e9afc9ddc8620121ebf9d8c3673e0ce50d28a" + dependencies: + cosmiconfig "^2.1.0" + object-assign "^4.1.0" + postcss-load-options "^1.2.0" + postcss-load-plugins "^2.3.0" + +postcss-load-options@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postcss-load-options/-/postcss-load-options-1.2.0.tgz#b098b1559ddac2df04bc0bb375f99a5cfe2b6d8c" + dependencies: + cosmiconfig "^2.1.0" + object-assign "^4.1.0" + +postcss-load-plugins@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/postcss-load-plugins/-/postcss-load-plugins-2.3.0.tgz#745768116599aca2f009fad426b00175049d8d92" + dependencies: + cosmiconfig "^2.1.1" + object-assign "^4.1.0" + +postcss-loader@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-2.1.0.tgz#038c2d6d59753fef4667827fd3ae03f5dc5e6a7a" + dependencies: + loader-utils "^1.1.0" + postcss "^6.0.0" + postcss-load-config "^1.2.0" + schema-utils "^0.4.0" + +postcss-media-minmax@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-media-minmax/-/postcss-media-minmax-3.0.0.tgz#675256037a43ef40bc4f0760bfd06d4dc69d48d2" + dependencies: + postcss "^6.0.1" + +postcss-media-query-parser@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244" + +postcss-merge-idents@^2.1.5: + version "2.1.7" + resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz#4c5530313c08e1d5b3bbf3d2bbc747e278eea270" + dependencies: + has "^1.0.1" + postcss "^5.0.10" + postcss-value-parser "^3.1.1" + +postcss-merge-longhand@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz#23d90cd127b0a77994915332739034a1a4f3d658" + dependencies: + postcss "^5.0.4" + +postcss-merge-rules@^2.0.3: + version "2.1.2" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz#d1df5dfaa7b1acc3be553f0e9e10e87c61b5f721" + dependencies: + browserslist "^1.5.2" + caniuse-api "^1.5.2" + postcss "^5.0.4" + postcss-selector-parser "^2.2.2" + vendors "^1.0.0" + +postcss-message-helpers@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e" + +postcss-minify-font-values@^1.0.2: + version "1.0.5" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz#4b58edb56641eba7c8474ab3526cafd7bbdecb69" + dependencies: + object-assign "^4.0.1" + postcss "^5.0.4" + postcss-value-parser "^3.0.2" + +postcss-minify-gradients@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz#5dbda11373703f83cfb4a3ea3881d8d75ff5e6e1" + dependencies: + postcss "^5.0.12" + postcss-value-parser "^3.3.0" + +postcss-minify-params@^1.0.4: + version "1.2.2" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz#ad2ce071373b943b3d930a3fa59a358c28d6f1f3" + dependencies: + alphanum-sort "^1.0.1" + postcss "^5.0.2" + postcss-value-parser "^3.0.2" + uniqs "^2.0.0" + +postcss-minify-selectors@^2.0.4: + version "2.1.1" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz#b2c6a98c0072cf91b932d1a496508114311735bf" + dependencies: + alphanum-sort "^1.0.2" + has "^1.0.1" + postcss "^5.0.14" + postcss-selector-parser "^2.0.0" + +postcss-modules-extract-imports@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz#66140ecece38ef06bf0d3e355d69bf59d141ea85" + dependencies: + postcss "^6.0.1" + +postcss-modules-local-by-default@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz#f7d80c398c5a393fa7964466bd19500a7d61c069" + dependencies: + css-selector-tokenizer "^0.7.0" + postcss "^6.0.1" + +postcss-modules-scope@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz#d6ea64994c79f97b62a72b426fbe6056a194bb90" + dependencies: + css-selector-tokenizer "^0.7.0" + postcss "^6.0.1" + +postcss-modules-values@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz#ecffa9d7e192518389f42ad0e83f72aec456ea20" + dependencies: + icss-replace-symbols "^1.1.0" + postcss "^6.0.1" + +postcss-nesting@^4.0.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-4.2.1.tgz#0483bce338b3f0828ced90ff530b29b98b00300d" + dependencies: + postcss "^6.0.11" + +postcss-normalize-charset@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz#ef9ee71212d7fe759c78ed162f61ed62b5cb93f1" + dependencies: + postcss "^5.0.5" + +postcss-normalize-url@^3.0.7: + version "3.0.8" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz#108f74b3f2fcdaf891a2ffa3ea4592279fc78222" + dependencies: + is-absolute-url "^2.0.0" + normalize-url "^1.4.0" + postcss "^5.0.14" + postcss-value-parser "^3.2.3" + +postcss-ordered-values@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz#eec6c2a67b6c412a8db2042e77fe8da43f95c11d" + dependencies: + postcss "^5.0.4" + postcss-value-parser "^3.0.1" + +postcss-pseudo-class-any-link@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-4.0.0.tgz#9152a0613d3450720513e8892854bae42d0ee68e" + dependencies: + postcss "^6.0.1" + postcss-selector-parser "^2.2.3" + +postcss-pseudoelements@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-pseudoelements/-/postcss-pseudoelements-5.0.0.tgz#eef194e8d524645ca520a949e95e518e812402cb" + dependencies: + postcss "^6.0.0" + +postcss-reduce-idents@^2.2.2: + version "2.4.0" + resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz#c2c6d20cc958284f6abfbe63f7609bf409059ad3" + dependencies: + postcss "^5.0.4" + postcss-value-parser "^3.0.2" + +postcss-reduce-initial@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz#68f80695f045d08263a879ad240df8dd64f644ea" + dependencies: + postcss "^5.0.4" + +postcss-reduce-transforms@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz#ff76f4d8212437b31c298a42d2e1444025771ae1" + dependencies: + has "^1.0.1" + postcss "^5.0.8" + postcss-value-parser "^3.0.1" + +postcss-replace-overflow-wrap@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-2.0.0.tgz#794db6faa54f8db100854392a93af45768b4e25b" + dependencies: + postcss "^6.0.1" + +postcss-selector-matches@^3.0.0, postcss-selector-matches@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/postcss-selector-matches/-/postcss-selector-matches-3.0.1.tgz#e5634011e13950881861bbdd58c2d0111ffc96ab" + dependencies: + balanced-match "^0.4.2" + postcss "^6.0.1" + +postcss-selector-not@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-3.0.1.tgz#2e4db2f0965336c01e7cec7db6c60dff767335d9" + dependencies: + balanced-match "^0.4.2" + postcss "^6.0.1" + +postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.2.2, postcss-selector-parser@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz#f9437788606c3c9acee16ffe8d8b16297f27bb90" + dependencies: + flatten "^1.0.2" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-svgo@^2.1.1: + version "2.1.6" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-2.1.6.tgz#b6df18aa613b666e133f08adb5219c2684ac108d" + dependencies: + is-svg "^2.0.0" + postcss "^5.0.14" + postcss-value-parser "^3.2.3" + svgo "^0.7.0" + +postcss-unique-selectors@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz#981d57d29ddcb33e7b1dfe1fd43b8649f933ca1d" + dependencies: + alphanum-sort "^1.0.1" + postcss "^5.0.4" + uniqs "^2.0.0" + +postcss-value-parser@^3.0.1, postcss-value-parser@^3.0.2, postcss-value-parser@^3.1.1, postcss-value-parser@^3.1.2, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15" + +postcss-zindex@^2.0.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-2.2.0.tgz#d2109ddc055b91af67fc4cb3b025946639d2af22" + dependencies: + has "^1.0.1" + postcss "^5.0.4" + uniqs "^2.0.0" + +postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.2.16: + version "5.2.18" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.18.tgz#badfa1497d46244f6390f58b319830d9107853c5" + dependencies: + chalk "^1.1.3" + js-base64 "^2.1.9" + source-map "^0.5.6" + supports-color "^3.2.3" + +postcss@^6.0, postcss@^6.0.0, postcss@^6.0.1, postcss@^6.0.11, postcss@^6.0.13, postcss@^6.0.14, postcss@^6.0.17, postcss@^6.0.5, postcss@^6.0.6: + version "6.0.17" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.17.tgz#e259a051ca513f81e9afd0c21f7f82eda50c65c5" + dependencies: + chalk "^2.3.0" + source-map "^0.6.1" + supports-color "^5.1.0" + +prepend-http@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + +private@^0.1.6, private@^0.1.7: + version "0.1.8" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + +process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + +proxy-addr@~2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.2.tgz#6571504f47bb988ec8180253f85dd7e14952bdec" + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.5.2" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +public-encrypt@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6" + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + +pump@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954" + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.4.0" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.4.0.tgz#80b7c5df7e24153d03f0e7ac8a05a5d068bd07fb" + dependencies: + duplexify "^3.5.3" + inherits "^2.0.3" + pump "^2.0.0" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + +punycode@^1.2.4, punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +q@^1.1.2: + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + +qs@6.5.1, qs@~6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" + +qs@~6.3.0: + version "6.3.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c" + +qs@~6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" + +query-string@^4.1.0: + version "4.3.4" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" + dependencies: + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + +querystringify@0.0.x: + version "0.0.4" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-0.0.4.tgz#0cf7f84f9463ff0ae51c4c4b142d95be37724d9c" + +querystringify@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-1.0.0.tgz#6286242112c5b712fa654e526652bf6a13ff05cb" + +randomatic@^1.1.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.3.tgz#b96b7df587f01dd91726c418f30553b1418e3d62" + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +range-parser@^1.0.3, range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + +raw-body@2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" + dependencies: + bytes "3.0.0" + http-errors "1.6.2" + iconv-lite "0.4.19" + unpipe "1.0.0" + +rc@^1.1.7: + version "1.2.5" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.5.tgz#275cd687f6e3b36cc756baa26dfee80a790301fd" + dependencies: + deep-extend "~0.4.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +read-cache@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" + dependencies: + pify "^2.3.0" + +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.3: + version "2.3.4" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.4.tgz#c946c3f47fa7d8eabc0b6150f4a12f69a4574071" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.0.3" + util-deprecate "~1.0.1" + +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + +redent@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + dependencies: + indent-string "^2.1.0" + strip-indent "^1.0.1" + +reduce-css-calc@^1.2.6, reduce-css-calc@^1.2.7: + version "1.3.0" + resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716" + dependencies: + balanced-match "^0.4.2" + math-expression-evaluator "^1.2.14" + reduce-function-call "^1.0.1" + +reduce-css-calc@^2.0.0: + version "2.1.4" + resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-2.1.4.tgz#c20e9cda8445ad73d4ff4bea960c6f8353791708" + dependencies: + css-unit-converter "^1.1.1" + postcss-value-parser "^3.3.0" + +reduce-function-call@^1.0.1, reduce-function-call@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.2.tgz#5a200bf92e0e37751752fe45b0ab330fd4b6be99" + dependencies: + balanced-match "^0.4.2" + +regenerate@^1.2.1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f" + +regenerator-runtime@^0.10.5: + version "0.10.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + +regenerator-transform@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" + dependencies: + babel-runtime "^6.18.0" + babel-types "^6.19.0" + private "^0.1.6" + +regex-cache@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" + dependencies: + is-equal-shallow "^0.1.3" + +regex-not@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.0.tgz#42f83e39771622df826b02af176525d6a5f157f9" + dependencies: + extend-shallow "^2.0.1" + +regexpu-core@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + dependencies: + jsesc "~0.5.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.5.2, repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + +request@2: + version "2.83.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.6.0" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.1" + forever-agent "~0.6.1" + form-data "~2.3.1" + har-validator "~5.0.3" + hawk "~6.0.2" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.17" + oauth-sign "~0.8.2" + performance-now "^2.1.0" + qs "~6.5.1" + safe-buffer "^5.1.1" + stringstream "~0.0.5" + tough-cookie "~2.3.3" + tunnel-agent "^0.6.0" + uuid "^3.1.0" + +request@2.81.0: + version "2.81.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~4.2.1" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + performance-now "^0.2.0" + qs "~6.4.0" + safe-buffer "^5.0.1" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "^0.6.0" + uuid "^3.0.0" + +request@~2.79.0: + version "2.79.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~2.0.6" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + qs "~6.3.0" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "~0.4.1" + uuid "^3.0.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + +require-from-string@^1.1.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-1.2.1.tgz#529c9ccef27380adfec9a2f965b649bbee636418" + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + +requires-port@1.0.x, requires-port@1.x.x, requires-port@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + +resolve-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + dependencies: + resolve-from "^3.0.0" + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + +resolve@^1.1.7: + version "1.5.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" + dependencies: + path-parse "^1.0.5" + +rgb-hex@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/rgb-hex/-/rgb-hex-2.1.0.tgz#c773c5fe2268a25578d92539a82a7a5ce53beda6" + +rgb@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/rgb/-/rgb-0.1.0.tgz#be27b291e8feffeac1bd99729721bfa40fc037b5" + +right-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + dependencies: + align-text "^0.1.1" + +rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.5.4, rimraf@^2.6.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + dependencies: + glob "^7.0.5" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7" + dependencies: + hash-base "^2.0.0" + inherits "^2.0.1" + +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + dependencies: + aproba "^1.1.1" + +safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" + +sass-graph@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49" + dependencies: + glob "^7.0.0" + lodash "^4.0.0" + scss-tokenizer "^0.2.3" + yargs "^7.0.0" + +sass-loader@^6.0.6: + version "6.0.6" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-6.0.6.tgz#e9d5e6c1f155faa32a4b26d7a9b7107c225e40f9" + dependencies: + async "^2.1.5" + clone-deep "^0.3.0" + loader-utils "^1.0.1" + lodash.tail "^4.1.1" + pify "^3.0.0" + +sax@~1.2.1: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + +schema-utils@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.3.0.tgz#f5877222ce3e931edae039f17eb3716e7137f8cf" + dependencies: + ajv "^5.0.0" + +schema-utils@^0.4.0, schema-utils@^0.4.2, schema-utils@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.3.tgz#e2a594d3395834d5e15da22b48be13517859458e" + dependencies: + ajv "^5.0.0" + ajv-keywords "^2.1.0" + +scss-tokenizer@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1" + dependencies: + js-base64 "^2.1.8" + source-map "^0.4.2" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + +selfsigned@^1.9.1: + version "1.10.2" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.2.tgz#b4449580d99929b65b10a48389301a6592088758" + dependencies: + node-forge "0.7.1" + +"semver@2 || 3 || 4 || 5", semver@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + +semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + +send@0.16.1: + version "0.16.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.16.1.tgz#a70e1ca21d1382c11d0d9f6231deb281080d7ab3" + dependencies: + debug "2.6.9" + depd "~1.1.1" + destroy "~1.0.4" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.6.2" + mime "1.4.1" + ms "2.0.0" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.3.1" + +serialize-javascript@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.4.0.tgz#7c958514db6ac2443a8abc062dc9f7886a7f6005" + +serve-index@^1.7.2: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + dependencies: + accepts "~1.3.4" + batch "0.6.1" + debug "2.6.9" + escape-html "~1.0.3" + http-errors "~1.6.2" + mime-types "~2.1.17" + parseurl "~1.3.2" + +serve-static@1.13.1: + version "1.13.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.1.tgz#4c57d53404a761d8f2e7c1e8a18a47dbf278a719" + dependencies: + encodeurl "~1.0.1" + escape-html "~1.0.3" + parseurl "~1.3.2" + send "0.16.1" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-getter@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/set-getter/-/set-getter-0.1.0.tgz#d769c182c9d5a51f409145f2fba82e5e86e80376" + dependencies: + to-object-path "^0.3.0" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +set-value@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.1" + to-object-path "^0.3.0" + +set-value@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + +setprototypeof@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.10" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.10.tgz#b1fde5cd7d11a5626638a07c604ab909cfa31f9b" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shallow-clone@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-0.1.2.tgz#5909e874ba77106d73ac414cfec1ffca87d97060" + dependencies: + is-extendable "^0.1.1" + kind-of "^2.0.1" + lazy-cache "^0.2.3" + mixin-object "^2.0.1" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + +signal-exit@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + dependencies: + is-arrayish "^0.3.1" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.1.tgz#e12b5487faded3e3dea0ac91e9400bf75b401370" + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^2.0.0" + +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + +sntp@2.x.x: + version "2.1.0" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8" + dependencies: + hoek "4.x.x" + +sockjs-client@1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.1.4.tgz#5babe386b775e4cf14e7520911452654016c8b12" + dependencies: + debug "^2.6.6" + eventsource "0.1.6" + faye-websocket "~0.11.0" + inherits "^2.0.1" + json3 "^3.3.2" + url-parse "^1.1.8" + +sockjs@0.3.19: + version "0.3.19" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.19.tgz#d976bbe800af7bd20ae08598d582393508993c0d" + dependencies: + faye-websocket "^0.10.0" + uuid "^3.0.1" + +sort-keys@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" + dependencies: + is-plain-obj "^1.0.0" + +source-list-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" + +source-map-resolve@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.1.tgz#7ad0f593f2281598e854df80f19aae4b92d7a11a" + dependencies: + atob "^2.0.0" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@^0.4.15: + version "0.4.18" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + dependencies: + source-map "^0.5.6" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + +source-map@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + dependencies: + amdefine ">=0.0.4" + +source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + +source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + +spdx-correct@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" + dependencies: + spdx-license-ids "^1.0.2" + +spdx-expression-parse@~1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" + +spdx-license-ids@^1.0.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" + +spdy-transport@^2.0.18: + version "2.0.20" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-2.0.20.tgz#735e72054c486b2354fe89e702256004a39ace4d" + dependencies: + debug "^2.6.8" + detect-node "^2.0.3" + hpack.js "^2.1.6" + obuf "^1.1.1" + readable-stream "^2.2.9" + safe-buffer "^5.0.1" + wbuf "^1.7.2" + +spdy@^3.4.1: + version "3.4.7" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-3.4.7.tgz#42ff41ece5cc0f99a3a6c28aabb73f5c3b03acbc" + dependencies: + debug "^2.6.8" + handle-thing "^1.2.5" + http-deceiver "^1.2.7" + safe-buffer "^5.0.1" + select-hose "^2.0.0" + spdy-transport "^2.0.18" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +sshpk@^1.7.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +ssri@^5.0.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.2.1.tgz#8b6eb873688759bd3c75a88dee74593d179bb73c" + dependencies: + safe-buffer "^5.1.1" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.3.1 < 2": + version "1.4.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + +statuses@~1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + +stdout-stream@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.0.tgz#a2c7c8587e54d9427ea9edb3ac3f2cd522df378b" + dependencies: + readable-stream "^2.0.1" + +stream-browserify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-each@^1.1.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.2.tgz#8e8c463f91da8991778765873fe4d960d8f616bd" + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" + +stream-http@^2.7.2: + version "2.8.0" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.0.tgz#fd86546dac9b1c91aff8fc5d287b98fafb41bc10" + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.3.3" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + +string-width@^1.0.1, string-width@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string_decoder@^1.0.0, string_decoder@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" + dependencies: + safe-buffer "~5.1.0" + +stringstream@~0.0.4, stringstream@~0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + dependencies: + is-utf8 "^0.2.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + +strip-indent@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + dependencies: + get-stdin "^4.0.1" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +style-loader@^0.20.1: + version "0.20.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.20.1.tgz#33ac2bf4d5c65a8906bc586ad253334c246998d0" + dependencies: + loader-utils "^1.1.0" + schema-utils "^0.4.3" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + dependencies: + has-flag "^1.0.0" + +supports-color@^4.2.1: + version "4.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b" + dependencies: + has-flag "^2.0.0" + +supports-color@^5.1.0, supports-color@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.2.0.tgz#b0d5333b1184dd3666cbe5aa0b45c5ac7ac17a4a" + dependencies: + has-flag "^3.0.0" + +svgo@^0.7.0: + version "0.7.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5" + dependencies: + coa "~1.0.1" + colors "~1.1.2" + csso "~2.3.1" + js-yaml "~3.7.0" + mkdirp "~0.5.1" + sax "~1.2.1" + whet.extend "~0.9.9" + +tapable@^0.2.7: + version "0.2.8" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22" + +tar-pack@^3.4.0: + version "3.4.1" + resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f" + dependencies: + debug "^2.2.0" + fstream "^1.0.10" + fstream-ignore "^1.0.5" + once "^1.3.3" + readable-stream "^2.1.4" + rimraf "^2.5.1" + tar "^2.2.1" + uid-number "^0.0.6" + +tar@^2.0.0, tar@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +through2@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" + dependencies: + readable-stream "^2.1.5" + xtend "~4.0.1" + +thunky@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.0.2.tgz#a862e018e3fb1ea2ec3fce5d55605cf57f247371" + +time-stamp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-2.0.0.tgz#95c6a44530e15ba8d6f4a3ecb8c3a3fac46da357" + +timers-browserify@^2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.6.tgz#241e76927d9ca05f4d959819022f5b3664b64bae" + dependencies: + setimmediate "^1.0.4" + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + +to-fast-properties@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.1.tgz#15358bee4a2c83bd76377ba1dc049d0f18837aae" + dependencies: + define-property "^0.2.5" + extend-shallow "^2.0.1" + regex-not "^1.0.0" + +tough-cookie@~2.3.0, tough-cookie@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" + dependencies: + punycode "^1.4.1" + +trim-newlines@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + +trix@^0.11.1: + version "0.11.1" + resolved "https://registry.yarnpkg.com/trix/-/trix-0.11.1.tgz#ffe54f2757c2c2385b8424fd5c5d2ab712a09acc" + +"true-case-path@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.2.tgz#7ec91130924766c7f573be3020c34f8fdfd00d62" + dependencies: + glob "^6.0.4" + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + dependencies: + safe-buffer "^5.0.1" + +tunnel-agent@~0.4.1: + version "0.4.3" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + +type-is@~1.6.15: + version "1.6.15" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.15" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +uglify-es@^3.3.4: + version "3.3.10" + resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.10.tgz#8b0b7992cebe20edc26de1bf325cef797b8f3fa5" + dependencies: + commander "~2.14.1" + source-map "~0.6.1" + +uglify-js@^2.8.29: + version "2.8.29" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" + dependencies: + source-map "~0.5.1" + yargs "~3.10.0" + optionalDependencies: + uglify-to-browserify "~1.0.0" + +uglify-to-browserify@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + +uglifyjs-webpack-plugin@^0.4.6: + version "0.4.6" + resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz#b951f4abb6bd617e66f63eb891498e391763e309" + dependencies: + source-map "^0.5.6" + uglify-js "^2.8.29" + webpack-sources "^1.0.1" + +uglifyjs-webpack-plugin@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.1.8.tgz#1302fb9471a7daf3d0a5174da6d65f0f415e75ad" + dependencies: + cacache "^10.0.1" + find-cache-dir "^1.0.0" + schema-utils "^0.4.2" + serialize-javascript "^1.4.0" + source-map "^0.6.1" + uglify-es "^3.3.4" + webpack-sources "^1.1.0" + worker-farm "^1.5.2" + +uid-number@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + +underscore.string@2.3.x: + version "2.3.3" + resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.3.3.tgz#71c08bf6b428b1133f37e78fa3a21c82f7329b0d" + +union-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^0.4.3" + +uniq@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + +uniqid@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/uniqid/-/uniqid-4.1.1.tgz#89220ddf6b751ae52b5f72484863528596bb84c1" + dependencies: + macaddress "^0.2.8" + +uniqs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" + +unique-filename@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.0.tgz#d05f2fe4032560871f30e93cbe735eea201514f3" + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab" + dependencies: + imurmurhash "^0.1.4" + +units-css@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/units-css/-/units-css-0.4.0.tgz#d6228653a51983d7c16ff28f8b9dc3b1ffed3a07" + dependencies: + isnumeric "^0.2.0" + viewport-dimensions "^0.2.0" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +upath@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.0.0.tgz#b4706b9461ca8473adf89133d235689ca17f3656" + dependencies: + lodash "3.x" + underscore.string "2.3.x" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + +url-parse@1.0.x: + version "1.0.5" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.0.5.tgz#0854860422afdcfefeb6c965c662d4800169927b" + dependencies: + querystringify "0.0.x" + requires-port "1.0.x" + +url-parse@^1.1.8: + version "1.2.0" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.2.0.tgz#3a19e8aaa6d023ddd27dcc44cb4fc8f7fec23986" + dependencies: + querystringify "~1.0.0" + requires-port "~1.0.0" + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/use/-/use-2.0.2.tgz#ae28a0d72f93bf22422a18a2e379993112dec8e8" + dependencies: + define-property "^0.2.5" + isobject "^3.0.0" + lazy-cache "^2.0.2" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +util@0.10.3, util@^0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + dependencies: + inherits "2.0.1" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + +uuid@^3.0.0, uuid@^3.0.1, uuid@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" + +validate-npm-package-license@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" + dependencies: + spdx-correct "~1.0.0" + spdx-expression-parse "~1.0.0" + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + +vendors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.1.tgz#37ad73c8ee417fb3d580e785312307d274847f22" + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +viewport-dimensions@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/viewport-dimensions/-/viewport-dimensions-0.2.0.tgz#de740747db5387fd1725f5175e91bac76afdf36c" + +vm-browserify@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" + dependencies: + indexof "0.0.1" + +watchpack@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.4.0.tgz#4a1472bcbb952bd0a9bb4036801f954dfb39faac" + dependencies: + async "^2.1.2" + chokidar "^1.7.0" + graceful-fs "^4.1.2" + +wbuf@^1.1.0, wbuf@^1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.2.tgz#d697b99f1f59512df2751be42769c1580b5801fe" + dependencies: + minimalistic-assert "^1.0.0" + +webpack-dev-middleware@1.12.2: + version "1.12.2" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.12.2.tgz#f8fc1120ce3b4fc5680ceecb43d777966b21105e" + dependencies: + memory-fs "~0.4.1" + mime "^1.5.0" + path-is-absolute "^1.0.0" + range-parser "^1.0.3" + time-stamp "^2.0.0" + +webpack-dev-server@^2.11.1: + version "2.11.1" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-2.11.1.tgz#6f9358a002db8403f016e336816f4485384e5ec0" + dependencies: + ansi-html "0.0.7" + array-includes "^3.0.3" + bonjour "^3.5.0" + chokidar "^2.0.0" + compression "^1.5.2" + connect-history-api-fallback "^1.3.0" + debug "^3.1.0" + del "^3.0.0" + express "^4.16.2" + html-entities "^1.2.0" + http-proxy-middleware "~0.17.4" + import-local "^1.0.0" + internal-ip "1.2.0" + ip "^1.1.5" + killable "^1.0.0" + loglevel "^1.4.1" + opn "^5.1.0" + portfinder "^1.0.9" + selfsigned "^1.9.1" + serve-index "^1.7.2" + sockjs "0.3.19" + sockjs-client "1.1.4" + spdy "^3.4.1" + strip-ansi "^3.0.0" + supports-color "^5.1.0" + webpack-dev-middleware "1.12.2" + yargs "6.6.0" + +webpack-manifest-plugin@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/webpack-manifest-plugin/-/webpack-manifest-plugin-1.3.2.tgz#5ea8ee5756359ddc1d98814324fe43496349a7d4" + dependencies: + fs-extra "^0.30.0" + lodash ">=3.5 <5" + +webpack-sources@^1.0.1, webpack-sources@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack@^3.10.0: + version "3.11.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.11.0.tgz#77da451b1d7b4b117adaf41a1a93b5742f24d894" + dependencies: + acorn "^5.0.0" + acorn-dynamic-import "^2.0.0" + ajv "^6.1.0" + ajv-keywords "^3.1.0" + async "^2.1.2" + enhanced-resolve "^3.4.0" + escope "^3.6.0" + interpret "^1.0.0" + json-loader "^0.5.4" + json5 "^0.5.1" + loader-runner "^2.3.0" + loader-utils "^1.1.0" + memory-fs "~0.4.1" + mkdirp "~0.5.0" + node-libs-browser "^2.0.0" + source-map "^0.5.3" + supports-color "^4.2.1" + tapable "^0.2.7" + uglifyjs-webpack-plugin "^0.4.6" + watchpack "^1.4.0" + webpack-sources "^1.0.1" + yargs "^8.0.2" + +websocket-driver@>=0.5.1: + version "0.7.0" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" + dependencies: + http-parser-js ">=0.4.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" + +whet.extend@~0.9.9: + version "0.9.9" + resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1" + +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + +which@1, which@^1.2.9: + version "1.3.0" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" + dependencies: + string-width "^1.0.2" + +window-size@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + +wordwrap@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + +worker-farm@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.5.2.tgz#32b312e5dc3d5d45d79ef44acc2587491cd729ae" + dependencies: + errno "^0.1.4" + xtend "^4.0.1" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + +yargs-parser@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c" + dependencies: + camelcase "^3.0.0" + +yargs-parser@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" + dependencies: + camelcase "^3.0.0" + +yargs-parser@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" + dependencies: + camelcase "^4.1.0" + +yargs@6.6.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + y18n "^3.2.1" + yargs-parser "^4.2.0" + +yargs@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + y18n "^3.2.1" + yargs-parser "^5.0.0" + +yargs@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360" + dependencies: + camelcase "^4.1.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + read-pkg-up "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^7.0.0" + +yargs@~3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + dependencies: + camelcase "^1.0.2" + cliui "^2.1.0" + decamelize "^1.0.0" + window-size "0.1.0" -- cgit v1.2.3 From 986d6a6da4a42a9e92e8c0cc96b7edca35e778de Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Mon, 12 Feb 2018 15:50:42 -0500 Subject: Add initial ActiveStorage integration --- app/javascript/activetext/index.js | 32 ++++++++++++++++++++++ package.json | 3 +- ..._create_active_storage_tables.active_storage.rb | 26 ++++++++++++++++++ test/dummy/db/schema.rb | 23 +++++++++++++++- test/dummy/yarn.lock | 5 ++++ yarn.lock | 4 +++ 6 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 test/dummy/db/migrate/20180212164506_create_active_storage_tables.active_storage.rb diff --git a/app/javascript/activetext/index.js b/app/javascript/activetext/index.js index c77ed0ab26..03cb9960cb 100644 --- a/app/javascript/activetext/index.js +++ b/app/javascript/activetext/index.js @@ -1 +1,33 @@ import * as Trix from "trix" +import { DirectUpload } from "activestorage" + +// FIXME: Hard coded routes +const directUploadsURL = "/rails/active_storage/direct_uploads" +const blobsURL = "/rails/active_storage/blobs" + +addEventListener("trix-attachment-add", event => { + const { attachment } = event + if (!attachment.file) return + + const delegate = { + directUploadWillStoreFileWithXHR: (xhr) => { + xhr.upload.addEventListener("progress", event => { + const progress = event.loaded / event.total * 100 + attachment.setUploadProgress(progress) + }) + } + } + + const directUpload = new DirectUpload(attachment.file, directUploadsURL, delegate) + + directUpload.create((error, attributes) => { + if (error) { + console.warn("Failed to store file for attachment", attachment, error) + } else { + console.log("Created blob for attachment", attributes, attachment) + const { signed_id } = attributes + const url = `${blobsURL}/${signed_id}/${encodeURIComponent(attachment.file.name)}` + attachment.setAttributes({ url, signed_id }) + } + }) +}) diff --git a/package.json b/package.json index 7f0c79a054..62d5b702db 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ ], "license": "MIT", "dependencies": { - "trix": "^0.11.1" + "trix": "^0.11.1", + "activestorage": ">= 5.2.0-rc1" }, "private": true } diff --git a/test/dummy/db/migrate/20180212164506_create_active_storage_tables.active_storage.rb b/test/dummy/db/migrate/20180212164506_create_active_storage_tables.active_storage.rb new file mode 100644 index 0000000000..360e0d1b7a --- /dev/null +++ b/test/dummy/db/migrate/20180212164506_create_active_storage_tables.active_storage.rb @@ -0,0 +1,26 @@ +# This migration comes from active_storage (originally 20170806125915) +class CreateActiveStorageTables < ActiveRecord::Migration[5.2] + def change + create_table :active_storage_blobs do |t| + t.string :key, null: false + t.string :filename, null: false + t.string :content_type + t.text :metadata + t.bigint :byte_size, null: false + t.string :checksum, null: false + t.datetime :created_at, null: false + + t.index [ :key ], unique: true + end + + create_table :active_storage_attachments do |t| + t.string :name, null: false + t.references :record, null: false, polymorphic: true, index: false + t.references :blob, null: false + + t.datetime :created_at, null: false + + t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true + end + end +end diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb index 21d6c8d847..f892368183 100644 --- a/test/dummy/db/schema.rb +++ b/test/dummy/db/schema.rb @@ -10,7 +10,28 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2018_02_08_205311) do +ActiveRecord::Schema.define(version: 2018_02_12_164506) do + + create_table "active_storage_attachments", force: :cascade do |t| + t.string "name", null: false + t.string "record_type", null: false + t.integer "record_id", null: false + t.integer "blob_id", null: false + t.datetime "created_at", null: false + t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id" + t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true + end + + create_table "active_storage_blobs", force: :cascade do |t| + t.string "key", null: false + t.string "filename", null: false + t.string "content_type" + t.text "metadata" + t.bigint "byte_size", null: false + t.string "checksum", null: false + t.datetime "created_at", null: false + t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true + end create_table "messages", force: :cascade do |t| t.string "subject" diff --git a/test/dummy/yarn.lock b/test/dummy/yarn.lock index 3b1f47bf41..af299bfcf8 100644 --- a/test/dummy/yarn.lock +++ b/test/dummy/yarn.lock @@ -56,9 +56,14 @@ acorn@^5.0.0: version "5.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.4.1.tgz#fdc58d9d17f4a4e98d102ded826a9b9759125102" +"activestorage@>= 5.2.0-rc1": + version "5.2.0-rc1" + resolved "https://registry.yarnpkg.com/activestorage/-/activestorage-5.2.0-rc1.tgz#79898996eceb0f13575eff41fb109051fbfa49b0" + "activetext@file:../..": version "0.1" dependencies: + activestorage ">= 5.2.0-rc1" trix "^0.11.1" ajv-keywords@^2.1.0: diff --git a/yarn.lock b/yarn.lock index fbaef41eaa..f98622eb64 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,10 @@ # yarn lockfile v1 +"activestorage@>= 5.2.0-rc1": + version "5.2.0-rc1" + resolved "https://registry.yarnpkg.com/activestorage/-/activestorage-5.2.0-rc1.tgz#79898996eceb0f13575eff41fb109051fbfa49b0" + trix@^0.11.1: version "0.11.1" resolved "https://registry.yarnpkg.com/trix/-/trix-0.11.1.tgz#ffe54f2757c2c2385b8424fd5c5d2ab712a09acc" -- cgit v1.2.3 From b79bf62196f1032d4a6f95799ced79cbbadad856 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Mon, 12 Feb 2018 18:21:49 -0500 Subject: Add sgid support --- app/javascript/activetext/index.js | 7 ++++--- lib/active_text/attachable.rb | 42 +++++++++++++++++++++++++++++++++++++- lib/active_text/engine.rb | 12 +++++++++++ 3 files changed, 57 insertions(+), 4 deletions(-) diff --git a/app/javascript/activetext/index.js b/app/javascript/activetext/index.js index 03cb9960cb..cdcd1d311f 100644 --- a/app/javascript/activetext/index.js +++ b/app/javascript/activetext/index.js @@ -25,9 +25,10 @@ addEventListener("trix-attachment-add", event => { console.warn("Failed to store file for attachment", attachment, error) } else { console.log("Created blob for attachment", attributes, attachment) - const { signed_id } = attributes - const url = `${blobsURL}/${signed_id}/${encodeURIComponent(attachment.file.name)}` - attachment.setAttributes({ url, signed_id }) + attachment.setAttributes({ + url: `${blobsURL}/${attributes.signed_id}/${encodeURIComponent(attachment.file.name)}`, + sgid: attributes.attachable_sgid + }) } }) }) diff --git a/lib/active_text/attachable.rb b/lib/active_text/attachable.rb index 445ee30605..3a6648331e 100644 --- a/lib/active_text/attachable.rb +++ b/lib/active_text/attachable.rb @@ -1,5 +1,9 @@ module ActiveText module Attachable + extend ActiveSupport::Concern + + LOCATOR_NAME = "attachable" + class << self def from_node(node) if attachable = attachable_from_sgid(node["sgid"]) @@ -13,12 +17,48 @@ module ActiveText end end + def from_attachable_sgid(sgid, options = {}) + method = sgid.is_a?(Array) ? :locate_many_signed : :locate_signed + record = GlobalID::Locator.public_send(method, sgid, options.merge(for: LOCATOR_NAME)) + record or raise ActiveRecord::RecordNotFound + end + private def attachable_from_sgid(sgid) - ::Attachable.from_attachable_sgid(sgid) + from_attachable_sgid(sgid) rescue ActiveRecord::RecordNotFound nil end end + + class_methods do + def from_attachable_sgid(sgid) + ActiveText::Attachable.from_attachable_sgid(sgid, only: self) + end + end + + def attachable_sgid + to_sgid(expires_in: nil, for: LOCATOR_NAME).to_s + end + + def attachable_content_type + try(:content_type) || "application/octet-stream" + end + + def previewable_attachable? + false + end + + def as_json(*) + super.merge(attachable_sgid: attachable_sgid) + end + + def to_active_text_attributes(attributes = {}) + attributes.dup.tap do |attributes| + attributes[:sgid] = attachable_sgid + attributes[:content_type] = attachable_content_type + attributes[:previewable] = true if previewable_attachable? + end + end end end diff --git a/lib/active_text/engine.rb b/lib/active_text/engine.rb index 5b16acab04..9a1d08e1ad 100644 --- a/lib/active_text/engine.rb +++ b/lib/active_text/engine.rb @@ -11,6 +11,18 @@ module ActiveText end end + initializer "active_text.active_storage_extension" do + require "active_storage/blob" + + class ActiveStorage::Blob + include ActiveText::Attachable + + def previewable_attachable? + representable? + end + end + end + # FIXME: Aren't helpers supposed to load automatically? # https://github.com/rails/rails/issues/26627 ? initializer "active_text.helper" do -- cgit v1.2.3 From 2ae84d647feac338082175f581bd1ca0c33d003a Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Tue, 13 Feb 2018 15:07:29 -0500 Subject: Initial Attachment rendering support --- app/views/active_storage/blobs/_blob.html.erb | 7 +++++++ lib/active_text/attachment.rb | 6 +++++- lib/active_text/content.rb | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 app/views/active_storage/blobs/_blob.html.erb diff --git a/app/views/active_storage/blobs/_blob.html.erb b/app/views/active_storage/blobs/_blob.html.erb new file mode 100644 index 0000000000..2b17745c8d --- /dev/null +++ b/app/views/active_storage/blobs/_blob.html.erb @@ -0,0 +1,7 @@ +

Engine blob/_blob:

+ +<%= debug blob %> + +
+ <%= image_tag rails_blob_path(blob) %> +
diff --git a/lib/active_text/attachment.rb b/lib/active_text/attachment.rb index 870390f63e..e349c721b2 100644 --- a/lib/active_text/attachment.rb +++ b/lib/active_text/attachment.rb @@ -74,7 +74,11 @@ module ActiveText end def to_html - HtmlConversion.node_to_html(node) + if attachable.respond_to?(:to_partial_path) + ApplicationController.render(self) + else + HtmlConversion.node_to_html(node) + end end def to_s diff --git a/lib/active_text/content.rb b/lib/active_text/content.rb index 0154cea17e..c9546fb4c5 100644 --- a/lib/active_text/content.rb +++ b/lib/active_text/content.rb @@ -46,7 +46,7 @@ module ActiveText end def to_html - fragment.to_html + render_attachments(&:to_html).to_html end def to_s -- cgit v1.2.3 From d1f50a4cbe54d15a07608b20ed2fc05e8960bc1d Mon Sep 17 00:00:00 2001 From: Sam Stephenson Date: Tue, 13 Feb 2018 15:00:14 -0600 Subject: Preserve the outer attachment element and fix editing --- lib/active_text/attachment.rb | 6 +----- lib/active_text/content.rb | 6 +++++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/active_text/attachment.rb b/lib/active_text/attachment.rb index e349c721b2..870390f63e 100644 --- a/lib/active_text/attachment.rb +++ b/lib/active_text/attachment.rb @@ -74,11 +74,7 @@ module ActiveText end def to_html - if attachable.respond_to?(:to_partial_path) - ApplicationController.render(self) - else - HtmlConversion.node_to_html(node) - end + HtmlConversion.node_to_html(node) end def to_s diff --git a/lib/active_text/content.rb b/lib/active_text/content.rb index c9546fb4c5..190f7d3c7b 100644 --- a/lib/active_text/content.rb +++ b/lib/active_text/content.rb @@ -46,7 +46,11 @@ module ActiveText end def to_html - render_attachments(&:to_html).to_html + render_attachments do |attachment| + attachment.node.tap do |node| + node.inner_html = ApplicationController.render(attachment) + end + end.to_html end def to_s -- cgit v1.2.3 From 0f6e9b7cc59e3fe94013c5b9730129930ada370b Mon Sep 17 00:00:00 2001 From: Sam Stephenson Date: Tue, 13 Feb 2018 15:01:26 -0600 Subject: Delegate Content#html_safe to #to_s --- lib/active_text/content.rb | 2 +- test/dummy/app/views/messages/show.html.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/active_text/content.rb b/lib/active_text/content.rb index 190f7d3c7b..58589cc110 100644 --- a/lib/active_text/content.rb +++ b/lib/active_text/content.rb @@ -4,7 +4,7 @@ module ActiveText attr_reader :fragment - delegate :blank?, :empty?, :present?, to: :to_s + delegate :blank?, :empty?, :html_safe, :present?, to: :to_s def initialize(content = nil) @fragment = ActiveText::Attachment.fragment_by_canonicalizing_attachments(content) diff --git a/test/dummy/app/views/messages/show.html.erb b/test/dummy/app/views/messages/show.html.erb index feec71cb93..052d358206 100644 --- a/test/dummy/app/views/messages/show.html.erb +++ b/test/dummy/app/views/messages/show.html.erb @@ -7,7 +7,7 @@

Content: - <%= raw @message.content %> + <%= @message.content.html_safe %>

<%= link_to 'Edit', edit_message_path(@message) %> | -- cgit v1.2.3 From 28525b4ccad9aca42e4e1d9588c4f0724449f1c7 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Wed, 14 Feb 2018 09:19:12 -0500 Subject: Build out basic blob template to match the editor's --- app/views/active_storage/blobs/_blob.html.erb | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/app/views/active_storage/blobs/_blob.html.erb b/app/views/active_storage/blobs/_blob.html.erb index 2b17745c8d..c7c70c110e 100644 --- a/app/views/active_storage/blobs/_blob.html.erb +++ b/app/views/active_storage/blobs/_blob.html.erb @@ -1,7 +1,16 @@ -

Engine blob/_blob:

+
attachment--<%= blob.filename.extension %>"> + <% if blob.variable? %> + <%= image_tag blob.variant(resize: "1024x768>") %> + <% elsif blob.previewable? %> + <%= image_tag blob.preview(resize: "1024x768>") %> + <% end %> -<%= debug blob %> - -
- <%= image_tag rails_blob_path(blob) %> +
+ <% if caption = blob.try(:caption) %> + <%= caption %> + <% else %> + <%= blob.filename %> + <%= number_to_human_size blob.byte_size %> + <% end %> +
-- cgit v1.2.3 From 424070574dd61dfa3710c915526064157411327f Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Wed, 14 Feb 2018 09:43:49 -0500 Subject: Make renderer configurable --- lib/active_text.rb | 2 ++ lib/active_text/attachments/trix_conversion.rb | 2 +- lib/active_text/content.rb | 2 +- lib/active_text/engine.rb | 6 ++++++ 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/active_text.rb b/lib/active_text.rb index 1981abc4c6..8275d7d17a 100644 --- a/lib/active_text.rb +++ b/lib/active_text.rb @@ -5,6 +5,8 @@ require "nokogiri" module ActiveText extend ActiveSupport::Autoload + mattr_accessor(:renderer) + autoload :Attachable autoload :Attachment autoload :Attribute diff --git a/lib/active_text/attachments/trix_conversion.rb b/lib/active_text/attachments/trix_conversion.rb index 25eada6709..3eb83453f4 100644 --- a/lib/active_text/attachments/trix_conversion.rb +++ b/lib/active_text/attachments/trix_conversion.rb @@ -24,7 +24,7 @@ module ActiveText private def trix_attachment_content if partial_path = attachable.try(:to_trix_content_attachment_partial_path) - ApplicationRenderer.render(partial: partial_path, object: self, as: model_name.element) + ActiveText.renderer.render(partial: partial_path, object: self, as: model_name.element) end end end diff --git a/lib/active_text/content.rb b/lib/active_text/content.rb index 58589cc110..8bc2356060 100644 --- a/lib/active_text/content.rb +++ b/lib/active_text/content.rb @@ -48,7 +48,7 @@ module ActiveText def to_html render_attachments do |attachment| attachment.node.tap do |node| - node.inner_html = ApplicationController.render(attachment) + node.inner_html = ActiveText.renderer.render(attachment) end end.to_html end diff --git a/lib/active_text/engine.rb b/lib/active_text/engine.rb index 9a1d08e1ad..ab266aa58d 100644 --- a/lib/active_text/engine.rb +++ b/lib/active_text/engine.rb @@ -30,5 +30,11 @@ module ActiveText helper ActiveText::TagHelper end end + + initializer "active_text.config" do + config.after_initialize do |app| + ActiveText.renderer ||= ApplicationController.renderer + end + end end end -- cgit v1.2.3 From fec73898d26d943f8f8f6da897fcf0fecbcffcdb Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Wed, 14 Feb 2018 09:45:17 -0500 Subject: Dummy: Set ActiveText renderer for current request --- test/dummy/app/controllers/application_controller.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/dummy/app/controllers/application_controller.rb b/test/dummy/app/controllers/application_controller.rb index 09705d12ab..baaa725746 100644 --- a/test/dummy/app/controllers/application_controller.rb +++ b/test/dummy/app/controllers/application_controller.rb @@ -1,2 +1,8 @@ class ApplicationController < ActionController::Base + before_action :set_active_text_renderer + + private + def set_active_text_renderer + ActiveText.renderer = self.class.renderer.new(request.env) + end end -- cgit v1.2.3 From 377d16b8b590982e98356af779a79014bd5ff754 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Wed, 14 Feb 2018 09:45:44 -0500 Subject: Dummy: Add mini_magick for variants --- Gemfile.lock | 2 ++ activetext.gemspec | 1 + 2 files changed, 3 insertions(+) diff --git a/Gemfile.lock b/Gemfile.lock index e693ad5c38..ba3c8b4be8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -67,6 +67,7 @@ GEM mimemagic (~> 0.3.2) method_source (0.9.0) mimemagic (0.3.2) + mini_magick (4.8.0) mini_mime (1.0.0) mini_portile2 (2.3.0) minitest (5.11.3) @@ -129,6 +130,7 @@ PLATFORMS DEPENDENCIES activetext! bundler (~> 1.15) + mini_magick sqlite3 webpacker (~> 3.2.2) diff --git a/activetext.gemspec b/activetext.gemspec index 6c0fea16c6..37fe805279 100644 --- a/activetext.gemspec +++ b/activetext.gemspec @@ -19,6 +19,7 @@ Gem::Specification.new do |s| s.add_dependency "nokogiri" s.add_development_dependency "bundler", "~> 1.15" + s.add_development_dependency "mini_magick" s.add_development_dependency "sqlite3" s.add_development_dependency "webpacker", "~> 3.2.2" -- cgit v1.2.3 From 6408111e71c1c693835de40a590a677cde596584 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Wed, 14 Feb 2018 09:55:31 -0500 Subject: Dummy: Use Trix styles --- test/dummy/app/views/messages/_form.html.erb | 2 +- test/dummy/app/views/messages/show.html.erb | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/test/dummy/app/views/messages/_form.html.erb b/test/dummy/app/views/messages/_form.html.erb index 6ead526229..c8edcb78e5 100644 --- a/test/dummy/app/views/messages/_form.html.erb +++ b/test/dummy/app/views/messages/_form.html.erb @@ -18,7 +18,7 @@
<%= form.label :content %> - <%= form.active_text_field :content %> + <%= form.active_text_field :content, class: "trix-content" %>
diff --git a/test/dummy/app/views/messages/show.html.erb b/test/dummy/app/views/messages/show.html.erb index 052d358206..25fad1efba 100644 --- a/test/dummy/app/views/messages/show.html.erb +++ b/test/dummy/app/views/messages/show.html.erb @@ -5,10 +5,9 @@ <%= @message.subject %>

-

- Content: +

<%= @message.content.html_safe %> -

+
<%= link_to 'Edit', edit_message_path(@message) %> | <%= link_to 'Back', messages_path %> -- cgit v1.2.3 From 9ded0f3c420350144a9d41ccee3dc4b7ad9d8813 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Wed, 14 Feb 2018 10:33:30 -0500 Subject: Create ASt::Attachment records for ASt::Blobs in content --- lib/active_text/attribute.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/active_text/attribute.rb b/lib/active_text/attribute.rb index 577adde83a..9d872a87a1 100644 --- a/lib/active_text/attribute.rb +++ b/lib/active_text/attribute.rb @@ -5,6 +5,13 @@ module ActiveText class_methods do def active_text_attribute(attribute_name) serialize(attribute_name, ActiveText::Content) + + has_many_attached "#{attribute_name}_attachments" + + after_save do + blobs = public_send(attribute_name).attachments.map(&:attachable) + public_send("#{attribute_name}_attachments_blobs=", blobs) + end end end end -- cgit v1.2.3 From ba71c73836c084c95ca89021f9c9a455d8c94134 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Wed, 14 Feb 2018 14:11:54 -0500 Subject: Move hard coded URLs to computed data attributes --- app/helpers/active_text/tag_helper.rb | 8 +++++--- app/javascript/activetext/index.js | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/app/helpers/active_text/tag_helper.rb b/app/helpers/active_text/tag_helper.rb index c2ec7e5e8f..590ff93fd5 100644 --- a/app/helpers/active_text/tag_helper.rb +++ b/app/helpers/active_text/tag_helper.rb @@ -4,7 +4,11 @@ module ActiveText def active_text_field_tag(name, value = nil, options = {}) options = options.symbolize_keys + options[:input] ||= "trix_input_#{ActiveText::TagHelper.id += 1}" + options[:data] ||= {} + options[:data][:direct_upload_url] = rails_direct_uploads_url + options[:data][:blob_url_template] = rails_service_blob_url(":signed_id", ":filename") editor_tag = content_tag("trix-editor", "", options) input_tag = hidden_field_tag(name, value, id: options[:input]) @@ -16,15 +20,13 @@ end module ActionView::Helpers class Tags::ActiveText < Tags::Base - include ActiveText::TagHelper - delegate :dom_id, to: ActionView::RecordIdentifier def render options = @options.stringify_keys add_default_name_and_id(options) options["input"] ||= dom_id(object, [options["id"], :trix_input].compact.join("_")) - active_text_field_tag(options.delete("name"), editable_value, options) + @template_object.active_text_field_tag(options.delete("name"), editable_value, options) end def editable_value diff --git a/app/javascript/activetext/index.js b/app/javascript/activetext/index.js index cdcd1d311f..e1c59dd50d 100644 --- a/app/javascript/activetext/index.js +++ b/app/javascript/activetext/index.js @@ -1,14 +1,12 @@ import * as Trix from "trix" import { DirectUpload } from "activestorage" -// FIXME: Hard coded routes -const directUploadsURL = "/rails/active_storage/direct_uploads" -const blobsURL = "/rails/active_storage/blobs" - addEventListener("trix-attachment-add", event => { const { attachment } = event if (!attachment.file) return + const { directUploadUrl, blobUrlTemplate } = event.target.dataset + const delegate = { directUploadWillStoreFileWithXHR: (xhr) => { xhr.upload.addEventListener("progress", event => { @@ -18,17 +16,19 @@ addEventListener("trix-attachment-add", event => { } } - const directUpload = new DirectUpload(attachment.file, directUploadsURL, delegate) + const directUpload = new DirectUpload(attachment.file, directUploadUrl, delegate) directUpload.create((error, attributes) => { if (error) { console.warn("Failed to store file for attachment", attachment, error) } else { - console.log("Created blob for attachment", attributes, attachment) - attachment.setAttributes({ - url: `${blobsURL}/${attributes.signed_id}/${encodeURIComponent(attachment.file.name)}`, - sgid: attributes.attachable_sgid - }) + const sgid = attributes.attachable_sgid + + const url = blobUrlTemplate + .replace(":signed_id", attributes.signed_id) + .replace(":filename", encodeURIComponent(attributes.filename)) + + attachment.setAttributes({ sgid, url }) } }) }) -- cgit v1.2.3 From 55e2df15cdf86671801a22caaa4ea26d4e8497d5 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Wed, 14 Feb 2018 14:35:34 -0500 Subject: Extract AttachmentUpload --- app/javascript/activetext/attachment_upload.js | 45 ++++++++++++++++++++++++++ app/javascript/activetext/index.js | 33 +++---------------- 2 files changed, 50 insertions(+), 28 deletions(-) create mode 100644 app/javascript/activetext/attachment_upload.js diff --git a/app/javascript/activetext/attachment_upload.js b/app/javascript/activetext/attachment_upload.js new file mode 100644 index 0000000000..a716f1f589 --- /dev/null +++ b/app/javascript/activetext/attachment_upload.js @@ -0,0 +1,45 @@ +import { DirectUpload } from "activestorage" + +export class AttachmentUpload { + constructor(attachment, element) { + this.attachment = attachment + this.element = element + this.directUpload = new DirectUpload(attachment.file, this.directUploadUrl, this) + } + + start() { + this.directUpload.create(this.directUploadDidComplete.bind(this)) + } + + directUploadWillStoreFileWithXHR(xhr) { + xhr.upload.addEventListener("progress", event => { + const progress = event.loaded / event.total * 100 + this.attachment.setUploadProgress(progress) + }) + } + + directUploadDidComplete(error, attributes) { + if (error) { + throw new Error(`Direct upload failed: ${error}`) + } + + this.attachment.setAttributes({ + sgid: attributes.attachable_sgid, + url: this.createBlobUrl(attributes.signed_id, attributes.filename) + }) + } + + createBlobUrl(signedId, filename) { + return this.blobUrlTemplate + .replace(":signed_id", signedId) + .replace(":filename", encodeURIComponent(filename)) + } + + get directUploadUrl() { + return this.element.dataset.directUploadUrl + } + + get blobUrlTemplate() { + return this.element.dataset.blobUrlTemplate + } +} diff --git a/app/javascript/activetext/index.js b/app/javascript/activetext/index.js index e1c59dd50d..c149eda952 100644 --- a/app/javascript/activetext/index.js +++ b/app/javascript/activetext/index.js @@ -1,34 +1,11 @@ import * as Trix from "trix" -import { DirectUpload } from "activestorage" +import { AttachmentUpload } from "./attachment_upload" addEventListener("trix-attachment-add", event => { - const { attachment } = event - if (!attachment.file) return + const { attachment, target } = event - const { directUploadUrl, blobUrlTemplate } = event.target.dataset - - const delegate = { - directUploadWillStoreFileWithXHR: (xhr) => { - xhr.upload.addEventListener("progress", event => { - const progress = event.loaded / event.total * 100 - attachment.setUploadProgress(progress) - }) - } + if (attachment.file) { + const upload = new AttachmentUpload(attachment, target) + upload.start() } - - const directUpload = new DirectUpload(attachment.file, directUploadUrl, delegate) - - directUpload.create((error, attributes) => { - if (error) { - console.warn("Failed to store file for attachment", attachment, error) - } else { - const sgid = attributes.attachable_sgid - - const url = blobUrlTemplate - .replace(":signed_id", attributes.signed_id) - .replace(":filename", encodeURIComponent(attributes.filename)) - - attachment.setAttributes({ sgid, url }) - } - }) }) -- cgit v1.2.3 From bef79f49922cb6b3e8bbd4f5578888b4bcc67078 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Wed, 14 Feb 2018 15:10:33 -0500 Subject: Isolated engines don't expose their helpers, so no --- lib/active_text/engine.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/active_text/engine.rb b/lib/active_text/engine.rb index ab266aa58d..c11bb7cce9 100644 --- a/lib/active_text/engine.rb +++ b/lib/active_text/engine.rb @@ -23,8 +23,6 @@ module ActiveText end end - # FIXME: Aren't helpers supposed to load automatically? - # https://github.com/rails/rails/issues/26627 ? initializer "active_text.helper" do ActiveSupport.on_load(:action_controller_base) do helper ActiveText::TagHelper -- cgit v1.2.3 From 6054f044c1bb07ca939e40660b58045128bf6f45 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Wed, 14 Feb 2018 15:11:01 -0500 Subject: Remove unused model --- app/models/active_text/document.rb | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 app/models/active_text/document.rb diff --git a/app/models/active_text/document.rb b/app/models/active_text/document.rb deleted file mode 100644 index 74b1ddc746..0000000000 --- a/app/models/active_text/document.rb +++ /dev/null @@ -1,4 +0,0 @@ -module ActiveText - class Document < ActiveRecord::Base - end -end -- cgit v1.2.3 From 43b166ad5115fb72a6edd3e416988b9fb75f5ee3 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Wed, 14 Feb 2018 15:44:38 -0500 Subject: Add basic install guide --- README.md | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 07e2238c34..9c0b8d777b 100644 --- a/README.md +++ b/README.md @@ -1 +1,56 @@ -# activetext +# Active Text + +🤸‍♂️💰📝 + +## Installing + +Assumes a Rails 5.2+ application with Active Storage and Webpacker installed. + +1. Install the gem: + + ```ruby + # Gemfile + gem "activetext", github: "basecamp/activetext", require: "active_text" + gem "mini_magick" # for Active Storage variants + ``` + +1. Install the npm package: + + ```js + // package.json + "dependencies": { + "activetext": "basecamp/activetext" + } + ``` + + ```sh + $ yarn install + ``` + + ```js + // app/javascript/packs/application.js + import "activetext" + ``` + +1. Declare text columns as Active Text attributes: + + ```ruby + # app/models/message.rb + class Message < ActiveRecord::Base + active_text_attribute :content + end + ``` + +1. Replace form `text_area`s with `active_text_field`s: + + ```erb + <%# app/views/messages/_form.html.erb %> + <%= form_with(model: message) do |form| %> + … +
+ <%= form.label :content %> + <%= form.active_text_field :content %> +
+ … + <% end %> + ``` -- cgit v1.2.3 From 59b7fc1a0dad579b5bc36909e2d70fb2be1cfd02 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Wed, 14 Feb 2018 15:49:19 -0500 Subject: Fix formatting --- README.md | 76 +++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 9c0b8d777b..ca7566b2d9 100644 --- a/README.md +++ b/README.md @@ -8,49 +8,49 @@ Assumes a Rails 5.2+ application with Active Storage and Webpacker installed. 1. Install the gem: - ```ruby - # Gemfile - gem "activetext", github: "basecamp/activetext", require: "active_text" - gem "mini_magick" # for Active Storage variants - ``` - + ```ruby + # Gemfile + gem "activetext", github: "basecamp/activetext", require: "active_text" + gem "mini_magick" # for Active Storage variants + ``` + 1. Install the npm package: - ```js - // package.json - "dependencies": { - "activetext": "basecamp/activetext" - } - ``` - - ```sh - $ yarn install - ``` - - ```js - // app/javascript/packs/application.js - import "activetext" - ``` + ```js + // package.json + "dependencies": { + "activetext": "basecamp/activetext" + } + ``` + + ```sh + $ yarn install + ``` + + ```js + // app/javascript/packs/application.js + import "activetext" + ``` 1. Declare text columns as Active Text attributes: - ```ruby - # app/models/message.rb - class Message < ActiveRecord::Base - active_text_attribute :content - end - ``` + ```ruby + # app/models/message.rb + class Message < ActiveRecord::Base + active_text_attribute :content + end + ``` 1. Replace form `text_area`s with `active_text_field`s: - ```erb - <%# app/views/messages/_form.html.erb %> - <%= form_with(model: message) do |form| %> - … -
- <%= form.label :content %> - <%= form.active_text_field :content %> -
- … - <% end %> - ``` + ```erb + <%# app/views/messages/_form.html.erb %> + <%= form_with(model: message) do |form| %> + … +
+ <%= form.label :content %> + <%= form.active_text_field :content %> +
+ … + <% end %> + ``` -- cgit v1.2.3 From 8b5ff483ef2af1bf897a9cf0db3d367be0112938 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Wed, 14 Feb 2018 15:50:01 -0500 Subject: Missed a spot --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ca7566b2d9..8a21ed843b 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ Assumes a Rails 5.2+ application with Active Storage and Webpacker installed. …
<%= form.label :content %> - <%= form.active_text_field :content %> + <%= form.active_text_field :content %>
… <% end %> -- cgit v1.2.3 From 7c4e70ea0bf0f00c0e919128447412fab49772f9 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Fri, 13 Apr 2018 13:54:48 -0700 Subject: Try to please semver theory --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 62d5b702db..0f11cee9b5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "activetext", - "version": "0.1", + "version": "0.1.0", "description": "Edit and display rich text in Rails applications", "main": "app/javascript/activetext/index.js", "files": [ -- cgit v1.2.3 From 491bee6e64863f2dc6e8d1f59829e61d4a8c86ad Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Fri, 13 Apr 2018 14:10:18 -0700 Subject: Use rich_text instead of active_text Just like we use has_many_attachments instead of active_storage_attachements. --- README.md | 6 +++--- app/helpers/active_text/tag_helper.rb | 10 +++++----- lib/active_text/attachable.rb | 2 +- lib/active_text/attachment.rb | 4 ++-- lib/active_text/attribute.rb | 2 +- test/dummy/app/models/message.rb | 2 +- test/dummy/app/views/messages/_form.html.erb | 2 +- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 8a21ed843b..b01cb8bbf3 100644 --- a/README.md +++ b/README.md @@ -37,11 +37,11 @@ Assumes a Rails 5.2+ application with Active Storage and Webpacker installed. ```ruby # app/models/message.rb class Message < ActiveRecord::Base - active_text_attribute :content + has_rich_text :content end ``` -1. Replace form `text_area`s with `active_text_field`s: +1. Replace form `text_area`s with `rich_text_field`s: ```erb <%# app/views/messages/_form.html.erb %> @@ -49,7 +49,7 @@ Assumes a Rails 5.2+ application with Active Storage and Webpacker installed. …
<%= form.label :content %> - <%= form.active_text_field :content %> + <%= form.rich_text_field :content %>
… <% end %> diff --git a/app/helpers/active_text/tag_helper.rb b/app/helpers/active_text/tag_helper.rb index 590ff93fd5..1b97621dac 100644 --- a/app/helpers/active_text/tag_helper.rb +++ b/app/helpers/active_text/tag_helper.rb @@ -2,7 +2,7 @@ module ActiveText module TagHelper cattr_accessor(:id, instance_accessor: false) { 0 } - def active_text_field_tag(name, value = nil, options = {}) + def rich_text_field_tag(name, value = nil, options = {}) options = options.symbolize_keys options[:input] ||= "trix_input_#{ActiveText::TagHelper.id += 1}" @@ -26,7 +26,7 @@ module ActionView::Helpers options = @options.stringify_keys add_default_name_and_id(options) options["input"] ||= dom_id(object, [options["id"], :trix_input].compact.join("_")) - @template_object.active_text_field_tag(options.delete("name"), editable_value, options) + @template_object.rich_text_field_tag(options.delete("name"), editable_value, options) end def editable_value @@ -35,14 +35,14 @@ module ActionView::Helpers end module FormHelper - def active_text_field(object_name, method, options = {}) + def rich_text_field(object_name, method, options = {}) Tags::ActiveText.new(object_name, method, self, options).render end end class FormBuilder - def active_text_field(method, options = {}) - @template.active_text_field(@object_name, method, objectify_options(options)) + def rich_text_field(method, options = {}) + @template.rich_text_field(@object_name, method, objectify_options(options)) end end end diff --git a/lib/active_text/attachable.rb b/lib/active_text/attachable.rb index 3a6648331e..f3ea47282f 100644 --- a/lib/active_text/attachable.rb +++ b/lib/active_text/attachable.rb @@ -53,7 +53,7 @@ module ActiveText super.merge(attachable_sgid: attachable_sgid) end - def to_active_text_attributes(attributes = {}) + def to_rich_text_attributes(attributes = {}) attributes.dup.tap do |attributes| attributes[:sgid] = attachable_sgid attributes[:content_type] = attachable_content_type diff --git a/lib/active_text/attachment.rb b/lib/active_text/attachment.rb index 870390f63e..fab6c3507b 100644 --- a/lib/active_text/attachment.rb +++ b/lib/active_text/attachment.rb @@ -20,7 +20,7 @@ module ActiveText end def from_attachable(attachable, attributes = {}) - if node = node_from_attributes(attachable.to_active_text_attributes(attributes)) + if node = node_from_attributes(attachable.to_rich_text_attributes(attributes)) new(node, attachable) end end @@ -91,7 +91,7 @@ module ActiveText end def attachable_attributes - @attachable_attributes ||= (attachable.try(:to_active_text_attributes) || {}).stringify_keys + @attachable_attributes ||= (attachable.try(:to_rich_text_attributes) || {}).stringify_keys end def sgid_attributes diff --git a/lib/active_text/attribute.rb b/lib/active_text/attribute.rb index 9d872a87a1..9f3ee49998 100644 --- a/lib/active_text/attribute.rb +++ b/lib/active_text/attribute.rb @@ -3,7 +3,7 @@ module ActiveText extend ActiveSupport::Concern class_methods do - def active_text_attribute(attribute_name) + def has_rich_text(attribute_name) serialize(attribute_name, ActiveText::Content) has_many_attached "#{attribute_name}_attachments" diff --git a/test/dummy/app/models/message.rb b/test/dummy/app/models/message.rb index bb0ae59ad7..db63a1fe3f 100644 --- a/test/dummy/app/models/message.rb +++ b/test/dummy/app/models/message.rb @@ -1,3 +1,3 @@ class Message < ApplicationRecord - active_text_attribute :content + has_rich_text :content end diff --git a/test/dummy/app/views/messages/_form.html.erb b/test/dummy/app/views/messages/_form.html.erb index c8edcb78e5..bd5f0bea4a 100644 --- a/test/dummy/app/views/messages/_form.html.erb +++ b/test/dummy/app/views/messages/_form.html.erb @@ -18,7 +18,7 @@
<%= form.label :content %> - <%= form.active_text_field :content, class: "trix-content" %> + <%= form.rich_text_field :content, class: "trix-content" %>
-- cgit v1.2.3 From 0bb72a4cda9ddeabcb1357a3ac41aef01057f82b Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Fri, 13 Apr 2018 16:09:39 -0700 Subject: Relieve the need for having to manually set a before_action in ApplicationController --- lib/active_text/engine.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/active_text/engine.rb b/lib/active_text/engine.rb index c11bb7cce9..aac0c57881 100644 --- a/lib/active_text/engine.rb +++ b/lib/active_text/engine.rb @@ -32,6 +32,13 @@ module ActiveText initializer "active_text.config" do config.after_initialize do |app| ActiveText.renderer ||= ApplicationController.renderer + + # FIXME: ApplicationController should have a per-request specific renderer + # that's been set with the request.env env, and ActiveText should just piggyback off + # that by default rather than doing this work directly. + ApplicationController.before_action do + ActiveText.renderer = ActiveText.renderer.new(request.env) + end end end end -- cgit v1.2.3 From 3bc244abc1800c7617cbfbbe1dd2597053a638c9 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Fri, 13 Apr 2018 16:12:35 -0700 Subject: Content has already been through a whitelist --- lib/active_text/content.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/active_text/content.rb b/lib/active_text/content.rb index 8bc2356060..0e97374ded 100644 --- a/lib/active_text/content.rb +++ b/lib/active_text/content.rb @@ -54,7 +54,7 @@ module ActiveText end def to_s - to_html + to_html.html_safe end def as_json(*) -- cgit v1.2.3 From f1d74871e7f00e8bbde3501a759487ac8cc4c3fc Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Fri, 13 Apr 2018 16:23:04 -0700 Subject: Rename from Active Text to Action Text This is more like Action View than Active Model. --- README.md | 6 +- Rakefile | 2 +- actiontext.gemspec | 28 ++++++ activetext.gemspec | 28 ------ app/helpers/action_text/tag_helper.rb | 48 ++++++++++ app/helpers/active_text/tag_helper.rb | 48 ---------- app/javascript/actiontext/attachment_upload.js | 45 +++++++++ app/javascript/actiontext/index.js | 11 +++ app/javascript/activetext/attachment_upload.js | 45 --------- app/javascript/activetext/index.js | 11 --- lib/action_text.rb | 35 +++++++ lib/action_text/attachable.rb | 64 +++++++++++++ lib/action_text/attachables/content_attachment.rb | 36 ++++++++ lib/action_text/attachables/missing_attachable.rb | 11 +++ lib/action_text/attachables/remote_image.rb | 44 +++++++++ lib/action_text/attachment.rb | 101 +++++++++++++++++++++ lib/action_text/attachments/caching.rb | 14 +++ lib/action_text/attachments/minification.rb | 15 +++ lib/action_text/attachments/trix_conversion.rb | 32 +++++++ lib/action_text/attribute.rb | 18 ++++ lib/action_text/content.rb | 84 +++++++++++++++++ lib/action_text/engine.rb | 45 +++++++++ lib/action_text/fragment.rb | 55 +++++++++++ lib/action_text/html_conversion.rb | 22 +++++ lib/action_text/plain_text_conversion.rb | 79 ++++++++++++++++ lib/action_text/serialization.rb | 32 +++++++ lib/action_text/trix_attachment.rb | 89 ++++++++++++++++++ lib/action_text/version.rb | 3 + lib/active_text.rb | 35 ------- lib/active_text/attachable.rb | 64 ------------- lib/active_text/attachables/content_attachment.rb | 36 -------- lib/active_text/attachables/missing_attachable.rb | 11 --- lib/active_text/attachables/remote_image.rb | 44 --------- lib/active_text/attachment.rb | 101 --------------------- lib/active_text/attachments/caching.rb | 14 --- lib/active_text/attachments/minification.rb | 15 --- lib/active_text/attachments/trix_conversion.rb | 32 ------- lib/active_text/attribute.rb | 18 ---- lib/active_text/content.rb | 84 ----------------- lib/active_text/engine.rb | 45 --------- lib/active_text/fragment.rb | 55 ----------- lib/active_text/html_conversion.rb | 22 ----- lib/active_text/plain_text_conversion.rb | 79 ---------------- lib/active_text/serialization.rb | 32 ------- lib/active_text/trix_attachment.rb | 89 ------------------ lib/active_text/version.rb | 3 - .../app/controllers/application_controller.rb | 6 +- test/dummy/config/application.rb | 2 +- test/unit/content_test.rb | 2 +- 49 files changed, 920 insertions(+), 920 deletions(-) create mode 100644 actiontext.gemspec delete mode 100644 activetext.gemspec create mode 100644 app/helpers/action_text/tag_helper.rb delete mode 100644 app/helpers/active_text/tag_helper.rb create mode 100644 app/javascript/actiontext/attachment_upload.js create mode 100644 app/javascript/actiontext/index.js delete mode 100644 app/javascript/activetext/attachment_upload.js delete mode 100644 app/javascript/activetext/index.js create mode 100644 lib/action_text.rb create mode 100644 lib/action_text/attachable.rb create mode 100644 lib/action_text/attachables/content_attachment.rb create mode 100644 lib/action_text/attachables/missing_attachable.rb create mode 100644 lib/action_text/attachables/remote_image.rb create mode 100644 lib/action_text/attachment.rb create mode 100644 lib/action_text/attachments/caching.rb create mode 100644 lib/action_text/attachments/minification.rb create mode 100644 lib/action_text/attachments/trix_conversion.rb create mode 100644 lib/action_text/attribute.rb create mode 100644 lib/action_text/content.rb create mode 100644 lib/action_text/engine.rb create mode 100644 lib/action_text/fragment.rb create mode 100644 lib/action_text/html_conversion.rb create mode 100644 lib/action_text/plain_text_conversion.rb create mode 100644 lib/action_text/serialization.rb create mode 100644 lib/action_text/trix_attachment.rb create mode 100644 lib/action_text/version.rb delete mode 100644 lib/active_text.rb delete mode 100644 lib/active_text/attachable.rb delete mode 100644 lib/active_text/attachables/content_attachment.rb delete mode 100644 lib/active_text/attachables/missing_attachable.rb delete mode 100644 lib/active_text/attachables/remote_image.rb delete mode 100644 lib/active_text/attachment.rb delete mode 100644 lib/active_text/attachments/caching.rb delete mode 100644 lib/active_text/attachments/minification.rb delete mode 100644 lib/active_text/attachments/trix_conversion.rb delete mode 100644 lib/active_text/attribute.rb delete mode 100644 lib/active_text/content.rb delete mode 100644 lib/active_text/engine.rb delete mode 100644 lib/active_text/fragment.rb delete mode 100644 lib/active_text/html_conversion.rb delete mode 100644 lib/active_text/plain_text_conversion.rb delete mode 100644 lib/active_text/serialization.rb delete mode 100644 lib/active_text/trix_attachment.rb delete mode 100644 lib/active_text/version.rb diff --git a/README.md b/README.md index b01cb8bbf3..715c60e9c2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Active Text +# Action Text 🤸‍♂️💰📝 @@ -10,7 +10,7 @@ Assumes a Rails 5.2+ application with Active Storage and Webpacker installed. ```ruby # Gemfile - gem "activetext", github: "basecamp/activetext", require: "active_text" + gem "activetext", github: "basecamp/activetext", require: "action_text" gem "mini_magick" # for Active Storage variants ``` @@ -32,7 +32,7 @@ Assumes a Rails 5.2+ application with Active Storage and Webpacker installed. import "activetext" ``` -1. Declare text columns as Active Text attributes: +1. Declare text columns as Action Text attributes: ```ruby # app/models/message.rb diff --git a/Rakefile b/Rakefile index f6c2a1304c..fdcbee9c15 100644 --- a/Rakefile +++ b/Rakefile @@ -8,7 +8,7 @@ require 'rdoc/task' RDoc::Task.new(:rdoc) do |rdoc| rdoc.rdoc_dir = 'rdoc' - rdoc.title = 'Active Text' + rdoc.title = 'Action Text' rdoc.options << '--line-numbers' rdoc.rdoc_files.include('README.md') rdoc.rdoc_files.include('lib/**/*.rb') diff --git a/actiontext.gemspec b/actiontext.gemspec new file mode 100644 index 0000000000..8139154e74 --- /dev/null +++ b/actiontext.gemspec @@ -0,0 +1,28 @@ +$:.push File.expand_path("lib", __dir__) + +# Maintain your gem's version: +require "action_text/version" + +# Describe your gem and declare its dependencies: +Gem::Specification.new do |s| + s.name = "activetext" + s.version = ActionText::VERSION + s.authors = ["Javan Makhmali", "Sam Stephenson"] + s.email = ["javan@javan.us", "sstephenson@gmail.com"] + s.summary = "Edit and display rich text in Rails applications" + s.homepage = "https://github.com/basecamp/activetext" + s.license = "MIT" + + s.required_ruby_version = ">= 2.2.2" + + s.add_dependency "rails", ">= 5.2.0.rc1" + s.add_dependency "nokogiri" + + s.add_development_dependency "bundler", "~> 1.15" + s.add_development_dependency "mini_magick" + s.add_development_dependency "sqlite3" + s.add_development_dependency "webpacker", "~> 3.2.2" + + s.files = `git ls-files`.split("\n") + s.test_files = `git ls-files -- test/*`.split("\n") +end diff --git a/activetext.gemspec b/activetext.gemspec deleted file mode 100644 index 37fe805279..0000000000 --- a/activetext.gemspec +++ /dev/null @@ -1,28 +0,0 @@ -$:.push File.expand_path("lib", __dir__) - -# Maintain your gem's version: -require "active_text/version" - -# Describe your gem and declare its dependencies: -Gem::Specification.new do |s| - s.name = "activetext" - s.version = ActiveText::VERSION - s.authors = ["Javan Makhmali", "Sam Stephenson"] - s.email = ["javan@javan.us", "sstephenson@gmail.com"] - s.summary = "Edit and display rich text in Rails applications" - s.homepage = "https://github.com/basecamp/activetext" - s.license = "MIT" - - s.required_ruby_version = ">= 2.2.2" - - s.add_dependency "rails", ">= 5.2.0.rc1" - s.add_dependency "nokogiri" - - s.add_development_dependency "bundler", "~> 1.15" - s.add_development_dependency "mini_magick" - s.add_development_dependency "sqlite3" - s.add_development_dependency "webpacker", "~> 3.2.2" - - s.files = `git ls-files`.split("\n") - s.test_files = `git ls-files -- test/*`.split("\n") -end diff --git a/app/helpers/action_text/tag_helper.rb b/app/helpers/action_text/tag_helper.rb new file mode 100644 index 0000000000..bd2727bca6 --- /dev/null +++ b/app/helpers/action_text/tag_helper.rb @@ -0,0 +1,48 @@ +module ActionText + module TagHelper + cattr_accessor(:id, instance_accessor: false) { 0 } + + def rich_text_field_tag(name, value = nil, options = {}) + options = options.symbolize_keys + + options[:input] ||= "trix_input_#{ActionText::TagHelper.id += 1}" + options[:data] ||= {} + options[:data][:direct_upload_url] = rails_direct_uploads_url + options[:data][:blob_url_template] = rails_service_blob_url(":signed_id", ":filename") + + editor_tag = content_tag("trix-editor", "", options) + input_tag = hidden_field_tag(name, value, id: options[:input]) + + editor_tag + input_tag + end + end +end + +module ActionView::Helpers + class Tags::ActionText < Tags::Base + delegate :dom_id, to: ActionView::RecordIdentifier + + def render + options = @options.stringify_keys + add_default_name_and_id(options) + options["input"] ||= dom_id(object, [options["id"], :trix_input].compact.join("_")) + @template_object.rich_text_field_tag(options.delete("name"), editable_value, options) + end + + def editable_value + value.try(:to_trix_html) + end + end + + module FormHelper + def rich_text_field(object_name, method, options = {}) + Tags::ActionText.new(object_name, method, self, options).render + end + end + + class FormBuilder + def rich_text_field(method, options = {}) + @template.rich_text_field(@object_name, method, objectify_options(options)) + end + end +end diff --git a/app/helpers/active_text/tag_helper.rb b/app/helpers/active_text/tag_helper.rb deleted file mode 100644 index 1b97621dac..0000000000 --- a/app/helpers/active_text/tag_helper.rb +++ /dev/null @@ -1,48 +0,0 @@ -module ActiveText - module TagHelper - cattr_accessor(:id, instance_accessor: false) { 0 } - - def rich_text_field_tag(name, value = nil, options = {}) - options = options.symbolize_keys - - options[:input] ||= "trix_input_#{ActiveText::TagHelper.id += 1}" - options[:data] ||= {} - options[:data][:direct_upload_url] = rails_direct_uploads_url - options[:data][:blob_url_template] = rails_service_blob_url(":signed_id", ":filename") - - editor_tag = content_tag("trix-editor", "", options) - input_tag = hidden_field_tag(name, value, id: options[:input]) - - editor_tag + input_tag - end - end -end - -module ActionView::Helpers - class Tags::ActiveText < Tags::Base - delegate :dom_id, to: ActionView::RecordIdentifier - - def render - options = @options.stringify_keys - add_default_name_and_id(options) - options["input"] ||= dom_id(object, [options["id"], :trix_input].compact.join("_")) - @template_object.rich_text_field_tag(options.delete("name"), editable_value, options) - end - - def editable_value - value.try(:to_trix_html) - end - end - - module FormHelper - def rich_text_field(object_name, method, options = {}) - Tags::ActiveText.new(object_name, method, self, options).render - end - end - - class FormBuilder - def rich_text_field(method, options = {}) - @template.rich_text_field(@object_name, method, objectify_options(options)) - end - end -end diff --git a/app/javascript/actiontext/attachment_upload.js b/app/javascript/actiontext/attachment_upload.js new file mode 100644 index 0000000000..a716f1f589 --- /dev/null +++ b/app/javascript/actiontext/attachment_upload.js @@ -0,0 +1,45 @@ +import { DirectUpload } from "activestorage" + +export class AttachmentUpload { + constructor(attachment, element) { + this.attachment = attachment + this.element = element + this.directUpload = new DirectUpload(attachment.file, this.directUploadUrl, this) + } + + start() { + this.directUpload.create(this.directUploadDidComplete.bind(this)) + } + + directUploadWillStoreFileWithXHR(xhr) { + xhr.upload.addEventListener("progress", event => { + const progress = event.loaded / event.total * 100 + this.attachment.setUploadProgress(progress) + }) + } + + directUploadDidComplete(error, attributes) { + if (error) { + throw new Error(`Direct upload failed: ${error}`) + } + + this.attachment.setAttributes({ + sgid: attributes.attachable_sgid, + url: this.createBlobUrl(attributes.signed_id, attributes.filename) + }) + } + + createBlobUrl(signedId, filename) { + return this.blobUrlTemplate + .replace(":signed_id", signedId) + .replace(":filename", encodeURIComponent(filename)) + } + + get directUploadUrl() { + return this.element.dataset.directUploadUrl + } + + get blobUrlTemplate() { + return this.element.dataset.blobUrlTemplate + } +} diff --git a/app/javascript/actiontext/index.js b/app/javascript/actiontext/index.js new file mode 100644 index 0000000000..c149eda952 --- /dev/null +++ b/app/javascript/actiontext/index.js @@ -0,0 +1,11 @@ +import * as Trix from "trix" +import { AttachmentUpload } from "./attachment_upload" + +addEventListener("trix-attachment-add", event => { + const { attachment, target } = event + + if (attachment.file) { + const upload = new AttachmentUpload(attachment, target) + upload.start() + } +}) diff --git a/app/javascript/activetext/attachment_upload.js b/app/javascript/activetext/attachment_upload.js deleted file mode 100644 index a716f1f589..0000000000 --- a/app/javascript/activetext/attachment_upload.js +++ /dev/null @@ -1,45 +0,0 @@ -import { DirectUpload } from "activestorage" - -export class AttachmentUpload { - constructor(attachment, element) { - this.attachment = attachment - this.element = element - this.directUpload = new DirectUpload(attachment.file, this.directUploadUrl, this) - } - - start() { - this.directUpload.create(this.directUploadDidComplete.bind(this)) - } - - directUploadWillStoreFileWithXHR(xhr) { - xhr.upload.addEventListener("progress", event => { - const progress = event.loaded / event.total * 100 - this.attachment.setUploadProgress(progress) - }) - } - - directUploadDidComplete(error, attributes) { - if (error) { - throw new Error(`Direct upload failed: ${error}`) - } - - this.attachment.setAttributes({ - sgid: attributes.attachable_sgid, - url: this.createBlobUrl(attributes.signed_id, attributes.filename) - }) - } - - createBlobUrl(signedId, filename) { - return this.blobUrlTemplate - .replace(":signed_id", signedId) - .replace(":filename", encodeURIComponent(filename)) - } - - get directUploadUrl() { - return this.element.dataset.directUploadUrl - } - - get blobUrlTemplate() { - return this.element.dataset.blobUrlTemplate - } -} diff --git a/app/javascript/activetext/index.js b/app/javascript/activetext/index.js deleted file mode 100644 index c149eda952..0000000000 --- a/app/javascript/activetext/index.js +++ /dev/null @@ -1,11 +0,0 @@ -import * as Trix from "trix" -import { AttachmentUpload } from "./attachment_upload" - -addEventListener("trix-attachment-add", event => { - const { attachment, target } = event - - if (attachment.file) { - const upload = new AttachmentUpload(attachment, target) - upload.start() - } -}) diff --git a/lib/action_text.rb b/lib/action_text.rb new file mode 100644 index 0000000000..0559dce2ba --- /dev/null +++ b/lib/action_text.rb @@ -0,0 +1,35 @@ +require "active_record" +require "action_text/engine" +require "nokogiri" + +module ActionText + extend ActiveSupport::Autoload + + mattr_accessor(:renderer) + + autoload :Attachable + autoload :Attachment + autoload :Attribute + autoload :Content + autoload :Fragment + autoload :HtmlConversion + autoload :PlainTextConversion + autoload :Serialization + autoload :TrixAttachment + + module Attachables + extend ActiveSupport::Autoload + + autoload :ContentAttachment + autoload :MissingAttachable + autoload :RemoteImage + end + + module Attachments + extend ActiveSupport::Autoload + + autoload :Caching + autoload :Minification + autoload :TrixConversion + end +end diff --git a/lib/action_text/attachable.rb b/lib/action_text/attachable.rb new file mode 100644 index 0000000000..83a6cf0c17 --- /dev/null +++ b/lib/action_text/attachable.rb @@ -0,0 +1,64 @@ +module ActionText + module Attachable + extend ActiveSupport::Concern + + LOCATOR_NAME = "attachable" + + class << self + def from_node(node) + if attachable = attachable_from_sgid(node["sgid"]) + attachable + elsif attachable = ActionText::Attachables::ContentAttachment.from_node(node) + attachable + elsif attachable = ActionText::Attachables::RemoteImage.from_node(node) + attachable + else + ActionText::Attachables::MissingAttachable + end + end + + def from_attachable_sgid(sgid, options = {}) + method = sgid.is_a?(Array) ? :locate_many_signed : :locate_signed + record = GlobalID::Locator.public_send(method, sgid, options.merge(for: LOCATOR_NAME)) + record or raise ActiveRecord::RecordNotFound + end + + private + def attachable_from_sgid(sgid) + from_attachable_sgid(sgid) + rescue ActiveRecord::RecordNotFound + nil + end + end + + class_methods do + def from_attachable_sgid(sgid) + ActionText::Attachable.from_attachable_sgid(sgid, only: self) + end + end + + def attachable_sgid + to_sgid(expires_in: nil, for: LOCATOR_NAME).to_s + end + + def attachable_content_type + try(:content_type) || "application/octet-stream" + end + + def previewable_attachable? + false + end + + def as_json(*) + super.merge(attachable_sgid: attachable_sgid) + end + + def to_rich_text_attributes(attributes = {}) + attributes.dup.tap do |attributes| + attributes[:sgid] = attachable_sgid + attributes[:content_type] = attachable_content_type + attributes[:previewable] = true if previewable_attachable? + end + end + end +end diff --git a/lib/action_text/attachables/content_attachment.rb b/lib/action_text/attachables/content_attachment.rb new file mode 100644 index 0000000000..3ebd734786 --- /dev/null +++ b/lib/action_text/attachables/content_attachment.rb @@ -0,0 +1,36 @@ +module ActionText + module Attachables + class ContentAttachment + include ActiveModel::Model + + def self.from_node(node) + if node["content-type"] + if matches = node["content-type"].match(/vnd\.rubyonrails\.(.+)\.html/) + attachment = new(name: matches[1]) + attachment if attachment.valid? + end + end + end + + attr_accessor :name + validates_inclusion_of :name, in: %w( horizontal-rule ) + + def attachable_plain_text_representation(caption) + case name + when "horizontal-rule" + " ┄ " + else + " " + end + end + + def to_partial_path + "action_text/attachables/content_attachment" + end + + def to_trix_content_attachment_partial_path + "action_text/attachables/content_attachments/#{name.underscore}" + end + end + end +end diff --git a/lib/action_text/attachables/missing_attachable.rb b/lib/action_text/attachables/missing_attachable.rb new file mode 100644 index 0000000000..54b36d3cce --- /dev/null +++ b/lib/action_text/attachables/missing_attachable.rb @@ -0,0 +1,11 @@ +module ActionText + module Attachables + module MissingAttachable + extend ActiveModel::Naming + + def self.to_partial_path + "action_text/attachables/missing_attachable" + end + end + end +end diff --git a/lib/action_text/attachables/remote_image.rb b/lib/action_text/attachables/remote_image.rb new file mode 100644 index 0000000000..2333427371 --- /dev/null +++ b/lib/action_text/attachables/remote_image.rb @@ -0,0 +1,44 @@ +module ActionText + module Attachables + class RemoteImage + extend ActiveModel::Naming + + class << self + def from_node(node) + if node["url"] && content_type_is_image?(node["content-type"]) + new(attributes_from_node(node)) + end + end + + private + def content_type_is_image?(content_type) + content_type.to_s =~ /^image(\/.+|$)/ + end + + def attributes_from_node(node) + { url: node["url"], + content_type: node["content-type"], + width: node["width"], + height: node["height"] } + end + end + + attr_reader :url, :content_type, :width, :height + + def initialize(attributes = {}) + @url = attributes[:url] + @content_type = attributes[:content_type] + @width = attributes[:width] + @height = attributes[:height] + end + + def attachable_plain_text_representation(caption) + "[#{caption || "Image"}]" + end + + def to_partial_path + "action_text/attachables/remote_image" + end + end + end +end diff --git a/lib/action_text/attachment.rb b/lib/action_text/attachment.rb new file mode 100644 index 0000000000..2129a3985b --- /dev/null +++ b/lib/action_text/attachment.rb @@ -0,0 +1,101 @@ +module ActionText + class Attachment + include Attachments::TrixConversion, Attachments::Minification, Attachments::Caching + + TAG_NAME = "active-text-attachment" + SELECTOR = TAG_NAME + ATTRIBUTES = %w( sgid content-type url href filename filesize width height previewable caption ) + + class << self + def fragment_by_canonicalizing_attachments(content) + fragment_by_minifying_attachments(fragment_by_converting_trix_attachments(content)) + end + + def from_node(node, attachable = nil) + new(node, attachable || ActionText::Attachable.from_node(node)) + end + + def from_attachables(attachables) + Array(attachables).map { |attachable| from_attachable(attachable) }.compact + end + + def from_attachable(attachable, attributes = {}) + if node = node_from_attributes(attachable.to_rich_text_attributes(attributes)) + new(node, attachable) + end + end + + def from_attributes(attributes, attachable = nil) + if node = node_from_attributes(attributes) + from_node(node, attachable) + end + end + + private + def node_from_attributes(attributes) + if attributes = process_attributes(attributes).presence + ActionText::HtmlConversion.create_element(TAG_NAME, attributes) + end + end + + def process_attributes(attributes) + attributes.transform_keys { |key| key.to_s.underscore.dasherize }.slice(*ATTRIBUTES) + end + end + + attr_reader :node, :attachable + + delegate :to_param, to: :attachable + delegate_missing_to :attachable + + def initialize(node, attachable) + @node = node + @attachable = attachable + end + + def caption + node_attributes["caption"].presence + end + + def full_attributes + node_attributes.merge(attachable_attributes).merge(sgid_attributes) + end + + def with_full_attributes + self.class.from_attributes(full_attributes, attachable) + end + + def to_plain_text + if respond_to?(:attachable_plain_text_representation) + attachable_plain_text_representation(caption) + else + caption.to_s + end + end + + def to_html + HtmlConversion.node_to_html(node) + end + + def to_s + to_html + end + + def inspect + "#<#{self.class.name} attachable=#{attachable.inspect}>" + end + + private + def node_attributes + @node_attributes ||= ATTRIBUTES.map { |name| [ name.underscore, node[name] ] }.to_h.compact + end + + def attachable_attributes + @attachable_attributes ||= (attachable.try(:to_rich_text_attributes) || {}).stringify_keys + end + + def sgid_attributes + @sgid_attributes ||= node_attributes.slice("sgid").presence || attachable_attributes.slice("sgid") + end + end +end diff --git a/lib/action_text/attachments/caching.rb b/lib/action_text/attachments/caching.rb new file mode 100644 index 0000000000..b867e2ff91 --- /dev/null +++ b/lib/action_text/attachments/caching.rb @@ -0,0 +1,14 @@ +module ActionText + module Attachments + module Caching + def cache_key(*args) + [self.class.name, cache_digest, *attachable.cache_key(*args)].join("/") + end + + private + def cache_digest + Digest::SHA256.hexdigest(node.to_s) + end + end + end +end diff --git a/lib/action_text/attachments/minification.rb b/lib/action_text/attachments/minification.rb new file mode 100644 index 0000000000..b1ca43b7b8 --- /dev/null +++ b/lib/action_text/attachments/minification.rb @@ -0,0 +1,15 @@ +module ActionText + module Attachments + module Minification + extend ActiveSupport::Concern + + class_methods do + def fragment_by_minifying_attachments(content) + Fragment.wrap(content).replace(ActionText::Attachment::SELECTOR) do |node| + node.tap { |n| n.inner_html = "" } + end + end + end + end + end +end diff --git a/lib/action_text/attachments/trix_conversion.rb b/lib/action_text/attachments/trix_conversion.rb new file mode 100644 index 0000000000..39989ce644 --- /dev/null +++ b/lib/action_text/attachments/trix_conversion.rb @@ -0,0 +1,32 @@ +module ActionText + module Attachments + module TrixConversion + extend ActiveSupport::Concern + + class_methods do + def fragment_by_converting_trix_attachments(content) + Fragment.wrap(content).replace(TrixAttachment::SELECTOR) do |node| + from_trix_attachment(TrixAttachment.new(node)) + end + end + + def from_trix_attachment(trix_attachment) + from_attributes(trix_attachment.attributes) + end + end + + def to_trix_attachment(content = trix_attachment_content) + attributes = full_attributes.dup + attributes["content"] = content if content + TrixAttachment.from_attributes(attributes) + end + + private + def trix_attachment_content + if partial_path = attachable.try(:to_trix_content_attachment_partial_path) + ActionText.renderer.render(partial: partial_path, object: self, as: model_name.element) + end + end + end + end +end diff --git a/lib/action_text/attribute.rb b/lib/action_text/attribute.rb new file mode 100644 index 0000000000..32dd1d0e3f --- /dev/null +++ b/lib/action_text/attribute.rb @@ -0,0 +1,18 @@ +module ActionText + module Attribute + extend ActiveSupport::Concern + + class_methods do + def has_rich_text(attribute_name) + serialize(attribute_name, ActionText::Content) + + has_many_attached "#{attribute_name}_attachments" + + after_save do + blobs = public_send(attribute_name).attachments.map(&:attachable) + public_send("#{attribute_name}_attachments_blobs=", blobs) + end + end + end + end +end diff --git a/lib/action_text/content.rb b/lib/action_text/content.rb new file mode 100644 index 0000000000..c63e0c3525 --- /dev/null +++ b/lib/action_text/content.rb @@ -0,0 +1,84 @@ +module ActionText + class Content + include Serialization + + attr_reader :fragment + + delegate :blank?, :empty?, :html_safe, :present?, to: :to_s + + def initialize(content = nil) + @fragment = ActionText::Attachment.fragment_by_canonicalizing_attachments(content) + end + + def links + @links ||= fragment.find_all("a[href]").map { |a| a["href"] }.uniq + end + + def attachments + @attachments ||= attachment_nodes.map do |node| + attachment_for_node(node) + end + end + + def attachables + @attachables ||= attachment_nodes.map do |node| + ActionText::Attachable.from_node(node) + end + end + + def append_attachables(attachables) + attachments = ActionText::Attachment.from_attachables(attachables) + self.class.new([self.to_s.presence, *attachments].compact.join("\n")) + end + + def render_attachments(**options, &block) + fragment.replace(ActionText::Attachment::SELECTOR) do |node| + block.call(attachment_for_node(node, **options)) + end + end + + def to_plain_text + render_attachments(with_full_attributes: false, &:to_plain_text).to_plain_text + end + + def to_trix_html + render_attachments(&:to_trix_attachment).to_html + end + + def to_html + render_attachments do |attachment| + attachment.node.tap do |node| + node.inner_html = ActionText.renderer.render(attachment) + end + end.to_html + end + + def to_s + to_html.html_safe + end + + def as_json(*) + to_html + end + + def inspect + "#<#{self.class.name} #{to_s.truncate(25).inspect}>" + end + + def ==(other) + if other.is_a?(self.class) + to_s == other.to_s + end + end + + private + def attachment_nodes + @attachment_nodes ||= fragment.find_all(ActionText::Attachment::SELECTOR) + end + + def attachment_for_node(node, with_full_attributes: true) + attachment = ActionText::Attachment.from_node(node) + with_full_attributes ? attachment.with_full_attributes : attachment + end + end +end diff --git a/lib/action_text/engine.rb b/lib/action_text/engine.rb new file mode 100644 index 0000000000..71db6d6a26 --- /dev/null +++ b/lib/action_text/engine.rb @@ -0,0 +1,45 @@ +require "rails/engine" + +module ActionText + class Engine < Rails::Engine + isolate_namespace ActionText + config.eager_load_namespaces << ActionText + + initializer "action_text.attribute" do + ActiveSupport.on_load(:active_record) do + include ActionText::Attribute + end + end + + initializer "action_text.active_storage_extension" do + require "active_storage/blob" + + class ActiveStorage::Blob + include ActionText::Attachable + + def previewable_attachable? + representable? + end + end + end + + initializer "action_text.helper" do + ActiveSupport.on_load(:action_controller_base) do + helper ActionText::TagHelper + end + end + + initializer "action_text.config" do + config.after_initialize do |app| + ActionText.renderer ||= ApplicationController.renderer + + # FIXME: ApplicationController should have a per-request specific renderer + # that's been set with the request.env env, and ActionText should just piggyback off + # that by default rather than doing this work directly. + ApplicationController.before_action do + ActionText.renderer = ActionText.renderer.new(request.env) + end + end + end + end +end diff --git a/lib/action_text/fragment.rb b/lib/action_text/fragment.rb new file mode 100644 index 0000000000..63b088f3e1 --- /dev/null +++ b/lib/action_text/fragment.rb @@ -0,0 +1,55 @@ +module ActionText + class Fragment + class << self + def wrap(fragment_or_html) + case fragment_or_html + when self + fragment_or_html + when Nokogiri::HTML::DocumentFragment + new(fragment_or_html) + else + from_html(fragment_or_html) + end + end + + def from_html(html) + new(ActionText::HtmlConversion.fragment_for_html(html.to_s.strip)) + end + end + + attr_reader :source + + def initialize(source) + @source = source + end + + def find_all(selector) + source.css(selector) + end + + def update + yield source = self.source.clone + self.class.new(source) + end + + def replace(selector) + update do |source| + source.css(selector).each do |node| + node.replace(yield(node).to_s) + end + end + end + + def to_plain_text + @plain_text ||= PlainTextConversion.node_to_plain_text(source) + end + + def to_html + @html ||= HtmlConversion.node_to_html(source) + end + + def to_s + to_html + end + end +end diff --git a/lib/action_text/html_conversion.rb b/lib/action_text/html_conversion.rb new file mode 100644 index 0000000000..1c70504fb7 --- /dev/null +++ b/lib/action_text/html_conversion.rb @@ -0,0 +1,22 @@ +module ActionText + module HtmlConversion + extend self + + def node_to_html(node) + node.to_html(save_with: Nokogiri::XML::Node::SaveOptions::AS_HTML) + end + + def fragment_for_html(html) + document.fragment(html) + end + + def create_element(tag_name, attributes = {}) + document.create_element(tag_name, attributes) + end + + private + def document + Nokogiri::HTML::Document.new.tap { |doc| doc.encoding = "UTF-8" } + end + end +end diff --git a/lib/action_text/plain_text_conversion.rb b/lib/action_text/plain_text_conversion.rb new file mode 100644 index 0000000000..c9867bd8c9 --- /dev/null +++ b/lib/action_text/plain_text_conversion.rb @@ -0,0 +1,79 @@ +module ActionText + module PlainTextConversion + extend self + + def node_to_plain_text(node) + remove_trailing_newlines(plain_text_for_node(node)) + end + + private + def plain_text_for_node(node, index = 0) + if respond_to?(plain_text_method_for_node(node), true) + send(plain_text_method_for_node(node), node, index) + else + plain_text_for_node_children(node) + end + end + + def plain_text_for_node_children(node) + node.children.each_with_index.map do |child, index| + plain_text_for_node(child, index) + end.compact.join("") + end + + def plain_text_method_for_node(node) + :"plain_text_for_#{node.name}_node" + end + + def plain_text_for_block(node, index = 0) + "#{remove_trailing_newlines(plain_text_for_node_children(node))}\n\n" + end + + %i[ p ul ol ].each do |element| + alias_method :"plain_text_for_#{element}_node", :plain_text_for_block + end + + def plain_text_for_br_node(node, index) + "\n" + end + + def plain_text_for_text_node(node, index) + remove_trailing_newlines(node.text) + end + + def plain_text_for_div_node(node, index) + "#{remove_trailing_newlines(plain_text_for_node_children(node))}\n" + end + + def plain_text_for_figcaption_node(node, index) + "[#{remove_trailing_newlines(plain_text_for_node_children(node))}]" + end + + def plain_text_for_blockquote_node(node, index) + text = plain_text_for_block(node) + text.sub(/\A(\s*)(.+?)(\s*)\Z/m, '\1“\2”\3') + end + + def plain_text_for_li_node(node, index) + bullet = bullet_for_li_node(node, index) + text = remove_trailing_newlines(plain_text_for_node_children(node)) + "#{bullet} #{text}\n" + end + + def remove_trailing_newlines(text) + text.chomp("") + end + + def bullet_for_li_node(node, index) + if list_node_name_for_li_node(node) == "ol" + "#{index + 1}." + else + "•" + end + end + + def list_node_name_for_li_node(node) + node.ancestors.lazy.map(&:name).grep(/^[uo]l$/).first + end + end +end diff --git a/lib/action_text/serialization.rb b/lib/action_text/serialization.rb new file mode 100644 index 0000000000..ac2b0602d5 --- /dev/null +++ b/lib/action_text/serialization.rb @@ -0,0 +1,32 @@ +module ActionText + module Serialization + extend ActiveSupport::Concern + + class_methods do + def load(content) + new(content) if content + end + + def dump(content) + case content + when nil + nil + when self + content.to_html + else + new(content).to_html + end + end + end + + # Marshal compatibility + + class_methods do + alias_method :_load, :load + end + + def _dump(*) + self.class.dump(self) + end + end +end diff --git a/lib/action_text/trix_attachment.rb b/lib/action_text/trix_attachment.rb new file mode 100644 index 0000000000..717d130d12 --- /dev/null +++ b/lib/action_text/trix_attachment.rb @@ -0,0 +1,89 @@ +module ActionText + class TrixAttachment + TAG_NAME = "figure" + SELECTOR = "[data-trix-attachment]" + + ATTRIBUTES = %w( sgid contentType url href filename filesize width height previewable content caption ) + ATTRIBUTE_TYPES = { + "previewable" => ->(value) { value.to_s == "true" }, + "filesize" => ->(value) { Integer(value.to_s) rescue value }, + "width" => ->(value) { Integer(value.to_s) rescue nil }, + "height" => ->(value) { Integer(value.to_s) rescue nil }, + :default => ->(value) { value.to_s } + } + + class << self + def from_attributes(attributes) + attributes = process_attributes(attributes) + + trix_attachment_attributes = attributes.except("caption") + trix_attributes = attributes.slice("caption") + + node = ActionText::HtmlConversion.create_element(TAG_NAME) + node["data-trix-attachment"] = JSON.generate(trix_attachment_attributes) + node["data-trix-attributes"] = JSON.generate(trix_attributes) if trix_attributes.any? + + new(node) + end + + private + def process_attributes(attributes) + typecast_attribute_values(transform_attribute_keys(attributes)) + end + + def transform_attribute_keys(attributes) + attributes.transform_keys { |key| key.to_s.underscore.camelize(:lower) } + end + + def typecast_attribute_values(attributes) + attributes.map do |key, value| + typecast = ATTRIBUTE_TYPES[key] || ATTRIBUTE_TYPES[:default] + [key, typecast.call(value)] + end.to_h + end + end + + attr_reader :node + + def initialize(node) + @node = node + end + + def attributes + @attributes ||= attachment_attributes.merge(composed_attributes).slice(*ATTRIBUTES) + end + + def to_html + ActionText::HtmlConversion.node_to_html(node) + end + + def to_s + to_html + end + + private + def attachment_attributes + read_json_object_attribute("data-trix-attachment") + end + + def composed_attributes + read_json_object_attribute("data-trix-attributes") + end + + def read_json_object_attribute(name) + read_json_attribute(name) || {} + end + + def read_json_attribute(name) + if value = node[name] + begin + JSON.parse(value) + rescue => e + Rails.logger.error "[#{self.class.name}] Couldn't parse JSON #{value} from NODE #{node.inspect}" + Rails.logger.error "[#{self.class.name}] Failed with #{e.class}: #{e.backtrace}" + nil + end + end + end + end +end diff --git a/lib/action_text/version.rb b/lib/action_text/version.rb new file mode 100644 index 0000000000..bc34656697 --- /dev/null +++ b/lib/action_text/version.rb @@ -0,0 +1,3 @@ +module ActionText + VERSION = '0.1.0' +end diff --git a/lib/active_text.rb b/lib/active_text.rb deleted file mode 100644 index 8275d7d17a..0000000000 --- a/lib/active_text.rb +++ /dev/null @@ -1,35 +0,0 @@ -require "active_record" -require "active_text/engine" -require "nokogiri" - -module ActiveText - extend ActiveSupport::Autoload - - mattr_accessor(:renderer) - - autoload :Attachable - autoload :Attachment - autoload :Attribute - autoload :Content - autoload :Fragment - autoload :HtmlConversion - autoload :PlainTextConversion - autoload :Serialization - autoload :TrixAttachment - - module Attachables - extend ActiveSupport::Autoload - - autoload :ContentAttachment - autoload :MissingAttachable - autoload :RemoteImage - end - - module Attachments - extend ActiveSupport::Autoload - - autoload :Caching - autoload :Minification - autoload :TrixConversion - end -end diff --git a/lib/active_text/attachable.rb b/lib/active_text/attachable.rb deleted file mode 100644 index f3ea47282f..0000000000 --- a/lib/active_text/attachable.rb +++ /dev/null @@ -1,64 +0,0 @@ -module ActiveText - module Attachable - extend ActiveSupport::Concern - - LOCATOR_NAME = "attachable" - - class << self - def from_node(node) - if attachable = attachable_from_sgid(node["sgid"]) - attachable - elsif attachable = ActiveText::Attachables::ContentAttachment.from_node(node) - attachable - elsif attachable = ActiveText::Attachables::RemoteImage.from_node(node) - attachable - else - ActiveText::Attachables::MissingAttachable - end - end - - def from_attachable_sgid(sgid, options = {}) - method = sgid.is_a?(Array) ? :locate_many_signed : :locate_signed - record = GlobalID::Locator.public_send(method, sgid, options.merge(for: LOCATOR_NAME)) - record or raise ActiveRecord::RecordNotFound - end - - private - def attachable_from_sgid(sgid) - from_attachable_sgid(sgid) - rescue ActiveRecord::RecordNotFound - nil - end - end - - class_methods do - def from_attachable_sgid(sgid) - ActiveText::Attachable.from_attachable_sgid(sgid, only: self) - end - end - - def attachable_sgid - to_sgid(expires_in: nil, for: LOCATOR_NAME).to_s - end - - def attachable_content_type - try(:content_type) || "application/octet-stream" - end - - def previewable_attachable? - false - end - - def as_json(*) - super.merge(attachable_sgid: attachable_sgid) - end - - def to_rich_text_attributes(attributes = {}) - attributes.dup.tap do |attributes| - attributes[:sgid] = attachable_sgid - attributes[:content_type] = attachable_content_type - attributes[:previewable] = true if previewable_attachable? - end - end - end -end diff --git a/lib/active_text/attachables/content_attachment.rb b/lib/active_text/attachables/content_attachment.rb deleted file mode 100644 index 316d7e304a..0000000000 --- a/lib/active_text/attachables/content_attachment.rb +++ /dev/null @@ -1,36 +0,0 @@ -module ActiveText - module Attachables - class ContentAttachment - include ActiveModel::Model - - def self.from_node(node) - if node["content-type"] - if matches = node["content-type"].match(/vnd\.rubyonrails\.(.+)\.html/) - attachment = new(name: matches[1]) - attachment if attachment.valid? - end - end - end - - attr_accessor :name - validates_inclusion_of :name, in: %w( horizontal-rule ) - - def attachable_plain_text_representation(caption) - case name - when "horizontal-rule" - " ┄ " - else - " " - end - end - - def to_partial_path - "active_text/attachables/content_attachment" - end - - def to_trix_content_attachment_partial_path - "active_text/attachables/content_attachments/#{name.underscore}" - end - end - end -end diff --git a/lib/active_text/attachables/missing_attachable.rb b/lib/active_text/attachables/missing_attachable.rb deleted file mode 100644 index 94a095ce09..0000000000 --- a/lib/active_text/attachables/missing_attachable.rb +++ /dev/null @@ -1,11 +0,0 @@ -module ActiveText - module Attachables - module MissingAttachable - extend ActiveModel::Naming - - def self.to_partial_path - "active_text/attachables/missing_attachable" - end - end - end -end diff --git a/lib/active_text/attachables/remote_image.rb b/lib/active_text/attachables/remote_image.rb deleted file mode 100644 index 0624b5564d..0000000000 --- a/lib/active_text/attachables/remote_image.rb +++ /dev/null @@ -1,44 +0,0 @@ -module ActiveText - module Attachables - class RemoteImage - extend ActiveModel::Naming - - class << self - def from_node(node) - if node["url"] && content_type_is_image?(node["content-type"]) - new(attributes_from_node(node)) - end - end - - private - def content_type_is_image?(content_type) - content_type.to_s =~ /^image(\/.+|$)/ - end - - def attributes_from_node(node) - { url: node["url"], - content_type: node["content-type"], - width: node["width"], - height: node["height"] } - end - end - - attr_reader :url, :content_type, :width, :height - - def initialize(attributes = {}) - @url = attributes[:url] - @content_type = attributes[:content_type] - @width = attributes[:width] - @height = attributes[:height] - end - - def attachable_plain_text_representation(caption) - "[#{caption || "Image"}]" - end - - def to_partial_path - "active_text/attachables/remote_image" - end - end - end -end diff --git a/lib/active_text/attachment.rb b/lib/active_text/attachment.rb deleted file mode 100644 index fab6c3507b..0000000000 --- a/lib/active_text/attachment.rb +++ /dev/null @@ -1,101 +0,0 @@ -module ActiveText - class Attachment - include Attachments::TrixConversion, Attachments::Minification, Attachments::Caching - - TAG_NAME = "active-text-attachment" - SELECTOR = TAG_NAME - ATTRIBUTES = %w( sgid content-type url href filename filesize width height previewable caption ) - - class << self - def fragment_by_canonicalizing_attachments(content) - fragment_by_minifying_attachments(fragment_by_converting_trix_attachments(content)) - end - - def from_node(node, attachable = nil) - new(node, attachable || ActiveText::Attachable.from_node(node)) - end - - def from_attachables(attachables) - Array(attachables).map { |attachable| from_attachable(attachable) }.compact - end - - def from_attachable(attachable, attributes = {}) - if node = node_from_attributes(attachable.to_rich_text_attributes(attributes)) - new(node, attachable) - end - end - - def from_attributes(attributes, attachable = nil) - if node = node_from_attributes(attributes) - from_node(node, attachable) - end - end - - private - def node_from_attributes(attributes) - if attributes = process_attributes(attributes).presence - ActiveText::HtmlConversion.create_element(TAG_NAME, attributes) - end - end - - def process_attributes(attributes) - attributes.transform_keys { |key| key.to_s.underscore.dasherize }.slice(*ATTRIBUTES) - end - end - - attr_reader :node, :attachable - - delegate :to_param, to: :attachable - delegate_missing_to :attachable - - def initialize(node, attachable) - @node = node - @attachable = attachable - end - - def caption - node_attributes["caption"].presence - end - - def full_attributes - node_attributes.merge(attachable_attributes).merge(sgid_attributes) - end - - def with_full_attributes - self.class.from_attributes(full_attributes, attachable) - end - - def to_plain_text - if respond_to?(:attachable_plain_text_representation) - attachable_plain_text_representation(caption) - else - caption.to_s - end - end - - def to_html - HtmlConversion.node_to_html(node) - end - - def to_s - to_html - end - - def inspect - "#<#{self.class.name} attachable=#{attachable.inspect}>" - end - - private - def node_attributes - @node_attributes ||= ATTRIBUTES.map { |name| [ name.underscore, node[name] ] }.to_h.compact - end - - def attachable_attributes - @attachable_attributes ||= (attachable.try(:to_rich_text_attributes) || {}).stringify_keys - end - - def sgid_attributes - @sgid_attributes ||= node_attributes.slice("sgid").presence || attachable_attributes.slice("sgid") - end - end -end diff --git a/lib/active_text/attachments/caching.rb b/lib/active_text/attachments/caching.rb deleted file mode 100644 index b0194170e1..0000000000 --- a/lib/active_text/attachments/caching.rb +++ /dev/null @@ -1,14 +0,0 @@ -module ActiveText - module Attachments - module Caching - def cache_key(*args) - [self.class.name, cache_digest, *attachable.cache_key(*args)].join("/") - end - - private - def cache_digest - Digest::SHA256.hexdigest(node.to_s) - end - end - end -end diff --git a/lib/active_text/attachments/minification.rb b/lib/active_text/attachments/minification.rb deleted file mode 100644 index aa25875aae..0000000000 --- a/lib/active_text/attachments/minification.rb +++ /dev/null @@ -1,15 +0,0 @@ -module ActiveText - module Attachments - module Minification - extend ActiveSupport::Concern - - class_methods do - def fragment_by_minifying_attachments(content) - Fragment.wrap(content).replace(ActiveText::Attachment::SELECTOR) do |node| - node.tap { |n| n.inner_html = "" } - end - end - end - end - end -end diff --git a/lib/active_text/attachments/trix_conversion.rb b/lib/active_text/attachments/trix_conversion.rb deleted file mode 100644 index 3eb83453f4..0000000000 --- a/lib/active_text/attachments/trix_conversion.rb +++ /dev/null @@ -1,32 +0,0 @@ -module ActiveText - module Attachments - module TrixConversion - extend ActiveSupport::Concern - - class_methods do - def fragment_by_converting_trix_attachments(content) - Fragment.wrap(content).replace(TrixAttachment::SELECTOR) do |node| - from_trix_attachment(TrixAttachment.new(node)) - end - end - - def from_trix_attachment(trix_attachment) - from_attributes(trix_attachment.attributes) - end - end - - def to_trix_attachment(content = trix_attachment_content) - attributes = full_attributes.dup - attributes["content"] = content if content - TrixAttachment.from_attributes(attributes) - end - - private - def trix_attachment_content - if partial_path = attachable.try(:to_trix_content_attachment_partial_path) - ActiveText.renderer.render(partial: partial_path, object: self, as: model_name.element) - end - end - end - end -end diff --git a/lib/active_text/attribute.rb b/lib/active_text/attribute.rb deleted file mode 100644 index 9f3ee49998..0000000000 --- a/lib/active_text/attribute.rb +++ /dev/null @@ -1,18 +0,0 @@ -module ActiveText - module Attribute - extend ActiveSupport::Concern - - class_methods do - def has_rich_text(attribute_name) - serialize(attribute_name, ActiveText::Content) - - has_many_attached "#{attribute_name}_attachments" - - after_save do - blobs = public_send(attribute_name).attachments.map(&:attachable) - public_send("#{attribute_name}_attachments_blobs=", blobs) - end - end - end - end -end diff --git a/lib/active_text/content.rb b/lib/active_text/content.rb deleted file mode 100644 index 0e97374ded..0000000000 --- a/lib/active_text/content.rb +++ /dev/null @@ -1,84 +0,0 @@ -module ActiveText - class Content - include Serialization - - attr_reader :fragment - - delegate :blank?, :empty?, :html_safe, :present?, to: :to_s - - def initialize(content = nil) - @fragment = ActiveText::Attachment.fragment_by_canonicalizing_attachments(content) - end - - def links - @links ||= fragment.find_all("a[href]").map { |a| a["href"] }.uniq - end - - def attachments - @attachments ||= attachment_nodes.map do |node| - attachment_for_node(node) - end - end - - def attachables - @attachables ||= attachment_nodes.map do |node| - ActiveText::Attachable.from_node(node) - end - end - - def append_attachables(attachables) - attachments = ActiveText::Attachment.from_attachables(attachables) - self.class.new([self.to_s.presence, *attachments].compact.join("\n")) - end - - def render_attachments(**options, &block) - fragment.replace(ActiveText::Attachment::SELECTOR) do |node| - block.call(attachment_for_node(node, **options)) - end - end - - def to_plain_text - render_attachments(with_full_attributes: false, &:to_plain_text).to_plain_text - end - - def to_trix_html - render_attachments(&:to_trix_attachment).to_html - end - - def to_html - render_attachments do |attachment| - attachment.node.tap do |node| - node.inner_html = ActiveText.renderer.render(attachment) - end - end.to_html - end - - def to_s - to_html.html_safe - end - - def as_json(*) - to_html - end - - def inspect - "#<#{self.class.name} #{to_s.truncate(25).inspect}>" - end - - def ==(other) - if other.is_a?(self.class) - to_s == other.to_s - end - end - - private - def attachment_nodes - @attachment_nodes ||= fragment.find_all(ActiveText::Attachment::SELECTOR) - end - - def attachment_for_node(node, with_full_attributes: true) - attachment = ActiveText::Attachment.from_node(node) - with_full_attributes ? attachment.with_full_attributes : attachment - end - end -end diff --git a/lib/active_text/engine.rb b/lib/active_text/engine.rb deleted file mode 100644 index aac0c57881..0000000000 --- a/lib/active_text/engine.rb +++ /dev/null @@ -1,45 +0,0 @@ -require "rails/engine" - -module ActiveText - class Engine < Rails::Engine - isolate_namespace ActiveText - config.eager_load_namespaces << ActiveText - - initializer "active_text.attribute" do - ActiveSupport.on_load(:active_record) do - include ActiveText::Attribute - end - end - - initializer "active_text.active_storage_extension" do - require "active_storage/blob" - - class ActiveStorage::Blob - include ActiveText::Attachable - - def previewable_attachable? - representable? - end - end - end - - initializer "active_text.helper" do - ActiveSupport.on_load(:action_controller_base) do - helper ActiveText::TagHelper - end - end - - initializer "active_text.config" do - config.after_initialize do |app| - ActiveText.renderer ||= ApplicationController.renderer - - # FIXME: ApplicationController should have a per-request specific renderer - # that's been set with the request.env env, and ActiveText should just piggyback off - # that by default rather than doing this work directly. - ApplicationController.before_action do - ActiveText.renderer = ActiveText.renderer.new(request.env) - end - end - end - end -end diff --git a/lib/active_text/fragment.rb b/lib/active_text/fragment.rb deleted file mode 100644 index 9e0af6f57a..0000000000 --- a/lib/active_text/fragment.rb +++ /dev/null @@ -1,55 +0,0 @@ -module ActiveText - class Fragment - class << self - def wrap(fragment_or_html) - case fragment_or_html - when self - fragment_or_html - when Nokogiri::HTML::DocumentFragment - new(fragment_or_html) - else - from_html(fragment_or_html) - end - end - - def from_html(html) - new(ActiveText::HtmlConversion.fragment_for_html(html.to_s.strip)) - end - end - - attr_reader :source - - def initialize(source) - @source = source - end - - def find_all(selector) - source.css(selector) - end - - def update - yield source = self.source.clone - self.class.new(source) - end - - def replace(selector) - update do |source| - source.css(selector).each do |node| - node.replace(yield(node).to_s) - end - end - end - - def to_plain_text - @plain_text ||= PlainTextConversion.node_to_plain_text(source) - end - - def to_html - @html ||= HtmlConversion.node_to_html(source) - end - - def to_s - to_html - end - end -end diff --git a/lib/active_text/html_conversion.rb b/lib/active_text/html_conversion.rb deleted file mode 100644 index 7c35e5cf94..0000000000 --- a/lib/active_text/html_conversion.rb +++ /dev/null @@ -1,22 +0,0 @@ -module ActiveText - module HtmlConversion - extend self - - def node_to_html(node) - node.to_html(save_with: Nokogiri::XML::Node::SaveOptions::AS_HTML) - end - - def fragment_for_html(html) - document.fragment(html) - end - - def create_element(tag_name, attributes = {}) - document.create_element(tag_name, attributes) - end - - private - def document - Nokogiri::HTML::Document.new.tap { |doc| doc.encoding = "UTF-8" } - end - end -end diff --git a/lib/active_text/plain_text_conversion.rb b/lib/active_text/plain_text_conversion.rb deleted file mode 100644 index ecd598e192..0000000000 --- a/lib/active_text/plain_text_conversion.rb +++ /dev/null @@ -1,79 +0,0 @@ -module ActiveText - module PlainTextConversion - extend self - - def node_to_plain_text(node) - remove_trailing_newlines(plain_text_for_node(node)) - end - - private - def plain_text_for_node(node, index = 0) - if respond_to?(plain_text_method_for_node(node), true) - send(plain_text_method_for_node(node), node, index) - else - plain_text_for_node_children(node) - end - end - - def plain_text_for_node_children(node) - node.children.each_with_index.map do |child, index| - plain_text_for_node(child, index) - end.compact.join("") - end - - def plain_text_method_for_node(node) - :"plain_text_for_#{node.name}_node" - end - - def plain_text_for_block(node, index = 0) - "#{remove_trailing_newlines(plain_text_for_node_children(node))}\n\n" - end - - %i[ p ul ol ].each do |element| - alias_method :"plain_text_for_#{element}_node", :plain_text_for_block - end - - def plain_text_for_br_node(node, index) - "\n" - end - - def plain_text_for_text_node(node, index) - remove_trailing_newlines(node.text) - end - - def plain_text_for_div_node(node, index) - "#{remove_trailing_newlines(plain_text_for_node_children(node))}\n" - end - - def plain_text_for_figcaption_node(node, index) - "[#{remove_trailing_newlines(plain_text_for_node_children(node))}]" - end - - def plain_text_for_blockquote_node(node, index) - text = plain_text_for_block(node) - text.sub(/\A(\s*)(.+?)(\s*)\Z/m, '\1“\2”\3') - end - - def plain_text_for_li_node(node, index) - bullet = bullet_for_li_node(node, index) - text = remove_trailing_newlines(plain_text_for_node_children(node)) - "#{bullet} #{text}\n" - end - - def remove_trailing_newlines(text) - text.chomp("") - end - - def bullet_for_li_node(node, index) - if list_node_name_for_li_node(node) == "ol" - "#{index + 1}." - else - "•" - end - end - - def list_node_name_for_li_node(node) - node.ancestors.lazy.map(&:name).grep(/^[uo]l$/).first - end - end -end diff --git a/lib/active_text/serialization.rb b/lib/active_text/serialization.rb deleted file mode 100644 index 46ebeba1aa..0000000000 --- a/lib/active_text/serialization.rb +++ /dev/null @@ -1,32 +0,0 @@ -module ActiveText - module Serialization - extend ActiveSupport::Concern - - class_methods do - def load(content) - new(content) if content - end - - def dump(content) - case content - when nil - nil - when self - content.to_html - else - new(content).to_html - end - end - end - - # Marshal compatibility - - class_methods do - alias_method :_load, :load - end - - def _dump(*) - self.class.dump(self) - end - end -end diff --git a/lib/active_text/trix_attachment.rb b/lib/active_text/trix_attachment.rb deleted file mode 100644 index 19add53414..0000000000 --- a/lib/active_text/trix_attachment.rb +++ /dev/null @@ -1,89 +0,0 @@ -module ActiveText - class TrixAttachment - TAG_NAME = "figure" - SELECTOR = "[data-trix-attachment]" - - ATTRIBUTES = %w( sgid contentType url href filename filesize width height previewable content caption ) - ATTRIBUTE_TYPES = { - "previewable" => ->(value) { value.to_s == "true" }, - "filesize" => ->(value) { Integer(value.to_s) rescue value }, - "width" => ->(value) { Integer(value.to_s) rescue nil }, - "height" => ->(value) { Integer(value.to_s) rescue nil }, - :default => ->(value) { value.to_s } - } - - class << self - def from_attributes(attributes) - attributes = process_attributes(attributes) - - trix_attachment_attributes = attributes.except("caption") - trix_attributes = attributes.slice("caption") - - node = ActiveText::HtmlConversion.create_element(TAG_NAME) - node["data-trix-attachment"] = JSON.generate(trix_attachment_attributes) - node["data-trix-attributes"] = JSON.generate(trix_attributes) if trix_attributes.any? - - new(node) - end - - private - def process_attributes(attributes) - typecast_attribute_values(transform_attribute_keys(attributes)) - end - - def transform_attribute_keys(attributes) - attributes.transform_keys { |key| key.to_s.underscore.camelize(:lower) } - end - - def typecast_attribute_values(attributes) - attributes.map do |key, value| - typecast = ATTRIBUTE_TYPES[key] || ATTRIBUTE_TYPES[:default] - [key, typecast.call(value)] - end.to_h - end - end - - attr_reader :node - - def initialize(node) - @node = node - end - - def attributes - @attributes ||= attachment_attributes.merge(composed_attributes).slice(*ATTRIBUTES) - end - - def to_html - ActiveText::HtmlConversion.node_to_html(node) - end - - def to_s - to_html - end - - private - def attachment_attributes - read_json_object_attribute("data-trix-attachment") - end - - def composed_attributes - read_json_object_attribute("data-trix-attributes") - end - - def read_json_object_attribute(name) - read_json_attribute(name) || {} - end - - def read_json_attribute(name) - if value = node[name] - begin - JSON.parse(value) - rescue => e - Rails.logger.error "[#{self.class.name}] Couldn't parse JSON #{value} from NODE #{node.inspect}" - Rails.logger.error "[#{self.class.name}] Failed with #{e.class}: #{e.backtrace}" - nil - end - end - end - end -end diff --git a/lib/active_text/version.rb b/lib/active_text/version.rb deleted file mode 100644 index 29b47f7eab..0000000000 --- a/lib/active_text/version.rb +++ /dev/null @@ -1,3 +0,0 @@ -module ActiveText - VERSION = '0.1.0' -end diff --git a/test/dummy/app/controllers/application_controller.rb b/test/dummy/app/controllers/application_controller.rb index baaa725746..c774981e25 100644 --- a/test/dummy/app/controllers/application_controller.rb +++ b/test/dummy/app/controllers/application_controller.rb @@ -1,8 +1,8 @@ class ApplicationController < ActionController::Base - before_action :set_active_text_renderer + before_action :set_action_text_renderer private - def set_active_text_renderer - ActiveText.renderer = self.class.renderer.new(request.env) + def set_action_text_renderer + ActionText.renderer = self.class.renderer.new(request.env) end end diff --git a/test/dummy/config/application.rb b/test/dummy/config/application.rb index 7f41fce8d0..ddee05a4db 100644 --- a/test/dummy/config/application.rb +++ b/test/dummy/config/application.rb @@ -3,7 +3,7 @@ require_relative 'boot' require 'rails/all' Bundler.require(*Rails.groups) -require "active_text" +require "action_text" module Dummy class Application < Rails::Application diff --git a/test/unit/content_test.rb b/test/unit/content_test.rb index 5299ae3f8f..e5773361e4 100644 --- a/test/unit/content_test.rb +++ b/test/unit/content_test.rb @@ -1,6 +1,6 @@ require_relative '../test_helper' -module ActiveText +module ActionText class ContentTest < ActiveSupport::TestCase test "plain text conversion" do message = Message.create!(subject: "Greetings", content: "

Hello world

") -- cgit v1.2.3 From 421b185dab403b44216147dbca4964a52241e531 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Fri, 13 Apr 2018 16:26:19 -0700 Subject: Missed a spot --- actiontext.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actiontext.gemspec b/actiontext.gemspec index 8139154e74..16dc61e595 100644 --- a/actiontext.gemspec +++ b/actiontext.gemspec @@ -5,7 +5,7 @@ require "action_text/version" # Describe your gem and declare its dependencies: Gem::Specification.new do |s| - s.name = "activetext" + s.name = "actiontext" s.version = ActionText::VERSION s.authors = ["Javan Makhmali", "Sam Stephenson"] s.email = ["javan@javan.us", "sstephenson@gmail.com"] -- cgit v1.2.3 From 7daa8cc63e1966e4cf677c4162856da896965449 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Fri, 13 Apr 2018 16:47:33 -0700 Subject: WIP --- app/models/action_text/rich_text.rb | 9 +++++++++ lib/action_text/attribute.rb | 31 ++++++++++++++++++++++++------- 2 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 app/models/action_text/rich_text.rb diff --git a/app/models/action_text/rich_text.rb b/app/models/action_text/rich_text.rb new file mode 100644 index 0000000000..a56a18efda --- /dev/null +++ b/app/models/action_text/rich_text.rb @@ -0,0 +1,9 @@ +class ActionText::RichText < ActiveRecord::Base + serialize :body, ActionText::Content + + has_many_attached :embeds + + after_save do + self.embeds_attachments_blobs = body.attachments.map(&:attachable) + end +end diff --git a/lib/action_text/attribute.rb b/lib/action_text/attribute.rb index 32dd1d0e3f..bd76999167 100644 --- a/lib/action_text/attribute.rb +++ b/lib/action_text/attribute.rb @@ -3,16 +3,33 @@ module ActionText extend ActiveSupport::Concern class_methods do - def has_rich_text(attribute_name) - serialize(attribute_name, ActionText::Content) + def has_rich_text(name) + class_eval <<-CODE, __FILE__, __LINE__ + 1 + def #{name} + rich_text_#{name} + end - has_many_attached "#{attribute_name}_attachments" + def #{name}=(body) + #{name}.body = body + end + CODE - after_save do - blobs = public_send(attribute_name).attachments.map(&:attachable) - public_send("#{attribute_name}_attachments_blobs=", blobs) - end + has_one :"rich_text_#{name}", -> { where(name: name) }, class_name: "ActionText::RichText", as: :record, inverse_of: :record, dependent: false + + scope :"with_rich_text_#{name}", -> { includes("rich_text_#{name}") } end + + + # def has_rich_text(attribute_name) + # serialize(attribute_name, ActionText::Content) + # + # has_many_attached "#{attribute_name}_attachments" + # + # after_save do + # blobs = public_send(attribute_name).attachments.map(&:attachable) + # public_send("#{attribute_name}_attachments_blobs=", blobs) + # end + # end end end end -- cgit v1.2.3 From a4af9580d604221ec36d2cd5671eb7f256ae5173 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 15 Apr 2018 14:02:04 -0700 Subject: Updated name --- Gemfile.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index ba3c8b4be8..116635c788 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - activetext (0.1.0) + actiontext (0.1.0) nokogiri rails (>= 5.2.0.rc1) @@ -63,7 +63,7 @@ GEM nokogiri (>= 1.5.9) mail (2.7.0) mini_mime (>= 0.1.1) - marcel (0.3.1) + marcel (0.3.2) mimemagic (~> 0.3.2) method_source (0.9.0) mimemagic (0.3.2) @@ -71,7 +71,7 @@ GEM mini_mime (1.0.0) mini_portile2 (2.3.0) minitest (5.11.3) - nio4r (2.2.0) + nio4r (2.3.0) nokogiri (1.8.2) mini_portile2 (~> 2.3.0) rack (2.0.4) @@ -128,7 +128,7 @@ PLATFORMS ruby DEPENDENCIES - activetext! + actiontext! bundler (~> 1.15) mini_magick sqlite3 -- cgit v1.2.3 From 89be59345b08e070f2e20b92541b6f801793e388 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 28 May 2018 17:14:27 +0200 Subject: Use actiontext references in Gemfile.lock --- Gemfile.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index ba3c8b4be8..d40eabf684 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - activetext (0.1.0) + actiontext (0.1.0) nokogiri rails (>= 5.2.0.rc1) @@ -63,7 +63,7 @@ GEM nokogiri (>= 1.5.9) mail (2.7.0) mini_mime (>= 0.1.1) - marcel (0.3.1) + marcel (0.3.2) mimemagic (~> 0.3.2) method_source (0.9.0) mimemagic (0.3.2) @@ -71,7 +71,7 @@ GEM mini_mime (1.0.0) mini_portile2 (2.3.0) minitest (5.11.3) - nio4r (2.2.0) + nio4r (2.3.1) nokogiri (1.8.2) mini_portile2 (~> 2.3.0) rack (2.0.4) @@ -128,11 +128,11 @@ PLATFORMS ruby DEPENDENCIES - activetext! + actiontext! bundler (~> 1.15) mini_magick sqlite3 webpacker (~> 3.2.2) BUNDLED WITH - 1.16.1 + 1.16.2 -- cgit v1.2.3 From aa42bf20275c797d890852416d35dd1a54881fe4 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 28 May 2018 17:42:41 +0200 Subject: Table needed for Rich Text AR model --- db/migrate/201805281641_create_action_text_tables.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 db/migrate/201805281641_create_action_text_tables.rb diff --git a/db/migrate/201805281641_create_action_text_tables.rb b/db/migrate/201805281641_create_action_text_tables.rb new file mode 100644 index 0000000000..80bcb5cdbc --- /dev/null +++ b/db/migrate/201805281641_create_action_text_tables.rb @@ -0,0 +1,14 @@ +class CreateActionTextTables < ActiveRecord::Migration[5.2] + def change + create_table :action_text_rich_texts do |t| + t.string :name, null: false + t.text :body, null: false + t.references :record, null: false, polymorphic: true, index: false + + t.datetime :created_at, null: false + t.datetime :updated_at, null: false + + t.index [ :record_type, :record_id, :name ], name: "index_action_text_rich_texts_uniqueness", unique: true + end + end +end -- cgit v1.2.3 From 94a95db2f5cf48b63d1bd08d849790156572a1f5 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 28 May 2018 17:43:08 +0200 Subject: Lazy initialization of rich text model --- lib/action_text/attribute.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/action_text/attribute.rb b/lib/action_text/attribute.rb index bd76999167..3b855901e8 100644 --- a/lib/action_text/attribute.rb +++ b/lib/action_text/attribute.rb @@ -6,7 +6,7 @@ module ActionText def has_rich_text(name) class_eval <<-CODE, __FILE__, __LINE__ + 1 def #{name} - rich_text_#{name} + self.rich_text_#{name} ||= ActionText::RichText.new(name: "#{name}", record: self) end def #{name}=(body) -- cgit v1.2.3 From e63acf4513dec5f2dc08293d8141971850fe4853 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 28 May 2018 17:43:21 +0200 Subject: Auto-save changes to rich text model --- lib/action_text/attribute.rb | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/lib/action_text/attribute.rb b/lib/action_text/attribute.rb index 3b855901e8..81bd226646 100644 --- a/lib/action_text/attribute.rb +++ b/lib/action_text/attribute.rb @@ -17,19 +17,9 @@ module ActionText has_one :"rich_text_#{name}", -> { where(name: name) }, class_name: "ActionText::RichText", as: :record, inverse_of: :record, dependent: false scope :"with_rich_text_#{name}", -> { includes("rich_text_#{name}") } - end - - # def has_rich_text(attribute_name) - # serialize(attribute_name, ActionText::Content) - # - # has_many_attached "#{attribute_name}_attachments" - # - # after_save do - # blobs = public_send(attribute_name).attachments.map(&:attachable) - # public_send("#{attribute_name}_attachments_blobs=", blobs) - # end - # end + after_save { public_send(name).save if public_send(name).changed? } + end end end end -- cgit v1.2.3 From ff5ae47a4bfb8fb71aea883b42372fc500b75ce5 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 28 May 2018 17:43:40 +0200 Subject: Back by fully qualified table name --- app/models/action_text/rich_text.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/action_text/rich_text.rb b/app/models/action_text/rich_text.rb index a56a18efda..7c5211a67e 100644 --- a/app/models/action_text/rich_text.rb +++ b/app/models/action_text/rich_text.rb @@ -1,4 +1,6 @@ class ActionText::RichText < ActiveRecord::Base + self.table_name = "action_text_rich_texts" + serialize :body, ActionText::Content has_many_attached :embeds -- cgit v1.2.3 From 69daf8f21dbceaa2414d17af46c5fd72e8d0050e Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 28 May 2018 17:44:02 +0200 Subject: Link rich text to owning record --- app/models/action_text/rich_text.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/action_text/rich_text.rb b/app/models/action_text/rich_text.rb index 7c5211a67e..8ef3436cc2 100644 --- a/app/models/action_text/rich_text.rb +++ b/app/models/action_text/rich_text.rb @@ -3,6 +3,7 @@ class ActionText::RichText < ActiveRecord::Base serialize :body, ActionText::Content + belongs_to :record, polymorphic: true, touch: true has_many_attached :embeds after_save do -- cgit v1.2.3 From 751d5edc70f67a6b29571a2005b700781ffec075 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 28 May 2018 17:44:19 +0200 Subject: Ease the rendering of a rich text attribute --- app/models/action_text/rich_text.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/action_text/rich_text.rb b/app/models/action_text/rich_text.rb index 8ef3436cc2..efc35a6465 100644 --- a/app/models/action_text/rich_text.rb +++ b/app/models/action_text/rich_text.rb @@ -2,6 +2,7 @@ class ActionText::RichText < ActiveRecord::Base self.table_name = "action_text_rich_texts" serialize :body, ActionText::Content + delegate :to_s, to: :body belongs_to :record, polymorphic: true, touch: true has_many_attached :embeds -- cgit v1.2.3 From 0c1d78b128aa4a1c2a8acd7986d753a56a93c697 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 28 May 2018 17:44:34 +0200 Subject: Use the correct API for blob assignment --- app/models/action_text/rich_text.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/action_text/rich_text.rb b/app/models/action_text/rich_text.rb index efc35a6465..e4fc178ba4 100644 --- a/app/models/action_text/rich_text.rb +++ b/app/models/action_text/rich_text.rb @@ -8,6 +8,6 @@ class ActionText::RichText < ActiveRecord::Base has_many_attached :embeds after_save do - self.embeds_attachments_blobs = body.attachments.map(&:attachable) + self.embeds_blobs = body.attachments.map(&:attachable) end end -- cgit v1.2.3 From 4c7f345fda0533e81ec3082247e05172b2f7fe4c Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 28 May 2018 18:07:55 +0200 Subject: Reference action text for js packaging --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 0f11cee9b5..ef4481fbfd 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { - "name": "activetext", + "name": "actiontext", "version": "0.1.0", "description": "Edit and display rich text in Rails applications", - "main": "app/javascript/activetext/index.js", + "main": "app/javascript/actiontext/index.js", "files": [ - "app/javascript/activetext/*.js" + "app/javascript/actiontext/*.js" ], - "repository": "https://github.com/basecamp/activetext", + "repository": "https://github.com/basecamp/actiontext", "author": "Basecamp, LLC", "contributors": [ "Javan Makhmali ", -- cgit v1.2.3 From 3a515bb3083f5e594b38ee7c9b8e2e755e2c19ac Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 28 May 2018 18:08:16 +0200 Subject: Implicit transformation to html-safe string ready for display --- app/models/action_text/rich_text.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/models/action_text/rich_text.rb b/app/models/action_text/rich_text.rb index e4fc178ba4..6747def9a5 100644 --- a/app/models/action_text/rich_text.rb +++ b/app/models/action_text/rich_text.rb @@ -2,7 +2,6 @@ class ActionText::RichText < ActiveRecord::Base self.table_name = "action_text_rich_texts" serialize :body, ActionText::Content - delegate :to_s, to: :body belongs_to :record, polymorphic: true, touch: true has_many_attached :embeds @@ -10,4 +9,9 @@ class ActionText::RichText < ActiveRecord::Base after_save do self.embeds_blobs = body.attachments.map(&:attachable) end + + + def to_s + body.to_s.html_safe + end end -- cgit v1.2.3 From a79fa9d2233be0ac968dbec6c00e8eca5b1d0117 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 29 May 2018 16:12:28 +0200 Subject: Destroy rich text dependents --- lib/action_text/attribute.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/action_text/attribute.rb b/lib/action_text/attribute.rb index 81bd226646..30cbab70db 100644 --- a/lib/action_text/attribute.rb +++ b/lib/action_text/attribute.rb @@ -14,7 +14,7 @@ module ActionText end CODE - has_one :"rich_text_#{name}", -> { where(name: name) }, class_name: "ActionText::RichText", as: :record, inverse_of: :record, dependent: false + has_one :"rich_text_#{name}", -> { where(name: name) }, class_name: "ActionText::RichText", as: :record, inverse_of: :record, dependent: :destroy scope :"with_rich_text_#{name}", -> { includes("rich_text_#{name}") } -- cgit v1.2.3 From d8086477b1e5906d42c6f60e7882a50c0daee02b Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 29 May 2018 16:12:50 +0200 Subject: Not needed for migrations etc (And yarning is currently failing) --- test/dummy/config/environments/development.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/dummy/config/environments/development.rb b/test/dummy/config/environments/development.rb index 42768bf68c..f09b9a00c4 100644 --- a/test/dummy/config/environments/development.rb +++ b/test/dummy/config/environments/development.rb @@ -1,6 +1,6 @@ Rails.application.configure do # Verifies that versions and hashed value of the package contents in the project's package.json - config.webpacker.check_yarn_integrity = true + # config.webpacker.check_yarn_integrity = true # Settings specified here will take precedence over those in config/application.rb. # In the development environment your application's code is reloaded on -- cgit v1.2.3 From ddfc963d35dc1ecd7e78af9cd96ed4ce058a8dc8 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 29 May 2018 16:13:07 +0200 Subject: Content is now supplied by dedicated model --- test/dummy/db/migrate/20180208205311_create_messages.rb | 2 -- test/dummy/db/schema.rb | 11 ++++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/test/dummy/db/migrate/20180208205311_create_messages.rb b/test/dummy/db/migrate/20180208205311_create_messages.rb index 6817d5933f..8e43559672 100644 --- a/test/dummy/db/migrate/20180208205311_create_messages.rb +++ b/test/dummy/db/migrate/20180208205311_create_messages.rb @@ -2,8 +2,6 @@ class CreateMessages < ActiveRecord::Migration[5.2] def change create_table :messages do |t| t.string :subject - t.text :content - t.timestamps end end diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb index f892368183..67668b6e78 100644 --- a/test/dummy/db/schema.rb +++ b/test/dummy/db/schema.rb @@ -12,6 +12,16 @@ ActiveRecord::Schema.define(version: 2018_02_12_164506) do + create_table "action_text_rich_texts", force: :cascade do |t| + t.string "name", null: false + t.text "body", null: false + t.string "record_type", null: false + t.integer "record_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["record_type", "record_id", "name"], name: "index_action_text_rich_texts_uniqueness", unique: true + end + create_table "active_storage_attachments", force: :cascade do |t| t.string "name", null: false t.string "record_type", null: false @@ -35,7 +45,6 @@ ActiveRecord::Schema.define(version: 2018_02_12_164506) do create_table "messages", force: :cascade do |t| t.string "subject" - t.text "content" t.datetime "created_at", null: false t.datetime "updated_at", null: false end -- cgit v1.2.3 From 4b6509c6f28edf40dbb4a284dd1d7f3fd583971f Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 29 May 2018 16:13:19 +0200 Subject: Adding the rich text tables --- .../db/migrate/2018052816_create_action_text_tables.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 test/dummy/db/migrate/2018052816_create_action_text_tables.rb diff --git a/test/dummy/db/migrate/2018052816_create_action_text_tables.rb b/test/dummy/db/migrate/2018052816_create_action_text_tables.rb new file mode 100644 index 0000000000..80bcb5cdbc --- /dev/null +++ b/test/dummy/db/migrate/2018052816_create_action_text_tables.rb @@ -0,0 +1,14 @@ +class CreateActionTextTables < ActiveRecord::Migration[5.2] + def change + create_table :action_text_rich_texts do |t| + t.string :name, null: false + t.text :body, null: false + t.references :record, null: false, polymorphic: true, index: false + + t.datetime :created_at, null: false + t.datetime :updated_at, null: false + + t.index [ :record_type, :record_id, :name ], name: "index_action_text_rich_texts_uniqueness", unique: true + end + end +end -- cgit v1.2.3 From ed42e6193050cac070f7d68033ab454b4622bedd Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 29 May 2018 16:13:39 +0200 Subject: Just test text pipeline without dependencies/saving --- test/unit/content_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/content_test.rb b/test/unit/content_test.rb index e5773361e4..b1a06e2cfa 100644 --- a/test/unit/content_test.rb +++ b/test/unit/content_test.rb @@ -3,8 +3,8 @@ require_relative '../test_helper' module ActionText class ContentTest < ActiveSupport::TestCase test "plain text conversion" do - message = Message.create!(subject: "Greetings", content: "

Hello world

") - assert_equal "Hello world", message.content.to_plain_text + message = Message.new(subject: "Greetings", content: "

Hello world

") + assert_equal "Hello world", message.content.body.to_plain_text end end end -- cgit v1.2.3 From 4cc241dc6c04913b3c84bb35d9cffd1a58a1d61f Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 29 May 2018 16:13:49 +0200 Subject: Test saving the dependent models --- test/unit/model_test.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 test/unit/model_test.rb diff --git a/test/unit/model_test.rb b/test/unit/model_test.rb new file mode 100644 index 0000000000..b7c5333c4d --- /dev/null +++ b/test/unit/model_test.rb @@ -0,0 +1,10 @@ +require_relative '../test_helper' + +module ActionText + class ModelTest < ActiveSupport::TestCase + test "saving content" do + message = Message.create!(subject: "Greetings", content: "

Hello world

") + assert_equal "Hello world", message.content.body.to_plain_text + end + end +end -- cgit v1.2.3 From f27a0c88e0e48b1b4f4b64590443e0bb23c6738e Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 29 May 2018 16:24:48 +0200 Subject: Use mediumtext-size columns Room to grow, room to flourish! --- db/migrate/201805281641_create_action_text_tables.rb | 2 +- test/dummy/db/migrate/2018052816_create_action_text_tables.rb | 2 +- test/dummy/db/schema.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/db/migrate/201805281641_create_action_text_tables.rb b/db/migrate/201805281641_create_action_text_tables.rb index 80bcb5cdbc..872987749a 100644 --- a/db/migrate/201805281641_create_action_text_tables.rb +++ b/db/migrate/201805281641_create_action_text_tables.rb @@ -2,7 +2,7 @@ class CreateActionTextTables < ActiveRecord::Migration[5.2] def change create_table :action_text_rich_texts do |t| t.string :name, null: false - t.text :body, null: false + t.text :body, limit: 16777215, null: false t.references :record, null: false, polymorphic: true, index: false t.datetime :created_at, null: false diff --git a/test/dummy/db/migrate/2018052816_create_action_text_tables.rb b/test/dummy/db/migrate/2018052816_create_action_text_tables.rb index 80bcb5cdbc..872987749a 100644 --- a/test/dummy/db/migrate/2018052816_create_action_text_tables.rb +++ b/test/dummy/db/migrate/2018052816_create_action_text_tables.rb @@ -2,7 +2,7 @@ class CreateActionTextTables < ActiveRecord::Migration[5.2] def change create_table :action_text_rich_texts do |t| t.string :name, null: false - t.text :body, null: false + t.text :body, limit: 16777215, null: false t.references :record, null: false, polymorphic: true, index: false t.datetime :created_at, null: false diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb index 67668b6e78..30bf844e9c 100644 --- a/test/dummy/db/schema.rb +++ b/test/dummy/db/schema.rb @@ -14,7 +14,7 @@ ActiveRecord::Schema.define(version: 2018_02_12_164506) do create_table "action_text_rich_texts", force: :cascade do |t| t.string "name", null: false - t.text "body", null: false + t.text "body", limit: 16777215, null: false t.string "record_type", null: false t.integer "record_id", null: false t.datetime "created_at", null: false -- cgit v1.2.3 From 735734647e119b1ef13a321ad1381dab9b2f22e2 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 29 May 2018 16:55:04 +0200 Subject: Add installer that copies migration and stylesheet link --- lib/tasks/actiontext.rake | 28 ++++++++++++++++++++++++++++ lib/templates/actiontext.css | 7 +++++++ 2 files changed, 35 insertions(+) create mode 100644 lib/tasks/actiontext.rake create mode 100644 lib/templates/actiontext.css diff --git a/lib/tasks/actiontext.rake b/lib/tasks/actiontext.rake new file mode 100644 index 0000000000..817a4c67f0 --- /dev/null +++ b/lib/tasks/actiontext.rake @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +namespace :action_text do + # Prevent migration installation task from showing up twice. + Rake::Task["install:migrations"].clear_comments + + desc "Copy over the migration, stylesheet, and JavaScript files" + task install: %i( environment copy_migration copy_stylesheet ) + + task :copy_migration do + if Rake::Task.task_defined?("action_text:install:migrations") + Rake::Task["action_text:install:migrations"].invoke + else + Rake::Task["app:action_text:install:migrations"].invoke + end + end + + STYLESHEET_TEMPLATE_PATH = File.expand_path("../templates/actiontext.css", __dir__) + STYLESHEET_APP_PATH = Rails.root.join("app/assets/stylesheets/actiontext.css") + + task :copy_stylesheet do + if File.exist?(STYLESHEET_APP_PATH) + puts "Won't copy Action Text stylesheet as it already exists" + else + FileUtils.cp STYLESHEET_TEMPLATE_PATH, STYLESHEET_APP_PATH + end + end +end diff --git a/lib/templates/actiontext.css b/lib/templates/actiontext.css new file mode 100644 index 0000000000..97c083c24b --- /dev/null +++ b/lib/templates/actiontext.css @@ -0,0 +1,7 @@ +/* + * Provides a drop-in pointer for the default Trix stylesheet that will format the toolbar and + * the trix-editor content (whether displayed or under editing). Feel free to incorporate this + * inclusion directly in any other asset bundle and remove this file. + * + *= require trix/dist/trix +*/ -- cgit v1.2.3 From e04093386705aa8c00e5162614a9d0122cd31891 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 5 Jun 2018 16:20:55 +0200 Subject: We are leveling up the text_area, not the text_field, so match names --- README.md | 4 ++-- app/helpers/action_text/tag_helper.rb | 10 +++++----- test/dummy/app/views/messages/_form.html.erb | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 715c60e9c2..2e53935412 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Assumes a Rails 5.2+ application with Active Storage and Webpacker installed. end ``` -1. Replace form `text_area`s with `rich_text_field`s: +1. Replace form `text_area`s with `rich_text_area`s: ```erb <%# app/views/messages/_form.html.erb %> @@ -49,7 +49,7 @@ Assumes a Rails 5.2+ application with Active Storage and Webpacker installed. …
<%= form.label :content %> - <%= form.rich_text_field :content %> + <%= form.rich_text_area :content %>
… <% end %> diff --git a/app/helpers/action_text/tag_helper.rb b/app/helpers/action_text/tag_helper.rb index bd2727bca6..ae52e270a7 100644 --- a/app/helpers/action_text/tag_helper.rb +++ b/app/helpers/action_text/tag_helper.rb @@ -2,7 +2,7 @@ module ActionText module TagHelper cattr_accessor(:id, instance_accessor: false) { 0 } - def rich_text_field_tag(name, value = nil, options = {}) + def rich_text_area_tag(name, value = nil, options = {}) options = options.symbolize_keys options[:input] ||= "trix_input_#{ActionText::TagHelper.id += 1}" @@ -26,7 +26,7 @@ module ActionView::Helpers options = @options.stringify_keys add_default_name_and_id(options) options["input"] ||= dom_id(object, [options["id"], :trix_input].compact.join("_")) - @template_object.rich_text_field_tag(options.delete("name"), editable_value, options) + @template_object.rich_text_area_tag(options.delete("name"), editable_value, options) end def editable_value @@ -35,14 +35,14 @@ module ActionView::Helpers end module FormHelper - def rich_text_field(object_name, method, options = {}) + def rich_text_area(object_name, method, options = {}) Tags::ActionText.new(object_name, method, self, options).render end end class FormBuilder - def rich_text_field(method, options = {}) - @template.rich_text_field(@object_name, method, objectify_options(options)) + def rich_text_area(method, options = {}) + @template.rich_text_area(@object_name, method, objectify_options(options)) end end end diff --git a/test/dummy/app/views/messages/_form.html.erb b/test/dummy/app/views/messages/_form.html.erb index bd5f0bea4a..3b8a174884 100644 --- a/test/dummy/app/views/messages/_form.html.erb +++ b/test/dummy/app/views/messages/_form.html.erb @@ -18,7 +18,7 @@
<%= form.label :content %> - <%= form.rich_text_field :content, class: "trix-content" %> + <%= form.rich_text_area :content, class: "trix-content" %>
-- cgit v1.2.3 From 33c8f20c3339f1726e7ad5537adb1433ad8af6ec Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 5 Jun 2018 16:21:04 +0200 Subject: Provide default styling by default --- app/helpers/action_text/tag_helper.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/helpers/action_text/tag_helper.rb b/app/helpers/action_text/tag_helper.rb index ae52e270a7..72b36b58e3 100644 --- a/app/helpers/action_text/tag_helper.rb +++ b/app/helpers/action_text/tag_helper.rb @@ -6,6 +6,8 @@ module ActionText options = options.symbolize_keys options[:input] ||= "trix_input_#{ActionText::TagHelper.id += 1}" + options[:class] ||= "trix-content" + options[:data] ||= {} options[:data][:direct_upload_url] = rails_direct_uploads_url options[:data][:blob_url_template] = rails_service_blob_url(":signed_id", ":filename") -- cgit v1.2.3 From 21aa1d4b55686eda40eb8315822d32de157964ba Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 5 Jun 2018 16:31:07 +0200 Subject: Edit the body of the RichText value Needed now that we have that intermediary object. --- app/helpers/action_text/tag_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/action_text/tag_helper.rb b/app/helpers/action_text/tag_helper.rb index 72b36b58e3..0033538773 100644 --- a/app/helpers/action_text/tag_helper.rb +++ b/app/helpers/action_text/tag_helper.rb @@ -32,7 +32,7 @@ module ActionView::Helpers end def editable_value - value.try(:to_trix_html) + value.body.try(:to_trix_html) end end -- cgit v1.2.3 From 9e5ab1ebd9a80a78f9daaf38a9ee244e60b8af1c Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 5 Jun 2018 16:37:50 +0200 Subject: By default, coercing to a string should produce a formatted output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Open to other ways of doing this, but didn’t want to require embedding the trix-content class inside the actual HTML that Trix persists. So this seemed like a reasonable alternative. Thoughts @javan or @sstephenson? --- lib/action_text/content.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/action_text/content.rb b/lib/action_text/content.rb index c63e0c3525..ce40505329 100644 --- a/lib/action_text/content.rb +++ b/lib/action_text/content.rb @@ -54,7 +54,7 @@ module ActionText end def to_s - to_html.html_safe + "
#{to_html}
".html_safe end def as_json(*) -- cgit v1.2.3 From d5623dc634dc6e8ce8294485e1fdb6adb5f16271 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Thu, 7 Jun 2018 14:38:41 +0200 Subject: Provide to_html rendering within a layout and use that as the to_s default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I like the idea of thinking about the rendering as happening within a layout. Since that’s basically what this wrapper is. Thoughts @javan? --- app/views/action_text/content/_layout.html.erb | 3 +++ lib/action_text/content.rb | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 app/views/action_text/content/_layout.html.erb diff --git a/app/views/action_text/content/_layout.html.erb b/app/views/action_text/content/_layout.html.erb new file mode 100644 index 0000000000..be3ca295c8 --- /dev/null +++ b/app/views/action_text/content/_layout.html.erb @@ -0,0 +1,3 @@ +
+ <%= document %> +
diff --git a/lib/action_text/content.rb b/lib/action_text/content.rb index ce40505329..2eff8bb361 100644 --- a/lib/action_text/content.rb +++ b/lib/action_text/content.rb @@ -53,8 +53,12 @@ module ActionText end.to_html end + def to_html_with_layout + ActionText.renderer.render(partial: "action_text/content/layout", locals: { document: to_html.html_safe }).html_safe + end + def to_s - "
#{to_html}
".html_safe + to_html_with_layout end def as_json(*) -- cgit v1.2.3 From 83d781ed01459cb80d10a1c8e91e3d6f36c01913 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Thu, 7 Jun 2018 14:38:57 +0200 Subject: Add scope to preload embeds as well --- lib/action_text/attribute.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/action_text/attribute.rb b/lib/action_text/attribute.rb index 30cbab70db..6ed72fd852 100644 --- a/lib/action_text/attribute.rb +++ b/lib/action_text/attribute.rb @@ -17,6 +17,7 @@ module ActionText has_one :"rich_text_#{name}", -> { where(name: name) }, class_name: "ActionText::RichText", as: :record, inverse_of: :record, dependent: :destroy scope :"with_rich_text_#{name}", -> { includes("rich_text_#{name}") } + scope :"with_rich_text_#{name}_and_embeds", -> { includes("rich_text_#{name}": { embeds_attachments: :blob }) } after_save { public_send(name).save if public_send(name).changed? } end -- cgit v1.2.3 From 228044c5c21d128f366dbca2a527586b7a5e33f4 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Thu, 7 Jun 2018 14:39:09 +0200 Subject: Some basic documentation for the has_rich_text macro --- lib/action_text/attribute.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/action_text/attribute.rb b/lib/action_text/attribute.rb index 6ed72fd852..299c26b29f 100644 --- a/lib/action_text/attribute.rb +++ b/lib/action_text/attribute.rb @@ -3,6 +3,24 @@ module ActionText extend ActiveSupport::Concern class_methods do + # Provides access to a dependent RichText model that holds the body and attachments for a single named rich text attribute. + # This dependent attribute is lazily instantiated and will be auto-saved when it's been changed. Example: + # + # class Message < ActiveRecord::Base + # has_rich_text :content + # end + # + # message = Message.create!(content: "

Funny times!

") + # message.content.to_s # => "

Funny times!

" + # message.content.body.to_plain_text # => "Funny times!" + # + # The dependent RichText model will also automatically process attachments links as sent via the Trix-powered editor. + # These attachments are associated with the RichText model using Active Storage. + # + # If you wish to preload the dependent RichText model, you can use the named scope: + # + # Message.all.with_rich_text_content # Avoids N+1 queries when you just want the body, not the attachments. + # Message.all.with_rich_text_content_and_emebds # Avoids N+1 queries when you just want the body and attachments. def has_rich_text(name) class_eval <<-CODE, __FILE__, __LINE__ + 1 def #{name} -- cgit v1.2.3 From 206c04f716cbc608e0913f31e19b79458014e519 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Thu, 7 Jun 2018 14:41:17 +0200 Subject: Move the escaping choice to the layout --- app/views/action_text/content/_layout.html.erb | 2 +- lib/action_text/content.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/action_text/content/_layout.html.erb b/app/views/action_text/content/_layout.html.erb index be3ca295c8..c0b86a189e 100644 --- a/app/views/action_text/content/_layout.html.erb +++ b/app/views/action_text/content/_layout.html.erb @@ -1,3 +1,3 @@
- <%= document %> + <%=raw document %>
diff --git a/lib/action_text/content.rb b/lib/action_text/content.rb index 2eff8bb361..9dae07cf0c 100644 --- a/lib/action_text/content.rb +++ b/lib/action_text/content.rb @@ -54,7 +54,7 @@ module ActionText end def to_html_with_layout - ActionText.renderer.render(partial: "action_text/content/layout", locals: { document: to_html.html_safe }).html_safe + ActionText.renderer.render(partial: "action_text/content/layout", locals: { document: to_html }).html_safe end def to_s -- cgit v1.2.3 From 2f530577ce998a9e71385dcfa6bb33da6a34fe57 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Thu, 7 Jun 2018 14:41:57 +0200 Subject: #render already provides something html_safe --- lib/action_text/content.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/action_text/content.rb b/lib/action_text/content.rb index 9dae07cf0c..c296896ac4 100644 --- a/lib/action_text/content.rb +++ b/lib/action_text/content.rb @@ -54,7 +54,7 @@ module ActionText end def to_html_with_layout - ActionText.renderer.render(partial: "action_text/content/layout", locals: { document: to_html }).html_safe + ActionText.renderer.render(partial: "action_text/content/layout", locals: { document: to_html }) end def to_s -- cgit v1.2.3 From 60050ee41275eda25601beaa453e26841511d492 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Wed, 27 Jun 2018 13:38:24 +0200 Subject: Change to current approach --- README.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2e53935412..72eb6d44cf 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ Assumes a Rails 5.2+ application with Active Storage and Webpacker installed. ```ruby # Gemfile - gem "activetext", github: "basecamp/activetext", require: "action_text" - gem "mini_magick" # for Active Storage variants + gem "actiontext", github: "basecamp/actiontext", require: "action_text" + gem "image_processing", "~> 1.2" # for Active Storage variants ``` 1. Install the npm package: @@ -19,7 +19,7 @@ Assumes a Rails 5.2+ application with Active Storage and Webpacker installed. ```js // package.json "dependencies": { - "activetext": "basecamp/activetext" + "actiontext": "basecamp/actiontext" } ``` @@ -29,9 +29,17 @@ Assumes a Rails 5.2+ application with Active Storage and Webpacker installed. ```js // app/javascript/packs/application.js - import "activetext" + import "actiontext" ``` +1. Migrate the database + + ``` + ./bin/rails active_storage:install + ./bin/rails action_text:install + ./bin/rails db:migrate + ``` + 1. Declare text columns as Action Text attributes: ```ruby -- cgit v1.2.3 From d8a26dab3eb8c4c1c5f9d81bf2987e211ba7f80e Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 30 Jul 2018 16:41:26 -0700 Subject: You cant run Action Text without Active Storage setup, so lets just set it up for you, rather than ask you to. --- README.md | 1 - lib/tasks/actiontext.rake | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 72eb6d44cf..ca6a395e8e 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,6 @@ Assumes a Rails 5.2+ application with Active Storage and Webpacker installed. 1. Migrate the database ``` - ./bin/rails active_storage:install ./bin/rails action_text:install ./bin/rails db:migrate ``` diff --git a/lib/tasks/actiontext.rake b/lib/tasks/actiontext.rake index 817a4c67f0..01f8697c61 100644 --- a/lib/tasks/actiontext.rake +++ b/lib/tasks/actiontext.rake @@ -5,7 +5,7 @@ namespace :action_text do Rake::Task["install:migrations"].clear_comments desc "Copy over the migration, stylesheet, and JavaScript files" - task install: %i( environment copy_migration copy_stylesheet ) + task install: %w( environment active_storage:install copy_migration copy_stylesheet ) task :copy_migration do if Rake::Task.task_defined?("action_text:install:migrations") -- cgit v1.2.3 From 36b69850cc6cafa60230ca92eabb9ad93adf7e81 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 31 Jul 2018 15:55:53 -0700 Subject: Update instructions to get the local version of actiontext --- README.md | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index ca6a395e8e..c066323e1f 100644 --- a/README.md +++ b/README.md @@ -14,17 +14,10 @@ Assumes a Rails 5.2+ application with Active Storage and Webpacker installed. gem "image_processing", "~> 1.2" # for Active Storage variants ``` -1. Install the npm package: +1. Install the npm package (with a local reference to this checked out repository): - ```js - // package.json - "dependencies": { - "actiontext": "basecamp/actiontext" - } - ``` - ```sh - $ yarn install + $ yarn add file:../actiontext ``` ```js -- cgit v1.2.3 From 0fd8ba6ffff07a4556ec47840ef8c9dbd10e5e8b Mon Sep 17 00:00:00 2001 From: George Claghorn Date: Tue, 31 Jul 2018 20:49:35 -0400 Subject: Prefer the ASt API --- app/models/action_text/rich_text.rb | 7 +++---- test/fixtures/files/racecar.jpg | Bin 0 -> 1124062 bytes test/test_helper.rb | 7 +++++++ test/unit/content_test.rb | 6 ++++++ 4 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 test/fixtures/files/racecar.jpg diff --git a/app/models/action_text/rich_text.rb b/app/models/action_text/rich_text.rb index 6747def9a5..7c0fdf240d 100644 --- a/app/models/action_text/rich_text.rb +++ b/app/models/action_text/rich_text.rb @@ -2,15 +2,14 @@ class ActionText::RichText < ActiveRecord::Base self.table_name = "action_text_rich_texts" serialize :body, ActionText::Content - + belongs_to :record, polymorphic: true, touch: true has_many_attached :embeds - after_save do - self.embeds_blobs = body.attachments.map(&:attachable) + before_save do + self.embeds = body.attachments.map(&:attachable) end - def to_s body.to_s.html_safe end diff --git a/test/fixtures/files/racecar.jpg b/test/fixtures/files/racecar.jpg new file mode 100644 index 0000000000..934b4caa22 Binary files /dev/null and b/test/fixtures/files/racecar.jpg differ diff --git a/test/test_helper.rb b/test/test_helper.rb index 94fec6b8be..79fde51549 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -19,3 +19,10 @@ if ActiveSupport::TestCase.respond_to?(:fixture_path=) ActiveSupport::TestCase.file_fixture_path = ActiveSupport::TestCase.fixture_path + "/files" ActiveSupport::TestCase.fixtures :all end + +class ActiveSupport::TestCase + private + def create_file_blob(filename:, content_type:, metadata: nil) + ActiveStorage::Blob.create_after_upload! io: file_fixture(filename).open, filename: filename, content_type: content_type, metadata: metadata + end +end diff --git a/test/unit/content_test.rb b/test/unit/content_test.rb index b1a06e2cfa..f1acf054db 100644 --- a/test/unit/content_test.rb +++ b/test/unit/content_test.rb @@ -6,5 +6,11 @@ module ActionText message = Message.new(subject: "Greetings", content: "

Hello world

") assert_equal "Hello world", message.content.body.to_plain_text end + + test "embed extraction" do + blob = create_file_blob(filename: "racecar.jpg", content_type: "image/jpg") + message = Message.create!(subject: "Greetings", content: ActionText::Content.new("Hello world").append_attachables(blob)) + assert_equal "racecar.jpg", message.content.embeds.first.filename.to_s + end end end -- cgit v1.2.3 From 3431c0b3eeaf284901bd9aa4265c578207d4c820 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Wed, 12 Sep 2018 10:58:23 -0700 Subject: Ensure blank rich text records aren't saved or required --- app/models/action_text/rich_text.rb | 2 ++ lib/action_text/attribute.rb | 15 ++++++++++++++- lib/action_text/content.rb | 2 +- test/unit/content_test.rb | 13 +++++++++++++ 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/app/models/action_text/rich_text.rb b/app/models/action_text/rich_text.rb index 7c0fdf240d..445b444867 100644 --- a/app/models/action_text/rich_text.rb +++ b/app/models/action_text/rich_text.rb @@ -6,6 +6,8 @@ class ActionText::RichText < ActiveRecord::Base belongs_to :record, polymorphic: true, touch: true has_many_attached :embeds + validate { errors.add(:body, "is missing") if body.blank? } + before_save do self.embeds = body.attachments.map(&:attachable) end diff --git a/lib/action_text/attribute.rb b/lib/action_text/attribute.rb index 299c26b29f..67ade42eb1 100644 --- a/lib/action_text/attribute.rb +++ b/lib/action_text/attribute.rb @@ -37,7 +37,20 @@ module ActionText scope :"with_rich_text_#{name}", -> { includes("rich_text_#{name}") } scope :"with_rich_text_#{name}_and_embeds", -> { includes("rich_text_#{name}": { embeds_attachments: :blob }) } - after_save { public_send(name).save if public_send(name).changed? } + before_save do + # If there's no body set, we need to reset the rich text record such that it is not autosaved. + public_send("#{name}=", nil) if public_send(name).body.blank? + end + + after_save do + rich_text = public_send(name) + + if rich_text.changed? && rich_text.body.present? + rich_text.save + elsif rich_text.persisted? && rich_text.body.blank? + rich_text.destroy + end + end end end end diff --git a/lib/action_text/content.rb b/lib/action_text/content.rb index c296896ac4..22b52cff1c 100644 --- a/lib/action_text/content.rb +++ b/lib/action_text/content.rb @@ -4,7 +4,7 @@ module ActionText attr_reader :fragment - delegate :blank?, :empty?, :html_safe, :present?, to: :to_s + delegate :blank?, :empty?, :html_safe, :present?, to: :to_html # Delegating to to_html to avoid including the layout def initialize(content = nil) @fragment = ActionText::Attachment.fragment_by_canonicalizing_attachments(content) diff --git a/test/unit/content_test.rb b/test/unit/content_test.rb index f1acf054db..60fb39610b 100644 --- a/test/unit/content_test.rb +++ b/test/unit/content_test.rb @@ -7,6 +7,19 @@ module ActionText assert_equal "Hello world", message.content.body.to_plain_text end + test "creating a model with rich text content will not create a rich text record" do + message = Message.create!(subject: "Greetings") + assert message.content.body.nil? + end + + test "removing content removes the rich text record" do + message = Message.create!(subject: "Greetings", content: "

Hello world

") + + assert_difference -> { ActionText::RichText.all.count }, -1 do + message.update!(content: "") + end + end + test "embed extraction" do blob = create_file_blob(filename: "racecar.jpg", content_type: "image/jpg") message = Message.create!(subject: "Greetings", content: ActionText::Content.new("Hello world").append_attachables(blob)) -- cgit v1.2.3 From 531d7dd584267e81ba57d4de7f0fe21b18a83cbb Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Wed, 12 Sep 2018 15:51:06 -0700 Subject: Never mind on allowing blank More hassle than its worth. Just account for the fact that rich text can be blank instead, but continue to create the record. --- app/models/action_text/rich_text.rb | 4 +--- db/migrate/201805281641_create_action_text_tables.rb | 2 +- lib/action_text/attribute.rb | 13 +------------ .../db/migrate/2018052816_create_action_text_tables.rb | 2 +- test/dummy/db/schema.rb | 2 +- test/unit/content_test.rb | 10 +--------- 6 files changed, 6 insertions(+), 27 deletions(-) diff --git a/app/models/action_text/rich_text.rb b/app/models/action_text/rich_text.rb index 445b444867..0b6043bd74 100644 --- a/app/models/action_text/rich_text.rb +++ b/app/models/action_text/rich_text.rb @@ -6,10 +6,8 @@ class ActionText::RichText < ActiveRecord::Base belongs_to :record, polymorphic: true, touch: true has_many_attached :embeds - validate { errors.add(:body, "is missing") if body.blank? } - before_save do - self.embeds = body.attachments.map(&:attachable) + self.embeds = body.attachments.map(&:attachable) if body.present? end def to_s diff --git a/db/migrate/201805281641_create_action_text_tables.rb b/db/migrate/201805281641_create_action_text_tables.rb index 872987749a..ed97ad46c0 100644 --- a/db/migrate/201805281641_create_action_text_tables.rb +++ b/db/migrate/201805281641_create_action_text_tables.rb @@ -2,7 +2,7 @@ class CreateActionTextTables < ActiveRecord::Migration[5.2] def change create_table :action_text_rich_texts do |t| t.string :name, null: false - t.text :body, limit: 16777215, null: false + t.text :body, limit: 16777215 t.references :record, null: false, polymorphic: true, index: false t.datetime :created_at, null: false diff --git a/lib/action_text/attribute.rb b/lib/action_text/attribute.rb index 67ade42eb1..8426726a38 100644 --- a/lib/action_text/attribute.rb +++ b/lib/action_text/attribute.rb @@ -37,19 +37,8 @@ module ActionText scope :"with_rich_text_#{name}", -> { includes("rich_text_#{name}") } scope :"with_rich_text_#{name}_and_embeds", -> { includes("rich_text_#{name}": { embeds_attachments: :blob }) } - before_save do - # If there's no body set, we need to reset the rich text record such that it is not autosaved. - public_send("#{name}=", nil) if public_send(name).body.blank? - end - after_save do - rich_text = public_send(name) - - if rich_text.changed? && rich_text.body.present? - rich_text.save - elsif rich_text.persisted? && rich_text.body.blank? - rich_text.destroy - end + public_send(name).save if public_send(name).changed? end end end diff --git a/test/dummy/db/migrate/2018052816_create_action_text_tables.rb b/test/dummy/db/migrate/2018052816_create_action_text_tables.rb index 872987749a..ed97ad46c0 100644 --- a/test/dummy/db/migrate/2018052816_create_action_text_tables.rb +++ b/test/dummy/db/migrate/2018052816_create_action_text_tables.rb @@ -2,7 +2,7 @@ class CreateActionTextTables < ActiveRecord::Migration[5.2] def change create_table :action_text_rich_texts do |t| t.string :name, null: false - t.text :body, limit: 16777215, null: false + t.text :body, limit: 16777215 t.references :record, null: false, polymorphic: true, index: false t.datetime :created_at, null: false diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb index 30bf844e9c..5179d7269f 100644 --- a/test/dummy/db/schema.rb +++ b/test/dummy/db/schema.rb @@ -14,7 +14,7 @@ ActiveRecord::Schema.define(version: 2018_02_12_164506) do create_table "action_text_rich_texts", force: :cascade do |t| t.string "name", null: false - t.text "body", limit: 16777215, null: false + t.text "body", limit: 16777215 t.string "record_type", null: false t.integer "record_id", null: false t.datetime "created_at", null: false diff --git a/test/unit/content_test.rb b/test/unit/content_test.rb index 60fb39610b..59beb323cf 100644 --- a/test/unit/content_test.rb +++ b/test/unit/content_test.rb @@ -7,19 +7,11 @@ module ActionText assert_equal "Hello world", message.content.body.to_plain_text end - test "creating a model with rich text content will not create a rich text record" do + test "without content" do message = Message.create!(subject: "Greetings") assert message.content.body.nil? end - test "removing content removes the rich text record" do - message = Message.create!(subject: "Greetings", content: "

Hello world

") - - assert_difference -> { ActionText::RichText.all.count }, -1 do - message.update!(content: "") - end - end - test "embed extraction" do blob = create_file_blob(filename: "racecar.jpg", content_type: "image/jpg") message = Message.create!(subject: "Greetings", content: ActionText::Content.new("Hello world").append_attachables(blob)) -- cgit v1.2.3 From 0839aa70d55951309441824d6d7badb5804042de Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Wed, 12 Sep 2018 16:22:40 -0700 Subject: Add default fixtures file on install --- lib/tasks/actiontext.rake | 15 ++++++++++++++- lib/templates/fixtures.yml | 4 ++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 lib/templates/fixtures.yml diff --git a/lib/tasks/actiontext.rake b/lib/tasks/actiontext.rake index 01f8697c61..5381c5486f 100644 --- a/lib/tasks/actiontext.rake +++ b/lib/tasks/actiontext.rake @@ -5,7 +5,7 @@ namespace :action_text do Rake::Task["install:migrations"].clear_comments desc "Copy over the migration, stylesheet, and JavaScript files" - task install: %w( environment active_storage:install copy_migration copy_stylesheet ) + task install: %w( environment active_storage:install copy_migration copy_stylesheet copy_fixtures ) task :copy_migration do if Rake::Task.task_defined?("action_text:install:migrations") @@ -25,4 +25,17 @@ namespace :action_text do FileUtils.cp STYLESHEET_TEMPLATE_PATH, STYLESHEET_APP_PATH end end + + FIXTURE_TEMPLATE_PATH = File.expand_path("../templates/fixtures.yml", __dir__) + FIXTURE_APP_DIR_PATH = Rails.root.join("test/fixtures/action_text") + FIXTURE_APP_PATH = FIXTURE_APP_DIR_PATH.join("fixtures.yml") + + task :copy_fixtures do + if File.exist?(FIXTURE_APP_PATH) + puts "Won't copy Action Text fixtures as it already exists" + else + FileUtils.mkdir FIXTURE_APP_DIR_PATH + FileUtils.cp FIXTURE_TEMPLATE_PATH, FIXTURE_APP_PATH + end + end end diff --git a/lib/templates/fixtures.yml b/lib/templates/fixtures.yml new file mode 100644 index 0000000000..8b371ea604 --- /dev/null +++ b/lib/templates/fixtures.yml @@ -0,0 +1,4 @@ +# one: +# record: name_of_fixture (ClassOfFixture) +# name: content +# body:

In a million stars!

-- cgit v1.2.3 From c6f8e59949d9c69eb2621094b541d0b770922df0 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Wed, 12 Sep 2018 16:24:20 -0700 Subject: Use correct fixtures destination name --- lib/tasks/actiontext.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tasks/actiontext.rake b/lib/tasks/actiontext.rake index 5381c5486f..32f3b90184 100644 --- a/lib/tasks/actiontext.rake +++ b/lib/tasks/actiontext.rake @@ -28,7 +28,7 @@ namespace :action_text do FIXTURE_TEMPLATE_PATH = File.expand_path("../templates/fixtures.yml", __dir__) FIXTURE_APP_DIR_PATH = Rails.root.join("test/fixtures/action_text") - FIXTURE_APP_PATH = FIXTURE_APP_DIR_PATH.join("fixtures.yml") + FIXTURE_APP_PATH = FIXTURE_APP_DIR_PATH.join("rich_texts.yml") task :copy_fixtures do if File.exist?(FIXTURE_APP_PATH) -- cgit v1.2.3 From 369f4926774843f418c35f1efffc0f391529e6f7 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 17 Sep 2018 16:03:00 -0700 Subject: Update gemspec links and Rails dependency and humbly add myself as a coauthor --- actiontext.gemspec | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/actiontext.gemspec b/actiontext.gemspec index 16dc61e595..bce0bf1332 100644 --- a/actiontext.gemspec +++ b/actiontext.gemspec @@ -7,15 +7,15 @@ require "action_text/version" Gem::Specification.new do |s| s.name = "actiontext" s.version = ActionText::VERSION - s.authors = ["Javan Makhmali", "Sam Stephenson"] - s.email = ["javan@javan.us", "sstephenson@gmail.com"] + s.authors = ["Javan Makhmali", "Sam Stephenson", "David Heinemeier Hansson"] + s.email = ["javan@javan.us", "sstephenson@gmail.com", "david@loudthinking.com"] s.summary = "Edit and display rich text in Rails applications" - s.homepage = "https://github.com/basecamp/activetext" + s.homepage = "https://github.com/basecamp/actiontext" s.license = "MIT" s.required_ruby_version = ">= 2.2.2" - s.add_dependency "rails", ">= 5.2.0.rc1" + s.add_dependency "rails", ">= 5.2.0" s.add_dependency "nokogiri" s.add_development_dependency "bundler", "~> 1.15" -- cgit v1.2.3 From 2dfec5ec85aa3e8339a82f961c25428b67c4c209 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 1 Oct 2018 17:04:46 -0700 Subject: Use released version of Rails 5.2.0 as the dependency --- Gemfile.lock | 74 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index d40eabf684..12d7f94fb7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,48 +3,48 @@ PATH specs: actiontext (0.1.0) nokogiri - rails (>= 5.2.0.rc1) + rails (>= 5.2.0) GEM remote: https://rubygems.org/ specs: - actioncable (5.2.0.rc1) - actionpack (= 5.2.0.rc1) + actioncable (5.2.0) + actionpack (= 5.2.0) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailer (5.2.0.rc1) - actionpack (= 5.2.0.rc1) - actionview (= 5.2.0.rc1) - activejob (= 5.2.0.rc1) + actionmailer (5.2.0) + actionpack (= 5.2.0) + actionview (= 5.2.0) + activejob (= 5.2.0) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.2.0.rc1) - actionview (= 5.2.0.rc1) - activesupport (= 5.2.0.rc1) + actionpack (5.2.0) + actionview (= 5.2.0) + activesupport (= 5.2.0) rack (~> 2.0) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.2.0.rc1) - activesupport (= 5.2.0.rc1) + actionview (5.2.0) + activesupport (= 5.2.0) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (5.2.0.rc1) - activesupport (= 5.2.0.rc1) + activejob (5.2.0) + activesupport (= 5.2.0) globalid (>= 0.3.6) - activemodel (5.2.0.rc1) - activesupport (= 5.2.0.rc1) - activerecord (5.2.0.rc1) - activemodel (= 5.2.0.rc1) - activesupport (= 5.2.0.rc1) + activemodel (5.2.0) + activesupport (= 5.2.0) + activerecord (5.2.0) + activemodel (= 5.2.0) + activesupport (= 5.2.0) arel (>= 9.0) - activestorage (5.2.0.rc1) - actionpack (= 5.2.0.rc1) - activerecord (= 5.2.0.rc1) + activestorage (5.2.0) + actionpack (= 5.2.0) + activerecord (= 5.2.0) marcel (~> 0.3.1) - activesupport (5.2.0.rc1) + activesupport (5.2.0) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (~> 0.7) minitest (~> 5.1) @@ -79,27 +79,27 @@ GEM rack rack-test (0.8.2) rack (>= 1.0, < 3) - rails (5.2.0.rc1) - actioncable (= 5.2.0.rc1) - actionmailer (= 5.2.0.rc1) - actionpack (= 5.2.0.rc1) - actionview (= 5.2.0.rc1) - activejob (= 5.2.0.rc1) - activemodel (= 5.2.0.rc1) - activerecord (= 5.2.0.rc1) - activestorage (= 5.2.0.rc1) - activesupport (= 5.2.0.rc1) + rails (5.2.0) + actioncable (= 5.2.0) + actionmailer (= 5.2.0) + actionpack (= 5.2.0) + actionview (= 5.2.0) + activejob (= 5.2.0) + activemodel (= 5.2.0) + activerecord (= 5.2.0) + activestorage (= 5.2.0) + activesupport (= 5.2.0) bundler (>= 1.3.0) - railties (= 5.2.0.rc1) + railties (= 5.2.0) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) rails-html-sanitizer (1.0.3) loofah (~> 2.0) - railties (5.2.0.rc1) - actionpack (= 5.2.0.rc1) - activesupport (= 5.2.0.rc1) + railties (5.2.0) + actionpack (= 5.2.0) + activesupport (= 5.2.0) method_source rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) -- cgit v1.2.3 From dac1e1ca07aedcb0a04bbecb37abdf0b8931cf5e Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 1 Oct 2018 17:05:15 -0700 Subject: Ruby Active Storage install last as it may halt the dependency list --- lib/tasks/actiontext.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tasks/actiontext.rake b/lib/tasks/actiontext.rake index 32f3b90184..767fbf71b7 100644 --- a/lib/tasks/actiontext.rake +++ b/lib/tasks/actiontext.rake @@ -5,7 +5,7 @@ namespace :action_text do Rake::Task["install:migrations"].clear_comments desc "Copy over the migration, stylesheet, and JavaScript files" - task install: %w( environment active_storage:install copy_migration copy_stylesheet copy_fixtures ) + task install: %w( environment copy_migration copy_stylesheet copy_fixtures active_storage:install ) task :copy_migration do if Rake::Task.task_defined?("action_text:install:migrations") -- cgit v1.2.3 From 39d9b7ca50be0bb2f2326485299ec5fae1f0fda4 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 1 Oct 2018 17:47:07 -0700 Subject: Fix that both migrations wouldnt be copied over because railties:install:migrations could only be invoked once per run --- lib/tasks/actiontext.rake | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/tasks/actiontext.rake b/lib/tasks/actiontext.rake index 767fbf71b7..e73ed34691 100644 --- a/lib/tasks/actiontext.rake +++ b/lib/tasks/actiontext.rake @@ -5,14 +5,12 @@ namespace :action_text do Rake::Task["install:migrations"].clear_comments desc "Copy over the migration, stylesheet, and JavaScript files" - task install: %w( environment copy_migration copy_stylesheet copy_fixtures active_storage:install ) + task install: %w( environment copy_migrations copy_stylesheet copy_fixtures ) - task :copy_migration do - if Rake::Task.task_defined?("action_text:install:migrations") - Rake::Task["action_text:install:migrations"].invoke - else - Rake::Task["app:action_text:install:migrations"].invoke - end + task :copy_migrations do + Rake::Task["active_storage:install:migrations"].invoke + Rake::Task["railties:install:migrations"].reenable # Otherwise you can't run 2 migration copy tasks in one invocation + Rake::Task["action_text:install:migrations"].invoke end STYLESHEET_TEMPLATE_PATH = File.expand_path("../templates/actiontext.css", __dir__) -- cgit v1.2.3 From faffd9b2784f39ea386629c23006ceb4755dbc74 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Tue, 2 Oct 2018 12:44:09 -0400 Subject: Freshen dependencies --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index ef4481fbfd..63802fb47c 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,8 @@ ], "license": "MIT", "dependencies": { - "trix": "^0.11.1", - "activestorage": ">= 5.2.0-rc1" + "trix": ">=1.0.0", + "activestorage": ">=5.2.0" }, "private": true } -- cgit v1.2.3 From a37b90881dc6566281fd711b6c22f3dadecce9d5 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Tue, 2 Oct 2018 13:32:06 -0400 Subject: =?UTF-8?q?active=20=E2=86=92=20action?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/action_text/attachment.rb | 2 +- test/dummy/app/javascript/packs/application.js | 2 +- test/dummy/package.json | 2 +- test/dummy/yarn.lock | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/action_text/attachment.rb b/lib/action_text/attachment.rb index 2129a3985b..a0e0c2f396 100644 --- a/lib/action_text/attachment.rb +++ b/lib/action_text/attachment.rb @@ -2,7 +2,7 @@ module ActionText class Attachment include Attachments::TrixConversion, Attachments::Minification, Attachments::Caching - TAG_NAME = "active-text-attachment" + TAG_NAME = "action-text-attachment" SELECTOR = TAG_NAME ATTRIBUTES = %w( sgid content-type url href filename filesize width height previewable caption ) diff --git a/test/dummy/app/javascript/packs/application.js b/test/dummy/app/javascript/packs/application.js index f12ff2fdc3..90eb1a1841 100644 --- a/test/dummy/app/javascript/packs/application.js +++ b/test/dummy/app/javascript/packs/application.js @@ -1 +1 @@ -import "activetext" +import "actiontext" diff --git a/test/dummy/package.json b/test/dummy/package.json index 59fdfb8a60..ff2b802bba 100644 --- a/test/dummy/package.json +++ b/test/dummy/package.json @@ -3,7 +3,7 @@ "private": true, "dependencies": { "@rails/webpacker": "^3.2.2", - "activetext": "file:../.." + "actiontext": "file:../.." }, "devDependencies": { "webpack-dev-server": "^2.11.1" diff --git a/test/dummy/yarn.lock b/test/dummy/yarn.lock index af299bfcf8..40444165f0 100644 --- a/test/dummy/yarn.lock +++ b/test/dummy/yarn.lock @@ -60,7 +60,7 @@ acorn@^5.0.0: version "5.2.0-rc1" resolved "https://registry.yarnpkg.com/activestorage/-/activestorage-5.2.0-rc1.tgz#79898996eceb0f13575eff41fb109051fbfa49b0" -"activetext@file:../..": +"actiontext@file:../..": version "0.1" dependencies: activestorage ">= 5.2.0-rc1" -- cgit v1.2.3 From dea30ecd0bf4137e8c75976499df3fdddde8f844 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Tue, 2 Oct 2018 13:33:40 -0400 Subject: Insert hidden before Fixes #3 --- app/helpers/action_text/tag_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/action_text/tag_helper.rb b/app/helpers/action_text/tag_helper.rb index 0033538773..28c62166dd 100644 --- a/app/helpers/action_text/tag_helper.rb +++ b/app/helpers/action_text/tag_helper.rb @@ -15,7 +15,7 @@ module ActionText editor_tag = content_tag("trix-editor", "", options) input_tag = hidden_field_tag(name, value, id: options[:input]) - editor_tag + input_tag + input_tag + editor_tag end end end -- cgit v1.2.3 From 8fc09a892284f2692ec21a4632bc74ed48365d57 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Tue, 2 Oct 2018 13:56:27 -0400 Subject: Bring some tests over --- test/unit/attachment_test.rb | 57 +++++++++++++++ test/unit/content_test.rb | 124 +++++++++++++++++++++++++++----- test/unit/model_test.rb | 30 +++++--- test/unit/plain_text_conversion_test.rb | 92 ++++++++++++++++++++++++ test/unit/trix_attachment_test.rb | 81 +++++++++++++++++++++ 5 files changed, 357 insertions(+), 27 deletions(-) create mode 100644 test/unit/attachment_test.rb create mode 100644 test/unit/plain_text_conversion_test.rb create mode 100644 test/unit/trix_attachment_test.rb diff --git a/test/unit/attachment_test.rb b/test/unit/attachment_test.rb new file mode 100644 index 0000000000..dec2b8244d --- /dev/null +++ b/test/unit/attachment_test.rb @@ -0,0 +1,57 @@ +require 'test_helper' + +class ActionText::AttachmentTest < ActiveSupport::TestCase + test "from_attachable" do + attachment = ActionText::Attachment.from_attachable(attachable, caption: "Captioned") + assert_equal attachable, attachment.attachable + assert_equal "Captioned", attachment.caption + end + + test "proxies missing methods to attachable" do + attachable.instance_eval { def proxied; "proxied"; end } + attachment = ActionText::Attachment.from_attachable(attachable) + assert_equal "proxied", attachment.proxied + end + + test "proxies #to_param to attachable" do + attachment = ActionText::Attachment.from_attachable(attachable) + assert_equal attachable.to_param, attachment.to_param + end + + # test "converts to TrixAttachment" do + # attachment = attachment_from_html(%Q()) + # + # trix_attachment = attachment.to_trix_attachment + # assert_kind_of ActionText::TrixAttachment, trix_attachment + # + # assert_equal attachable.attachable_sgid, trix_attachment.attributes["sgid"] + # assert_equal attachable.attachable_content_type, trix_attachment.attributes["contentType"] + # assert_equal attachable.filename.to_s, trix_attachment.attributes["filename"] + # assert_equal attachable.byte_size, trix_attachment.attributes["filesize"] + # assert_equal "Captioned", trix_attachment.attributes["caption"] + # + # assert_nil trix_attachment.attributes["content"] + # end + + # test "converts to TrixAttachment with content" do + # attachment = attachment_from_html(%Q()) + # + # trix_attachment = attachment.to_trix_attachment + # assert_kind_of ActionText::TrixAttachment, trix_attachment + # + # assert_equal attachable.attachable_sgid, trix_attachment.attributes["sgid"] + # assert_equal attachable.attachable_content_type, trix_attachment.attributes["contentType"] + # + # assert_not_nil attachable.to_trix_content_attachment_partial_path + # assert_not_nil trix_attachment.attributes["content"] + # end + + private + def attachment_from_html(html) + ActionText::Content.new(html).attachments.first + end + + def attachable + @attachment ||= create_file_blob(filename: "racecar.jpg", content_type: "image/jpg") + end +end diff --git a/test/unit/content_test.rb b/test/unit/content_test.rb index 59beb323cf..8f32a85110 100644 --- a/test/unit/content_test.rb +++ b/test/unit/content_test.rb @@ -1,21 +1,107 @@ -require_relative '../test_helper' - -module ActionText - class ContentTest < ActiveSupport::TestCase - test "plain text conversion" do - message = Message.new(subject: "Greetings", content: "

Hello world

") - assert_equal "Hello world", message.content.body.to_plain_text - end - - test "without content" do - message = Message.create!(subject: "Greetings") - assert message.content.body.nil? - end - - test "embed extraction" do - blob = create_file_blob(filename: "racecar.jpg", content_type: "image/jpg") - message = Message.create!(subject: "Greetings", content: ActionText::Content.new("Hello world").append_attachables(blob)) - assert_equal "racecar.jpg", message.content.embeds.first.filename.to_s - end +require 'test_helper' + +class ActionText::ContentTest < ActiveSupport::TestCase + test "equality" do + html = %Q(
test
) + content = ActionText::Content.new(html) + assert_equal content, ActionText::Content.new(html) + assert_not_equal content, html + end + + test "marshal serialization" do + content = ActionText::Content.new("Hello!") + assert_equal content, Marshal.load(Marshal.dump(content)) + end + + test "roundtrips HTML without additional newlines" do + html = %Q(
a
) + content = ActionText::Content.new(html) + assert_equal html, content.to_html end + + test "extracts links" do + html = %Q(1
1) + content = ActionText::Content.new(html) + assert_equal ["http://example.com/1"], content.links + end + + test "extracts attachables" do + attachable = create_file_blob(filename: "racecar.jpg", content_type: "image/jpg") + html = %Q() + + content = ActionText::Content.new(html) + assert_equal 1, content.attachments.size + + attachment = content.attachments.first + assert_equal "Captioned", attachment.caption + assert_equal attachable, attachment.attachable + end + + test "extracts remote image attachables" do + html = %Q() + + content = ActionText::Content.new(html) + assert_equal 1, content.attachments.size + + attachment = content.attachments.first + assert_equal "Captioned", attachment.caption + + attachable = attachment.attachable + assert_kind_of ActionText::Attachables::RemoteImage, attachable + assert_equal "http://example.com/cat.jpg", attachable.url + assert_equal "100", attachable.width + assert_equal "100", attachable.height + end + + test "identifies destroyed attachables as missing" do + attachable = create_file_blob(filename: "racecar.jpg", content_type: "image/jpg") + html = %Q() + attachable.destroy! + content = ActionText::Content.new(html) + assert_equal 1, content.attachments.size + assert_equal ActionText::Attachables::MissingAttachable, content.attachments.first.attachable + end + + # test "extracts missing attachables" do + # html = %Q() + # content = ActionText::Content.new(html) + # assert_equal 1, content.attachments.size + # assert_equal ActionText::Attachables::MissingAttachable, content.attachments.first.attachable + # end + # + # test "converts Trix-formatted attachments" do + # html = %Q(
) + # content = ActionText::Content.new(html) + # assert_equal 1, content.attachments.size + # assert_equal %Q(), content.to_html + # end + # + # test "ignores Trix-formatted attachments with malformed JSON" do + # html = %Q(
) + # content = ActionText::Content.new(html) + # assert_equal 0, content.attachments.size + # end + # + # test "minifies attachment markup" do + # html = %Q(
HTML
) + # assert_equal %Q(), ActionText::Content.new(html).to_html + # end + # + # test "canonicalizes attachment gallery markup" do + # attachment_html = %Q() + # html = %Q() + # assert_equal %Q(
#{attachment_html}
), ActionText::Content.new(html).to_html + # end + # + # test "canonicalizes attachment gallery markup with whitespace" do + # attachment_html = %Q(\n \n \n) + # html = %Q() + # assert_equal %Q(
#{attachment_html}
), ActionText::Content.new(html).to_html + # end + # + # test "canonicalizes nested attachment gallery markup" do + # attachment_html = %Q() + # html = %Q(
) + # assert_equal %Q(
#{attachment_html}
), ActionText::Content.new(html).to_html + # end end diff --git a/test/unit/model_test.rb b/test/unit/model_test.rb index b7c5333c4d..bdfe88adc8 100644 --- a/test/unit/model_test.rb +++ b/test/unit/model_test.rb @@ -1,10 +1,24 @@ -require_relative '../test_helper' - -module ActionText - class ModelTest < ActiveSupport::TestCase - test "saving content" do - message = Message.create!(subject: "Greetings", content: "

Hello world

") - assert_equal "Hello world", message.content.body.to_plain_text - end +require 'test_helper' + +class ActionText::ModelTest < ActiveSupport::TestCase + test "plain text conversion" do + message = Message.new(subject: "Greetings", content: "

Hello world

") + assert_equal "Hello world", message.content.body.to_plain_text + end + + test "without content" do + message = Message.create!(subject: "Greetings") + assert message.content.body.nil? + end + + test "embed extraction" do + blob = create_file_blob(filename: "racecar.jpg", content_type: "image/jpg") + message = Message.create!(subject: "Greetings", content: ActionText::Content.new("Hello world").append_attachables(blob)) + assert_equal "racecar.jpg", message.content.embeds.first.filename.to_s + end + + test "saving content" do + message = Message.create!(subject: "Greetings", content: "

Hello world

") + assert_equal "Hello world", message.content.body.to_plain_text end end diff --git a/test/unit/plain_text_conversion_test.rb b/test/unit/plain_text_conversion_test.rb new file mode 100644 index 0000000000..47c95b6bc3 --- /dev/null +++ b/test/unit/plain_text_conversion_test.rb @@ -0,0 +1,92 @@ +require 'test_helper' + +class ActionText::PlainTextConversionTest < ActiveSupport::TestCase + test "

tags are separated by two new lines" do + assert_converted_to( + "Hello world!\n\nHow are you?", + "

Hello world!

How are you?

" + ) + end + + test "
tags are separated by two new lines" do + assert_converted_to( + "“Hello world!”\n\n“How are you?”", + "
Hello world!
How are you?
" + ) + end + + test "
    tags are separated by two new lines" do + assert_converted_to( + "Hello world!\n\n1. list1\n\n1. list2\n\nHow are you?", + "

    Hello world!

    1. list1
    1. list2

    How are you?

    " + ) + end + + test "
      tags are separated by two new lines" do + assert_converted_to( + "Hello world!\n\n• list1\n\n• list2\n\nHow are you?", + "

      Hello world!

      • list1
      • list2

      How are you?

      " + ) + end + + test "

      tags are separated by two new lines" do + assert_converted_to( + "Hello world!\n\nHow are you?", + "

      Hello world!

      How are you?
      " + ) + end + + test "
    • tags are separated by one new line" do + assert_converted_to( + "• one\n• two\n• three", + "
      • one
      • two
      • three
      " + ) + end + + test "
    • tags without a parent list" do + assert_converted_to( + "• one\n• two\n• three", + "
    • one
    • two
    • three
    • " + ) + end + + test "
      tags are separated by one new line" do + assert_converted_to( + "Hello world!\none\ntwo\nthree", + "

      Hello world!
      one
      two
      three

      " + ) + end + + test "
      tags are separated by one new line" do + assert_converted_to( + "Hello world!\nHow are you?", + "
      Hello world!
      How are you?
      " + ) + end + + test " tags are converted to their plain-text representation" do + assert_converted_to( + "Hello world! [Cat]", + %Q(Hello world! ) + ) + end + + test "preserves non-linebreak whitespace after text" do + assert_converted_to( + "Hello world!", + %Q(
      Hello world!
      ) + ) + end + + test "preserves trailing linebreaks after text" do + assert_converted_to( + "Hello\nHow are you?", + "Hello
      How are you?" + ) + end + + private + def assert_converted_to(plain_text, html) + assert_equal plain_text, ActionText::Content.new(html).to_plain_text + end +end diff --git a/test/unit/trix_attachment_test.rb b/test/unit/trix_attachment_test.rb new file mode 100644 index 0000000000..fe834c8663 --- /dev/null +++ b/test/unit/trix_attachment_test.rb @@ -0,0 +1,81 @@ +require 'test_helper' + +class ActionText::TrixAttachmentTest < ActiveSupport::TestCase + test "from_attributes" do + attributes = { + "data-trix-attachment" => { + "sgid" => "123", + "contentType" => "text/plain", + "href" => "http://example.com/", + "filename" => "example.txt", + "filesize" => 12345, + "previewable" => true + }, + "data-trix-attributes" => { + "caption" => "hello" + } + } + + attachment = attachment( + sgid: "123", + content_type: "text/plain", + href: "http://example.com/", + filename: "example.txt", + filesize: "12345", + previewable: "true", + caption: "hello" + ) + + assert_attachment_json_attributes(attachment, attributes) + end + + test "previewable is typecast" do + assert_attachment_attribute(attachment(previewable: ""), "previewable", false) + assert_attachment_attribute(attachment(previewable: false), "previewable", false) + assert_attachment_attribute(attachment(previewable: "false"), "previewable", false) + assert_attachment_attribute(attachment(previewable: "garbage"), "previewable", false) + assert_attachment_attribute(attachment(previewable: true), "previewable", true) + assert_attachment_attribute(attachment(previewable: "true"), "previewable", true) + end + + test "filesize is typecast when integer-like" do + assert_attachment_attribute(attachment(filesize: 123), "filesize", 123) + assert_attachment_attribute(attachment(filesize: "123"), "filesize", 123) + assert_attachment_attribute(attachment(filesize: "3.5 MB"), "filesize", "3.5 MB") + assert_attachment_attribute(attachment(filesize: nil), "filesize", nil) + assert_attachment_attribute(attachment(filesize: ""), "filesize", "") + end + + test "#attributes strips unmappable attributes" do + attributes = { + "sgid" => "123", + "caption" => "hello" + } + + attachment = attachment(sgid: "123", caption: "hello", nonexistent: "garbage") + assert_attachment_attributes(attachment, attributes) + end + + def assert_attachment_attribute(attachment, name, value) + if value.nil? + assert_nil(attachment.attributes[name]) + else + assert_equal(value, attachment.attributes[name]) + end + end + + def assert_attachment_attributes(attachment, attributes) + assert_equal(attributes, attachment.attributes) + end + + def assert_attachment_json_attributes(attachment, attributes) + attributes.each do |name, expected| + actual = JSON.parse(attachment.node[name]) + assert_equal(expected, actual) + end + end + + def attachment(**attributes) + ActionText::TrixAttachment.from_attributes(attributes) + end +end -- cgit v1.2.3 From 7bbddb01738cd8c2a3bda65d32f30ec5e386b4a9 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Tue, 2 Oct 2018 13:57:50 -0400 Subject: Fix

      plain text conversion Fixes #4 --- lib/action_text/plain_text_conversion.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/action_text/plain_text_conversion.rb b/lib/action_text/plain_text_conversion.rb index c9867bd8c9..ea168f1c4e 100644 --- a/lib/action_text/plain_text_conversion.rb +++ b/lib/action_text/plain_text_conversion.rb @@ -29,7 +29,7 @@ module ActionText "#{remove_trailing_newlines(plain_text_for_node_children(node))}\n\n" end - %i[ p ul ol ].each do |element| + %i[ h1 p ul ol ].each do |element| alias_method :"plain_text_for_#{element}_node", :plain_text_for_block end -- cgit v1.2.3 From b5d14e3291a3b20f004d881836a2a42cb129f898 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 2 Oct 2018 15:45:48 -0700 Subject: No need for the verbose warning --- lib/tasks/actiontext.rake | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/tasks/actiontext.rake b/lib/tasks/actiontext.rake index e73ed34691..d451b0fec1 100644 --- a/lib/tasks/actiontext.rake +++ b/lib/tasks/actiontext.rake @@ -17,9 +17,7 @@ namespace :action_text do STYLESHEET_APP_PATH = Rails.root.join("app/assets/stylesheets/actiontext.css") task :copy_stylesheet do - if File.exist?(STYLESHEET_APP_PATH) - puts "Won't copy Action Text stylesheet as it already exists" - else + unless File.exist?(STYLESHEET_APP_PATH) FileUtils.cp STYLESHEET_TEMPLATE_PATH, STYLESHEET_APP_PATH end end @@ -29,9 +27,7 @@ namespace :action_text do FIXTURE_APP_PATH = FIXTURE_APP_DIR_PATH.join("rich_texts.yml") task :copy_fixtures do - if File.exist?(FIXTURE_APP_PATH) - puts "Won't copy Action Text fixtures as it already exists" - else + unless File.exist?(FIXTURE_APP_PATH) FileUtils.mkdir FIXTURE_APP_DIR_PATH FileUtils.cp FIXTURE_TEMPLATE_PATH, FIXTURE_APP_PATH end -- cgit v1.2.3 From 462af91c74b5e9d34388fec6156fbe02a8ef794e Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 2 Oct 2018 15:46:51 -0700 Subject: Now we add the npm dependency as part of the installer --- README.md | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/README.md b/README.md index c066323e1f..304fe644c1 100644 --- a/README.md +++ b/README.md @@ -14,18 +14,7 @@ Assumes a Rails 5.2+ application with Active Storage and Webpacker installed. gem "image_processing", "~> 1.2" # for Active Storage variants ``` -1. Install the npm package (with a local reference to this checked out repository): - - ```sh - $ yarn add file:../actiontext - ``` - - ```js - // app/javascript/packs/application.js - import "actiontext" - ``` - -1. Migrate the database +1. Install assets, npm dependency, and migrations ``` ./bin/rails action_text:install -- cgit v1.2.3 From fc2c786e1236737f2e06384969e84dd88641b9b3 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 2 Oct 2018 15:47:01 -0700 Subject: Add via yarn in the installer --- lib/tasks/actiontext.rake | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/tasks/actiontext.rake b/lib/tasks/actiontext.rake index d451b0fec1..6ec30f86e7 100644 --- a/lib/tasks/actiontext.rake +++ b/lib/tasks/actiontext.rake @@ -5,7 +5,7 @@ namespace :action_text do Rake::Task["install:migrations"].clear_comments desc "Copy over the migration, stylesheet, and JavaScript files" - task install: %w( environment copy_migrations copy_stylesheet copy_fixtures ) + task install: %w( environment copy_migrations copy_stylesheet copy_fixtures yarn_add ) task :copy_migrations do Rake::Task["active_storage:install:migrations"].invoke @@ -32,4 +32,9 @@ namespace :action_text do FileUtils.cp FIXTURE_TEMPLATE_PATH, FIXTURE_APP_PATH end end + + task :yarn_add do + # FIXME: Replace with release version on release + system "yarn add https://github.com/basecamp/actiontext" + end end -- cgit v1.2.3 From e11f84ee3a6d9a7fe77e3b1e112a6625c1df0ee4 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 2 Oct 2018 16:05:03 -0700 Subject: Use an app template installer instead for nicer overwriting checks --- lib/tasks/actiontext.rake | 32 ++++++-------------------------- lib/templates/installer.rb | 9 +++++++++ 2 files changed, 15 insertions(+), 26 deletions(-) create mode 100644 lib/templates/installer.rb diff --git a/lib/tasks/actiontext.rake b/lib/tasks/actiontext.rake index 6ec30f86e7..4f90e4930c 100644 --- a/lib/tasks/actiontext.rake +++ b/lib/tasks/actiontext.rake @@ -5,36 +5,16 @@ namespace :action_text do Rake::Task["install:migrations"].clear_comments desc "Copy over the migration, stylesheet, and JavaScript files" - task install: %w( environment copy_migrations copy_stylesheet copy_fixtures yarn_add ) + task install: %w( environment run_installer copy_migrations ) + + task :run_installer do + installer_template = File.expand_path("../templates/installer.rb", __dir__) + system "#{RbConfig.ruby} ./bin/rails app:template LOCATION=#{installer_template}" + end task :copy_migrations do Rake::Task["active_storage:install:migrations"].invoke Rake::Task["railties:install:migrations"].reenable # Otherwise you can't run 2 migration copy tasks in one invocation Rake::Task["action_text:install:migrations"].invoke end - - STYLESHEET_TEMPLATE_PATH = File.expand_path("../templates/actiontext.css", __dir__) - STYLESHEET_APP_PATH = Rails.root.join("app/assets/stylesheets/actiontext.css") - - task :copy_stylesheet do - unless File.exist?(STYLESHEET_APP_PATH) - FileUtils.cp STYLESHEET_TEMPLATE_PATH, STYLESHEET_APP_PATH - end - end - - FIXTURE_TEMPLATE_PATH = File.expand_path("../templates/fixtures.yml", __dir__) - FIXTURE_APP_DIR_PATH = Rails.root.join("test/fixtures/action_text") - FIXTURE_APP_PATH = FIXTURE_APP_DIR_PATH.join("rich_texts.yml") - - task :copy_fixtures do - unless File.exist?(FIXTURE_APP_PATH) - FileUtils.mkdir FIXTURE_APP_DIR_PATH - FileUtils.cp FIXTURE_TEMPLATE_PATH, FIXTURE_APP_PATH - end - end - - task :yarn_add do - # FIXME: Replace with release version on release - system "yarn add https://github.com/basecamp/actiontext" - end end diff --git a/lib/templates/installer.rb b/lib/templates/installer.rb new file mode 100644 index 0000000000..4019b35490 --- /dev/null +++ b/lib/templates/installer.rb @@ -0,0 +1,9 @@ +say "Copying actiontext.css to app/assets/stylesheets" +copy_file "#{__dir__}/actiontext.css", "app/assets/stylesheets/actiontext.css" + +say "Copying fixtures to test/fixtures/action_text/rich_texts.yml" +copy_file "#{__dir__}/fixtures.yml", "test/fixtures/action_text/rich_texts.yml" + +# FIXME: Replace with release version on release +say "Installing JavaScript dependency" +run "yarn add https://github.com/basecamp/actiontext" -- cgit v1.2.3 From 4f5fe2b5784f21eaccd3f8a3a1c95c50072de31a Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 2 Oct 2018 16:10:25 -0700 Subject: Add import statement to default pack file if relevant --- lib/templates/installer.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/templates/installer.rb b/lib/templates/installer.rb index 4019b35490..44769c5193 100644 --- a/lib/templates/installer.rb +++ b/lib/templates/installer.rb @@ -7,3 +7,12 @@ copy_file "#{__dir__}/fixtures.yml", "test/fixtures/action_text/rich_texts.yml" # FIXME: Replace with release version on release say "Installing JavaScript dependency" run "yarn add https://github.com/basecamp/actiontext" + +APPLICATION_PATH_PATH = "app/javascript/packs/application.js" + +if File.exists?(APPLICATION_PATH_PATH) && File.read(APPLICATION_PATH_PATH) !~ /import "actiontext"/ + say "Adding import to default JavaScript pack" + append_to_file APPLICATION_PATH_PATH, <<-EOS +import "actiontext" +EOS +end -- cgit v1.2.3 From 9fb3dd7551a2bdb8acedf3ceb056071070b6fd66 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Tue, 2 Oct 2018 19:36:01 -0400 Subject: Uncomment failing tests --- test/unit/attachment_test.rb | 54 ++++++++++++++-------------- test/unit/content_test.rb | 84 ++++++++++++++++++++++---------------------- 2 files changed, 69 insertions(+), 69 deletions(-) diff --git a/test/unit/attachment_test.rb b/test/unit/attachment_test.rb index dec2b8244d..a31ef1afd0 100644 --- a/test/unit/attachment_test.rb +++ b/test/unit/attachment_test.rb @@ -18,33 +18,33 @@ class ActionText::AttachmentTest < ActiveSupport::TestCase assert_equal attachable.to_param, attachment.to_param end - # test "converts to TrixAttachment" do - # attachment = attachment_from_html(%Q()) - # - # trix_attachment = attachment.to_trix_attachment - # assert_kind_of ActionText::TrixAttachment, trix_attachment - # - # assert_equal attachable.attachable_sgid, trix_attachment.attributes["sgid"] - # assert_equal attachable.attachable_content_type, trix_attachment.attributes["contentType"] - # assert_equal attachable.filename.to_s, trix_attachment.attributes["filename"] - # assert_equal attachable.byte_size, trix_attachment.attributes["filesize"] - # assert_equal "Captioned", trix_attachment.attributes["caption"] - # - # assert_nil trix_attachment.attributes["content"] - # end - - # test "converts to TrixAttachment with content" do - # attachment = attachment_from_html(%Q()) - # - # trix_attachment = attachment.to_trix_attachment - # assert_kind_of ActionText::TrixAttachment, trix_attachment - # - # assert_equal attachable.attachable_sgid, trix_attachment.attributes["sgid"] - # assert_equal attachable.attachable_content_type, trix_attachment.attributes["contentType"] - # - # assert_not_nil attachable.to_trix_content_attachment_partial_path - # assert_not_nil trix_attachment.attributes["content"] - # end + test "converts to TrixAttachment" do + attachment = attachment_from_html(%Q()) + + trix_attachment = attachment.to_trix_attachment + assert_kind_of ActionText::TrixAttachment, trix_attachment + + assert_equal attachable.attachable_sgid, trix_attachment.attributes["sgid"] + assert_equal attachable.attachable_content_type, trix_attachment.attributes["contentType"] + assert_equal attachable.filename.to_s, trix_attachment.attributes["filename"] + assert_equal attachable.byte_size, trix_attachment.attributes["filesize"] + assert_equal "Captioned", trix_attachment.attributes["caption"] + + assert_nil trix_attachment.attributes["content"] + end + + test "converts to TrixAttachment with content" do + attachment = attachment_from_html(%Q()) + + trix_attachment = attachment.to_trix_attachment + assert_kind_of ActionText::TrixAttachment, trix_attachment + + assert_equal attachable.attachable_sgid, trix_attachment.attributes["sgid"] + assert_equal attachable.attachable_content_type, trix_attachment.attributes["contentType"] + + assert_not_nil attachable.to_trix_content_attachment_partial_path + assert_not_nil trix_attachment.attributes["content"] + end private def attachment_from_html(html) diff --git a/test/unit/content_test.rb b/test/unit/content_test.rb index 8f32a85110..c0b8ad024c 100644 --- a/test/unit/content_test.rb +++ b/test/unit/content_test.rb @@ -62,46 +62,46 @@ class ActionText::ContentTest < ActiveSupport::TestCase assert_equal ActionText::Attachables::MissingAttachable, content.attachments.first.attachable end - # test "extracts missing attachables" do - # html = %Q() - # content = ActionText::Content.new(html) - # assert_equal 1, content.attachments.size - # assert_equal ActionText::Attachables::MissingAttachable, content.attachments.first.attachable - # end - # - # test "converts Trix-formatted attachments" do - # html = %Q(
      ) - # content = ActionText::Content.new(html) - # assert_equal 1, content.attachments.size - # assert_equal %Q(), content.to_html - # end - # - # test "ignores Trix-formatted attachments with malformed JSON" do - # html = %Q(
      ) - # content = ActionText::Content.new(html) - # assert_equal 0, content.attachments.size - # end - # - # test "minifies attachment markup" do - # html = %Q(
      HTML
      ) - # assert_equal %Q(), ActionText::Content.new(html).to_html - # end - # - # test "canonicalizes attachment gallery markup" do - # attachment_html = %Q() - # html = %Q() - # assert_equal %Q(
      #{attachment_html}
      ), ActionText::Content.new(html).to_html - # end - # - # test "canonicalizes attachment gallery markup with whitespace" do - # attachment_html = %Q(\n \n \n) - # html = %Q() - # assert_equal %Q(
      #{attachment_html}
      ), ActionText::Content.new(html).to_html - # end - # - # test "canonicalizes nested attachment gallery markup" do - # attachment_html = %Q() - # html = %Q(
      ) - # assert_equal %Q(
      #{attachment_html}
      ), ActionText::Content.new(html).to_html - # end + test "extracts missing attachables" do + html = %Q() + content = ActionText::Content.new(html) + assert_equal 1, content.attachments.size + assert_equal ActionText::Attachables::MissingAttachable, content.attachments.first.attachable + end + + test "converts Trix-formatted attachments" do + html = %Q(
      ) + content = ActionText::Content.new(html) + assert_equal 1, content.attachments.size + assert_equal %Q(), content.to_html + end + + test "ignores Trix-formatted attachments with malformed JSON" do + html = %Q(
      ) + content = ActionText::Content.new(html) + assert_equal 0, content.attachments.size + end + + test "minifies attachment markup" do + html = %Q(
      HTML
      ) + assert_equal %Q(), ActionText::Content.new(html).to_html + end + + test "canonicalizes attachment gallery markup" do + attachment_html = %Q() + html = %Q() + assert_equal %Q(
      #{attachment_html}
      ), ActionText::Content.new(html).to_html + end + + test "canonicalizes attachment gallery markup with whitespace" do + attachment_html = %Q(\n \n \n) + html = %Q() + assert_equal %Q(
      #{attachment_html}
      ), ActionText::Content.new(html).to_html + end + + test "canonicalizes nested attachment gallery markup" do + attachment_html = %Q() + html = %Q(
      ) + assert_equal %Q(
      #{attachment_html}
      ), ActionText::Content.new(html).to_html + end end -- cgit v1.2.3 From b39478de43716e1ee49acd0b95c278dcb143fdae Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 2 Oct 2018 16:51:46 -0700 Subject: Default sanitization --- app/views/action_text/content/_layout.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/action_text/content/_layout.html.erb b/app/views/action_text/content/_layout.html.erb index c0b86a189e..b8c8ab6fc6 100644 --- a/app/views/action_text/content/_layout.html.erb +++ b/app/views/action_text/content/_layout.html.erb @@ -1,3 +1,3 @@
      - <%=raw document %> + <%= sanitize document %>
      -- cgit v1.2.3 From 4034515ac66499f30196b2e4f938ee2ab5ed6a2e Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 2 Oct 2018 16:56:09 -0700 Subject: Copy over the blobs/_blob partial so it can be specialized --- lib/templates/installer.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/templates/installer.rb b/lib/templates/installer.rb index 44769c5193..03ba0722cd 100644 --- a/lib/templates/installer.rb +++ b/lib/templates/installer.rb @@ -4,6 +4,10 @@ copy_file "#{__dir__}/actiontext.css", "app/assets/stylesheets/actiontext.css" say "Copying fixtures to test/fixtures/action_text/rich_texts.yml" copy_file "#{__dir__}/fixtures.yml", "test/fixtures/action_text/rich_texts.yml" +say "Copying blob rendering partial to app/views/active_storage/blobs/_blob.html.erb" +copy_file "#{__dir__}/../../app/views/active_storage/blobs/_blob.html.erb", + "app/views/active_storage/blobs/_blob.html.erb" + # FIXME: Replace with release version on release say "Installing JavaScript dependency" run "yarn add https://github.com/basecamp/actiontext" -- cgit v1.2.3 From 283023f826165153d23d2373e1e023f873a46b41 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 2 Oct 2018 17:10:09 -0700 Subject: Flush out the README --- README.md | 88 ++++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 65 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 304fe644c1..e781e1cde2 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,25 @@ # Action Text -🤸‍♂️💰📝 +Action Text brings rich text content and editing to Rails. It includes the [Trix editor](https://trix-editor.org/) that handles everything from formatting to links to quotes to lists to embedded images and galleries. The rich text content generated by the Trix editor is saved in its own RichText model that's associated with any existing Active Record model in the application. Any embedded images (or other attachments) are automatically stored using Active Storage and associated with the included RichText model. + + +## Trix compared to other rich text editors + +Most WYSIWYG editors are wrappers around HTML’s `contenteditable` and `execCommand` APIs, designed by Microsoft to support live editing of web pages in Internet Explorer 5.5, and [eventually reverse-engineered](https://blog.whatwg.org/the-road-to-html-5-contenteditable#history) and copied by other browsers. + +Because these APIs were never fully specified or documented, and because WYSIWYG HTML editors are enormous in scope, each browser’s implementation has its own set of bugs and quirks, and JavaScript developers are left to resolve the inconsistencies. + +Trix sidesteps these inconsistencies by treating contenteditable as an I/O device: when input makes its way to the editor, Trix converts that input into an editing operation on its internal document model, then re-renders that document back into the editor. This gives Trix complete control over what happens after every keystroke, and avoids the need to use execCommand at all. ## Installing -Assumes a Rails 5.2+ application with Active Storage and Webpacker installed. +Assumes a Rails 6+ application with Active Storage and Webpacker installed. 1. Install the gem: ```ruby # Gemfile - gem "actiontext", github: "basecamp/actiontext", require: "action_text" + gem "actiontext", github: "rails/actiontext", require: "action_text" gem "image_processing", "~> 1.2" # for Active Storage variants ``` @@ -21,25 +30,58 @@ Assumes a Rails 5.2+ application with Active Storage and Webpacker installed. ./bin/rails db:migrate ``` -1. Declare text columns as Action Text attributes: +## Examples - ```ruby - # app/models/message.rb - class Message < ActiveRecord::Base - has_rich_text :content - end - ``` +Adding a rich text field to an existing model: -1. Replace form `text_area`s with `rich_text_area`s: - - ```erb - <%# app/views/messages/_form.html.erb %> - <%= form_with(model: message) do |form| %> - … -
      - <%= form.label :content %> - <%= form.rich_text_area :content %> -
      - … - <% end %> - ``` +```ruby +# app/models/message.rb +class Message < ActiveRecord::Base + has_rich_text :content +end +``` + +Then refer to this field in the form for the model: + +```erb +<%# app/views/messages/_form.html.erb %> +<%= form_with(model: message) do |form| %> + … +
      + <%= form.label :content %> + <%= form.rich_text_area :content %> +
      + … +<% end %> +``` + +And finally display the rich text on a page: + +```erb +<%= @message.content %> +``` + +To accept the rich text content, all you have to do is permit the referenced attribute: + +```ruby +class MessagesController < ApplicationController + def create + message = Message.create! params.require(:message).permit(:title, :content) + redirect_to message + end +end +``` + +## Custom styling + +By default, the Action Text editor and content is styled by the Trix defaults. If you want to change these defaults, you'll want to remove the `app/assets/stylesheets/actiontext.css` linker and base your stylings on the [contents of that file](https://raw.githubusercontent.com/basecamp/trix/master/dist/trix.css). + +You can also style the HTML used for embedded images and other attachments (known as blobs). On installation, Action Text will copy over a partial to `app/views/active_storage/blobs/_blob.html.erb`, which you can specialize. + +## Development road map + +Action Text is destined for inclusion in Rails 6, which is due to be released some time in 2019. We will refine the framework in this separate rails/actiontext repository until we're ready to promote it via a pull request to rails/rails. + +## License + +Action Text is released under the [MIT License](https://opensource.org/licenses/MIT). \ No newline at end of file -- cgit v1.2.3 From 1663bfad247732aa928e60489d4d394e338d1c49 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 2 Oct 2018 17:30:22 -0700 Subject: Add a bit more documentation --- app/helpers/action_text/tag_helper.rb | 23 +++++++++++++++++++++++ app/models/action_text/rich_text.rb | 4 ++++ 2 files changed, 27 insertions(+) diff --git a/app/helpers/action_text/tag_helper.rb b/app/helpers/action_text/tag_helper.rb index 28c62166dd..8d1ff0aaad 100644 --- a/app/helpers/action_text/tag_helper.rb +++ b/app/helpers/action_text/tag_helper.rb @@ -2,6 +2,17 @@ module ActionText module TagHelper cattr_accessor(:id, instance_accessor: false) { 0 } + # Returns a `trix-editor` tag that instantiates the Trix JavaScript editor as well as a hidden field + # that Trix will write to on changes, so the content will be sent on form submissions. + # + # ==== Options + # * :class - Defaults to "trix-content" which ensures default styling is applied. + # + # ==== Example + # + # rich_text_area_tag "content", message.content + # # + # # def rich_text_area_tag(name, value = nil, options = {}) options = options.symbolize_keys @@ -37,6 +48,18 @@ module ActionView::Helpers end module FormHelper + # Returns a `trix-editor` tag that instantiates the Trix JavaScript editor as well as a hidden field + # that Trix will write to on changes, so the content will be sent on form submissions. + # + # ==== Options + # * :class - Defaults to "trix-content" which ensures default styling is applied. + # + # ==== Example + # form_with(model: @message) do |form| + # form.rich_text_area :content + # end + # # + # # def rich_text_area(object_name, method, options = {}) Tags::ActionText.new(object_name, method, self, options).render end diff --git a/app/models/action_text/rich_text.rb b/app/models/action_text/rich_text.rb index 0b6043bd74..94cf595fac 100644 --- a/app/models/action_text/rich_text.rb +++ b/app/models/action_text/rich_text.rb @@ -1,3 +1,7 @@ +# The RichText record holds the content produced by the Trix editor in a serialized `body` attribute. +# It also holds all the references to the embedded files, which are stored using Active Storage. +# This record is then associated with the Active Record model the application desires to have +# rich text content using the `has_rich_text` class method. class ActionText::RichText < ActiveRecord::Base self.table_name = "action_text_rich_texts" -- cgit v1.2.3 From e5cc70ea172c063ca53f6556216dc61eb420e371 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Wed, 3 Oct 2018 12:10:09 -0400 Subject: Fill in Attachable rich text attributes --- lib/action_text/attachable.rb | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/action_text/attachable.rb b/lib/action_text/attachable.rb index 83a6cf0c17..1209f17e77 100644 --- a/lib/action_text/attachable.rb +++ b/lib/action_text/attachable.rb @@ -45,6 +45,18 @@ module ActionText try(:content_type) || "application/octet-stream" end + def attachable_filename + filename.to_s if respond_to?(:filename) + end + + def attachable_filesize + try(:byte_size) || try(:filesize) + end + + def attachable_metadata + try(:metadata) || {} + end + def previewable_attachable? false end @@ -58,7 +70,11 @@ module ActionText attributes[:sgid] = attachable_sgid attributes[:content_type] = attachable_content_type attributes[:previewable] = true if previewable_attachable? - end + attributes[:filename] = attachable_filename + attributes[:filesize] = attachable_filesize + attributes[:width] = attachable_metadata[:width] + attributes[:height] = attachable_metadata[:height] + end.compact end end end -- cgit v1.2.3 From 2bd0f608f268d6e98ad014ae6a2151e291ebce7c Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Wed, 3 Oct 2018 12:11:39 -0400 Subject: Add support for "presentation" gallery attribute --- lib/action_text/attachment.rb | 2 +- lib/action_text/trix_attachment.rb | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/action_text/attachment.rb b/lib/action_text/attachment.rb index a0e0c2f396..cba421c143 100644 --- a/lib/action_text/attachment.rb +++ b/lib/action_text/attachment.rb @@ -4,7 +4,7 @@ module ActionText TAG_NAME = "action-text-attachment" SELECTOR = TAG_NAME - ATTRIBUTES = %w( sgid content-type url href filename filesize width height previewable caption ) + ATTRIBUTES = %w( sgid content-type url href filename filesize width height previewable presentation caption ) class << self def fragment_by_canonicalizing_attachments(content) diff --git a/lib/action_text/trix_attachment.rb b/lib/action_text/trix_attachment.rb index 717d130d12..0c4a3869d8 100644 --- a/lib/action_text/trix_attachment.rb +++ b/lib/action_text/trix_attachment.rb @@ -3,7 +3,8 @@ module ActionText TAG_NAME = "figure" SELECTOR = "[data-trix-attachment]" - ATTRIBUTES = %w( sgid contentType url href filename filesize width height previewable content caption ) + COMPOSED_ATTRIBUTES = %w( caption presentation ) + ATTRIBUTES = %w( sgid contentType url href filename filesize width height previewable content ) + COMPOSED_ATTRIBUTES ATTRIBUTE_TYPES = { "previewable" => ->(value) { value.to_s == "true" }, "filesize" => ->(value) { Integer(value.to_s) rescue value }, @@ -16,8 +17,8 @@ module ActionText def from_attributes(attributes) attributes = process_attributes(attributes) - trix_attachment_attributes = attributes.except("caption") - trix_attributes = attributes.slice("caption") + trix_attachment_attributes = attributes.except(*COMPOSED_ATTRIBUTES) + trix_attributes = attributes.slice(*COMPOSED_ATTRIBUTES) node = ActionText::HtmlConversion.create_element(TAG_NAME) node["data-trix-attachment"] = JSON.generate(trix_attachment_attributes) -- cgit v1.2.3 From 60fe928d2f536249d297e92f31d9c126d3035df5 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Wed, 3 Oct 2018 12:11:59 -0400 Subject: Add default missing attachable template --- app/views/action_text/attachables/_missing_attachable.html.erb | 1 + 1 file changed, 1 insertion(+) create mode 100644 app/views/action_text/attachables/_missing_attachable.html.erb diff --git a/app/views/action_text/attachables/_missing_attachable.html.erb b/app/views/action_text/attachables/_missing_attachable.html.erb new file mode 100644 index 0000000000..5ffd93b89e --- /dev/null +++ b/app/views/action_text/attachables/_missing_attachable.html.erb @@ -0,0 +1 @@ +<%= "☒" -%> -- cgit v1.2.3 From 7a993324342d5542dcb40902eed097f7eaac3f1b Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Wed, 3 Oct 2018 12:46:05 -0400 Subject: WIP: Image gallery support --- .../_attachment_gallery.html.erb | 3 + lib/action_text.rb | 1 + lib/action_text/attachment_gallery.rb | 62 +++++++++++++++++++++ lib/action_text/content.rb | 65 +++++++++++++++++++--- 4 files changed, 124 insertions(+), 7 deletions(-) create mode 100644 app/views/action_text/attachment_galleries/_attachment_gallery.html.erb create mode 100644 lib/action_text/attachment_gallery.rb diff --git a/app/views/action_text/attachment_galleries/_attachment_gallery.html.erb b/app/views/action_text/attachment_galleries/_attachment_gallery.html.erb new file mode 100644 index 0000000000..6bc8674dc5 --- /dev/null +++ b/app/views/action_text/attachment_galleries/_attachment_gallery.html.erb @@ -0,0 +1,3 @@ + diff --git a/lib/action_text.rb b/lib/action_text.rb index 0559dce2ba..4182cacb8a 100644 --- a/lib/action_text.rb +++ b/lib/action_text.rb @@ -8,6 +8,7 @@ module ActionText mattr_accessor(:renderer) autoload :Attachable + autoload :AttachmentGallery autoload :Attachment autoload :Attribute autoload :Content diff --git a/lib/action_text/attachment_gallery.rb b/lib/action_text/attachment_gallery.rb new file mode 100644 index 0000000000..6f690551e6 --- /dev/null +++ b/lib/action_text/attachment_gallery.rb @@ -0,0 +1,62 @@ +module ActionText + class AttachmentGallery + include ActiveModel::Model + + class << self + def fragment_by_canonicalizing_attachment_galleries(content) + fragment_by_replacing_attachment_gallery_nodes(content) do |node| + "<#{TAG_NAME}>#{node.inner_html}" + end + end + + def fragment_by_replacing_attachment_gallery_nodes(content) + Fragment.wrap(content).update do |source| + find_attachment_gallery_nodes(source).each do |node| + node.replace(yield(node).to_s) + end + end + end + + def find_attachment_gallery_nodes(content) + Fragment.wrap(content).find_all(SELECTOR).select do |node| + node.children.all? do |child| + if child.text? + child.text =~ /\A(\n|\ )*\z/ + else + child.matches? ATTACHMENT_SELECTOR + end + end + end + end + + def from_node(node) + new(node) + end + end + + attr_reader :node + + def initialize(node) + @node = node + end + + def attachments + @attachments ||= node.css(ATTACHMENT_SELECTOR).map do |node| + ActionText::Attachment.from_node(node).with_full_attributes + end + end + + def size + attachments.size + end + + def inspect + "#<#{self.class.name} size=#{size.inspect}>" + end + + private + TAG_NAME = "div" + ATTACHMENT_SELECTOR = "#{ActionText::Attachment::SELECTOR}[presentation=gallery]" + SELECTOR = "#{TAG_NAME}:has(#{ATTACHMENT_SELECTOR} + #{ATTACHMENT_SELECTOR})" + end +end diff --git a/lib/action_text/content.rb b/lib/action_text/content.rb index 22b52cff1c..71d9e98657 100644 --- a/lib/action_text/content.rb +++ b/lib/action_text/content.rb @@ -6,8 +6,22 @@ module ActionText delegate :blank?, :empty?, :html_safe, :present?, to: :to_html # Delegating to to_html to avoid including the layout - def initialize(content = nil) - @fragment = ActionText::Attachment.fragment_by_canonicalizing_attachments(content) + class << self + def fragment_by_canonicalizing_content(content) + fragment = ActionText::Attachment.fragment_by_canonicalizing_attachments(content) + fragment = ActionText::AttachmentGallery.fragment_by_canonicalizing_attachment_galleries(fragment) + fragment + end + end + + def initialize(content = nil, options = {}) + options.with_defaults! canonicalize: true + + if options[:canonicalize] + @fragment = self.class.fragment_by_canonicalizing_content(content) + else + @fragment = ActionText::Fragment.wrap(content) + end end def links @@ -20,6 +34,16 @@ module ActionText end end + def attachment_galleries + @attachment_galleries ||= attachment_gallery_nodes.map do |node| + attachment_gallery_for_node(node) + end + end + + def gallery_attachments + @gallery_attachments ||= attachment_galleries.flat_map(&:attachments) + end + def attachables @attachables ||= attachment_nodes.map do |node| ActionText::Attachable.from_node(node) @@ -32,13 +56,21 @@ module ActionText end def render_attachments(**options, &block) - fragment.replace(ActionText::Attachment::SELECTOR) do |node| + content = fragment.replace(ActionText::Attachment::SELECTOR) do |node| block.call(attachment_for_node(node, **options)) end + self.class.new(content, canonicalize: false) + end + + def render_attachment_galleries(**options, &block) + content = ActionText::AttachmentGallery.fragment_by_replacing_attachment_gallery_nodes(fragment) do |node| + block.call(attachment_gallery_for_node(node, **options)) + end + self.class.new(content, canonicalize: false) end def to_plain_text - render_attachments(with_full_attributes: false, &:to_plain_text).to_plain_text + render_attachments(with_full_attributes: false, &:to_plain_text).fragment.to_plain_text end def to_trix_html @@ -46,19 +78,30 @@ module ActionText end def to_html + fragment.to_html + end + + def to_rendered_html render_attachments do |attachment| attachment.node.tap do |node| node.inner_html = ActionText.renderer.render(attachment) end + end.render_attachment_galleries do |attachment_gallery| + ActionText.renderer.render(layout: attachment_gallery, object: attachment_gallery, formats: "html") do + attachment_gallery.attachments.map do |attachment| + attachment.node.inner_html = ActionText.renderer.render(attachment) + attachment.to_html + end.join("").html_safe + end end.to_html end - def to_html_with_layout - ActionText.renderer.render(partial: "action_text/content/layout", locals: { document: to_html }) + def to_rendered_html_with_layout + ActionText.renderer.render(partial: "action_text/content/layout", locals: { document: to_rendered_html }) end def to_s - to_html_with_layout + to_rendered_html_with_layout end def as_json(*) @@ -80,9 +123,17 @@ module ActionText @attachment_nodes ||= fragment.find_all(ActionText::Attachment::SELECTOR) end + def attachment_gallery_nodes + @attachment_gallery_nodes ||= ActionText::AttachmentGallery.find_attachment_gallery_nodes(fragment) + end + def attachment_for_node(node, with_full_attributes: true) attachment = ActionText::Attachment.from_node(node) with_full_attributes ? attachment.with_full_attributes : attachment end + + def attachment_gallery_for_node(node, **options) + ActionText::AttachmentGallery.from_node(node) + end end end -- cgit v1.2.3 From 30443121286c3bb970d4d24bf7f24472498e9633 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Wed, 3 Oct 2018 14:41:47 -0400 Subject: Move attachment rendering to a helper Fixes #5 --- app/helpers/action_text/content_helper.rb | 24 ++++++++++++++++++++++++ app/views/action_text/content/_layout.html.erb | 2 +- app/views/active_storage/blobs/_blob.html.erb | 5 +++-- lib/action_text/content.rb | 17 +---------------- lib/action_text/engine.rb | 4 ++-- 5 files changed, 31 insertions(+), 21 deletions(-) create mode 100644 app/helpers/action_text/content_helper.rb diff --git a/app/helpers/action_text/content_helper.rb b/app/helpers/action_text/content_helper.rb new file mode 100644 index 0000000000..6d00eee648 --- /dev/null +++ b/app/helpers/action_text/content_helper.rb @@ -0,0 +1,24 @@ +module ActionText + module ContentHelper + def render_action_text_content(content) + content = content.render_attachments do |attachment| + unless attachment.in?(content.gallery_attachments) + attachment.node.tap do |node| + node.inner_html = render(attachment, in_gallery: false).chomp + end + end + end + + content = content.render_attachment_galleries do |attachment_gallery| + render(layout: attachment_gallery, object: attachment_gallery) do + attachment_gallery.attachments.map do |attachment| + attachment.node.inner_html = render(attachment, in_gallery: true).chomp + attachment.to_html + end.join("").html_safe + end.chomp + end + + content.to_html + end + end +end diff --git a/app/views/action_text/content/_layout.html.erb b/app/views/action_text/content/_layout.html.erb index b8c8ab6fc6..60d65cd0d5 100644 --- a/app/views/action_text/content/_layout.html.erb +++ b/app/views/action_text/content/_layout.html.erb @@ -1,3 +1,3 @@
      - <%= sanitize document %> + <%= sanitize render_action_text_content(content) %>
      diff --git a/app/views/active_storage/blobs/_blob.html.erb b/app/views/active_storage/blobs/_blob.html.erb index c7c70c110e..6e4105d5cf 100644 --- a/app/views/active_storage/blobs/_blob.html.erb +++ b/app/views/active_storage/blobs/_blob.html.erb @@ -1,8 +1,9 @@ +<% transformations = { resize: local_assigns[:in_gallery] ? "800x600>" : "1024x768>" } %>
      attachment--<%= blob.filename.extension %>"> <% if blob.variable? %> - <%= image_tag blob.variant(resize: "1024x768>") %> + <%= image_tag blob.variant(transformations) %> <% elsif blob.previewable? %> - <%= image_tag blob.preview(resize: "1024x768>") %> + <%= image_tag blob.preview(transformations) %> <% end %>
      diff --git a/lib/action_text/content.rb b/lib/action_text/content.rb index 71d9e98657..4061613e35 100644 --- a/lib/action_text/content.rb +++ b/lib/action_text/content.rb @@ -81,23 +81,8 @@ module ActionText fragment.to_html end - def to_rendered_html - render_attachments do |attachment| - attachment.node.tap do |node| - node.inner_html = ActionText.renderer.render(attachment) - end - end.render_attachment_galleries do |attachment_gallery| - ActionText.renderer.render(layout: attachment_gallery, object: attachment_gallery, formats: "html") do - attachment_gallery.attachments.map do |attachment| - attachment.node.inner_html = ActionText.renderer.render(attachment) - attachment.to_html - end.join("").html_safe - end - end.to_html - end - def to_rendered_html_with_layout - ActionText.renderer.render(partial: "action_text/content/layout", locals: { document: to_rendered_html }) + ActionText.renderer.render(partial: "action_text/content/layout", locals: { content: self }) end def to_s diff --git a/lib/action_text/engine.rb b/lib/action_text/engine.rb index 71db6d6a26..4055bbbb29 100644 --- a/lib/action_text/engine.rb +++ b/lib/action_text/engine.rb @@ -25,7 +25,7 @@ module ActionText initializer "action_text.helper" do ActiveSupport.on_load(:action_controller_base) do - helper ActionText::TagHelper + helper ActionText::Engine.helpers end end @@ -33,7 +33,7 @@ module ActionText config.after_initialize do |app| ActionText.renderer ||= ApplicationController.renderer - # FIXME: ApplicationController should have a per-request specific renderer + # FIXME: ApplicationController should have a per-request specific renderer # that's been set with the request.env env, and ActionText should just piggyback off # that by default rather than doing this work directly. ApplicationController.before_action do -- cgit v1.2.3 From 6a77309d66b04220321e12873a083110e47840e7 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Wed, 3 Oct 2018 15:05:16 -0400 Subject: Fix content attachment test --- test/dummy/app/models/person.rb | 7 +++++++ test/dummy/app/views/people/_trix_content_attachment.html.erb | 3 +++ test/dummy/db/migrate/20181003185713_create_people.rb | 9 +++++++++ test/dummy/db/schema.rb | 8 +++++++- test/unit/attachment_test.rb | 1 + 5 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 test/dummy/app/models/person.rb create mode 100644 test/dummy/app/views/people/_trix_content_attachment.html.erb create mode 100644 test/dummy/db/migrate/20181003185713_create_people.rb diff --git a/test/dummy/app/models/person.rb b/test/dummy/app/models/person.rb new file mode 100644 index 0000000000..0ded356d5b --- /dev/null +++ b/test/dummy/app/models/person.rb @@ -0,0 +1,7 @@ +class Person < ApplicationRecord + include ActionText::Attachable + + def to_trix_content_attachment_partial_path + "people/trix_content_attachment" + end +end diff --git a/test/dummy/app/views/people/_trix_content_attachment.html.erb b/test/dummy/app/views/people/_trix_content_attachment.html.erb new file mode 100644 index 0000000000..7db2334126 --- /dev/null +++ b/test/dummy/app/views/people/_trix_content_attachment.html.erb @@ -0,0 +1,3 @@ + + <%= person.name %> + diff --git a/test/dummy/db/migrate/20181003185713_create_people.rb b/test/dummy/db/migrate/20181003185713_create_people.rb new file mode 100644 index 0000000000..1d5922d389 --- /dev/null +++ b/test/dummy/db/migrate/20181003185713_create_people.rb @@ -0,0 +1,9 @@ +class CreatePeople < ActiveRecord::Migration[5.2] + def change + create_table :people do |t| + t.string :name + + t.timestamps + end + end +end diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb index 5179d7269f..39216ebd23 100644 --- a/test/dummy/db/schema.rb +++ b/test/dummy/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2018_02_12_164506) do +ActiveRecord::Schema.define(version: 2018_10_03_185713) do create_table "action_text_rich_texts", force: :cascade do |t| t.string "name", null: false @@ -49,4 +49,10 @@ ActiveRecord::Schema.define(version: 2018_02_12_164506) do t.datetime "updated_at", null: false end + create_table "people", force: :cascade do |t| + t.string "name" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + end diff --git a/test/unit/attachment_test.rb b/test/unit/attachment_test.rb index a31ef1afd0..56a4ea1dd8 100644 --- a/test/unit/attachment_test.rb +++ b/test/unit/attachment_test.rb @@ -34,6 +34,7 @@ class ActionText::AttachmentTest < ActiveSupport::TestCase end test "converts to TrixAttachment with content" do + attachable = Person.create! name: "Javan" attachment = attachment_from_html(%Q()) trix_attachment = attachment.to_trix_attachment -- cgit v1.2.3 From aa1d46389a8cc9635f4354b3e7be70a8361ed7ed Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Wed, 3 Oct 2018 16:35:12 -0400 Subject: Fix image gallery styles --- lib/templates/actiontext.css | 7 ------- lib/templates/actiontext.scss | 36 ++++++++++++++++++++++++++++++++++++ lib/templates/installer.rb | 6 +++--- 3 files changed, 39 insertions(+), 10 deletions(-) delete mode 100644 lib/templates/actiontext.css create mode 100644 lib/templates/actiontext.scss diff --git a/lib/templates/actiontext.css b/lib/templates/actiontext.css deleted file mode 100644 index 97c083c24b..0000000000 --- a/lib/templates/actiontext.css +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Provides a drop-in pointer for the default Trix stylesheet that will format the toolbar and - * the trix-editor content (whether displayed or under editing). Feel free to incorporate this - * inclusion directly in any other asset bundle and remove this file. - * - *= require trix/dist/trix -*/ diff --git a/lib/templates/actiontext.scss b/lib/templates/actiontext.scss new file mode 100644 index 0000000000..58a197e1e9 --- /dev/null +++ b/lib/templates/actiontext.scss @@ -0,0 +1,36 @@ +// +// Provides a drop-in pointer for the default Trix stylesheet that will format the toolbar and +// the trix-editor content (whether displayed or under editing). Feel free to incorporate this +// inclusion directly in any other asset bundle and remove this file. +// +//= require trix/dist/trix + +// We need to override trix.css’s image gallery styles to accomodate the +// element we wrap around attachments. Otherwise, +// images in galleries will be squished by the max-width: 33%; rule. +.trix-content { + .attachment-gallery { + > action-text-attachment, + > .attachment { + flex: 1 0 33%; + padding: 0 0.5em; + max-width: 33%; + } + + &.attachment-gallery--2, + &.attachment-gallery--4 { + > action-text-attachment, + > .attachment { + flex-basis: 50%; + max-width: 50%; + } + } + } + + action-text-attachment { + .attachment { + padding: 0 !important; + max-width: 100% !important; + } + } +} diff --git a/lib/templates/installer.rb b/lib/templates/installer.rb index 03ba0722cd..100b0a96a8 100644 --- a/lib/templates/installer.rb +++ b/lib/templates/installer.rb @@ -1,11 +1,11 @@ -say "Copying actiontext.css to app/assets/stylesheets" -copy_file "#{__dir__}/actiontext.css", "app/assets/stylesheets/actiontext.css" +say "Copying actiontext.scss to app/assets/stylesheets" +copy_file "#{__dir__}/actiontext.scss", "app/assets/stylesheets/actiontext.scss" say "Copying fixtures to test/fixtures/action_text/rich_texts.yml" copy_file "#{__dir__}/fixtures.yml", "test/fixtures/action_text/rich_texts.yml" say "Copying blob rendering partial to app/views/active_storage/blobs/_blob.html.erb" -copy_file "#{__dir__}/../../app/views/active_storage/blobs/_blob.html.erb", +copy_file "#{__dir__}/../../app/views/active_storage/blobs/_blob.html.erb", "app/views/active_storage/blobs/_blob.html.erb" # FIXME: Replace with release version on release -- cgit v1.2.3 From 598ef2ee82a4c502deba678ed9191f5f40930132 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Wed, 3 Oct 2018 17:49:32 -0400 Subject: Customize tag and attribute sanitization Fixes #6 --- app/helpers/action_text/content_helper.rb | 6 +++++- app/views/action_text/content/_layout.html.erb | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/helpers/action_text/content_helper.rb b/app/helpers/action_text/content_helper.rb index 6d00eee648..d6ced93502 100644 --- a/app/helpers/action_text/content_helper.rb +++ b/app/helpers/action_text/content_helper.rb @@ -18,7 +18,11 @@ module ActionText end.chomp end - content.to_html + sanitize content.to_html, tags: ActionText::ALLOWED_TAGS, attributes: ActionText::ALLOWED_ATTRIBUTES end end + + SANITIZER = Rails::Html::Sanitizer.white_list_sanitizer + ALLOWED_TAGS = SANITIZER.allowed_tags + [ ActionText::Attachment::TAG_NAME, "figure", "figcaption" ] + ALLOWED_ATTRIBUTES = SANITIZER.allowed_attributes + ActionText::Attachment::ATTRIBUTES end diff --git a/app/views/action_text/content/_layout.html.erb b/app/views/action_text/content/_layout.html.erb index 60d65cd0d5..55cb708ac4 100644 --- a/app/views/action_text/content/_layout.html.erb +++ b/app/views/action_text/content/_layout.html.erb @@ -1,3 +1,3 @@
      - <%= sanitize render_action_text_content(content) %> + <%= render_action_text_content(content) %>
      -- cgit v1.2.3 From 304e91765d89e4f8d190f3dbb80ad9ee277be95d Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Wed, 3 Oct 2018 16:07:08 -0700 Subject: The world is our stage --- actiontext.gemspec | 2 +- lib/templates/installer.rb | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/actiontext.gemspec b/actiontext.gemspec index bce0bf1332..d9de924efa 100644 --- a/actiontext.gemspec +++ b/actiontext.gemspec @@ -10,7 +10,7 @@ Gem::Specification.new do |s| s.authors = ["Javan Makhmali", "Sam Stephenson", "David Heinemeier Hansson"] s.email = ["javan@javan.us", "sstephenson@gmail.com", "david@loudthinking.com"] s.summary = "Edit and display rich text in Rails applications" - s.homepage = "https://github.com/basecamp/actiontext" + s.homepage = "https://github.com/rails/actiontext" s.license = "MIT" s.required_ruby_version = ">= 2.2.2" diff --git a/lib/templates/installer.rb b/lib/templates/installer.rb index 100b0a96a8..cfe6b66ed2 100644 --- a/lib/templates/installer.rb +++ b/lib/templates/installer.rb @@ -10,7 +10,7 @@ copy_file "#{__dir__}/../../app/views/active_storage/blobs/_blob.html.erb", # FIXME: Replace with release version on release say "Installing JavaScript dependency" -run "yarn add https://github.com/basecamp/actiontext" +run "yarn add https://github.com/rails/actiontext" APPLICATION_PATH_PATH = "app/javascript/packs/application.js" diff --git a/package.json b/package.json index 63802fb47c..aa6e6b7c22 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "files": [ "app/javascript/actiontext/*.js" ], - "repository": "https://github.com/basecamp/actiontext", + "repository": "https://github.com/rails/actiontext", "author": "Basecamp, LLC", "contributors": [ "Javan Makhmali ", -- cgit v1.2.3 From 3b6b70f0bcbf230e40ba8078c135eb68b6c3faa4 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Wed, 3 Oct 2018 17:02:54 -0700 Subject: Declare prior to use --- app/helpers/action_text/content_helper.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/helpers/action_text/content_helper.rb b/app/helpers/action_text/content_helper.rb index d6ced93502..aa2aeba44b 100644 --- a/app/helpers/action_text/content_helper.rb +++ b/app/helpers/action_text/content_helper.rb @@ -1,4 +1,8 @@ module ActionText + SANITIZER = Rails::Html::Sanitizer.white_list_sanitizer + ALLOWED_TAGS = SANITIZER.allowed_tags + [ ActionText::Attachment::TAG_NAME, "figure", "figcaption" ] + ALLOWED_ATTRIBUTES = SANITIZER.allowed_attributes + ActionText::Attachment::ATTRIBUTES + module ContentHelper def render_action_text_content(content) content = content.render_attachments do |attachment| @@ -21,8 +25,4 @@ module ActionText sanitize content.to_html, tags: ActionText::ALLOWED_TAGS, attributes: ActionText::ALLOWED_ATTRIBUTES end end - - SANITIZER = Rails::Html::Sanitizer.white_list_sanitizer - ALLOWED_TAGS = SANITIZER.allowed_tags + [ ActionText::Attachment::TAG_NAME, "figure", "figcaption" ] - ALLOWED_ATTRIBUTES = SANITIZER.allowed_attributes + ActionText::Attachment::ATTRIBUTES end -- cgit v1.2.3 From 1a4a582ddcf3dbacf37973f53e6dfacddd2fe2c3 Mon Sep 17 00:00:00 2001 From: George Claghorn Date: Wed, 3 Oct 2018 22:23:02 -0400 Subject: Install Active Storage extension lazily Avoid eagerly loading Active Record during app boot. Reinstall the extension when ActiveStorage::Blob is reloaded in dev. --- lib/action_text/engine.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/action_text/engine.rb b/lib/action_text/engine.rb index 4055bbbb29..9331ffff5e 100644 --- a/lib/action_text/engine.rb +++ b/lib/action_text/engine.rb @@ -12,9 +12,7 @@ module ActionText end initializer "action_text.active_storage_extension" do - require "active_storage/blob" - - class ActiveStorage::Blob + ActiveSupport.on_load(:active_storage_blob) do include ActionText::Attachable def previewable_attachable? -- cgit v1.2.3 From 6ae2ab4f447b286b00eaab0df9072aed9e3246e8 Mon Sep 17 00:00:00 2001 From: Lucas Caton Date: Thu, 4 Oct 2018 13:10:54 +1000 Subject: Recommend use of rails over bin/rails In order to make the recommendations consistent with Rails: https://github.com/rails/rails/commit/40b209db53 --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e781e1cde2..dca60ce431 100644 --- a/README.md +++ b/README.md @@ -22,12 +22,12 @@ Assumes a Rails 6+ application with Active Storage and Webpacker installed. gem "actiontext", github: "rails/actiontext", require: "action_text" gem "image_processing", "~> 1.2" # for Active Storage variants ``` - -1. Install assets, npm dependency, and migrations + +1. Install assets, npm dependency, and migrations: ``` - ./bin/rails action_text:install - ./bin/rails db:migrate + rails action_text:install + rails db:migrate ``` ## Examples -- cgit v1.2.3 From 6b0403dfae2fbae443d3cc0033e8c3c779918c5c Mon Sep 17 00:00:00 2001 From: Alexander Tsirel Date: Thu, 4 Oct 2018 15:28:09 +1000 Subject: Consistency in naming after rails 5 its ApplicationController and ApplicationRecord --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e781e1cde2..2fbe1ad878 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Adding a rich text field to an existing model: ```ruby # app/models/message.rb -class Message < ActiveRecord::Base +class Message < ApplicationRecord has_rich_text :content end ``` @@ -84,4 +84,4 @@ Action Text is destined for inclusion in Rails 6, which is due to be released so ## License -Action Text is released under the [MIT License](https://opensource.org/licenses/MIT). \ No newline at end of file +Action Text is released under the [MIT License](https://opensource.org/licenses/MIT). -- cgit v1.2.3 From d43d7f197005a10349ee08e482fffc94a772cf72 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Thu, 4 Oct 2018 08:00:38 -0400 Subject: Delegate string methods to content Closes #11 --- app/models/action_text/rich_text.rb | 8 +++----- lib/action_text/attribute.rb | 2 +- test/unit/model_test.rb | 14 +++++++++++--- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/app/models/action_text/rich_text.rb b/app/models/action_text/rich_text.rb index 94cf595fac..3cedef4d5f 100644 --- a/app/models/action_text/rich_text.rb +++ b/app/models/action_text/rich_text.rb @@ -1,11 +1,13 @@ # The RichText record holds the content produced by the Trix editor in a serialized `body` attribute. # It also holds all the references to the embedded files, which are stored using Active Storage. -# This record is then associated with the Active Record model the application desires to have +# This record is then associated with the Active Record model the application desires to have # rich text content using the `has_rich_text` class method. class ActionText::RichText < ActiveRecord::Base self.table_name = "action_text_rich_texts" serialize :body, ActionText::Content + delegate :to_s, :to_plain_text, :nil?, to: :body + delegate :blank?, :empty?, :present?, to: :to_s belongs_to :record, polymorphic: true, touch: true has_many_attached :embeds @@ -13,8 +15,4 @@ class ActionText::RichText < ActiveRecord::Base before_save do self.embeds = body.attachments.map(&:attachable) if body.present? end - - def to_s - body.to_s.html_safe - end end diff --git a/lib/action_text/attribute.rb b/lib/action_text/attribute.rb index 8426726a38..8439073c00 100644 --- a/lib/action_text/attribute.rb +++ b/lib/action_text/attribute.rb @@ -12,7 +12,7 @@ module ActionText # # message = Message.create!(content: "

      Funny times!

      ") # message.content.to_s # => "

      Funny times!

      " - # message.content.body.to_plain_text # => "Funny times!" + # message.content.to_plain_text # => "Funny times!" # # The dependent RichText model will also automatically process attachments links as sent via the Trix-powered editor. # These attachments are associated with the RichText model using Active Storage. diff --git a/test/unit/model_test.rb b/test/unit/model_test.rb index bdfe88adc8..a9a49cbffd 100644 --- a/test/unit/model_test.rb +++ b/test/unit/model_test.rb @@ -1,14 +1,22 @@ require 'test_helper' class ActionText::ModelTest < ActiveSupport::TestCase + test "html conversion" do + message = Message.new(subject: "Greetings", content: "

      Hello world

      ") + assert_equal %Q(
      \n

      Hello world

      \n
      \n), "#{message.content}" + end + test "plain text conversion" do message = Message.new(subject: "Greetings", content: "

      Hello world

      ") - assert_equal "Hello world", message.content.body.to_plain_text + assert_equal "Hello world", message.content.to_plain_text end test "without content" do message = Message.create!(subject: "Greetings") - assert message.content.body.nil? + assert message.content.nil? + assert message.content.blank? + assert message.content.empty? + assert_not message.content.present? end test "embed extraction" do @@ -19,6 +27,6 @@ class ActionText::ModelTest < ActiveSupport::TestCase test "saving content" do message = Message.create!(subject: "Greetings", content: "

      Hello world

      ") - assert_equal "Hello world", message.content.body.to_plain_text + assert_equal "Hello world", message.content.to_plain_text end end -- cgit v1.2.3 From 242dbfc23dfe6c8340d96932fbff21123a3f1b9c Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Thu, 4 Oct 2018 09:31:45 -0700 Subject: Add "sanitized" to the readme I think a prime concern people have here is sanitization and security. Adding this word to the readme provides a little bit of clarity and reassurance that we aren't just rendering raw data trusted from the client. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 98fd7a8f68..522ffbb79d 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ Then refer to this field in the form for the model: <% end %> ``` -And finally display the rich text on a page: +And finally display the sanitized rich text on a page: ```erb <%= @message.content %> -- cgit v1.2.3 From 33f940f1407870f451e19c479f816edaf9ab0c1e Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Sat, 6 Oct 2018 11:47:10 +0800 Subject: Fix has_rich_text with `:body` keywords error. (#16) --- lib/action_text/attribute.rb | 2 +- test/dummy/app/models/message.rb | 1 + test/unit/model_test.rb | 5 +++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/action_text/attribute.rb b/lib/action_text/attribute.rb index 8439073c00..992a6a410a 100644 --- a/lib/action_text/attribute.rb +++ b/lib/action_text/attribute.rb @@ -28,7 +28,7 @@ module ActionText end def #{name}=(body) - #{name}.body = body + self.#{name}.body = body end CODE diff --git a/test/dummy/app/models/message.rb b/test/dummy/app/models/message.rb index db63a1fe3f..9ea4dbfe78 100644 --- a/test/dummy/app/models/message.rb +++ b/test/dummy/app/models/message.rb @@ -1,3 +1,4 @@ class Message < ApplicationRecord has_rich_text :content + has_rich_text :body end diff --git a/test/unit/model_test.rb b/test/unit/model_test.rb index a9a49cbffd..50632c19a7 100644 --- a/test/unit/model_test.rb +++ b/test/unit/model_test.rb @@ -29,4 +29,9 @@ class ActionText::ModelTest < ActiveSupport::TestCase message = Message.create!(subject: "Greetings", content: "

      Hello world

      ") assert_equal "Hello world", message.content.to_plain_text end + + test "save body" do + message = Message.create(subject: "Greetings", body: "

      Hello world

      ") + assert_equal "Hello world", message.body.to_plain_text + end end -- cgit v1.2.3 From 2e9f3b5b0dcd217fb63c060da2f2110422319ee3 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Sat, 6 Oct 2018 22:27:54 +0800 Subject: Fix `uninitialized constant ActionText:: ALLOWED_TAGS` error on Rails reloading --- app/helpers/action_text/content_helper.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/helpers/action_text/content_helper.rb b/app/helpers/action_text/content_helper.rb index aa2aeba44b..99255494b1 100644 --- a/app/helpers/action_text/content_helper.rb +++ b/app/helpers/action_text/content_helper.rb @@ -1,9 +1,9 @@ module ActionText - SANITIZER = Rails::Html::Sanitizer.white_list_sanitizer - ALLOWED_TAGS = SANITIZER.allowed_tags + [ ActionText::Attachment::TAG_NAME, "figure", "figcaption" ] - ALLOWED_ATTRIBUTES = SANITIZER.allowed_attributes + ActionText::Attachment::ATTRIBUTES - module ContentHelper + SANITIZER = Rails::Html::Sanitizer.white_list_sanitizer + ALLOWED_TAGS = SANITIZER.allowed_tags + [ ActionText::Attachment::TAG_NAME, "figure", "figcaption" ] + ALLOWED_ATTRIBUTES = SANITIZER.allowed_attributes + ActionText::Attachment::ATTRIBUTES + def render_action_text_content(content) content = content.render_attachments do |attachment| unless attachment.in?(content.gallery_attachments) @@ -22,7 +22,7 @@ module ActionText end.chomp end - sanitize content.to_html, tags: ActionText::ALLOWED_TAGS, attributes: ActionText::ALLOWED_ATTRIBUTES + sanitize content.to_html, tags: ALLOWED_TAGS, attributes: ALLOWED_ATTRIBUTES end end end -- cgit v1.2.3 From 03647a3b7443eed0a11cd43d6cc327120e59f6a1 Mon Sep 17 00:00:00 2001 From: ven Date: Sat, 6 Oct 2018 16:51:39 +0200 Subject: Fix minor typo in code comment --- lib/action_text/attribute.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/action_text/attribute.rb b/lib/action_text/attribute.rb index 992a6a410a..2d520fa541 100644 --- a/lib/action_text/attribute.rb +++ b/lib/action_text/attribute.rb @@ -20,7 +20,7 @@ module ActionText # If you wish to preload the dependent RichText model, you can use the named scope: # # Message.all.with_rich_text_content # Avoids N+1 queries when you just want the body, not the attachments. - # Message.all.with_rich_text_content_and_emebds # Avoids N+1 queries when you just want the body and attachments. + # Message.all.with_rich_text_content_and_embeds # Avoids N+1 queries when you just want the body and attachments. def has_rich_text(name) class_eval <<-CODE, __FILE__, __LINE__ + 1 def #{name} -- cgit v1.2.3 From ba97db849cd34a83c05234572d3d7261864c1782 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Sat, 6 Oct 2018 12:11:10 -0400 Subject: Add template for ActionText::Attachables::RemoteImage Fixes #15 --- .../action_text/attachables/_remote_image.html.erb | 8 +++++ test/unit/content_test.rb | 37 +++++++++++++--------- 2 files changed, 30 insertions(+), 15 deletions(-) create mode 100644 app/views/action_text/attachables/_remote_image.html.erb diff --git a/app/views/action_text/attachables/_remote_image.html.erb b/app/views/action_text/attachables/_remote_image.html.erb new file mode 100644 index 0000000000..3372f8d940 --- /dev/null +++ b/app/views/action_text/attachables/_remote_image.html.erb @@ -0,0 +1,8 @@ +
      + <%= image_tag(remote_image.url, width: remote_image.width, height: remote_image.height) %> + <% if caption = remote_image.try(:caption) %> +
      + <%= caption %> +
      + <% end %> +
      diff --git a/test/unit/content_test.rb b/test/unit/content_test.rb index c0b8ad024c..dada9cc714 100644 --- a/test/unit/content_test.rb +++ b/test/unit/content_test.rb @@ -3,25 +3,25 @@ require 'test_helper' class ActionText::ContentTest < ActiveSupport::TestCase test "equality" do html = %Q(
      test
      ) - content = ActionText::Content.new(html) - assert_equal content, ActionText::Content.new(html) + content = content_from_html(html) + assert_equal content, content_from_html(html) assert_not_equal content, html end test "marshal serialization" do - content = ActionText::Content.new("Hello!") + content = content_from_html("Hello!") assert_equal content, Marshal.load(Marshal.dump(content)) end test "roundtrips HTML without additional newlines" do html = %Q(
      a
      ) - content = ActionText::Content.new(html) + content = content_from_html(html) assert_equal html, content.to_html end test "extracts links" do html = %Q(1
      1) - content = ActionText::Content.new(html) + content = content_from_html(html) assert_equal ["http://example.com/1"], content.links end @@ -29,7 +29,7 @@ class ActionText::ContentTest < ActiveSupport::TestCase attachable = create_file_blob(filename: "racecar.jpg", content_type: "image/jpg") html = %Q() - content = ActionText::Content.new(html) + content = content_from_html(html) assert_equal 1, content.attachments.size attachment = content.attachments.first @@ -40,7 +40,7 @@ class ActionText::ContentTest < ActiveSupport::TestCase test "extracts remote image attachables" do html = %Q() - content = ActionText::Content.new(html) + content = content_from_html(html) assert_equal 1, content.attachments.size attachment = content.attachments.first @@ -57,51 +57,58 @@ class ActionText::ContentTest < ActiveSupport::TestCase attachable = create_file_blob(filename: "racecar.jpg", content_type: "image/jpg") html = %Q() attachable.destroy! - content = ActionText::Content.new(html) + content = content_from_html(html) assert_equal 1, content.attachments.size assert_equal ActionText::Attachables::MissingAttachable, content.attachments.first.attachable end test "extracts missing attachables" do html = %Q() - content = ActionText::Content.new(html) + content = content_from_html(html) assert_equal 1, content.attachments.size assert_equal ActionText::Attachables::MissingAttachable, content.attachments.first.attachable end test "converts Trix-formatted attachments" do html = %Q(
      ) - content = ActionText::Content.new(html) + content = content_from_html(html) assert_equal 1, content.attachments.size assert_equal %Q(), content.to_html end test "ignores Trix-formatted attachments with malformed JSON" do html = %Q(
      ) - content = ActionText::Content.new(html) + content = content_from_html(html) assert_equal 0, content.attachments.size end test "minifies attachment markup" do html = %Q(
      HTML
      ) - assert_equal %Q(), ActionText::Content.new(html).to_html + assert_equal %Q(), content_from_html(html).to_html end test "canonicalizes attachment gallery markup" do attachment_html = %Q() html = %Q() - assert_equal %Q(
      #{attachment_html}
      ), ActionText::Content.new(html).to_html + assert_equal %Q(
      #{attachment_html}
      ), content_from_html(html).to_html end test "canonicalizes attachment gallery markup with whitespace" do attachment_html = %Q(\n \n \n) html = %Q() - assert_equal %Q(
      #{attachment_html}
      ), ActionText::Content.new(html).to_html + assert_equal %Q(
      #{attachment_html}
      ), content_from_html(html).to_html end test "canonicalizes nested attachment gallery markup" do attachment_html = %Q() html = %Q(
      ) - assert_equal %Q(
      #{attachment_html}
      ), ActionText::Content.new(html).to_html + assert_equal %Q(
      #{attachment_html}
      ), content_from_html(html).to_html end + + private + def content_from_html(html) + ActionText::Content.new(html).tap do |content| + assert_nothing_raised { content.to_s } + end + end end -- cgit v1.2.3 From e26626f4f9c8a0ba559f238a54adb0de5ce79f7c Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Sat, 6 Oct 2018 12:45:37 -0400 Subject: Add travis.yml --- travis.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 travis.yml diff --git a/travis.yml b/travis.yml new file mode 100644 index 0000000000..a8bece6a98 --- /dev/null +++ b/travis.yml @@ -0,0 +1,11 @@ +language: ruby +sudo: false + +rvm: + - 2.2 + +cache: + bundler: true + +script: + - bundle exec rake -- cgit v1.2.3 From dec130a80c4947f749782347d03469bd7358c43b Mon Sep 17 00:00:00 2001 From: George Claghorn Date: Sun, 7 Oct 2018 23:51:21 -0400 Subject: Use the ASt representation API --- app/views/active_storage/blobs/_blob.html.erb | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/views/active_storage/blobs/_blob.html.erb b/app/views/active_storage/blobs/_blob.html.erb index 6e4105d5cf..049f57e804 100644 --- a/app/views/active_storage/blobs/_blob.html.erb +++ b/app/views/active_storage/blobs/_blob.html.erb @@ -1,9 +1,6 @@ -<% transformations = { resize: local_assigns[:in_gallery] ? "800x600>" : "1024x768>" } %>
      attachment--<%= blob.filename.extension %>"> - <% if blob.variable? %> - <%= image_tag blob.variant(transformations) %> - <% elsif blob.previewable? %> - <%= image_tag blob.preview(transformations) %> + <% if blob.representable? %> + <%= image_tag blob.representation(resize_to_fit: local_assigns[:in_gallery] ? [ 800, 600 ] : [ 1024, 768 ]) %> <% end %>
      -- cgit v1.2.3 From 6ed4c36499cac1ba37628b5711f5ce1dff87d592 Mon Sep 17 00:00:00 2001 From: Alberto Almagro Sotelo Date: Mon, 8 Oct 2018 21:23:09 +0200 Subject: Upgrade Ruby version (#20) Upgrades .ruby-version to latest stable release --- .ruby-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ruby-version b/.ruby-version index 437459cd94..73462a5a13 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.5.0 +2.5.1 -- cgit v1.2.3 From 55a303da5e014fda22afb98f4dd2c59dd9766e1e Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Mon, 8 Oct 2018 16:34:49 -0400 Subject: =?UTF-8?q?travis.yml=20=E2=86=92=20.travis.yml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤦‍♂️ --- .travis.yml | 11 +++++++++++ travis.yml | 11 ----------- 2 files changed, 11 insertions(+), 11 deletions(-) create mode 100644 .travis.yml delete mode 100644 travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..a8bece6a98 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,11 @@ +language: ruby +sudo: false + +rvm: + - 2.2 + +cache: + bundler: true + +script: + - bundle exec rake diff --git a/travis.yml b/travis.yml deleted file mode 100644 index a8bece6a98..0000000000 --- a/travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -language: ruby -sudo: false - -rvm: - - 2.2 - -cache: - bundler: true - -script: - - bundle exec rake -- cgit v1.2.3 From 4edad3718a0ffc9dd2c6b40f3412e98dece773a4 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Mon, 8 Oct 2018 16:40:35 -0400 Subject: Match Rails Ruby version requirements --- .ruby-version | 1 - .travis.yml | 9 ++++++++- actiontext.gemspec | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) delete mode 100644 .ruby-version diff --git a/.ruby-version b/.ruby-version deleted file mode 100644 index 73462a5a13..0000000000 --- a/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -2.5.1 diff --git a/.travis.yml b/.travis.yml index a8bece6a98..f9ad1f699e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,10 +2,17 @@ language: ruby sudo: false rvm: - - 2.2 + - 2.4.4 + - 2.5.1 + - ruby-head cache: bundler: true +matrix: + allow_failures: + - rvm: ruby-head + fast_finish: true + script: - bundle exec rake diff --git a/actiontext.gemspec b/actiontext.gemspec index d9de924efa..1185dfc791 100644 --- a/actiontext.gemspec +++ b/actiontext.gemspec @@ -13,7 +13,7 @@ Gem::Specification.new do |s| s.homepage = "https://github.com/rails/actiontext" s.license = "MIT" - s.required_ruby_version = ">= 2.2.2" + s.required_ruby_version = ">= 2.4.1" s.add_dependency "rails", ">= 5.2.0" s.add_dependency "nokogiri" -- cgit v1.2.3 From b1f69fa126bbeccab8abb4d427ec5cf8f4227b24 Mon Sep 17 00:00:00 2001 From: Javan Makhmali Date: Mon, 8 Oct 2018 16:47:48 -0400 Subject: Test against Rails master --- Gemfile | 2 + Gemfile.lock | 132 ++++++++++++++++++++++++++++++----------------------------- 2 files changed, 70 insertions(+), 64 deletions(-) diff --git a/Gemfile b/Gemfile index 9b78acc762..65f1a6f190 100644 --- a/Gemfile +++ b/Gemfile @@ -2,3 +2,5 @@ source "https://rubygems.org" git_source(:github) { |repo_path| "https://github.com/#{repo_path}.git" } gemspec + +gem "rails", github: "rails/rails" diff --git a/Gemfile.lock b/Gemfile.lock index 12d7f94fb7..41f94a65c0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,74 +1,96 @@ -PATH - remote: . - specs: - actiontext (0.1.0) - nokogiri - rails (>= 5.2.0) - -GEM - remote: https://rubygems.org/ +GIT + remote: https://github.com/rails/rails.git + revision: a1ee4a9ff9d4a3cb255365310ead0dc7b739c6be specs: - actioncable (5.2.0) - actionpack (= 5.2.0) + actioncable (6.0.0.alpha) + actionpack (= 6.0.0.alpha) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailer (5.2.0) - actionpack (= 5.2.0) - actionview (= 5.2.0) - activejob (= 5.2.0) + actionmailer (6.0.0.alpha) + actionpack (= 6.0.0.alpha) + actionview (= 6.0.0.alpha) + activejob (= 6.0.0.alpha) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.2.0) - actionview (= 5.2.0) - activesupport (= 5.2.0) + actionpack (6.0.0.alpha) + actionview (= 6.0.0.alpha) + activesupport (= 6.0.0.alpha) rack (~> 2.0) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.2.0) - activesupport (= 5.2.0) + actionview (6.0.0.alpha) + activesupport (= 6.0.0.alpha) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (5.2.0) - activesupport (= 5.2.0) + activejob (6.0.0.alpha) + activesupport (= 6.0.0.alpha) globalid (>= 0.3.6) - activemodel (5.2.0) - activesupport (= 5.2.0) - activerecord (5.2.0) - activemodel (= 5.2.0) - activesupport (= 5.2.0) - arel (>= 9.0) - activestorage (5.2.0) - actionpack (= 5.2.0) - activerecord (= 5.2.0) + activemodel (6.0.0.alpha) + activesupport (= 6.0.0.alpha) + activerecord (6.0.0.alpha) + activemodel (= 6.0.0.alpha) + activesupport (= 6.0.0.alpha) + activestorage (6.0.0.alpha) + actionpack (= 6.0.0.alpha) + activerecord (= 6.0.0.alpha) marcel (~> 0.3.1) - activesupport (5.2.0) + activesupport (6.0.0.alpha) concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (~> 0.7) + i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) - arel (9.0.0) + rails (6.0.0.alpha) + actioncable (= 6.0.0.alpha) + actionmailer (= 6.0.0.alpha) + actionpack (= 6.0.0.alpha) + actionview (= 6.0.0.alpha) + activejob (= 6.0.0.alpha) + activemodel (= 6.0.0.alpha) + activerecord (= 6.0.0.alpha) + activestorage (= 6.0.0.alpha) + activesupport (= 6.0.0.alpha) + bundler (>= 1.3.0) + railties (= 6.0.0.alpha) + sprockets-rails (>= 2.0.0) + railties (6.0.0.alpha) + actionpack (= 6.0.0.alpha) + activesupport (= 6.0.0.alpha) + method_source + rake (>= 0.8.7) + thor (>= 0.19.0, < 2.0) + +PATH + remote: . + specs: + actiontext (0.1.0) + nokogiri + rails (>= 5.2.0) + +GEM + remote: https://rubygems.org/ + specs: builder (3.2.3) concurrent-ruby (1.0.5) - crass (1.0.3) - erubi (1.7.0) + crass (1.0.4) + erubi (1.7.1) globalid (0.4.1) activesupport (>= 4.2.0) - i18n (0.9.3) + i18n (1.1.0) concurrent-ruby (~> 1.0) - loofah (2.1.1) + loofah (2.2.2) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.0) mini_mime (>= 0.1.1) - marcel (0.3.2) + marcel (0.3.3) mimemagic (~> 0.3.2) method_source (0.9.0) mimemagic (0.3.2) mini_magick (4.8.0) - mini_mime (1.0.0) + mini_mime (1.0.1) mini_portile2 (2.3.0) minitest (5.11.3) nio4r (2.3.1) @@ -77,34 +99,15 @@ GEM rack (2.0.4) rack-proxy (0.6.3) rack - rack-test (0.8.2) + rack-test (1.1.0) rack (>= 1.0, < 3) - rails (5.2.0) - actioncable (= 5.2.0) - actionmailer (= 5.2.0) - actionpack (= 5.2.0) - actionview (= 5.2.0) - activejob (= 5.2.0) - activemodel (= 5.2.0) - activerecord (= 5.2.0) - activestorage (= 5.2.0) - activesupport (= 5.2.0) - bundler (>= 1.3.0) - railties (= 5.2.0) - sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) - rails-html-sanitizer (1.0.3) - loofah (~> 2.0) - railties (5.2.0) - actionpack (= 5.2.0) - activesupport (= 5.2.0) - method_source - rake (>= 0.8.7) - thor (>= 0.18.1, < 2.0) - rake (12.3.0) - sprockets (3.7.1) + rails-html-sanitizer (1.0.4) + loofah (~> 2.2, >= 2.2.2) + rake (12.3.1) + sprockets (3.7.2) concurrent-ruby (~> 1.0) rack (> 1, < 3) sprockets-rails (3.2.1) @@ -131,6 +134,7 @@ DEPENDENCIES actiontext! bundler (~> 1.15) mini_magick + rails! sqlite3 webpacker (~> 3.2.2) -- cgit v1.2.3 From 34f2e9492b37cb52ae5ffe69308deecdc4cb7709 Mon Sep 17 00:00:00 2001 From: Alberto Almagro Date: Mon, 8 Oct 2018 23:44:25 +0200 Subject: Add frozen_string_literal: true Adds frozen_string_literal: true comment on top of all currently existing files --- app/helpers/action_text/content_helper.rb | 2 ++ app/helpers/action_text/tag_helper.rb | 2 ++ app/models/action_text/rich_text.rb | 2 ++ bin/test | 1 + lib/action_text.rb | 2 ++ lib/action_text/attachable.rb | 2 ++ lib/action_text/attachables/content_attachment.rb | 2 ++ lib/action_text/attachables/remote_image.rb | 2 ++ lib/action_text/attachment.rb | 2 ++ lib/action_text/attachment_gallery.rb | 2 ++ lib/action_text/attachments/caching.rb | 2 ++ lib/action_text/attachments/minification.rb | 2 ++ lib/action_text/attachments/trix_conversion.rb | 2 ++ lib/action_text/attribute.rb | 2 ++ lib/action_text/content.rb | 2 ++ lib/action_text/engine.rb | 2 ++ lib/action_text/fragment.rb | 2 ++ lib/action_text/html_conversion.rb | 2 ++ lib/action_text/plain_text_conversion.rb | 2 ++ lib/action_text/serialization.rb | 2 ++ lib/action_text/trix_attachment.rb | 2 ++ lib/action_text/version.rb | 2 ++ test/test_helper.rb | 2 ++ test/unit/attachment_test.rb | 2 ++ test/unit/content_test.rb | 2 ++ test/unit/model_test.rb | 2 ++ test/unit/plain_text_conversion_test.rb | 2 ++ test/unit/trix_attachment_test.rb | 2 ++ 28 files changed, 55 insertions(+) diff --git a/app/helpers/action_text/content_helper.rb b/app/helpers/action_text/content_helper.rb index 99255494b1..b3335601f9 100644 --- a/app/helpers/action_text/content_helper.rb +++ b/app/helpers/action_text/content_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionText module ContentHelper SANITIZER = Rails::Html::Sanitizer.white_list_sanitizer diff --git a/app/helpers/action_text/tag_helper.rb b/app/helpers/action_text/tag_helper.rb index 8d1ff0aaad..103b65eb97 100644 --- a/app/helpers/action_text/tag_helper.rb +++ b/app/helpers/action_text/tag_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionText module TagHelper cattr_accessor(:id, instance_accessor: false) { 0 } diff --git a/app/models/action_text/rich_text.rb b/app/models/action_text/rich_text.rb index 3cedef4d5f..1f8ac0e7f7 100644 --- a/app/models/action_text/rich_text.rb +++ b/app/models/action_text/rich_text.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # The RichText record holds the content produced by the Trix editor in a serialized `body` attribute. # It also holds all the references to the embedded files, which are stored using Active Storage. # This record is then associated with the Active Record model the application desires to have diff --git a/bin/test b/bin/test index 5516a12bcd..3e28e212ed 100755 --- a/bin/test +++ b/bin/test @@ -1,4 +1,5 @@ #!/usr/bin/env ruby +# frozen_string_literal: true $: << File.expand_path("../test", __dir__) require "bundler/setup" diff --git a/lib/action_text.rb b/lib/action_text.rb index 4182cacb8a..d723508e74 100644 --- a/lib/action_text.rb +++ b/lib/action_text.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_record" require "action_text/engine" require "nokogiri" diff --git a/lib/action_text/attachable.rb b/lib/action_text/attachable.rb index 1209f17e77..fce3d6d9c3 100644 --- a/lib/action_text/attachable.rb +++ b/lib/action_text/attachable.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionText module Attachable extend ActiveSupport::Concern diff --git a/lib/action_text/attachables/content_attachment.rb b/lib/action_text/attachables/content_attachment.rb index 3ebd734786..804f74713f 100644 --- a/lib/action_text/attachables/content_attachment.rb +++ b/lib/action_text/attachables/content_attachment.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionText module Attachables class ContentAttachment diff --git a/lib/action_text/attachables/remote_image.rb b/lib/action_text/attachables/remote_image.rb index 2333427371..650b11862b 100644 --- a/lib/action_text/attachables/remote_image.rb +++ b/lib/action_text/attachables/remote_image.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionText module Attachables class RemoteImage diff --git a/lib/action_text/attachment.rb b/lib/action_text/attachment.rb index cba421c143..e90a3e7d48 100644 --- a/lib/action_text/attachment.rb +++ b/lib/action_text/attachment.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionText class Attachment include Attachments::TrixConversion, Attachments::Minification, Attachments::Caching diff --git a/lib/action_text/attachment_gallery.rb b/lib/action_text/attachment_gallery.rb index 6f690551e6..a4694fc359 100644 --- a/lib/action_text/attachment_gallery.rb +++ b/lib/action_text/attachment_gallery.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionText class AttachmentGallery include ActiveModel::Model diff --git a/lib/action_text/attachments/caching.rb b/lib/action_text/attachments/caching.rb index b867e2ff91..7c727bfc26 100644 --- a/lib/action_text/attachments/caching.rb +++ b/lib/action_text/attachments/caching.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionText module Attachments module Caching diff --git a/lib/action_text/attachments/minification.rb b/lib/action_text/attachments/minification.rb index b1ca43b7b8..edc8f876d6 100644 --- a/lib/action_text/attachments/minification.rb +++ b/lib/action_text/attachments/minification.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionText module Attachments module Minification diff --git a/lib/action_text/attachments/trix_conversion.rb b/lib/action_text/attachments/trix_conversion.rb index 39989ce644..f723d55231 100644 --- a/lib/action_text/attachments/trix_conversion.rb +++ b/lib/action_text/attachments/trix_conversion.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionText module Attachments module TrixConversion diff --git a/lib/action_text/attribute.rb b/lib/action_text/attribute.rb index 2d520fa541..f226dd21bd 100644 --- a/lib/action_text/attribute.rb +++ b/lib/action_text/attribute.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionText module Attribute extend ActiveSupport::Concern diff --git a/lib/action_text/content.rb b/lib/action_text/content.rb index 4061613e35..b99e9bb49c 100644 --- a/lib/action_text/content.rb +++ b/lib/action_text/content.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionText class Content include Serialization diff --git a/lib/action_text/engine.rb b/lib/action_text/engine.rb index 9331ffff5e..25e45bc72a 100644 --- a/lib/action_text/engine.rb +++ b/lib/action_text/engine.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails/engine" module ActionText diff --git a/lib/action_text/fragment.rb b/lib/action_text/fragment.rb index 63b088f3e1..af276b2b26 100644 --- a/lib/action_text/fragment.rb +++ b/lib/action_text/fragment.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionText class Fragment class << self diff --git a/lib/action_text/html_conversion.rb b/lib/action_text/html_conversion.rb index 1c70504fb7..1e1062ea3f 100644 --- a/lib/action_text/html_conversion.rb +++ b/lib/action_text/html_conversion.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionText module HtmlConversion extend self diff --git a/lib/action_text/plain_text_conversion.rb b/lib/action_text/plain_text_conversion.rb index ea168f1c4e..0eb4e2e7da 100644 --- a/lib/action_text/plain_text_conversion.rb +++ b/lib/action_text/plain_text_conversion.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionText module PlainTextConversion extend self diff --git a/lib/action_text/serialization.rb b/lib/action_text/serialization.rb index ac2b0602d5..8ecf8c9157 100644 --- a/lib/action_text/serialization.rb +++ b/lib/action_text/serialization.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionText module Serialization extend ActiveSupport::Concern diff --git a/lib/action_text/trix_attachment.rb b/lib/action_text/trix_attachment.rb index 0c4a3869d8..c16c1c090d 100644 --- a/lib/action_text/trix_attachment.rb +++ b/lib/action_text/trix_attachment.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionText class TrixAttachment TAG_NAME = "figure" diff --git a/lib/action_text/version.rb b/lib/action_text/version.rb index bc34656697..631f3d623c 100644 --- a/lib/action_text/version.rb +++ b/lib/action_text/version.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionText VERSION = '0.1.0' end diff --git a/test/test_helper.rb b/test/test_helper.rb index 79fde51549..7250cffea3 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Configure Rails Environment ENV["RAILS_ENV"] = "test" diff --git a/test/unit/attachment_test.rb b/test/unit/attachment_test.rb index 56a4ea1dd8..728742c366 100644 --- a/test/unit/attachment_test.rb +++ b/test/unit/attachment_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'test_helper' class ActionText::AttachmentTest < ActiveSupport::TestCase diff --git a/test/unit/content_test.rb b/test/unit/content_test.rb index dada9cc714..17bc6c0013 100644 --- a/test/unit/content_test.rb +++ b/test/unit/content_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'test_helper' class ActionText::ContentTest < ActiveSupport::TestCase diff --git a/test/unit/model_test.rb b/test/unit/model_test.rb index 50632c19a7..99a249946a 100644 --- a/test/unit/model_test.rb +++ b/test/unit/model_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'test_helper' class ActionText::ModelTest < ActiveSupport::TestCase diff --git a/test/unit/plain_text_conversion_test.rb b/test/unit/plain_text_conversion_test.rb index 47c95b6bc3..fd67f8eca8 100644 --- a/test/unit/plain_text_conversion_test.rb +++ b/test/unit/plain_text_conversion_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'test_helper' class ActionText::PlainTextConversionTest < ActiveSupport::TestCase diff --git a/test/unit/trix_attachment_test.rb b/test/unit/trix_attachment_test.rb index fe834c8663..9cb338b8c2 100644 --- a/test/unit/trix_attachment_test.rb +++ b/test/unit/trix_attachment_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'test_helper' class ActionText::TrixAttachmentTest < ActiveSupport::TestCase -- cgit v1.2.3 From 9febb318043e5320d7338f0267c6aef651cd9315 Mon Sep 17 00:00:00 2001 From: Alberto Almagro Sotelo Date: Tue, 9 Oct 2018 23:10:07 +0200 Subject: Prevent rich_text_area from raising when inexistent attribute is passed (#24) When an inexistent attribute is passed as a parameter to currently existing Rails' Form Helpers they render an empty tag instead of raising an exception. This commit confers the same behavior to `rich_text_area`. Fixes #19 --- app/helpers/action_text/tag_helper.rb | 2 +- test/template/form_helper_test.rb | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 test/template/form_helper_test.rb diff --git a/app/helpers/action_text/tag_helper.rb b/app/helpers/action_text/tag_helper.rb index 103b65eb97..c7ba416880 100644 --- a/app/helpers/action_text/tag_helper.rb +++ b/app/helpers/action_text/tag_helper.rb @@ -45,7 +45,7 @@ module ActionView::Helpers end def editable_value - value.body.try(:to_trix_html) + value&.body.try(:to_trix_html) end end diff --git a/test/template/form_helper_test.rb b/test/template/form_helper_test.rb new file mode 100644 index 0000000000..d7bdbad26c --- /dev/null +++ b/test/template/form_helper_test.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'test_helper' + +class ActionText::FormHelperTest < ActionView::TestCase + tests ActionText::TagHelper + + def form_with(*) + @output_buffer = super + end + + test "rich_text_area doesn't raise when attributes don't exist in the model" do + assert_nothing_raised do + form_with(model: Message.new, scope: :message, id: "create-message") do |form| + form.rich_text_area(:not_an_attribute) + end + end + + assert_match "message[not_an_attribute]", output_buffer + end +end -- cgit v1.2.3 From 2039da7ba029b2c9889847660aa0ba7c5d25bdc0 Mon Sep 17 00:00:00 2001 From: Liroy Leshed <37022194+liroyleshed@users.noreply.github.com> Date: Wed, 10 Oct 2018 20:29:32 +0300 Subject: Remove set_action_text_renderer from dummy app (#26) I don't think we need that since it's set automatically through ActionText::Engine. --- test/dummy/app/controllers/application_controller.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test/dummy/app/controllers/application_controller.rb b/test/dummy/app/controllers/application_controller.rb index c774981e25..09705d12ab 100644 --- a/test/dummy/app/controllers/application_controller.rb +++ b/test/dummy/app/controllers/application_controller.rb @@ -1,8 +1,2 @@ class ApplicationController < ActionController::Base - before_action :set_action_text_renderer - - private - def set_action_text_renderer - ActionText.renderer = self.class.renderer.new(request.env) - end end -- cgit v1.2.3 From 43a7adb0afd52a83b1d2850c43d007f9a4526034 Mon Sep 17 00:00:00 2001 From: Alberto Almagro Date: Wed, 10 Oct 2018 22:03:54 +0200 Subject: Add test coverage for form with rich-text-area --- test/template/form_helper_test.rb | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/template/form_helper_test.rb b/test/template/form_helper_test.rb index d7bdbad26c..18b5edbee5 100644 --- a/test/template/form_helper_test.rb +++ b/test/template/form_helper_test.rb @@ -18,4 +18,32 @@ class ActionText::FormHelperTest < ActionView::TestCase assert_match "message[not_an_attribute]", output_buffer end + + test "form with rich_text_area" do + expected = '
      '\ + ''\ + ''\ + ''\ + '
      ' + + form_with(model: Message.new, scope: :message, id: "create-message") do |form| + form.rich_text_area(:content) + end + + assert_dom_equal expected, output_buffer + end + + test "form with rich_text_area providing class option" do + expected = '
      '\ + ''\ + ''\ + ''\ + '
      ' + + form_with(model: Message.new, scope: :message, id: "create-message") do |form| + form.rich_text_area(:content, class: "custom-class") + end + + assert_dom_equal expected, output_buffer + end end -- cgit v1.2.3 From 558ccf4a21ada0dbd3452a9bf7fc06376bf1dd20 Mon Sep 17 00:00:00 2001 From: Alberto Almagro Date: Mon, 8 Oct 2018 23:58:37 +0200 Subject: Privatize constants This constants meant to be private but `private_constant` was missing, this commit makes them fully private by adding `private_constant`. --- lib/action_text/attachment_gallery.rb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/action_text/attachment_gallery.rb b/lib/action_text/attachment_gallery.rb index a4694fc359..45afbff058 100644 --- a/lib/action_text/attachment_gallery.rb +++ b/lib/action_text/attachment_gallery.rb @@ -56,9 +56,10 @@ module ActionText "#<#{self.class.name} size=#{size.inspect}>" end - private - TAG_NAME = "div" - ATTACHMENT_SELECTOR = "#{ActionText::Attachment::SELECTOR}[presentation=gallery]" - SELECTOR = "#{TAG_NAME}:has(#{ATTACHMENT_SELECTOR} + #{ATTACHMENT_SELECTOR})" + TAG_NAME = "div" + ATTACHMENT_SELECTOR = "#{ActionText::Attachment::SELECTOR}[presentation=gallery]" + SELECTOR = "#{TAG_NAME}:has(#{ATTACHMENT_SELECTOR} + #{ATTACHMENT_SELECTOR})" + + private_constant :TAG_NAME, :ATTACHMENT_SELECTOR, :SELECTOR end end -- cgit v1.2.3 From 7865da9d9511d37b1756891b1aad7f5ace52594a Mon Sep 17 00:00:00 2001 From: swamp09 Date: Fri, 12 Oct 2018 02:12:30 +0900 Subject: Fix typo --- lib/templates/actiontext.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/templates/actiontext.scss b/lib/templates/actiontext.scss index 58a197e1e9..107c31c091 100644 --- a/lib/templates/actiontext.scss +++ b/lib/templates/actiontext.scss @@ -5,7 +5,7 @@ // //= require trix/dist/trix -// We need to override trix.css’s image gallery styles to accomodate the +// We need to override trix.css’s image gallery styles to accommodate the // element we wrap around attachments. Otherwise, // images in galleries will be squished by the max-width: 33%; rule. .trix-content { -- cgit v1.2.3 From 71839aca6da796ee26a6a59bb1e01894c863958f Mon Sep 17 00:00:00 2001 From: George Claghorn Date: Fri, 12 Oct 2018 15:13:07 -0400 Subject: APPLICATION_PATH_PATH -> APPLICATION_PACK_PATH --- lib/templates/installer.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/templates/installer.rb b/lib/templates/installer.rb index cfe6b66ed2..ee5a5af75b 100644 --- a/lib/templates/installer.rb +++ b/lib/templates/installer.rb @@ -12,11 +12,11 @@ copy_file "#{__dir__}/../../app/views/active_storage/blobs/_blob.html.erb", say "Installing JavaScript dependency" run "yarn add https://github.com/rails/actiontext" -APPLICATION_PATH_PATH = "app/javascript/packs/application.js" +APPLICATION_PACK_PATH = "app/javascript/packs/application.js" -if File.exists?(APPLICATION_PATH_PATH) && File.read(APPLICATION_PATH_PATH) !~ /import "actiontext"/ +if File.exists?(APPLICATION_PACK_PATH) && File.read(APPLICATION_PACK_PATH) !~ /import "actiontext"/ say "Adding import to default JavaScript pack" - append_to_file APPLICATION_PATH_PATH, <<-EOS + append_to_file APPLICATION_PACK_PATH, <<-EOS import "actiontext" EOS end -- cgit v1.2.3 From 01b67837a116cd34c53d8d6e8e7eb1853a6a4710 Mon Sep 17 00:00:00 2001 From: George Claghorn Date: Fri, 12 Oct 2018 15:21:41 -0400 Subject: -> --- lib/templates/actiontext.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/templates/actiontext.scss b/lib/templates/actiontext.scss index 107c31c091..7cb26e74ac 100644 --- a/lib/templates/actiontext.scss +++ b/lib/templates/actiontext.scss @@ -6,7 +6,7 @@ //= require trix/dist/trix // We need to override trix.css’s image gallery styles to accommodate the -// element we wrap around attachments. Otherwise, +// element we wrap around attachments. Otherwise, // images in galleries will be squished by the max-width: 33%; rule. .trix-content { .attachment-gallery { -- cgit v1.2.3 From 0807dca2fa7508ee994dcdc84bc5129ea9a7330c Mon Sep 17 00:00:00 2001 From: Alberto Almagro Date: Sat, 13 Oct 2018 16:56:51 +0200 Subject: Remove unused **options I'm not sure if this is going to be used in the future or not, but for the time being we shouldn't maintain parameters that we aren't using. We can always add them later when needed. --- lib/action_text/content.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/action_text/content.rb b/lib/action_text/content.rb index b99e9bb49c..2cf6c96556 100644 --- a/lib/action_text/content.rb +++ b/lib/action_text/content.rb @@ -64,9 +64,9 @@ module ActionText self.class.new(content, canonicalize: false) end - def render_attachment_galleries(**options, &block) + def render_attachment_galleries(&block) content = ActionText::AttachmentGallery.fragment_by_replacing_attachment_gallery_nodes(fragment) do |node| - block.call(attachment_gallery_for_node(node, **options)) + block.call(attachment_gallery_for_node(node)) end self.class.new(content, canonicalize: false) end @@ -119,7 +119,7 @@ module ActionText with_full_attributes ? attachment.with_full_attributes : attachment end - def attachment_gallery_for_node(node, **options) + def attachment_gallery_for_node(node) ActionText::AttachmentGallery.from_node(node) end end -- cgit v1.2.3 From 123444ee0edaedca165c97472b3d2d84e2a1b65e Mon Sep 17 00:00:00 2001 From: Alberto Almagro Date: Sat, 13 Oct 2018 17:05:13 +0200 Subject: Rename shadowed variable This commit renames shadowed variable `attributes`. --- lib/action_text/attachable.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/action_text/attachable.rb b/lib/action_text/attachable.rb index fce3d6d9c3..9776d2cb13 100644 --- a/lib/action_text/attachable.rb +++ b/lib/action_text/attachable.rb @@ -68,14 +68,14 @@ module ActionText end def to_rich_text_attributes(attributes = {}) - attributes.dup.tap do |attributes| - attributes[:sgid] = attachable_sgid - attributes[:content_type] = attachable_content_type - attributes[:previewable] = true if previewable_attachable? - attributes[:filename] = attachable_filename - attributes[:filesize] = attachable_filesize - attributes[:width] = attachable_metadata[:width] - attributes[:height] = attachable_metadata[:height] + attributes.dup.tap do |attrs| + attrs[:sgid] = attachable_sgid + attrs[:content_type] = attachable_content_type + attrs[:previewable] = true if previewable_attachable? + attrs[:filename] = attachable_filename + attrs[:filesize] = attachable_filesize + attrs[:width] = attachable_metadata[:width] + attrs[:height] = attachable_metadata[:height] end.compact end end -- cgit v1.2.3 From e6f4201b595129d3a9b0976c6388526032a4a360 Mon Sep 17 00:00:00 2001 From: Tatsuya Ikeda <6753644+ikepon@users.noreply.github.com> Date: Thu, 13 Dec 2018 13:57:42 +0900 Subject: CI against Ruby 2.4.5 and 2.5.3 (#45) Bump CI to latest minor versions of Ruby 2.4 and 2.5 --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index f9ad1f699e..b66561a4ac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,8 @@ language: ruby sudo: false rvm: - - 2.4.4 - - 2.5.1 + - 2.4.5 + - 2.5.3 - ruby-head cache: -- cgit v1.2.3 From 99fa2e80fb2b9d5ba0ec03505e65996f3ab341dd Mon Sep 17 00:00:00 2001 From: bogdanvlviv Date: Fri, 21 Dec 2018 01:03:56 +0200 Subject: Remove Ruby 2.4 from the CI matrix Rails 6 requires Ruby 2.5+ or newer. See https://github.com/rails/rails/pull/34754. --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b66561a4ac..f913b006ca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ language: ruby sudo: false rvm: - - 2.4.5 - 2.5.3 - ruby-head -- cgit v1.2.3 From 097235bc41e7e4707369991eb79284b0f9ddd71c Mon Sep 17 00:00:00 2001 From: Kasper Timm Hansen Date: Fri, 21 Dec 2018 00:13:25 +0100 Subject: =?UTF-8?q?Fit=20Rails=E2=80=99=20Ruby=20requirement=20in=20here.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- actiontext.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actiontext.gemspec b/actiontext.gemspec index 1185dfc791..786953878e 100644 --- a/actiontext.gemspec +++ b/actiontext.gemspec @@ -13,7 +13,7 @@ Gem::Specification.new do |s| s.homepage = "https://github.com/rails/actiontext" s.license = "MIT" - s.required_ruby_version = ">= 2.4.1" + s.required_ruby_version = ">= 2.5.0" s.add_dependency "rails", ">= 5.2.0" s.add_dependency "nokogiri" -- cgit v1.2.3 From ecfada837a464df1ffa50789d4e555ffde6108f4 Mon Sep 17 00:00:00 2001 From: Lachlan Sylvester Date: Fri, 21 Dec 2018 12:04:30 +1100 Subject: use plain test to determine present/blank/empty as the html version will always contain content --- app/models/action_text/rich_text.rb | 8 ++++++-- test/unit/model_test.rb | 8 ++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/app/models/action_text/rich_text.rb b/app/models/action_text/rich_text.rb index 1f8ac0e7f7..d44046e863 100644 --- a/app/models/action_text/rich_text.rb +++ b/app/models/action_text/rich_text.rb @@ -8,8 +8,12 @@ class ActionText::RichText < ActiveRecord::Base self.table_name = "action_text_rich_texts" serialize :body, ActionText::Content - delegate :to_s, :to_plain_text, :nil?, to: :body - delegate :blank?, :empty?, :present?, to: :to_s + delegate :to_s, :nil?, to: :body + delegate :blank?, :empty?, :present?, to: :to_plain_text + + def to_plain_text + body&.to_plain_text.to_s + end belongs_to :record, polymorphic: true, touch: true has_many_attached :embeds diff --git a/test/unit/model_test.rb b/test/unit/model_test.rb index 99a249946a..43da9c7a73 100644 --- a/test/unit/model_test.rb +++ b/test/unit/model_test.rb @@ -21,6 +21,14 @@ class ActionText::ModelTest < ActiveSupport::TestCase assert_not message.content.present? end + test "with blank content" do + message = Message.create!(subject: "Greetings", content: "") + assert_not message.content.nil? + assert message.content.blank? + assert message.content.empty? + assert_not message.content.present? + end + test "embed extraction" do blob = create_file_blob(filename: "racecar.jpg", content_type: "image/jpg") message = Message.create!(subject: "Greetings", content: ActionText::Content.new("Hello world").append_attachables(blob)) -- cgit v1.2.3 From 4d1f3f832485920a5bd49bc3a2c13debeaab5608 Mon Sep 17 00:00:00 2001 From: George Claghorn Date: Fri, 21 Dec 2018 00:59:43 -0500 Subject: Move method definition below callbacks --- app/models/action_text/rich_text.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/models/action_text/rich_text.rb b/app/models/action_text/rich_text.rb index d44046e863..717e93599f 100644 --- a/app/models/action_text/rich_text.rb +++ b/app/models/action_text/rich_text.rb @@ -9,11 +9,6 @@ class ActionText::RichText < ActiveRecord::Base serialize :body, ActionText::Content delegate :to_s, :nil?, to: :body - delegate :blank?, :empty?, :present?, to: :to_plain_text - - def to_plain_text - body&.to_plain_text.to_s - end belongs_to :record, polymorphic: true, touch: true has_many_attached :embeds @@ -21,4 +16,10 @@ class ActionText::RichText < ActiveRecord::Base before_save do self.embeds = body.attachments.map(&:attachable) if body.present? end + + def to_plain_text + body&.to_plain_text.to_s + end + + delegate :blank?, :empty?, :present?, to: :to_plain_text end -- cgit v1.2.3 From dce22ba477e015fad910b17e2f148f96215b4ff7 Mon Sep 17 00:00:00 2001 From: George Claghorn Date: Mon, 31 Dec 2018 11:59:09 -0500 Subject: Bump Nokogiri for Ruby 2.6 compatibility --- Gemfile.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 41f94a65c0..32f07b0461 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -91,11 +91,11 @@ GEM mimemagic (0.3.2) mini_magick (4.8.0) mini_mime (1.0.1) - mini_portile2 (2.3.0) + mini_portile2 (2.4.0) minitest (5.11.3) nio4r (2.3.1) - nokogiri (1.8.2) - mini_portile2 (~> 2.3.0) + nokogiri (1.9.1) + mini_portile2 (~> 2.4.0) rack (2.0.4) rack-proxy (0.6.3) rack @@ -139,4 +139,4 @@ DEPENDENCIES webpacker (~> 3.2.2) BUNDLED WITH - 1.16.2 + 1.17.2 -- cgit v1.2.3 From f2a5c1a541342a886ed3de3b9a15ce06b6bdcde5 Mon Sep 17 00:00:00 2001 From: George Claghorn Date: Mon, 31 Dec 2018 12:16:21 -0500 Subject: Fix adding a rich_text_area to a form with no model --- .gitignore | 1 + Gemfile.lock | 2 + actiontext.gemspec | 1 + app/helpers/action_text/tag_helper.rb | 2 +- test/template/form_helper_test.rb | 78 ++++++++++++++++++++++------------- 5 files changed, 55 insertions(+), 29 deletions(-) diff --git a/.gitignore b/.gitignore index d1654bd7a4..8fda56f74b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .bundle/ +.byebug_history log/*.log node_modules/ pkg/ diff --git a/Gemfile.lock b/Gemfile.lock index 32f07b0461..1c5bd96494 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -73,6 +73,7 @@ GEM remote: https://rubygems.org/ specs: builder (3.2.3) + byebug (10.0.2) concurrent-ruby (1.0.5) crass (1.0.4) erubi (1.7.1) @@ -133,6 +134,7 @@ PLATFORMS DEPENDENCIES actiontext! bundler (~> 1.15) + byebug mini_magick rails! sqlite3 diff --git a/actiontext.gemspec b/actiontext.gemspec index 786953878e..c825a71c6b 100644 --- a/actiontext.gemspec +++ b/actiontext.gemspec @@ -22,6 +22,7 @@ Gem::Specification.new do |s| s.add_development_dependency "mini_magick" s.add_development_dependency "sqlite3" s.add_development_dependency "webpacker", "~> 3.2.2" + s.add_development_dependency "byebug" s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- test/*`.split("\n") diff --git a/app/helpers/action_text/tag_helper.rb b/app/helpers/action_text/tag_helper.rb index c7ba416880..0be2d2af36 100644 --- a/app/helpers/action_text/tag_helper.rb +++ b/app/helpers/action_text/tag_helper.rb @@ -40,7 +40,7 @@ module ActionView::Helpers def render options = @options.stringify_keys add_default_name_and_id(options) - options["input"] ||= dom_id(object, [options["id"], :trix_input].compact.join("_")) + options["input"] ||= dom_id(object, [options["id"], :trix_input].compact.join("_")) if object @template_object.rich_text_area_tag(options.delete("name"), editable_value, options) end diff --git a/test/template/form_helper_test.rb b/test/template/form_helper_test.rb index 18b5edbee5..cb900ffc36 100644 --- a/test/template/form_helper_test.rb +++ b/test/template/form_helper_test.rb @@ -5,45 +5,67 @@ require 'test_helper' class ActionText::FormHelperTest < ActionView::TestCase tests ActionText::TagHelper - def form_with(*) - @output_buffer = super + test "form with rich text area" do + form_with model: Message.new, scope: :message do |form| + form.rich_text_area :content + end + + assert_dom_equal \ + '
      ' \ + '' \ + '' \ + '' \ + '' \ + '
      ', + output_buffer end - test "rich_text_area doesn't raise when attributes don't exist in the model" do - assert_nothing_raised do - form_with(model: Message.new, scope: :message, id: "create-message") do |form| - form.rich_text_area(:not_an_attribute) - end + test "form with rich text area having class" do + form_with model: Message.new, scope: :message do |form| + form.rich_text_area :content, class: "custom-class" end - assert_match "message[not_an_attribute]", output_buffer + assert_dom_equal \ + '
      ' \ + '' \ + '' \ + '' \ + '' \ + '
      ', + output_buffer end - test "form with rich_text_area" do - expected = '
      '\ - ''\ - ''\ - ''\ - '
      ' - - form_with(model: Message.new, scope: :message, id: "create-message") do |form| - form.rich_text_area(:content) + test "form with rich text area for non-attribute" do + form_with model: Message.new, scope: :message do |form| + form.rich_text_area :not_an_attribute end - assert_dom_equal expected, output_buffer + assert_dom_equal \ + '
      ' \ + '' \ + '' \ + '' \ + '' \ + '
      ', + output_buffer end - test "form with rich_text_area providing class option" do - expected = '
      '\ - ''\ - ''\ - ''\ - '
      ' - - form_with(model: Message.new, scope: :message, id: "create-message") do |form| - form.rich_text_area(:content, class: "custom-class") + test "modelless form with rich text area" do + form_with url: "/messages", scope: :message do |form| + form.rich_text_area :content end - assert_dom_equal expected, output_buffer + assert_dom_equal \ + '
      ' \ + '' \ + '' \ + '' \ + '' \ + '
      ', + output_buffer + end + + def form_with(*) + @output_buffer = super end end -- cgit v1.2.3 From cfe4674d3637c746cdb3c2b5131e2de498775529 Mon Sep 17 00:00:00 2001 From: Rikki Pitt Date: Fri, 4 Jan 2019 21:57:43 +0000 Subject: Update tag helper routes for use in engines (#49) When using the `rich_text_area_tag` form helper from within a Rails engine, the direct_upload_url and blob_url_template options would default to non-existent routes. By prefixing these routes with `main_app` we ensure the application root is used rather than the engine. --- app/helpers/action_text/tag_helper.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/helpers/action_text/tag_helper.rb b/app/helpers/action_text/tag_helper.rb index 0be2d2af36..837b2264b1 100644 --- a/app/helpers/action_text/tag_helper.rb +++ b/app/helpers/action_text/tag_helper.rb @@ -22,8 +22,8 @@ module ActionText options[:class] ||= "trix-content" options[:data] ||= {} - options[:data][:direct_upload_url] = rails_direct_uploads_url - options[:data][:blob_url_template] = rails_service_blob_url(":signed_id", ":filename") + options[:data][:direct_upload_url] = main_app.rails_direct_uploads_url + options[:data][:blob_url_template] = main_app.rails_service_blob_url(":signed_id", ":filename") editor_tag = content_tag("trix-editor", "", options) input_tag = hidden_field_tag(name, value, id: options[:input]) -- cgit v1.2.3