card 1.20.0 → 1.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/card.gemspec +1 -1
  4. data/lib/card.rb +7 -3
  5. data/lib/card/act_manager/stage_director.rb +22 -10
  6. data/lib/card/cache/persistent.rb +15 -9
  7. data/lib/card/format/nest.rb +12 -5
  8. data/lib/card/format/nest/fetch.rb +2 -1
  9. data/lib/card/format/render.rb +5 -2
  10. data/lib/card/set/event.rb +7 -1
  11. data/lib/card/subcards.rb +3 -3
  12. data/lib/card/view/cache.rb +1 -1
  13. data/lib/card/view/fetch.rb +17 -5
  14. data/lib/card/view/options.rb +52 -26
  15. data/lib/cardio.rb +2 -1
  16. data/mod/account/spec/set/right/account_spec.rb +17 -3
  17. data/mod/admin/set/self/admin.rb +0 -2
  18. data/mod/admin/spec/set/self/admin_spec.rb +14 -11
  19. data/mod/bootstrap/set/all/bootstrap/helper.rb +27 -29
  20. data/mod/carrierwave/set/type/file.rb +1 -1
  21. data/mod/carrierwave/set/type/image.rb +18 -6
  22. data/mod/core/set/all/collection.rb +33 -7
  23. data/mod/core/set/all/fetch.rb +16 -3
  24. data/mod/core/set/all/permissions.rb +6 -12
  25. data/mod/core/set/all/trash.rb +3 -1
  26. data/mod/core/spec/set/all/collection_spec.rb +9 -8
  27. data/mod/email/set/all/notify.rb +27 -17
  28. data/mod/email/set/right/follow.rb +49 -36
  29. data/mod/email/set/type/email_template.rb +25 -69
  30. data/mod/email/set/type/email_template/email_config.rb +63 -0
  31. data/mod/email/set/type_plus_right/user/follow.rb +3 -3
  32. data/mod/machines/lib/stylesheets/style_cards.scss +292 -0
  33. data/mod/pointer/set/abstract/01_pointer.rb +8 -8
  34. data/mod/pointer/set/abstract/01_pointer/edit.rb +6 -2
  35. data/mod/prosemirror_editor/lib/javascript/script_prosemirror.js +12283 -11605
  36. data/mod/prosemirror_editor/lib/javascript/script_prosemirror_config.js.coffee +1 -1
  37. data/mod/standard/set/abstract/01_search_params.rb +1 -1
  38. data/mod/standard/set/abstract/search/paging.rb +4 -4
  39. data/mod/standard/set/all/comment.rb +67 -47
  40. data/mod/standard/set/all/links.rb +2 -2
  41. data/mod/standard/set/all/rich_html/content.rb +1 -1
  42. data/mod/standard/set/all/rich_html/editing.rb +3 -2
  43. data/mod/standard/set/all/rich_html/form.rb +21 -12
  44. data/mod/standard/set/all/rich_html/header.rb +9 -0
  45. data/mod/standard/set/all/rich_html/menu.rb +16 -12
  46. data/mod/standard/set/all/rich_html/toolbar.rb +140 -130
  47. data/mod/standard/set/all/rich_html/wrapper.rb +11 -1
  48. data/mod/standard/set/rstar/rules_editor.rb +2 -34
  49. data/mod/standard/set/self/search.rb +1 -1
  50. data/mod/standard/set/type/set.rb +4 -4
  51. data/mod/standard/spec/set/type/email_template/email_config_spec.rb +218 -0
  52. data/mod/standard/spec/set/type/email_template_spec.rb +3 -185
  53. data/spec/lib/card/cache_spec.rb +0 -1
  54. data/spec/lib/card/format/render_spec.rb +19 -0
  55. data/spec/lib/card/stage_director_spec.rb +1 -1
  56. data/tmpsets/set/mod001-core/all/actify.rb +5 -6
  57. data/tmpsets/set/mod001-core/all/fetch.rb +14 -12
  58. data/tmpsets/set/mod001-core/all/name.rb +1 -1
  59. data/tmpsets/set/mod001-core/all/permissions.rb +12 -22
  60. data/tmpsets/set/mod001-core/all/tracked_attributes.rb +76 -0
  61. data/tmpsets/set/mod001-core/all/utils.rb +40 -3
  62. data/tmpsets/set/mod002-history/all/history.rb +1 -2
  63. data/tmpsets/set/mod008-solid_cache/abstract/solid_cache.rb +1 -1
  64. data/tmpsets/set/mod013-carrierwave/abstract/attachment.rb +282 -0
  65. data/tmpsets/set/mod013-carrierwave/type/file.rb +155 -0
  66. data/tmpsets/set/mod013-carrierwave/type/image.rb +96 -0
  67. data/tmpsets/set/mod014-admin/self/admin.rb +113 -0
  68. data/tmpsets/set/mod014-admin/self/admin_info.rb +110 -0
  69. data/tmpsets/set/mod014-admin/self/version.rb +15 -0
  70. data/tmpsets/set/mod015-developer/all/event_viz.rb +59 -0
  71. data/tmpsets/set/mod015-developer/all/view_viz.rb +30 -0
  72. data/tmpsets/set/mod015-developer/right/debug.rb +96 -0
  73. metadata +15 -2
@@ -18,37 +18,50 @@ format :html do
18
18
  end
19
19
 
20
20
  view :follow_item, tags: :unknown_ok, cache: :never do |args|
21
- if card.new_card? || !card.include_item?(args[:condition])
22
- button_view = :add_follow_rule_button
23
- form_opts = { add_item: args[:condition] }
24
- else
25
- button_view = :delete_follow_rule_button
26
- form_opts = { drop_item: args[:condition] }
27
- end
28
-
29
- text = if (option_card = Card.fetch args[:condition])
30
- option_card.description(card.rule_set)
31
- else
32
- card.rule_set.follow_label
33
- end
34
- link_target = if card.rule_set.tag.codename == "self"
35
- card.rule_set_name.left
36
- else
37
- "#{card.rule_set_name}+by name"
38
- end
21
+ condition = args[:condition]
39
22
  wrap do
40
- card_form(
41
- { action: :update, name: card.name, success: { view: :follow_item } },
42
- hidden: { condition: args[:condition] }.merge(form_opts)
43
- ) do
44
- output [
45
- _optional_render(button_view, args),
46
- link_to_card(link_target, text)
23
+ card_form action: :update, success: { view: :follow_item } do
24
+ [
25
+ follow_item_hidden_tags(condition),
26
+ follow_item_button(condition),
27
+ follow_item_link(condition)
47
28
  ]
48
29
  end
49
30
  end
50
31
  end
51
32
 
33
+ def add_follow_item? condition
34
+ card.new_card? || !card.include_item?(condition)
35
+ end
36
+
37
+ def follow_item_hidden_tags condition
38
+ condkey = add_follow_item?(condition) ? :add_item : :drop_item
39
+ hidden_tags condition: condition, condkey => condition
40
+ end
41
+
42
+ def follow_item_button condition
43
+ action = add_follow_item?(condition) ? :add : :delete
44
+ _optional_render "#{action}_follow_rule_button"
45
+ end
46
+
47
+ def follow_item_link condition
48
+ link_to_card follow_item_link_target, follow_item_link_text(condition)
49
+ end
50
+
51
+ def follow_item_link_target
52
+ set = card.rule_set
53
+ setname = set.cardname
54
+ set.tag.codename == "self" ? setname.left : setname.field("by name")
55
+ end
56
+
57
+ def follow_item_link_text condition
58
+ if (option_card = Card.fetch condition)
59
+ option_card.description card.rule_set
60
+ else
61
+ card.rule_set.follow_label
62
+ end
63
+ end
64
+
52
65
  def default_follow_status_args args
53
66
  args[:card_key] ||= card.set_prototype.key
54
67
  end
@@ -60,9 +73,11 @@ format :html do
60
73
  end
61
74
 
62
75
  def follow_status_link name, key
63
- link_to_related key, "more options",
64
- path: { related: { name: name, view: :edit_single_rule } },
65
- class: "btn update-follow-link", "data-card_key" => key
76
+ # simplified this to straight link for now.
77
+ # consider restoring to slotter action
78
+ link_to_card name, "more options",
79
+ path: { view: :edit_single_rule },
80
+ class: "btn update-follow-link", "data-card_key" => key
66
81
  end
67
82
 
68
83
  view :follow_status_delete_options, cache: :never do
@@ -77,19 +92,17 @@ format :html do
77
92
  end
78
93
 
79
94
  view :delete_follow_rule_button do
80
- button_tag(
81
- type: :submit,
82
- class: "btn-xs btn-item-delete btn-primary", "aria-label" => "Left Align"
83
- ) do
95
+ button_tag(type: :submit,
96
+ class: "btn-xs btn-item-delete btn-primary",
97
+ "aria-label" => "Left Align") do
84
98
  tag :span, class: "glyphicon glyphicon-ok", "aria-hidden" => "true"
85
99
  end
86
100
  end
87
101
 
88
102
  view :add_follow_rule_button do
89
- button_tag(
90
- type: :submit,
91
- class: "btn-xs btn-item-add", "aria-label" => "Left Align"
92
- ) do
103
+ button_tag(type: :submit,
104
+ class: "btn-xs btn-item-add",
105
+ "aria-label" => "Left Align") do
93
106
  tag :span, class: "glyphicon glyphicon-plus", "aria-hidden" => "true"
94
107
  end
95
108
  end
@@ -10,82 +10,38 @@ rescue Net::SMTPError => exception
10
10
  errors.add :exception, exception.message
11
11
  end
12
12
 
13
- def process_email_field field, config, args
14
- config[field] =
15
- if args[field]
16
- args[field]
17
- elsif (field_card = fetch(trait: field))
18
- # configuration can be anything visible to configurer
19
- user = (args[:follower] && Card.fetch(args[:follower])) ||
20
- field_card.updater
21
- Auth.as(user) do
22
- yield(field_card)
23
- end
24
- else
25
- ""
26
- end
27
- end
28
-
29
- def process_message_field field, config, args, format, special_args=nil
30
- process_email_field(field, config, args) do |field_card|
31
- content_args = args.clone
32
- content_args.merge! special_args if special_args
33
- field_card.contextual_content args[:context], { format: format },
34
- content_args
35
- end
36
- end
37
-
38
- def email_config args={}
39
- config = {}
40
- args[:context] ||= self
41
-
42
- [:to, :from, :cc, :bcc].each do |field_name|
43
- process_email_field(field_name, config, args) do |field_card|
44
- field_card.process_email_addresses(
45
- args[:context], { format: "email_text" }, args
46
- )
47
- end
48
- end
49
- process_email_field(:attach, config, args) do |field_card|
50
- field_card.extended_item_contents args[:context]
51
- end
52
- process_message_field :subject, config, args, "email_text",
53
- content_opts: { chunk_list: :nest_only }
54
- process_message_field :text_message, config, args, "email_text"
55
- process_message_field :html_message, config, args, "email_html"
13
+ def process_html_message config, args, inline_attachment_url
14
+ process_message_field(
15
+ :html_message, config,
16
+ args.merge(inline_attachment_url: inline_attachment_url),
17
+ "email_html"
18
+ )
56
19
  if config[:html_message].present?
57
20
  config[:html_message] = Card::Mailer.layout config[:html_message]
58
21
  end
59
-
60
- from_name, from_email =
61
- if config[:from] =~ /(.*)\<(.*)>/
62
- [Regexp.last_match(1).strip, Regexp.last_match(2)]
63
- else
64
- [nil, config[:from]]
65
- end
66
-
67
- if (default_from = Card::Mailer.default[:from])
68
- config[:from] =
69
- if from_email
70
- %("#{from_name || from_email}" <#{default_from}>)
71
- else
72
- default_from
73
- end
74
- config[:reply_to] ||= config[:from]
75
- elsif config[:from].blank?
76
- config[:from] = Card[Card::WagnBotID].account.email
77
- end
78
- config.select { |_k, v| v.present? }
22
+ config
79
23
  end
80
24
 
81
25
  format do
82
26
  view :mail, perms: :none, cache: :never do |args|
83
- args = card.email_config(args)
84
- text_message = args.delete(:text_message)
85
- html_message = args.delete(:html_message)
86
- attachment_list = args.delete(:attach)
87
- alternative = (text_message.present? && html_message.present?)
88
- mail = Card::Mailer.new_mail(args) do
27
+ config = card.email_config(args)
28
+ text_message = config.delete(:text_message)
29
+ attachment_list = config.delete(:attach)
30
+ email_card = card # card is not accessible in the new_mail block
31
+ mail = Card::Mailer.new_mail(config) do
32
+ # inline attachments only work in the binding of this block
33
+ # so the current solution is to create a lambda here and pass it
34
+ # to the view where it is needed to create the image tag
35
+ # (see core view in Type::Image::EmailHtmlFormat)
36
+ inline_attachment_url =
37
+ lambda do |path|
38
+ attachments.inline[path] = ::File.read path
39
+ attachments[path].url
40
+ end
41
+ email_card.process_html_message config, args, inline_attachment_url
42
+ html_message = config.delete(:html_message)
43
+ alternative = (text_message.present? && html_message.present?)
44
+
89
45
  if alternative
90
46
  if attachment_list && !attachment_list.empty?
91
47
  content_type "multipart/mixed"
@@ -0,0 +1,63 @@
1
+ def email_config args={}
2
+ config = {}
3
+ args[:context] ||= self
4
+
5
+ [:to, :from, :cc, :bcc].each do |field_name|
6
+ process_email_field(field_name, config, args) do |field_card|
7
+ field_card.process_email_addresses(
8
+ args[:context], { format: "email_text" }, args
9
+ )
10
+ end
11
+ end
12
+ process_email_field(:attach, config, args) do |field_card|
13
+ field_card.extended_item_contents args[:context]
14
+ end
15
+ process_message_field :subject, config, args, "email_text",
16
+ content_opts: { chunk_list: :nest_only }
17
+ process_message_field :text_message, config, args, "email_text"
18
+
19
+ from_name, from_email =
20
+ if config[:from] =~ /(.*)\<(.*)>/
21
+ [Regexp.last_match(1).strip, Regexp.last_match(2)]
22
+ else
23
+ [nil, config[:from]]
24
+ end
25
+
26
+ if (default_from = Card::Mailer.default[:from])
27
+ config[:from] =
28
+ if from_email
29
+ %("#{from_name || from_email}" <#{default_from}>)
30
+ else
31
+ default_from
32
+ end
33
+ config[:reply_to] ||= config[:from]
34
+ elsif config[:from].blank?
35
+ config[:from] = Card[Card::WagnBotID].account.email
36
+ end
37
+ config.select { |_k, v| v.present? }
38
+ end
39
+
40
+ def process_email_field field, config, args
41
+ config[field] =
42
+ if args[field]
43
+ args[field]
44
+ elsif (field_card = fetch(trait: field))
45
+ # configuration can be anything visible to configurer
46
+ user = (args[:follower] && Card.fetch(args[:follower])) ||
47
+ field_card.updater
48
+ Auth.as(user) do
49
+ yield(field_card)
50
+ end
51
+ else
52
+ ""
53
+ end
54
+ end
55
+
56
+ def process_message_field field, config, args, format, special_args=nil
57
+ process_email_field(field, config, args) do |field_card|
58
+ content_args = args.clone
59
+ content_args.merge! special_args if special_args
60
+ field_card.contextual_content args[:context], { format: format },
61
+ content_args
62
+ end
63
+ end
@@ -120,9 +120,9 @@ format :html do
120
120
  subformat(rule[:card]).render_follow_item condition: option,
121
121
  hide: hide_buttons
122
122
  end
123
- end.join("\n")
124
- end.join("\n")
125
- end.join("\n")
123
+ end
124
+ end
125
+ end
126
126
  end
127
127
  end
128
128
  end
@@ -855,3 +855,295 @@ html>body .open-view {
855
855
  }
856
856
 
857
857
 
858
+ /*-------------------------- */
859
+ /*- ProseMirror - */
860
+ /*-------------------------- */
861
+
862
+ .ProseMirror {
863
+ position: relative;
864
+ }
865
+
866
+ .ProseMirror {
867
+ white-space: pre-wrap;
868
+ }
869
+
870
+ .ProseMirror ul, .ProseMirror ol {
871
+ padding-left: 30px;
872
+ cursor: default;
873
+ }
874
+
875
+ .ProseMirror blockquote {
876
+ padding-left: 1em;
877
+ border-left: 3px solid #eee;
878
+ margin-left: 0; margin-right: 0;
879
+ }
880
+
881
+ .ProseMirror pre {
882
+ white-space: pre-wrap;
883
+ }
884
+
885
+ .ProseMirror li {
886
+ position: relative;
887
+ pointer-events: none; /* Don't do weird stuff with marker clicks */
888
+ }
889
+ .ProseMirror li > * {
890
+ pointer-events: auto;
891
+ }
892
+
893
+ .ProseMirror-nodeselection *::selection, .ProseMirror-widget *::selection { background: transparent; }
894
+ .ProseMirror-nodeselection *::-moz-selection, .ProseMirror-widget *::-moz-selection { background: transparent; }
895
+
896
+ .ProseMirror-selectednode {
897
+ outline: 2px solid #8cf;
898
+ }
899
+
900
+ /* Make sure li selections wrap around markers */
901
+
902
+ li.ProseMirror-selectednode {
903
+ outline: none;
904
+ }
905
+
906
+ li.ProseMirror-selectednode:after {
907
+ content: "";
908
+ position: absolute;
909
+ left: -32px;
910
+ right: -2px; top: -2px; bottom: -2px;
911
+ border: 2px solid #8cf;
912
+ pointer-events: none;
913
+ }
914
+
915
+
916
+ .ProseMirror-textblock-dropdown {
917
+ min-width: 3em;
918
+ }
919
+
920
+ .ProseMirror-menu {
921
+ margin: 0 -4px;
922
+ line-height: 1;
923
+ }
924
+
925
+ .ProseMirror-tooltip .ProseMirror-menu {
926
+ width: -webkit-fit-content;
927
+ width: fit-content;
928
+ white-space: pre;
929
+ }
930
+
931
+ .ProseMirror-menuitem {
932
+ margin-right: 3px;
933
+ display: inline-block;
934
+ }
935
+
936
+ .ProseMirror-menuseparator {
937
+ border-right: 1px solid #ddd;
938
+ margin-right: 3px;
939
+ }
940
+
941
+ .ProseMirror-menu-dropdown, .ProseMirror-menu-dropdown-menu {
942
+ font-size: 90%;
943
+ white-space: nowrap;
944
+ }
945
+
946
+ .ProseMirror-menu-dropdown {
947
+ vertical-align: 1px;
948
+ cursor: pointer;
949
+ }
950
+
951
+ .ProseMirror-menu-dropdown-wrap {
952
+ padding: 1px 14px 1px 4px;
953
+ display: inline-block;
954
+ position: relative;
955
+ }
956
+
957
+ .ProseMirror-menu-dropdown:after {
958
+ content: "";
959
+ border-left: 4px solid transparent;
960
+ border-right: 4px solid transparent;
961
+ border-top: 4px solid currentColor;
962
+ opacity: .6;
963
+ position: absolute;
964
+ right: 2px;
965
+ top: calc(50% - 2px);
966
+ }
967
+
968
+ .ProseMirror-menu-dropdown-menu, .ProseMirror-menu-submenu {
969
+ position: absolute;
970
+ background: white;
971
+ color: #666;
972
+ border: 1px solid #aaa;
973
+ padding: 2px;
974
+ }
975
+
976
+ .ProseMirror-menu-dropdown-menu {
977
+ z-index: 15;
978
+ min-width: 6em;
979
+ }
980
+
981
+ .ProseMirror-menu-dropdown-item {
982
+ cursor: pointer;
983
+ padding: 2px 8px 2px 4px;
984
+ }
985
+
986
+ .ProseMirror-menu-dropdown-item:hover {
987
+ background: #f2f2f2;
988
+ }
989
+
990
+ .ProseMirror-menu-submenu-wrap {
991
+ position: relative;
992
+ margin-right: -4px;
993
+ }
994
+
995
+ .ProseMirror-menu-submenu-label:after {
996
+ content: "";
997
+ border-top: 4px solid transparent;
998
+ border-bottom: 4px solid transparent;
999
+ border-left: 4px solid currentColor;
1000
+ opacity: .6;
1001
+ position: absolute;
1002
+ right: 4px;
1003
+ top: calc(50% - 4px);
1004
+ }
1005
+
1006
+ .ProseMirror-menu-submenu {
1007
+ display: none;
1008
+ min-width: 4em;
1009
+ left: 100%;
1010
+ top: -3px;
1011
+ }
1012
+
1013
+ .ProseMirror-menu-active {
1014
+ background: #eee;
1015
+ border-radius: 4px;
1016
+ }
1017
+
1018
+ .ProseMirror-menu-active {
1019
+ background: #eee;
1020
+ border-radius: 4px;
1021
+ }
1022
+
1023
+ .ProseMirror-menu-disabled {
1024
+ opacity: .3;
1025
+ }
1026
+
1027
+ .ProseMirror-menu-submenu-wrap:hover .ProseMirror-menu-submenu, .ProseMirror-menu-submenu-wrap-active .ProseMirror-menu-submenu {
1028
+ display: block;
1029
+ }
1030
+
1031
+ .ProseMirror-menubar {
1032
+ border-top-left-radius: inherit;
1033
+ border-top-right-radius: inherit;
1034
+ position: relative;
1035
+ min-height: 1em;
1036
+ color: #666;
1037
+ padding: 1px 6px;
1038
+ top: 0; left: 0; right: 0;
1039
+ border-bottom: 1px solid silver;
1040
+ background: white;
1041
+ z-index: 10;
1042
+ -moz-box-sizing: border-box;
1043
+ box-sizing: border-box;
1044
+ overflow: visible;
1045
+ }
1046
+
1047
+ .ProseMirror-icon {
1048
+ display: inline-block;
1049
+ line-height: .8;
1050
+ vertical-align: -2px; /* Compensate for padding */
1051
+ padding: 2px 8px;
1052
+ cursor: pointer;
1053
+ }
1054
+
1055
+ .ProseMirror-icon svg {
1056
+ fill: currentColor;
1057
+ height: 1em;
1058
+ }
1059
+
1060
+ .ProseMirror-icon span {
1061
+ vertical-align: text-top;
1062
+ }
1063
+
1064
+
1065
+
1066
+ /* Add space around the hr to make clicking it easier */
1067
+
1068
+ .ProseMirror-example-setup-style hr {
1069
+ position: relative;
1070
+ height: 6px;
1071
+ border: none;
1072
+ }
1073
+
1074
+ .ProseMirror-example-setup-style hr:after {
1075
+ content: "";
1076
+ position: absolute;
1077
+ left: 10px;
1078
+ right: 10px;
1079
+ top: 2px;
1080
+ border-top: 2px solid silver;
1081
+ }
1082
+
1083
+ .ProseMirror-example-setup-style img {
1084
+ cursor: default;
1085
+ }
1086
+
1087
+ .ProseMirror-example-setup-style table {
1088
+ border-collapse: collapse;
1089
+ }
1090
+
1091
+ .ProseMirror-example-setup-style td {
1092
+ vertical-align: top;
1093
+ border: 1px solid #ddd;
1094
+ padding: 3px 5px;
1095
+ }
1096
+
1097
+ .ProseMirror-prompt {
1098
+ background: white;
1099
+ padding: 5px 10px 5px 15px;
1100
+ border: 1px solid silver;
1101
+ position: fixed;
1102
+ border-radius: 3px;
1103
+ z-index: 11;
1104
+ box-shadow: -.5px 2px 5px rgba(0, 0, 0, .2);
1105
+ }
1106
+
1107
+ .ProseMirror-prompt h5 {
1108
+ margin: 0;
1109
+ font-weight: normal;
1110
+ font-size: 100%;
1111
+ color: #444;
1112
+ }
1113
+
1114
+ .ProseMirror-prompt input[type="text"],
1115
+ .ProseMirror-prompt textarea {
1116
+ background: #eee;
1117
+ border: none;
1118
+ outline: none;
1119
+ }
1120
+
1121
+ .ProseMirror-prompt input[type="text"] {
1122
+ padding: 0 4px;
1123
+ }
1124
+
1125
+ .ProseMirror-prompt-close {
1126
+ position: absolute;
1127
+ left: 2px; top: 1px;
1128
+ color: #666;
1129
+ border: none; background: transparent; padding: 0;
1130
+ }
1131
+
1132
+ .ProseMirror-prompt-close:after {
1133
+ content: "✕";
1134
+ font-size: 12px;
1135
+ }
1136
+
1137
+ .ProseMirror-invalid {
1138
+ background: #ffc;
1139
+ border: 1px solid #cc7;
1140
+ border-radius: 4px;
1141
+ padding: 5px 10px;
1142
+ position: absolute;
1143
+ min-width: 10em;
1144
+ }
1145
+
1146
+ .ProseMirror-prompt-buttons {
1147
+ margin-top: 5px;
1148
+ display: none;
1149
+ }