Update from upstream

This commit is contained in:
Julian Herrero
2016-01-10 15:26:19 +01:00
39 changed files with 681 additions and 85 deletions

Binary file not shown.

View File

@@ -19,7 +19,6 @@
<glyph glyph-name="like" unicode="&#107;" d="M91 128c0 5-1 9-5 13-4 3-8 5-13 5-5 0-9-2-13-5-3-4-5-8-5-13 0-5 2-9 5-13 4-4 8-5 13-5 5 0 9 1 13 5 4 4 5 8 5 13z m46 146l0-183c0-5-2-9-5-12-4-4-8-6-13-6l-82 0c-5 0-10 2-13 6-4 3-6 7-6 12l0 183c0 5 2 10 6 13 3 4 8 6 13 6l82 0c5 0 9-2 13-6 3-3 5-8 5-13z m338 0c0-16-5-30-15-42 3-9 4-16 4-22 1-14-4-28-12-39 3-11 3-22 0-34-3-10-8-19-16-26 2-22-3-39-14-52-12-15-31-22-56-22l-37 0c-12 0-26 1-41 4-15 3-26 6-35 8-8 3-19 7-34 12-24 8-39 12-45 12-5 0-10 2-13 6-4 3-6 7-6 12l0 184c0 4 2 8 6 12 3 4 7 5 12 6 4 0 12 6 22 17 9 11 19 22 28 34 13 17 23 28 29 35 4 3 7 8 9 13 3 6 4 11 5 14 1 4 2 9 4 17 1 8 3 14 4 18 1 4 2 9 5 15 3 5 6 10 10 14 3 4 8 5 13 5 8 0 16-1 23-3 7-2 13-4 17-7 5-3 9-7 12-12 3-4 5-9 7-12 1-4 2-9 3-15 1-5 1-10 2-13 0-2 0-6 0-11 0-7-1-14-3-21-2-8-4-13-5-18-2-4-5-9-8-16-1-1-2-2-3-5-1-2-3-4-3-6-1-2-2-4-3-7l80 0c14 0 27-5 38-16 11-11 16-24 16-39z"/>
<glyph glyph-name="check" unicode="&#108;" d="M477 350c0-7-2-14-8-19l-206-207-39-39c-6-5-12-8-20-8-7 0-14 3-19 8l-142 142c-6 6-8 12-8 20 0 7 2 14 8 19l38 39c6 5 12 8 20 8 7 0 14-3 19-8l84-84 188 188c5 5 12 8 19 8 8 0 14-3 20-8l38-39c6-6 8-12 8-20z"/>
<glyph glyph-name="edit" unicode="&#109;" d="M140 73l26 26-67 67-26-26 0-30 37 0 0-37z m150 265c0 4-2 7-7 7-1 0-3-1-4-2l-155-155c-2-2-2-3-2-5 0-4 2-6 6-6 2 0 4 0 5 2l155 154c1 2 2 3 2 5z m-16 55l119-119-238-237-118 0 0 118z m195-27c0-10-3-19-10-26l-48-47-118 118 47 48c7 7 15 10 26 10 10 0 18-3 26-10l67-67c7-8 10-16 10-26z"/>
<glyph glyph-name="star" unicode="&#110;" d="M494 327c0-4-3-9-8-14l-103-101 24-143c0-1 0-3 0-5 0-4-1-8-3-10-2-3-4-5-8-5-4 0-8 2-12 4l-128 67-128-67c-4-2-8-4-12-4-4 0-7 2-9 5-2 2-3 6-3 10 0 1 0 3 1 5l24 143-104 101c-4 6-7 10-7 14 0 7 6 12 16 13l144 21 64 130c4 8 8 12 14 12 6 0 10-4 14-12l64-130 144-21c10-1 16-6 16-13z"/>
<glyph glyph-name="user" unicode="&#111;" d="M410 203l-80 38-34 16c15 9 27 24 35 41 6 14 10 29 10 46 0 9-1 18-4 27-10 41-42 72-81 72-38 0-70-30-81-70-2-9-4-19-4-29 0-18 4-34 11-49 8-16 20-30 35-39l-32-15-83-38c-7-4-12-12-12-21l0-91c0-12 8-22 19-22l294 0c11 0 19 10 19 22l0 91c0 9-4 17-12 21z"/>
<glyph glyph-name="settings" unicode="&#113;" d="M329 256c0 20-7 37-21 52-15 14-32 21-52 21-20 0-37-7-52-21-14-15-21-32-21-52 0-20 7-37 21-52 15-14 32-21 52-21 20 0 37 7 52 21 14 15 21 32 21 52z m146 31l0-63c0-3 0-5-2-7-1-2-3-3-6-4l-52-8c-4-10-8-19-12-26 7-9 17-22 31-39 2-2 3-5 3-7 0-3-1-5-3-7-5-7-14-17-28-31-14-13-23-20-27-20-2 0-5 1-7 3l-40 31c-8-5-17-8-26-11-3-26-6-44-8-53-1-6-5-8-10-8l-64 0c-2 0-5 0-7 2-2 2-3 4-3 6l-8 53c-9 3-18 6-26 10l-40-30c-2-2-4-3-7-3-3 0-5 1-7 3-24 22-40 38-47 48-2 2-2 4-2 7 0 2 0 4 2 6 3 4 8 11 14 19 7 9 12 16 16 21-5 9-9 19-12 28l-52 8c-3 0-5 1-6 3-2 2-2 4-2 7l0 63c0 3 0 5 2 7 1 2 3 3 5 4l53 8c3 8 7 17 12 26-8 11-18 24-31 39-2 3-3 5-3 7 0 2 1 4 3 7 5 7 14 17 28 30 14 14 23 21 27 21 2 0 5-1 7-3l40-31c8 5 17 8 26 11 3 26 6 44 8 53 1 6 5 8 10 8l64 0c2 0 5 0 7-2 2-2 3-4 3-6l8-53c9-3 18-6 26-10l40 30c2 2 4 3 7 3 3 0 5-1 7-3 25-23 41-39 47-49 2-1 2-3 2-6 0-2 0-4-2-6-3-4-8-11-14-19-7-9-12-16-16-21 5-9 9-18 12-28l52-8c3 0 5-1 6-3 2-2 2-4 2-7z"/>
<glyph glyph-name="stats" unicode="&#114;" d="M17 222c-14 4-20 13-16 29 3 14 12 20 27 16 0 0 50-12 50-12 0 0-26-41-26-41 0 0-35 8-35 8m455-6c4 4 10 6 16 6 7-1 12-3 16-8 11-11 11-22-1-33 0 0-128-115-128-115-5-4-10-6-16-6-5 0-9 2-14 5 0 0-146 112-146 112 0 0-28 8-28 8 0 0 26 40 26 40 0 0 18-4 18-4 4-1 7-2 8-4 0 0 135-104 135-104 0 0 114 103 114 103m-251 112c0 0-178-280-178-280-4-8-11-12-20-12-4 0-8 2-12 5-5 3-9 8-10 14-1 7 0 12 3 17 0 0 191 300 191 300 3 6 7 9 14 11 6 2 12 1 19-3 0 0 125-80 125-80 0 0 115 166 115 166 4 6 9 9 15 10 6 1 12-1 17-5 13-8 15-18 6-31 0 0-128-185-128-185-9-12-19-14-32-6 0 0-125 79-125 79"/>
@@ -30,12 +29,10 @@
<glyph glyph-name="eye" unicode="&#112;" d="M475 238c-29 45-65 78-108 101 11-20 17-42 17-65 0-35-13-65-38-90-25-25-55-38-90-38-35 0-65 13-90 38-25 25-38 55-38 90 0 23 6 45 17 65-43-23-79-56-108-101 25-39 57-70 95-94 38-23 79-34 124-34 45 0 86 11 124 34 38 24 70 55 95 94z m-205 109c0 4-2 7-4 10-3 3-6 4-10 4-24 0-44-8-61-25-17-17-26-38-26-62 0-4 1-7 4-9 3-3 6-4 10-4 4 0 7 1 10 4 2 2 4 5 4 9 0 17 5 31 17 42 12 12 26 18 42 18 4 0 7 1 10 4 2 2 4 6 4 9z m242-109c0-7-2-13-6-20-26-44-62-79-107-105-45-27-93-40-143-40-50 0-98 13-143 40-45 26-81 61-107 105-4 7-6 13-6 20 0 6 2 13 6 19 26 44 62 79 107 106 45 26 93 39 143 39 50 0 98-13 143-39 45-27 81-62 107-106 4-6 6-13 6-19z"/>
<glyph glyph-name="x" unicode="&#118;" d="M426 134c0-7-3-14-8-19l-39-39c-5-5-12-8-20-8-7 0-14 3-19 8l-84 84-84-84c-5-5-12-8-19-8-8 0-15 3-20 8l-39 39c-5 5-8 12-8 19 0 8 3 14 8 20l84 84-84 84c-5 5-8 12-8 19 0 8 3 14 8 20l39 38c5 6 12 8 20 8 7 0 14-2 19-8l84-84 84 84c5 6 12 8 19 8 8 0 15-2 20-8l39-38c5-6 8-12 8-20 0-7-3-14-8-19l-84-84 84-84c5-6 8-12 8-20z"/>
<glyph glyph-name="flag" unicode="&#119;" d="M434 389c-1 0-2 0-3 0l0 0c-17-9-37-14-58-14-38 0-73 17-95 45-21 19-49 31-80 31-29 0-56-11-77-29-4 9-13 15-24 15-15 0-27-12-27-27l0-322c0-15 12-27 27-27 15 0 27 12 27 27l0 145c17 9 36 13 56 13 39 0 73-17 96-45 21-19 49-31 79-31 33 0 63 14 84 36 2 2 3 4 3 6l0 169c0 5-4 8-8 8z"/>
<glyph glyph-name="notification" unicode="&#120;" d="M261 27c0 3-2 5-5 5-11 0-21 4-29 12-8 8-12 18-12 29 0 3-2 5-5 5-3 0-4-2-4-5 0-14 5-26 14-35 10-10 22-15 36-15 3 0 5 1 5 4z m-190 83l370 0c-31 34-54 73-70 117-16 44-24 90-24 139 0 48-30 73-91 73-61 0-91-25-91-73 0-49-8-95-24-139-16-44-39-83-70-117z m423 0c0-10-4-19-11-26-7-7-16-11-26-11l-128 0c0-20-7-37-21-52-15-14-32-21-52-21-20 0-37 7-52 21-14 15-21 32-21 52l-128 0c-10 0-19 4-26 11-7 7-11 16-11 26 36 30 64 68 82 113 19 45 28 93 28 143 0 31 9 56 27 75 19 18 44 29 76 33-2 3-2 7-2 11 0 7 2 14 8 19 5 5 11 8 19 8 8 0 14-3 19-8 6-5 8-12 8-19 0-4 0-8-2-11 32-4 57-15 76-33 18-19 27-44 27-75 0-50 9-98 28-143 18-45 46-83 82-113z"/>
<glyph glyph-name="comment" unicode="&#121;" d="M256 402c-39 0-75-6-109-20-34-13-61-31-81-53-19-23-29-47-29-73 0-21 6-42 20-61 14-19 33-36 58-50l24-14-7-28c-5-17-12-34-20-49 29 12 55 28 78 49l13 11 16-2c13-2 25-2 37-2 39 0 75 6 109 20 34 13 61 31 81 53 19 23 29 47 29 73 0 26-10 50-29 73-20 22-47 40-81 53-34 14-70 20-109 20z m256-146c0-33-11-64-34-92-23-28-54-50-93-66-40-17-83-25-129-25-13 0-27 1-41 2-38-33-82-56-132-69-9-2-20-4-32-6l-2 0c-3 0-5 1-8 3-2 2-3 5-4 8l0 0c-1 1-1 2 0 4 0 1 0 2 0 2 0 1 1 2 2 3l1 3c0 0 1 1 2 2 2 2 2 3 3 3 1 1 4 5 8 10 5 5 8 8 10 10 2 3 5 6 9 12 4 5 7 10 9 14 3 5 5 10 8 17 3 7 5 14 8 22-30 17-54 38-71 63-17 25-26 51-26 80 0 33 11 64 34 92 23 28 54 50 93 66 40 17 83 25 129 25 46 0 89-8 129-25 39-16 70-38 93-66 23-28 34-59 34-92z"/>
<glyph glyph-name="reply" unicode="&#122;" d="M183 203l0-20c0-8-4-14-11-17-3-1-5-1-7-1-6 0-10 1-13 5l-147 146c-3 4-5 8-5 13 0 5 2 9 5 13l147 146c5 6 12 8 20 4 7-3 11-9 11-17l0-19-114-114c-3-4-5-8-5-13 0-5 2-9 5-13z m329-11c0-11-2-24-5-38-3-15-7-28-11-40-4-11-9-23-14-35-5-12-8-21-11-26l-6-12c-1-3-4-4-8-4-1 0-2 0-2 0-5 1-7 5-7 10 8 76-2 130-30 161-12 14-29 24-49 32-20 7-46 12-76 15l0-72c0-8-4-14-12-17-2-1-4-1-7-1-5 0-9 1-13 5l-146 146c-3 4-5 8-5 13 0 5 2 9 5 13l146 146c6 6 13 8 20 4 8-3 12-9 12-17l0-74c78-6 135-27 171-64 32-33 48-81 48-145z"/>
<glyph glyph-name="facebook" unicode="&#65;" d="M292 353l74 0-9-81-65 0 0-235-97 0 0 235-49 0 0 81 49 0 0 49c0 35 8 61 24 79 17 18 44 26 81 26l65 0 0-81-40 0c-8 0-14 0-18-2-5-1-8-3-10-6-2-4-3-7-4-10 0-3-1-8-1-14z"/>
<glyph glyph-name="google-plus" unicode="&#66;" d="M269 93c0 4-1 8-2 12-1 4-1 7-2 10-1 3-3 7-5 10-3 4-5 6-6 9-2 2-5 5-8 8-3 4-6 6-8 8-2 1-5 4-9 7-4 3-7 5-9 6-1 2-5 4-9 7-5 3-8 5-9 6-3 0-8 1-14 1-11 0-21-1-31-2-9-2-20-4-30-8-11-3-20-7-28-13-8-5-15-12-20-21-5-9-8-19-8-31 0-13 4-24 10-34 7-11 16-19 27-24 11-6 22-11 34-13 12-3 24-5 37-5 11 0 22 1 32 4 10 2 19 6 28 11 9 5 16 12 22 21 5 9 8 19 8 31z m-35 247c0 11-1 23-4 36-4 13-8 25-14 37-6 12-14 22-24 30-10 8-21 12-34 12-18 0-31-7-41-20-10-13-15-29-15-47 0-9 1-18 4-28 2-10 5-20 10-30 4-10 10-19 16-27 6-8 13-14 22-19 9-5 18-7 28-7 18 0 32 5 40 17 8 11 12 27 12 46z m-37 135l125 0-39-22-38 0c13-9 24-21 31-36 7-16 11-32 11-48 0-15-2-27-6-38-5-11-10-20-16-26-7-7-13-13-19-19-7-5-12-11-16-17-5-6-7-13-7-20 0-5 2-9 5-14 3-5 7-9 12-14 5-4 11-9 17-14 6-4 12-10 18-15 6-6 12-13 17-19 5-7 9-15 12-25 3-9 5-19 5-30 0-30-13-57-40-81-29-25-69-37-120-37-11 0-23 1-34 3-12 2-23 5-35 9-12 5-22 10-31 17-9 7-16 15-22 25-6 11-9 22-9 35 0 12 4 25 11 39 6 12 15 22 27 31 12 9 26 16 42 21 15 4 30 8 44 10 14 2 28 3 43 4-12 16-18 30-18 42 0 3 0 5 0 7 1 2 1 4 2 6 0 1 1 3 2 6 1 2 1 4 2 6-8-1-14-2-20-2-29 0-53 10-73 28-20 19-31 43-31 71 0 26 9 50 28 71 18 21 40 35 66 41 18 4 36 5 54 5z m297-73l0-36-73 0 0-73-37 0 0 73-73 0 0 36 73 0 0 73 37 0 0-73z"/>
<glyph glyph-name="language" unicode="&#67;" d="M256 475c40 0 77-9 110-29 34-20 60-46 80-80 20-33 29-70 29-110 0-40-9-77-29-110-20-34-46-60-80-80-33-20-70-29-110-29-40 0-77 9-110 29-34 20-60 46-80 80-20 33-29 70-29 110 0 40 9 77 29 110 20 34 46 60 80 80 33 20 70 29 110 29z m78-148c0-1-1-2-2-3-2-2-3-3-4-3 0 0 1 1 1 2 0 1 1 2 1 3 1 1 1 2 1 2 2 1 4 2 7 4 2 1 7 2 15 3 6 2 11 1 14-3 0 1 1 2 3 4 2 2 3 3 4 3 1 1 2 1 4 2 3 0 4 1 5 2l0 6c-2 0-4 1-5 2-1 2-2 4-2 6 0 0 0-1-1-2 0 1-1 2-2 2-1 0-2 0-3 0-1-1-2-1-3 0-1 0-3 1-4 2-1 1-2 2-2 4-1 3-1 4-1 5-1 1-2 2-3 3-1 1-2 2-3 3 0 0 0 1 0 1-1 1-1 2-1 2-1 1-1 1-1 2-1 0-1 0-2 0-1 0-1 0-2-1-1-1-1-2-2-3-1-1-1-1-1-1-1 0-2 0-2 0-1 0-1 0-1 0-1 0-1-1-2-1 0 0-1-1-1-1-1 0-2-1-3-1-1 0-1 0-2 0 3 1 3 2 0 3-2 0-4 1-5 1 2 0 3 1 2 3 0 2-1 3-2 4l1 0c0 1-1 2-2 2-2 1-3 2-5 3-2 1-3 1-4 2-1 1-5 1-10 2-5 1-8 1-9 0-1-1-1-2-1-3 0 0 0-2 1-4 1-1 1-3 1-3 0-1 0-3-2-4-1-1-2-2-2-3 0-2 2-3 4-5 3-1 4-3 3-6 0-1-2-3-4-4-3-2-4-3-5-4-1-1-1-3 0-5 0-2 1-4 3-5 0 0 0-1 0-1 0 0 0-1-1-1 0-1-1-1-1-1-1-1-2-1-2-1l-1-1c-2-1-4 0-6 2-2 2-3 4-4 7-1 5-3 8-4 9-5 1-8 1-9-1-1 3-5 5-11 8-5 2-11 2-17 1 1 0 1 2 0 4-1 3-3 4-5 4 0 1 1 3 1 5 0 2 0 3 0 4 1 2 2 4 3 6 1 0 1 1 2 3 2 1 2 2 3 3 1 2 1 2 0 2 7-1 12 0 15 3 1 1 2 3 3 5 1 2 2 4 3 5 2 1 3 2 4 2 1-1 2-1 4-2 2-1 3-1 4-1 3-1 4 0 5 3 0 2-1 4-3 5 3 0 3 2 1 5-1 2-1 2-2 3-2 1-5 0-8-2-1 0-1-1 1-2 0 0-1-1-3-3-1-2-3-4-5-5-1-1-3-1-4 2 0 0-1 1-2 3-1 3-1 4-2 4-2 0-3-1-5-4 1 2 0 3-3 4-3 2-5 2-7 3 4 2 3 4-2 7-2 1-4 2-6 2-3 0-5 0-6-1-1-2-1-3-1-4 0-1 0-1 1-2 1-1 2-1 3-2 1 0 2 0 3-1 2 0 2 0 3-1 3-1 3-3 2-4 0 0-1 0-2-1-2 0-3 0-4-1-1 0-1-1-1-1-1-1-1-2 0-4 0-2 0-3-1-4-1 1-2 3-2 5-1 2-2 4-2 5 1-2-1-3-8-2l-2 0c-1 0-3 0-5 0-2-1-4-1-6-1-1 1-3 1-4 3 0 1 0 3 0 5 0 1 1 1 1 1 0 1-1 1-3 3-1 1-2 2-3 2-8-3-17-7-26-12 1 0 2 0 3 1 1 0 2 1 4 2 1 0 2 1 3 1 6 3 10 3 12 2l1 2c3-3 5-6 6-8-2 1-4 1-9 1-4-1-6-3-6-4 1-2 2-4 1-5 0 1-2 2-3 3-1 1-3 2-4 3-1 1-3 1-4 2-3 0-6-1-7-1-28-15-50-36-67-63 1-1 3-2 4-2 0-1 1-1 1-3 0-2 0-3 1-3 0-1 1 0 3 1 2-2 2-4 1-6 0 0 4-2 12-7 4-4 6-6 6-6 1-3 0-4-2-6-1 1-1 2-3 3-2 1-2 2-3 1 0-1 0-3 1-5 0-3 1-4 3-4-2 0-3-1-3-4-1-3-1-7-1-10 0-4 0-6 0-7l0 0c0-3 0-6 2-10 2-5 4-6 6-6-2 0 0-5 6-12 1-2 2-3 2-3 1 0 2-1 4-2 1-1 3-2 4-3 1-1 2-2 3-3 0-1 1-3 3-6 1-3 2-6 4-7-1-1 0-3 2-6 2-2 3-4 3-6 0 0 0 0 0 0-1-1-1-1-1-1 0-1 2-2 4-4 3-1 4-2 5-3 0-1 0-2 0-3 0-2 1-3 1-3 1-1 1-1 2-1 1 4-1 10-6 18-3 4-5 7-5 8-1 1-1 2-2 4 0 2-1 4-1 5 0 0 1-1 2-1 0 0 1 0 2-1 1 0 2-1 2-1 1 0 1-1 1-1-1-1-1-3 0-5 1-2 2-4 4-5 1-2 3-3 5-6 1-2 3-3 3-3 1-1 2-3 4-6 2-2 2-4 0-4 2 0 4-1 6-3 2-1 3-3 5-5 1-2 1-4 2-8 0-3 1-5 1-7 1-1 1-2 3-3 1-2 2-3 3-3l5-2c0 0 1-1 4-2 1-1 2-2 5-3 2-2 4-3 6-4 2 0 3-1 5-1 1 0 2 0 4 1 1 0 3 1 4 1 2 0 5-1 8-4 3-4 5-6 6-6 7-4 12-5 16-4-1 0-1 0 0-2 0-1 1-2 2-4 1-2 2-3 3-4 0-1 1-2 1-3 1-1 3-2 5-4 3-2 4-3 5-4 2 0 2 1 2 2 0-1 1-3 2-5 2-3 4-4 6-3 2 0 4 3 4 9-6-3-11-1-14 5 0 0-1 1-1 2-1 0-1 1-1 2-1 1-1 2-1 2 0 1 0 2 0 3 0 0 1 0 1 0 2 0 3 1 3 1 0 1 0 2 0 4-1 2-1 3-1 4-1 1-2 3-4 5-1 3-3 4-3 5-1-2-2-3-5-3-2 1-3 1-4 3 0 0 0-1-1-2 0 0 0-1 0-1-2 0-4 0-4 0 0 0 0 2 0 5 1 3 1 5 1 6 1 1 1 2 2 4 1 1 2 3 2 4 1 1 1 2 1 3 0 2 0 2-1 3-1 1-3 1-5 1-4 0-6-2-7-6-1 0-1-1-1-3-1-1-1-2-2-3 0-1-1-2-2-2-2-1-4-1-7-1-3 0-6 1-7 2-2 1-5 4-6 8-2 4-3 8-3 11 0 1 0 4 1 7 0 3 0 6 0 7 1 2 0 4-1 7 0 1 1 2 2 3 2 1 3 2 3 3 1 0 1 0 2 0 0 1 0 1 1 0 0 0 1 0 1 1 0 0 1 1 1 2 0 0-1 0-1 0-1 1-1 1-1 1 1 0 4 0 8 1 4 1 6 0 8-1 2-2 5-2 6 1 0 0 0 1-1 3 0 1 0 2 0 3 1-5 4-6 8-2 1-1 2-1 5-2 2 0 4 0 5-1 0 0 1-1 2-2 0 0 1-1 1-1 1 0 1 0 2 0 0 1 1 1 2 2 2-3 3-5 4-7 2-7 3-12 5-12 1-1 2-1 3-1 1 0 1 1 1 3 1 1 1 3 0 4 0 1 0 2 0 3l0 3 0 5-1 2c-2 1-4 2-5 4-1 1 0 3 1 5 1 2 2 3 4 5 0 0 1 1 2 1 1 1 3 1 5 2 1 1 2 2 3 2 4 4 6 7 4 10 2 0 3 1 4 3-1 0-1 0-2 1-1 0-1 1-2 1-1 1-1 1-1 1 1 1 2 2 0 4 1 1 2 2 2 3 1 2 2 3 3 3 1-2 3-2 6 0 1 1 1 3 0 4 1 2 3 3 6 3 3 1 4 2 5 3 1 0 2 0 2 1 0 0 1 1 1 3 0 2 0 3 0 3 1 1 3 2 5 3 2 1 3 1 3 1l5 4c1 0 1 1 0 1 4-1 7 0 9 3 2 2 1 4-2 6 1 1 1 2 0 2-2 1-3 1-5 2 1 0 2 0 4 0 1 0 2 0 3 0 2 2 2 4-2 5-4 1-8 0-13-3z m-46-251c39 7 72 25 100 54-1 1-2 1-4 1-1 1-3 1-3 1-4 2-6 2-7 3 0 1 0 2-1 3 0 1-1 2-2 3-1 0-2 1-4 2-1 1-2 2-3 2 0 1-1 1-2 2-1 1-1 1-2 1 0 1-1 1-2 2-1 0-2 0-2 0-1 0-2 0-3 0l-1 0c-1 0-1-1-2-1 0 0-1-1-1-1-1 0-1 0-1-1 0 0 0 0 0 0-4 3-8 5-11 6-1 0-2 1-3 1-1 1-2 2-3 2-1 1-2 1-3 1-1 0-2-1-3-2-1-1-1-3-2-4 0-2 0-4 0-4-1 1-1 2 0 5 1 2 1 4 0 5 0 1-1 2-3 1-1 0-2 0-3-1-1 0-2-1-3-2-2-1-2-2-3-2 0 0-1-1-2-2-2-1-2-1-3-2 0-1-1-2-1-3-1-2-1-3-2-3 0 0-1 1-3 1-2 1-3 1-3 2 1-2 1-5 1-10 1-5 1-8 2-11 1-6 0-10-4-14-5-4-8-8-8-11-1-4 0-7 3-7 0-2 0-4-2-6-1-3-2-5-2-6 0-2 0-3 1-5z"/>
<glyph glyph-name="search" unicode="&#69;" d="M347 274c0 36-12 66-37 91-25 25-55 37-91 37-35 0-65-12-90-37-25-25-38-55-38-91 0-35 13-65 38-90 25-25 55-38 90-38 36 0 66 13 91 38 25 25 37 55 37 90z m147-237c0-10-4-19-11-26-7-7-16-11-26-11-10 0-19 4-26 11l-98 98c-34-24-72-36-114-36-27 0-53 5-78 16-25 11-46 25-64 43-18 18-32 39-43 64-10 25-16 51-16 78 0 28 6 54 16 78 11 25 25 47 43 65 18 18 39 32 64 43 25 10 51 15 78 15 28 0 54-5 79-15 24-11 46-25 64-43 18-18 32-40 43-65 10-24 16-50 16-78 0-42-12-80-36-114l98-98c7-7 11-15 11-25z"/>
<glyph glyph-name="external" unicode="&#70;" d="M402 247l0-92c0-22-8-42-24-58-16-16-35-24-58-24l-238 0c-22 0-42 8-58 24-16 16-24 36-24 58l0 238c0 23 8 42 24 58 16 16 36 24 58 24l201 0c3 0 5 0 7-2 2-2 3-4 3-7l0-18c0-3-1-5-3-7-2-1-4-2-7-2l-201 0c-12 0-23-5-32-14-9-9-13-19-13-32l0-238c0-12 4-23 13-32 9-9 20-13 32-13l238 0c13 0 23 4 32 13 9 9 14 20 14 32l0 92c0 3 1 5 2 6 2 2 4 3 7 3l18 0c3 0 5-1 7-3 1-1 2-3 2-6z m110 247l0-147c0-5-2-9-5-12-4-4-8-6-13-6-5 0-10 2-13 6l-50 50-187-186c-2-2-4-3-6-3-3 0-5 1-7 3l-32 32c-2 2-3 4-3 7 0 2 1 4 3 6l186 187-50 50c-4 3-6 8-6 13 0 5 2 9 6 13 3 3 7 5 12 5l147 0c5 0 9-2 13-5 3-4 5-8 5-13z"/>
<glyph glyph-name="video" unicode="&#68;" d="M438 99c14 0 25 11 25 26l0 262c0 15-11 26-25 26l-364 0c-14 0-25-11-25-26l0-262c0-15 11-26 25-26z m-26 51l-312 0 0 212 312 0z m-80 105l-61-36-62-35 0 141 62-35z"/>
@@ -45,4 +42,8 @@
<glyph glyph-name="box" unicode="&#73;" d="M311 274c0 5-2 10-6 13-3 4-7 6-12 6l-74 0c-5 0-9-2-12-6-4-3-6-8-6-13 0-5 2-9 6-13 3-3 7-5 12-5l74 0c5 0 9 2 12 5 4 4 6 8 6 13z m164 55l0-274c0-5-1-9-5-13-4-4-8-5-13-5l-402 0c-5 0-9 1-13 5-4 4-5 8-5 13l0 274c0 5 1 9 5 13 4 4 8 5 13 5l402 0c5 0 9-1 13-5 4-4 5-8 5-13z m19 128l0-73c0-5-2-9-6-13-3-3-8-5-13-5l-438 0c-5 0-10 2-13 5-4 4-6 8-6 13l0 73c0 5 2 9 6 13 3 4 8 5 13 5l438 0c5 0 10-1 13-5 4-4 6-8 6-13z"/>
<glyph glyph-name="youtube" unicode="&#75;" d="M314 157l0-61c0-12-4-19-11-19-5 0-9 2-13 6l0 86c4 5 8 7 13 7 7 0 11-7 11-19z m97-1l0-13-26 0 0 13c0 13 4 20 13 20 8 0 13-7 13-20z m-276 63l30 0 0 26-89 0 0-26 30 0 0-163 29 0z m82-163l25 0 0 141-25 0 0-108c-6-8-11-12-16-12-4 0-6 2-6 6-1 1-1 4-1 10l0 104-25 0 0-112c0-9 1-16 2-20 2-7 8-11 17-11 9 0 19 6 29 17z m122 42l0 57c0 13 0 23-2 28-3 11-10 16-20 16-10 0-19-5-27-16l0 62-25 0 0-189 25 0 0 14c9-11 17-16 27-16 10 0 17 5 20 16 2 5 2 14 2 28z m97 3l0 4-26 0c0-10 0-16-1-18-1-6-5-10-11-10-9 0-13 7-13 20l0 25 51 0 0 29c0 15-3 26-8 33-7 10-17 15-30 15-13 0-23-5-31-15-5-7-8-18-8-33l0-49c0-15 3-26 9-33 7-10 17-15 31-15 13 0 24 5 30 15 4 5 6 10 6 16 1 1 1 7 1 16z m-174 261l0 60c0 13-4 20-12 20-8 0-12-7-12-20l0-60c0-13 4-20 12-20 8 0 12 7 12 20z m206-215c0-44-3-77-8-100-2-11-8-20-16-28-9-7-18-12-29-13-35-4-88-6-159-6-71 0-124 2-159 6-11 1-20 6-29 13-8 8-14 17-16 28-5 22-8 55-8 100 0 45 3 78 8 100 2 12 8 21 16 29 9 7 18 12 30 13 35 4 87 6 158 6 71 0 124-2 159-6 11-1 20-6 29-13 8-8 14-17 16-29 5-21 8-54 8-100z m-285 365l29 0-35-114 0-77-28 0 0 77c-3 14-9 34-18 61-7 19-13 37-18 53l30 0 20-75z m105-95l0-50c0-16-2-27-8-34-7-10-17-14-30-14-13 0-23 4-30 14-5 7-8 19-8 34l0 50c0 15 3 26 8 33 7 10 17 15 30 15 13 0 23-5 30-15 6-7 8-18 8-33z m96 46l0-142-26 0 0 15c-10-12-20-17-29-17-9 0-15 3-17 10-2 5-3 12-3 22l0 112 26 0 0-105c0-6 1-9 1-10 0-4 2-6 6-6 5 0 10 4 16 12l0 109z"/>
<glyph glyph-name="letter" unicode="&#76;" d="M475 82l0 220c-6-7-12-13-19-19-51-39-92-72-122-97-10-8-18-14-24-19-6-4-14-9-24-14-11-4-21-7-30-7l0 0c-9 0-19 3-30 7-10 5-18 10-24 14-6 5-14 11-24 19-30 25-71 58-122 97-7 6-13 12-19 19l0-220c0-2 0-4 2-6 2-2 4-3 7-3l420 0c3 0 5 1 7 3 2 2 2 4 2 6z m0 301l0 7c0 0 0 1 0 3 0 3 0 4-1 4 0 0-1 1-1 2-1 2-2 3-3 3-1-1-2-1-4 0l-420 0c-3 0-5-1-7-2-2-2-2-4-2-7 0-32 14-59 42-81 36-29 75-59 114-91 1-1 5-3 10-8 6-5 10-8 13-11 4-2 8-5 13-9 5-3 10-6 14-8 5-1 9-2 13-2l0 0c4 0 8 1 13 2 4 2 9 5 14 8 5 4 9 7 13 9 3 3 7 6 13 11 5 5 9 7 10 8 39 32 78 62 114 91 11 8 20 19 29 33 9 14 13 26 13 38z m37 10l0-311c0-12-4-23-13-32-9-9-20-13-33-13l-420 0c-13 0-24 4-33 13-9 9-13 20-13 32l0 311c0 13 4 23 13 32 9 9 20 14 33 14l420 0c13 0 24-5 33-14 9-9 13-19 13-32z"/>
<glyph glyph-name="no-notification" unicode="&#120;" d="M261 27c0 3-2 5-5 5-11 0-21 4-29 12-8 8-12 18-12 29 0 3-2 5-5 5-3 0-4-2-4-5 0-14 5-26 14-35 10-10 22-15 36-15 3 0 5 1 5 4z m-154 136l251 217c-8 17-21 31-38 42-17 11-39 17-64 17-18 0-34-3-48-9-15-6-27-14-35-23-9-9-15-19-20-30-4-10-7-20-7-30 0-73-13-134-39-184z m387-53c0-10-4-19-11-26-7-7-16-11-26-11l-128 0c0-20-7-37-21-52-15-14-32-21-52-21-20 0-37 7-52 21-14 14-21 32-21 52l42 37 217 0c-32 35-54 79-65 131l32 28c11-68 40-121 85-159z m24 397l24-27c2-2 3-4 2-7 0-2-1-4-3-6l-534-464c-2-1-5-2-7-2-3 1-5 2-6 4l-24 27c-2 2-3 4-2 7 0 2 1 4 3 6l53 46c-4 6-6 12-6 19 10 8 18 16 26 25 8 9 16 20 25 34 8 14 15 29 21 45 6 16 10 36 14 59 4 23 6 48 6 74 0 29 11 56 33 81 22 25 52 40 88 45-2 4-2 8-2 12 0 7 2 14 8 19 5 5 11 8 19 8 8 0 14-3 19-8 6-5 8-12 8-19 0-4 0-8-2-12 24-3 45-11 63-23 18-12 32-27 42-45l119 104c2 1 5 2 7 2 3-1 5-2 6-4z"/>
<glyph glyph-name="notification" unicode="&#110;" d="M261 27c0 3-2 5-5 5-11 0-21 4-29 12-8 8-12 18-12 29 0 3-2 5-5 5-3 0-4-2-4-5 0-14 5-26 14-35 10-10 22-15 36-15 3 0 5 1 5 4z m233 83c0-10-4-19-11-26-7-7-16-11-26-11l-128 0c0-20-7-37-21-52-15-14-32-21-52-21-20 0-37 7-52 21-14 15-21 32-21 52l-128 0c-10 0-19 4-26 11-7 7-11 16-11 26 10 8 18 16 26 25 8 9 16 20 25 34 8 14 15 29 21 45 6 16 10 36 14 59 4 23 6 48 6 74 0 29 11 56 33 81 22 25 52 40 88 45-2 4-2 8-2 12 0 7 2 14 8 19 5 5 11 8 19 8 8 0 14-3 19-8 6-5 8-12 8-19 0-4 0-8-2-12 36-5 66-20 88-45 22-25 33-52 33-81 0-26 2-51 6-74 4-23 8-43 14-59 6-16 13-31 21-45 9-14 17-25 25-34 8-9 16-17 26-25z"/>
<glyph glyph-name="circle" unicode="&#67;" d="M475 256c0-40-9-77-29-110-20-34-46-60-80-80-33-20-70-29-110-29-40 0-77 9-110 29-34 20-60 46-80 80-20 33-29 70-29 110 0 40 9 77 29 110 20 34 46 60 80 80 33 20 70 29 110 29 40 0 77-9 110-29 34-20 60-46 80-80 20-33 29-70 29-110z"/>
<glyph glyph-name="circle-o" unicode="&#77;" d="M256 411c-28 0-54-7-78-20-24-14-43-33-57-57-13-24-20-50-20-78 0-28 7-54 20-78 14-24 33-43 57-57 24-13 50-20 78-20 28 0 54 7 78 20 24 14 43 33 57 57 13 24 20 50 20 78 0 28-7 54-20 78-14 24-33 43-57 57-24 13-50 20-78 20z m219-155c0-40-9-77-29-110-20-34-46-60-80-80-33-20-70-29-110-29-40 0-77 9-110 29-34 20-60 46-80 80-20 33-29 70-29 110 0 40 9 77 29 110 20 34 46 60 80 80 33 20 70 29 110 29 40 0 77-9 110-29 34-20 60-46 80-80 20-33 29-70 29-110z"/>
</font></defs></svg>

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Binary file not shown.

View File

@@ -38,116 +38,119 @@
}
.icon-angle-down:before {
content: "a";
content: "\61";
}
.icon-angle-left:before {
content: "b";
content: "\62";
}
.icon-angle-right:before {
content: "c";
content: "\63";
}
.icon-angle-up:before {
content: "d";
content: "\64";
}
.icon-comments:before {
content: "e";
content: "\65";
}
.icon-twitter:before {
content: "f";
content: "\66";
}
.icon-calendar:before {
content: "g";
content: "\67";
}
.icon-debates:before {
content: "i";
content: "\69";
}
.icon-unlike:before {
content: "j";
content: "\6a";
}
.icon-like:before {
content: "k";
content: "\6b";
}
.icon-check:before {
content: "l";
content: "\6c";
}
.icon-edit:before {
content: "m";
}
.icon-star:before {
content: "n";
content: "\6d";
}
.icon-user:before {
content: "o";
content: "\6f";
}
.icon-settings:before {
content: "q";
content: "\71";
}
.icon-stats:before {
content: "r";
content: "\72";
}
.icon-proposals:before {
content: "h";
content: "\68";
}
.icon-organizations:before {
content: "s";
content: "\73";
}
.icon-deleted:before {
content: "t";
content: "\74";
}
.icon-tag:before {
content: "u";
content: "\75";
}
.icon-eye:before {
content: "p";
content: "\70";
}
.icon-x:before {
content: "v";
content: "\76";
}
.icon-flag:before {
content: "w";
}
.icon-notification:before {
content: "x";
content: "\77";
}
.icon-comment:before {
content: "y";
content: "\79";
}
.icon-reply:before {
content: "z";
content: "\7a";
}
.icon-facebook:before {
content: "A";
content: "\41";
}
.icon-google-plus:before {
content: "B";
}
.icon-language:before {
content: "C";
content: "\42";
}
.icon-search:before {
content: "E";
content: "\45";
}
.icon-external:before {
content: "F";
content: "\46";
}
.icon-video:before {
content: "D";
content: "\44";
}
.icon-document:before {
content: "G";
content: "\47";
}
.icon-print:before {
content: "H";
content: "\48";
}
.icon-blog:before {
content: "J";
content: "\4a";
}
.icon-box:before {
content: "I";
content: "\49";
}
.icon-youtube:before {
content: "K";
content: "\4b";
}
.icon-letter:before {
content: "L";
}
content: "\4c";
}
.icon-no-notification:before {
content: "\78";
}
.icon-notification:before {
content: "\6e";
}
.icon-circle:before {
content: "\43";
}
.icon-circle-o:before {
content: "\4d";
}

View File

@@ -396,7 +396,6 @@ header {
&:hover {
background: none;
color: white;
text-decoration: underline;
transition: text-decoration 275ms;
}
@@ -420,6 +419,7 @@ header {
&:hover, &:focus {
background-color: #007095 !important;
text-decoration: underline;
}
}
@@ -947,6 +947,77 @@ img.avatar, img.admin-avatar, img.moderator-avatar, img.initialjs-avatar {
}
}
.notifications {
position: relative;
&:hover {
text-decoration: none;
}
[class^="icon-"] {
font-size: $h4-font-size;
vertical-align: middle;
}
.icon-circle {
color: #ecf00b;
font-size: $tiny-font-size;
position: absolute;
right: 4px;
top: -6px;
}
}
.notifications-list:before {
background: $border;
content: '';
height: 100%;
left: 28px;
position: absolute;
top: 0;
width: 2px;
}
.notification {
display: block;
padding: $line-height/2 0 $line-height/2 $line-height*1.5;
position: relative;
&:hover {
a {
text-decoration: none;
}
p:not(.time) {
color: $link;
}
&:before {
content: "\43";
}
}
&:before {
background: white;
color: $brand;
content: "\4d";
font-family: "icons" !important;
left: 6px;
position: absolute;
}
p {
color: $text;
margin-bottom: 0;
}
.time {
font-size: $small-font-size;
color: $text-medium;
}
}
// 09. Filters & search
// - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -1574,7 +1645,6 @@ table {
font-family: $font-sans;
font-size: $small-font-size;
line-height: $line-height;
margin: rem-calc(10) $line-height/2 $line-height/4 0;
a {
color: $text-light;
@@ -1595,15 +1665,12 @@ table {
.comment-body {
margin-left: rem-calc(42);
p {
font-size: $small-font-size;
}
.reply {
background: white;
border: 1px solid $border;
font-family: $font-sans;
font-size: rem-calc(12);
border-left: 0;
border-right: 0;
font-size: $small-font-size;
margin: rem-calc(6) 0;
padding: rem-calc(6);

View File

@@ -39,6 +39,7 @@ $h6-font-size: rem-calc(13);
$h6-line-height: rem-calc(17);
$small-font-size: rem-calc(14);
$tiny-font-size: rem-calc(10);
$line-height: rem-calc(24);
// 02. Colors

View File

@@ -108,4 +108,5 @@ class ApplicationController < ActionController::Base
store_location_for(:user, request.path)
end
end
end

View File

@@ -1,5 +1,5 @@
class CommentsController < ApplicationController
before_action :authenticate_user!
before_action :authenticate_user!, only: :create
before_action :load_commentable, only: :create
before_action :build_comment, only: :create
@@ -9,11 +9,17 @@ class CommentsController < ApplicationController
def create
if @comment.save
CommentNotifier.new(comment: @comment).process
add_notification @comment
else
render :new
end
end
def show
@comment = Comment.find(params[:id])
set_comment_flags(@comment.subtree)
end
def vote
@comment.vote_by(voter: current_user, vote: params[:value])
respond_with @comment
@@ -62,4 +68,13 @@ class CommentsController < ApplicationController
["1", true].include?(comment_params[:as_moderator]) && can?(:comment_as_moderator, @commentable)
end
def add_notification(comment)
if comment.reply?
notifiable = comment.parent
else
notifiable = comment.commentable
end
Notification.add(notifiable.author_id, notifiable) unless comment.author_id == notifiable.author_id
end
end

View File

@@ -0,0 +1,26 @@
class NotificationsController < ApplicationController
before_action :authenticate_user!
after_action :mark_as_read, only: :show
skip_authorization_check
def index
@notifications = current_user.notifications.unread.recent.for_render
end
def show
@notification = current_user.notifications.find(params[:id])
redirect_to url_for(@notification.notifiable)
end
def mark_all_as_read
current_user.notifications.each { |notification| notification.mark_as_read }
redirect_to notifications_path
end
private
def mark_as_read
@notification.mark_as_read
end
end

View File

@@ -13,8 +13,11 @@ module CommentsHelper
end
def child_comments_of(parent)
return [] unless @comment_tree
@comment_tree.children_of(parent)
if @comment_tree.present?
@comment_tree.ordered_children_of(parent)
else
parent.children
end
end
def user_level_class(comment)

View File

@@ -0,0 +1,6 @@
module NotificationsHelper
def notification_action(notification)
notification.notifiable_type == "Comment" ? "replies_to" : "comments_on"
end
end

View File

@@ -5,6 +5,7 @@ module Abilities
def initialize(user)
can :read, Debate
can :read, Proposal
can :read, Comment
can :read, Legislation
can :read, User
can [:search, :read], Annotation

View File

@@ -1,5 +1,4 @@
class Activity < ActiveRecord::Base
belongs_to :actionable, -> { with_hidden }, polymorphic: true
belongs_to :user, -> { with_hidden }
@@ -24,5 +23,4 @@ class Activity < ActiveRecord::Base
def self.by(user)
where(user: user)
end
end

View File

@@ -0,0 +1,24 @@
class Notification < ActiveRecord::Base
belongs_to :user, counter_cache: true
belongs_to :notifiable, polymorphic: true
scope :unread, -> { all }
scope :recent, -> { order(id: :desc) }
scope :for_render, -> { includes(:notifiable) }
def timestamp
notifiable.created_at
end
def mark_as_read
self.destroy
end
def self.add(user_id, notifiable)
if notification = Notification.find_by(user_id: user_id, notifiable: notifiable)
Notification.increment_counter(:counter, notification.id)
else
Notification.create!(user_id: user_id, notifiable: notifiable)
end
end
end

View File

@@ -22,6 +22,7 @@ class User < ActiveRecord::Base
has_many :proposals, -> { with_hidden }, foreign_key: :author_id
has_many :comments, -> { with_hidden }
has_many :failed_census_calls
has_many :notifications
validates :username, presence: true, if: :username_required?
validates :username, uniqueness: true, if: :username_required?
@@ -199,7 +200,7 @@ class User < ActiveRecord::Base
def email_required?
!erased?
end
def has_official_email?
domain = Setting.value_for 'email_domain_for_officials'
!email.blank? && ( (email.end_with? "@#{domain}") || (email.end_with? ".#{domain}") )

View File

@@ -1,9 +1,9 @@
<% cache [locale_and_user_status(comment), comment, commentable_cache_key(@commentable), comment.author, (@comment_flags[comment.id] if @comment_flags)] do %>
<% cache [locale_and_user_status(comment), comment, commentable_cache_key(comment.commentable), comment.author, (@comment_flags[comment.id] if @comment_flags)] do %>
<div class="row">
<div id="<%= dom_id(comment) %>" class="comment small-12 column">
<% if comment.hidden? || comment.user.hidden? %>
<% if child_comments_of(comment).size > 0 %>
<% if comment.children.size > 0 %>
<div class="is-deleted">
<p><%= t("comments.comment.deleted") %></p>
</div>
@@ -49,7 +49,7 @@
<%= t("shared.collective") %>
</span>
<% end %>
<% if comment.user_id == @commentable.author_id %>
<% if comment.user_id == comment.commentable.author_id %>
&nbsp;&bull;&nbsp;
<span class="label round is-author">
<%= t("comments.comment.author") %>
@@ -63,16 +63,16 @@
<div class="comment-user
<%= user_level_class comment %>
<%= comment_author_class comment, @commentable.author_id %>">
<%= comment_author_class comment, comment.commentable.author_id %>">
<%= simple_format text_with_links comment.body %>
</div>
<span id="<%= dom_id(comment) %>_votes" class="comment-votes right">
<%= render 'comments/votes', comment: comment %>
</span>
<div id="<%= dom_id(comment) %>_reply" class="reply">
<span id="<%= dom_id(comment) %>_votes" class="comment-votes right">
<%= render 'comments/votes', comment: comment %>
</span>
<div class="reply">
<%= t("comments.comment.responses", count: child_comments_of(comment).size) %>
<%= t("comments.comment.responses", count: comment.children.size) %>
<% if user_signed_in? %>
<span class="divider">&nbsp;|&nbsp;</span>
@@ -81,11 +81,12 @@
<%= render 'comments/actions', comment: comment %>
<%= render 'comments/form', {commentable: @commentable, parent_id: comment.id, toggeable: true} %>
<%= render 'comments/form', {commentable: comment.commentable, parent_id: comment.id, toggeable: true} %>
<% end %>
</div>
</div>
<% end %>
<div class="comment-children">
<% child_comments_of(comment).each do |child| %>
<%= render 'comments/comment', comment: child %>

View File

@@ -0,0 +1,16 @@
<div class="row">
<div class="small-12 column margin-top">
<%= link_to @comment.commentable, class: "left back" do %>
<i class="icon-angle-left left"></i>
<%= t("comments.show.return_to_commentable") + @comment.commentable.title %>
<% end %>
</div>
</div>
<section class="comments">
<div class="row">
<div id="comments" class="small-12 column">
<%= render @comment %>
</div>
</div>
</section>

View File

@@ -1,5 +1,16 @@
<ul class="right">
<% if user_signed_in? %>
<li>
<%= link_to notifications_path, class: "notifications" do %>
<% if current_user.notifications_count > 0 %>
<i class="icon-circle"></i>
<i class="icon-notification" title="<%= t('layouts.header.new_notifications', count: current_user.notifications_count).html_safe %>">
</i>
<% else %>
<i class="icon-no-notification" title="<%= t('layouts.header.no_notifications') %>"></i>
<% end %>
<% end %>
</li>
<li>
<%= link_to(t("layouts.header.my_activity_link"), user_path(current_user)) %>
</li>

View File

@@ -0,0 +1,9 @@
<li id="<%= dom_id(notification) %>" class="notification">
<%= link_to notification do %>
<p>
<em><%= t("notifications.index.#{notification_action(notification)}", count: notification.counter) %></em>
<strong><%= notification.notifiable.is_a?(Comment) ? notification.notifiable.commentable.title : notification.notifiable.title %></strong>
</p>
<p class="time"><%= l notification.timestamp, format: :datetime %></p>
<% end %>
</li>

View File

@@ -0,0 +1,18 @@
<div class="row">
<div class="small-12 column">
<% if @notifications.empty? %>
<div class="alert-box radius info margin-top">
<%= t("notifications.index.empty_notifications") %>
</div>
<% else %>
<div class="right margin-top">
<%= link_to t("notifications.index.mark_all_as_read"),
mark_all_as_read_notifications_path, method: :put %>
</div>
<ul class="no-bullet clear notifications-list">
<%= render @notifications %>
</ul>
<% end %>
</div>
</div>

View File

@@ -127,6 +127,8 @@ ignore_unused:
- 'proposals.index.select_order'
- 'proposals.index.orders.*'
- 'proposals.index.search_form.*'
- 'notifications.index.comments_on*'
- 'notifications.index.replies_to*'
- 'helpers.page_entries_info.*' # kaminari
- 'views.pagination.*' # kaminari
# - '{devise,kaminari,will_paginate}.*'

View File

@@ -29,6 +29,10 @@ en:
more_information: "More information"
debates: "Debates"
proposals: "Proposals"
new_notifications:
one: "You have a new notification"
other: "You have %{count} new notifications"
no_notifications: "You don't have new notifications"
footer:
description: "This portal uses the %{consul} which is %{open_source}. From Madrid out into the world."
open_source: "open-source software"
@@ -241,6 +245,8 @@ en:
form:
submit_button: "Save changes"
comments:
show:
return_to_commentable: "Go back to "
select_order: "Sort by"
orders:
most_voted: "Most voted"
@@ -307,6 +313,16 @@ en:
user_permission_votes: "Participate on final voting"
user_permission_verify: "To perform all the actions verify your account."
user_permission_verify_info: "* Only for users on Madrid City Census."
notifications:
index:
mark_all_as_read: "Mark all as read"
empty_notifications: "You don't have new notifications."
comments_on:
one: "Someone commented on"
other: "There are %{count} new comments on"
replies_to:
one: "Someone replied to your comment on"
other: "There are %{count} new replies to your comment on"
simple_captcha:
placeholder: "Enter the text from the image"
label: "Enter the text from the image in the box below"

View File

@@ -29,6 +29,10 @@ es:
more_information: "Más información"
debates: "Debates"
proposals: "Propuestas"
new_notifications:
one: "Tienes una nueva notificación"
other: "Tienes %{count} notificaciones nuevas"
no_notifications: "No tienes notificaciones nuevas"
footer:
description: "Este portal usa la %{consul} que es %{open_source}. De Madrid, para el mundo entero."
open_source: "software libre"
@@ -241,6 +245,8 @@ es:
form:
submit_button: "Guardar cambios"
comments:
show:
return_to_commentable: "Volver a "
select_order: "Ordenar por"
orders:
most_voted: "Más votados"
@@ -307,6 +313,16 @@ es:
user_permission_votes: "Participar en las votaciones finales*"
user_permission_verify: "Para poder realizar todas las acciones verifica tu cuenta."
user_permission_verify_info: "* Sólo usuarios empadronados en el municipio de Madrid."
notifications:
index:
mark_all_as_read: "Marcar todas como leídas"
empty_notifications: "No tienes notificaciones nuevas."
comments_on:
one: "Hay un nuevo comentario en"
other: "Hay %{count} comentarios nuevos en"
replies_to:
one: "Hay una respuesta nueva a tu comentario en"
other: "Hay %{count} nuevas respuestas a tu comentario en"
simple_captcha:
placeholder: "Introduce el texto de la imagen"
label: "Introduce el texto de la imagen en la siguiente caja"

View File

@@ -53,7 +53,7 @@ Rails.application.routes.draw do
end
end
resources :comments, only: :create, shallow: true do
resources :comments, only: [:create, :show], shallow: true do
member do
post :vote
put :flag
@@ -74,6 +74,11 @@ Rails.application.routes.draw do
resource :account, controller: "account", only: [:show, :update, :delete] do
collection { get :erase }
end
resources :notifications, only: [:index, :show] do
collection { put :mark_all_as_read }
end
resource :verification, controller: "verification", only: [:show]
scope module: :verification do

View File

@@ -0,0 +1,9 @@
class CreateNotifications < ActiveRecord::Migration
def change
create_table :notifications do |t|
t.belongs_to :user, index: true, foreign_key: true
t.belongs_to :activity, index: true, foreign_key: true
t.boolean :read, default: false
end
end
end

View File

@@ -0,0 +1,10 @@
class MergeActivitiesAndNotifications < ActiveRecord::Migration
def change
change_table :notifications do |t|
t.remove :read
t.remove :activity_id
t.references :notifiable, polymorphic: true
end
end
end

View File

@@ -0,0 +1,5 @@
class AddCounterToNotifications < ActiveRecord::Migration
def change
add_column :notifications, :counter, :integer, default: 1
end
end

View File

@@ -0,0 +1,5 @@
class AddNotificationsCounterCacheToUser < ActiveRecord::Migration
def change
add_column :users, :notifications_count, :integer, default: 0
end
end

View File

@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20151215165824) do
ActiveRecord::Schema.define(version: 20160108133501) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -204,6 +204,15 @@ ActiveRecord::Schema.define(version: 20151215165824) do
add_index "moderators", ["user_id"], name: "index_moderators_on_user_id", using: :btree
create_table "notifications", force: :cascade do |t|
t.integer "user_id"
t.integer "notifiable_id"
t.string "notifiable_type"
t.integer "counter", default: 1
end
add_index "notifications", ["user_id"], name: "index_notifications_on_user_id", using: :btree
create_table "organizations", force: :cascade do |t|
t.integer "user_id"
t.string "name", limit: 60
@@ -330,6 +339,7 @@ ActiveRecord::Schema.define(version: 20151215165824) do
t.datetime "erased_at"
t.boolean "public_activity", default: true
t.boolean "newsletter", default: false
t.integer "notifications_count", default: 0
end
add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree
@@ -404,5 +414,6 @@ ActiveRecord::Schema.define(version: 20151215165824) do
add_foreign_key "identities", "users"
add_foreign_key "locks", "users"
add_foreign_key "moderators", "users"
add_foreign_key "notifications", "users"
add_foreign_key "organizations", "users"
end

View File

@@ -2,24 +2,34 @@ class CommentTree
ROOT_COMMENTS_PER_PAGE = 10
attr_accessor :root_comments, :comments
attr_accessor :root_comments, :comments, :commentable, :page, :order
def initialize(commentable, page, order = 'confidence_score')
@root_comments = commentable.comments.roots.send("sort_by_#{order}").page(page).per(ROOT_COMMENTS_PER_PAGE).for_render
root_descendants = @root_comments.each_with_object([]) do |root, col|
col.concat(Comment.descendants_of(root).send("sort_descendants_by_#{order}").for_render.to_a)
end
@commentable = commentable
@page = page
@order = order
@comments = root_comments + root_descendants
end
@comments_by_parent_id = @comments.each_with_object({}) do |comment, col|
(col[comment.parent_id] ||= []) << comment
def root_comments
commentable.comments.roots.send("sort_by_#{order}").page(page).per(ROOT_COMMENTS_PER_PAGE).for_render
end
def root_descendants
root_comments.each_with_object([]) do |root, array|
array.concat(Comment.descendants_of(root).send("sort_descendants_by_#{order}").for_render.to_a)
end
end
def children_of(parent)
@comments_by_parent_id[parent.id] || []
def ordered_children_of(parent)
comments_by_parent_id[parent.id] || []
end
def comments_by_parent_id
comments.each_with_object({}) do |comment, array|
(array[comment.parent_id] ||= []) << comment
end
end
def comment_authors

View File

@@ -290,4 +290,9 @@ FactoryGirl.define do
sequence(:track_id) { |n| "#{n}" }
end
factory :notification do
user
association :notifiable, factory: :proposal
end
end

View File

@@ -20,6 +20,21 @@ feature 'Commenting debates' do
end
end
scenario 'Show' do
parent_comment = create(:comment, commentable: debate)
first_child = create(:comment, commentable: debate, parent: parent_comment)
second_child = create(:comment, commentable: debate, parent: parent_comment)
visit comment_path(parent_comment)
expect(page).to have_css(".comment", count: 3)
expect(page).to have_content parent_comment.body
expect(page).to have_content first_child.body
expect(page).to have_content second_child.body
expect(page).to have_link "Go back to #{debate.title}", debate_path(debate)
end
scenario 'Comment order' do
c1 = create(:comment, :with_confidence_score, commentable: debate, cached_votes_up: 100, cached_votes_total: 120, created_at: Time.now - 2)
c2 = create(:comment, :with_confidence_score, commentable: debate, cached_votes_up: 10, cached_votes_total: 12, created_at: Time.now - 1)
@@ -254,7 +269,7 @@ feature 'Commenting debates' do
fill_in "comment-body-debate_#{debate.id}", with: 'Testing submit button!'
click_button 'Publish comment'
# The button's text should now be "..."
# This should be checked before the Ajax request is finished
expect(page).to_not have_button 'Publish comment'

View File

@@ -20,6 +20,21 @@ feature 'Commenting proposals' do
end
end
scenario 'Show' do
parent_comment = create(:comment, commentable: proposal)
first_child = create(:comment, commentable: proposal, parent: parent_comment)
second_child = create(:comment, commentable: proposal, parent: parent_comment)
visit comment_path(parent_comment)
expect(page).to have_css(".comment", count: 3)
expect(page).to have_content parent_comment.body
expect(page).to have_content first_child.body
expect(page).to have_content second_child.body
expect(page).to have_link "Go back to #{proposal.title}", proposal_path(proposal)
end
scenario 'Comment order' do
c1 = create(:comment, :with_confidence_score, commentable: proposal, cached_votes_up: 100, cached_votes_total: 120, created_at: Time.now - 2)
c2 = create(:comment, :with_confidence_score, commentable: proposal, cached_votes_up: 10, cached_votes_total: 12, created_at: Time.now - 1)

View File

@@ -0,0 +1,192 @@
require 'rails_helper'
feature "Notifications" do
let(:author) { create :user }
let(:user) { create :user }
let(:debate) { create :debate, author: author }
let(:proposal) { create :proposal, author: author }
scenario "User commented on my debate", :js do
login_as user
visit debate_path debate
fill_in "comment-body-debate_#{debate.id}", with: "I commented on your debate"
click_button "Publish comment"
within "#comments" do
expect(page).to have_content "I commented on your debate"
end
logout
login_as author
visit root_path
find(".icon-notification").click
expect(page).to have_css ".notification", count: 1
expect(page).to have_content "Someone commented on"
expect(page).to have_xpath "//a[@href='#{notification_path(Notification.last)}']"
end
scenario "Multiple comments on my proposal", :js do
login_as user
visit proposal_path proposal
fill_in "comment-body-proposal_#{proposal.id}", with: "I agree"
click_button "Publish comment"
within "#comments" do
expect(page).to have_content "I agree"
end
logout
login_as create(:user)
visit proposal_path proposal
fill_in "comment-body-proposal_#{proposal.id}", with: "I disagree"
click_button "Publish comment"
within "#comments" do
expect(page).to have_content "I disagree"
end
logout
login_as author
visit root_path
find(".icon-notification").click
expect(page).to have_css ".notification", count: 1
expect(page).to have_content "There are 2 new comments on"
expect(page).to have_xpath "//a[@href='#{notification_path(Notification.last)}']"
end
scenario "User replied to my comment", :js do
comment = create :comment, commentable: debate, user: author
login_as user
visit debate_path debate
click_link "Reply"
within "#js-comment-form-comment_#{comment.id}" do
fill_in "comment-body-comment_#{comment.id}", with: "I replied to your comment"
click_button "Publish reply"
end
within "#comment_#{comment.id}" do
expect(page).to have_content "I replied to your comment"
end
logout
login_as author
visit root_path
find(".icon-notification").click
expect(page).to have_css ".notification", count: 1
expect(page).to have_content "Someone replied to your comment on"
expect(page).to have_xpath "//a[@href='#{notification_path(Notification.last)}']"
end
scenario "Multiple replies to my comment", :js do
comment = create :comment, commentable: debate, user: author
3.times do |n|
login_as create(:user)
visit debate_path debate
within("#comment_#{comment.id}_reply") { click_link "Reply" }
within "#js-comment-form-comment_#{comment.id}" do
fill_in "comment-body-comment_#{comment.id}", with: "Reply number #{n}"
click_button "Publish reply"
end
within "#comment_#{comment.id}" do
expect(page).to have_content "Reply number #{n}"
end
logout
end
login_as author
visit root_path
find(".icon-notification").click
expect(page).to have_css ".notification", count: 1
expect(page).to have_content "There are 3 new replies to your comment on"
expect(page).to have_xpath "//a[@href='#{notification_path(Notification.last)}']"
end
scenario "Author commented on his own debate", :js do
login_as author
visit debate_path debate
fill_in "comment-body-debate_#{debate.id}", with: "I commented on my own debate"
click_button "Publish comment"
within "#comments" do
expect(page).to have_content "I commented on my own debate"
end
find(".icon-no-notification").click
expect(page).to have_css ".notification", count: 0
end
scenario "Author replied to his own comment", :js do
comment = create :comment, commentable: debate, user: author
login_as author
visit debate_path debate
click_link "Reply"
within "#js-comment-form-comment_#{comment.id}" do
fill_in "comment-body-comment_#{comment.id}", with: "I replied to my own comment"
click_button "Publish reply"
end
within "#comment_#{comment.id}" do
expect(page).to have_content "I replied to my own comment"
end
find(".icon-no-notification")
visit notifications_path
expect(page).to have_css ".notification", count: 0
end
context "mark as read" do
scenario "mark a single notification as read" do
user = create :user
notification = create :notification, user: user
login_as user
visit notifications_path
expect(page).to have_css ".notification", count: 1
first(".notification a").click
visit notifications_path
expect(page).to have_css ".notification", count: 0
end
scenario "mark all notifications as read" do
user = create :user
2.times { create :notification, user: user }
login_as user
visit notifications_path
expect(page).to have_css ".notification", count: 2
click_link "Mark all as read"
expect(page).to have_css ".notification", count: 0
expect(current_path).to eq(notifications_path)
end
end
scenario "no notifications" do
login_as user
visit notifications_path
expect(page).to have_content "You don't have new notifications"
end
end

View File

@@ -0,0 +1,25 @@
require 'rails_helper'
describe NotificationsHelper do
describe "#notification_action" do
let(:debate) { create :debate }
let(:debate_comment) { create :comment, commentable: debate }
context "when action was comment on a debate" do
it "returns correct text when someone comments on your debate" do
notification = create :notification, notifiable: debate
expect(notification_action(notification)).to eq "comments_on"
end
end
context "when action was comment on a debate" do
it "returns correct text when someone replies to your comment" do
notification = create :notification, notifiable: debate_comment
expect(notification_action(notification)).to eq "replies_to"
end
end
end
end

View File

@@ -21,4 +21,6 @@ describe "Abilities::Everyone" do
it { should_not be_able_to(:vote, Proposal) }
it { should_not be_able_to(:flag, Proposal) }
it { should_not be_able_to(:unflag, Proposal) }
it { should be_able_to(:show, Comment) }
end

View File

@@ -128,4 +128,5 @@ describe Comment do
expect(Comment.not_as_admin_or_moderator.first).to eq(comment1)
end
end
end

View File

@@ -0,0 +1,50 @@
require 'rails_helper'
describe Notification do
describe "#unread (scope)" do
it "returns only unread notifications" do
2.times { create :notification }
expect(Notification.unread.size).to be 2
end
end
describe "#recent (scope)" do
it "returns notifications sorted by id descendant" do
old_notification = create :notification
new_notification = create :notification
sorted_notifications = Notification.recent
expect(sorted_notifications.size).to be 2
expect(sorted_notifications.first).to eq new_notification
expect(sorted_notifications.last).to eq old_notification
end
end
describe "#for_render (scope)" do
it "returns notifications including notifiable and user" do
expect(Notification).to receive(:includes).with(:notifiable).exactly(:once)
Notification.for_render
end
end
describe "#timestamp" do
it "returns the timestamp of the trackable object" do
comment = create :comment
notification = create :notification, notifiable: comment
expect(notification.timestamp).to eq comment.created_at
end
end
describe "#mark_as_read" do
it "destroys notification" do
notification = create :notification
expect(Notification.unread.size).to eq 1
notification.mark_as_read
expect(Notification.unread.size).to eq 0
end
end
end