Commit 67fbbbe2088f5137b15e396b7defe60e8cb121ac

Authored by Leonardo Merlin
2 parents 0606c9a0 5f71cad8

Merge branch 'refact-home'

Showing 169 changed files with 4690 additions and 1213 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 169 files displayed.

bower.json
... ... @@ -11,7 +11,10 @@
11 11 "bootstrap-sass-official": "~3.3.4",
12 12 "animate.css": "~3.3.0",
13 13 "angular": "~1.4.0",
14   - "modernizr": "~2.8.3"
  14 + "modernizr": "~2.8.3",
  15 + "angular-slugify": "~1.0.1",
  16 + "open-sans-fontface": "~1.4.2",
  17 + "angular-social-links": "~0.0.19"
15 18 },
16 19 "devDependencies": {
17 20 "angular-mocks": "~1.4.0"
... ...
data.js 0 → 100644
... ... @@ -0,0 +1,738 @@
  1 +/**
  2 + * Use https://github.com/typicode/json-server for fake endpoint server.
  3 + * Example: $ json-server data.js -p 9000 -w data.js
  4 + */
  5 +module.exports = function () {
  6 + 'use strict';
  7 + var data = {};
  8 +
  9 + // add /api/v1/articles path
  10 + // data.api = {};
  11 + // data.api.v1 = {};
  12 + // data.api.v1.articles = [];
  13 +
  14 + // add data to articles path
  15 + // data.api.v1.articles.push({
  16 + data.articles = [];
  17 +
  18 + // json get from hom on 26/08/2015
  19 + var articleHome = {
  20 + id: 103358,
  21 + "article":{
  22 + "id": 103358,
  23 + "abstract": "<p style=\"text-align: center;\"><iframe src=\"https://www.youtube.com/embed/kpAdrO-emV0?rel=0&amp;showinfo=0&amp;iv_load_policy=3&amp;controls=1\" style=\"max-width: 1000px; left: 5%;\" width=\"275\" height=\"200\"></iframe></p>",
  24 +
  25 + "title": "Dialoga Brasil",
  26 + "categories": [
  27 + {
  28 + "name": "Saúde",
  29 + "id": 180,
  30 + "slug": "saude",
  31 + "image": null
  32 + },
  33 + {
  34 + "name": "Segurança Pública",
  35 + "id": 182,
  36 + "slug": "seguranca-publica",
  37 + "image": null
  38 + },
  39 + {
  40 + "name": "Educação",
  41 + "id": 181,
  42 + "slug": "educacao",
  43 + "image": null
  44 + },
  45 + {
  46 + "name": "Redução da Pobreza",
  47 + "id": 183,
  48 + "slug": "reducao-da-pobreza",
  49 + "image": null
  50 + },
  51 + {
  52 + "name": "Cultura",
  53 + "id": 194,
  54 + "slug": "cultura",
  55 + "image": null
  56 + }
  57 + ],
  58 + "image": null,
  59 + "setting": {
  60 + "custom_body_label": "Corpo",
  61 + "phase": "proposals",
  62 + "allow_topics": true,
  63 + "moderate_comments": false,
  64 + "comment_paragraph_plugin_activate": false,
  65 + "author_name": "Leandro Nunes dos Santos",
  66 + "moderate_proposals": true,
  67 + "allow_members_to_edit": false
  68 + },
  69 + "position": null,
  70 + "children": [
  71 + {
  72 + "id": 103390,
  73 + "abstract": "<p>Prevenção, tratamento e enfrentamento ao tráfico.</p>",
  74 + "title": "Crack, é possível vencer!",
  75 + "categories": [
  76 + {
  77 + "name": "Segurança Pública",
  78 + "id": 182,
  79 + "slug": "seguranca-publica",
  80 + "image": null
  81 + }
  82 + ],
  83 + "image": {
  84 + "url": "/image_uploads/dialoga/0000/0104/crack.jpg"
  85 + },
  86 + "setting": {
  87 + "color": "#00ff00",
  88 + "moderate_comments": false,
  89 + "comment_paragraph_plugin_activate": false,
  90 + "author_name": "Ronald Emerson Scherolt da Costa",
  91 + "allow_members_to_edit": false
  92 + },
  93 + "position": 14
  94 + },
  95 + {
  96 + "id": 103521,
  97 + "abstract": "<p>Mais atendimento nos municípios, mais saúde para quem mais precisa.</p>",
  98 + "title": "Mais Médicos",
  99 + "categories": [
  100 + {
  101 + "name": "Saúde",
  102 + "id": 180,
  103 + "slug": "saude",
  104 + "image": null
  105 + }
  106 + ],
  107 + "image": {
  108 + "url": "/image_uploads/dialoga/0000/0025/Mais_M_dicos.jpg"
  109 + },
  110 + "setting": {
  111 + "color": "#ffe599",
  112 + "moderate_comments": false,
  113 + "comment_paragraph_plugin_activate": false,
  114 + "author_name": "Ronald Emerson Scherolt da Costa",
  115 + "allow_members_to_edit": false
  116 + },
  117 + "position": 1
  118 + },
  119 + {
  120 + "id": 103457,
  121 + "abstract": "<p>Ação conjunta e cooperação transfronteiriça.</p>",
  122 + "title": "Proteção das Fronteiras",
  123 + "categories": [
  124 + {
  125 + "name": "Segurança Pública",
  126 + "id": 182,
  127 + "slug": "seguranca-publica",
  128 + "image": null
  129 + }
  130 + ],
  131 + "image": {
  132 + "url": "/image_uploads/dialoga/0000/0110/fronteira_redim.jpg"
  133 + },
  134 + "setting": {
  135 + "color": "#a64d79",
  136 + "moderate_comments": false,
  137 + "comment_paragraph_plugin_activate": false,
  138 + "author_name": "Ronald Emerson Scherolt da Costa",
  139 + "allow_members_to_edit": false
  140 + },
  141 + "position": 15
  142 + },
  143 + {
  144 + "id": 103612,
  145 + "abstract": "<p>Garantir água para beber e produzir.</p>",
  146 + "title": "Cisternas",
  147 + "categories": [
  148 + {
  149 + "name": "Redução da Pobreza",
  150 + "id": 183,
  151 + "slug": "reducao-da-pobreza",
  152 + "image": null
  153 + }
  154 + ],
  155 + "image": {
  156 + "url": "/image_uploads/dialoga/0000/0039/cisterna_redim.jpg"
  157 + },
  158 + "setting": {
  159 + "color": "#0000ff",
  160 + "moderate_comments": false,
  161 + "comment_paragraph_plugin_activate": false,
  162 + "author_name": "Ronald Emerson Scherolt da Costa",
  163 + "allow_members_to_edit": false
  164 + },
  165 + "position": 20
  166 + },
  167 + {
  168 + "id": 103442,
  169 + "abstract": "<p>Complemento à renda e acompanhamento em educação e saúde.</p>",
  170 + "title": "Bolsa Família",
  171 + "categories": [
  172 + {
  173 + "name": "Redução da Pobreza",
  174 + "id": 183,
  175 + "slug": "reducao-da-pobreza",
  176 + "image": null
  177 + }
  178 + ],
  179 + "image": {
  180 + "url": "/image_uploads/dialoga/0000/0013/bolsa_familia_redim.jpg"
  181 + },
  182 + "setting": {
  183 + "color": "#ff9900",
  184 + "moderate_comments": false,
  185 + "comment_paragraph_plugin_activate": false,
  186 + "author_name": "Ronald Emerson Scherolt da Costa",
  187 + "allow_members_to_edit": false
  188 + },
  189 + "position": 17
  190 + },
  191 + {
  192 + "id": 103673,
  193 + "abstract": "<p>A melhor escolha é se informar.</p>",
  194 + "title": "Incentivo ao Parto Normal",
  195 + "categories": [
  196 + {
  197 + "name": "Saúde",
  198 + "id": 180,
  199 + "slug": "saude",
  200 + "image": null
  201 + }
  202 + ],
  203 + "image": {
  204 + "url": "/image_uploads/dialoga/0000/0092/parto-normal.jpg"
  205 + },
  206 + "setting": {
  207 + "color": "#ff0000",
  208 + "moderate_comments": false,
  209 + "comment_paragraph_plugin_activate": false,
  210 + "author_name": "Ronald Emerson Scherolt da Costa",
  211 + "allow_members_to_edit": false
  212 + },
  213 + "position": 6
  214 + },
  215 + {
  216 + "id": 103397,
  217 + "abstract": "<p>Renda, inclusão produtiva e acesso a serviços.</p>",
  218 + "title": "Brasil Sem Miséria",
  219 + "categories": [
  220 + {
  221 + "name": "Redução da Pobreza",
  222 + "id": 183,
  223 + "slug": "reducao-da-pobreza",
  224 + "image": null
  225 + }
  226 + ],
  227 + "image": {
  228 + "url": "/image_uploads/dialoga/0000/0116/bsm_redim.jpg"
  229 + },
  230 + "setting": {
  231 + "color": "",
  232 + "moderate_comments": false,
  233 + "comment_paragraph_plugin_activate": false,
  234 + "author_name": "Ronald Emerson Scherolt da Costa",
  235 + "allow_members_to_edit": false
  236 + },
  237 + "position": 18
  238 + },
  239 + {
  240 + "id": 121505,
  241 + "abstract": "<p>Um novo jeito de ver e de fazer cultura</p>",
  242 + "title": "Agenda Seculo XXI",
  243 + "categories": [
  244 + {
  245 + "name": "Cultura",
  246 + "id": 194,
  247 + "slug": "cultura",
  248 + "image": null
  249 + }
  250 + ],
  251 + "image": {
  252 + "url": "/image_uploads/dialoga/0000/0166/Abertura_AGENDA_SECULO_XXI-v4.jpg"
  253 + },
  254 + "setting": {
  255 + "color": "",
  256 + "allow_members_to_edit": false,
  257 + "moderate_comments": false,
  258 + "comment_paragraph_plugin_activate": false,
  259 + "author_name": "leonardo.merlin"
  260 + },
  261 + "position": null
  262 + },
  263 + {
  264 + "id": 121526,
  265 + "abstract": "<p>Cultura e arte como base para a educação integral</p>",
  266 + "title": "Cultura e Educação",
  267 + "categories": [
  268 + {
  269 + "name": "Cultura",
  270 + "id": 194,
  271 + "slug": "cultura",
  272 + "image": null
  273 + }
  274 + ],
  275 + "image": {
  276 + "url": "/image_uploads/dialoga/0000/0177/Abertura-cultura-e-educacao-v2.jpg"
  277 + },
  278 + "setting": {
  279 + "color": "",
  280 + "allow_members_to_edit": false,
  281 + "moderate_comments": false,
  282 + "comment_paragraph_plugin_activate": false,
  283 + "author_name": "leonardo.merlin"
  284 + },
  285 + "position": null
  286 + },
  287 + {
  288 + "id": 103485,
  289 + "abstract": "<p>Caminho para uma educação de qualidade.</p>",
  290 + "title": "Valorização dos Professores",
  291 + "categories": [
  292 + {
  293 + "name": "Educação",
  294 + "id": 181,
  295 + "slug": "educacao",
  296 + "image": null
  297 + }
  298 + ],
  299 + "image": {
  300 + "url": "/image_uploads/dialoga/0000/0140/valorizacao_professor.jpg"
  301 + },
  302 + "setting": {
  303 + "color": "#ffff00",
  304 + "moderate_comments": false,
  305 + "comment_paragraph_plugin_activate": false,
  306 + "author_name": "Ronald Emerson Scherolt da Costa",
  307 + "allow_members_to_edit": false
  308 + },
  309 + "position": 11
  310 + },
  311 + {
  312 + "id": 103663,
  313 + "abstract": "<p>Mais educação profissional e tecnológica, mais desenvolvimento</p>",
  314 + "title": "Ensino Técnico",
  315 + "categories": [
  316 + {
  317 + "name": "Educação",
  318 + "id": 181,
  319 + "slug": "educacao",
  320 + "image": null
  321 + }
  322 + ],
  323 + "image": {
  324 + "url": "/image_uploads/dialoga/0000/0134/Ensino_tecnico.jpg"
  325 + },
  326 + "setting": {
  327 + "color": "#d0e0e3",
  328 + "moderate_comments": false,
  329 + "comment_paragraph_plugin_activate": false,
  330 + "author_name": "Ronald Emerson Scherolt da Costa",
  331 + "allow_members_to_edit": false
  332 + },
  333 + "position": 10
  334 + },
  335 + {
  336 + "id": 121514,
  337 + "abstract": "<p>Reconhecimento, fortalecimento e mobilização das comunidades que fazem cultura no Brasil</p>",
  338 + "title": "Cultura Viva",
  339 + "categories": [
  340 + {
  341 + "name": "Cultura",
  342 + "id": 194,
  343 + "slug": "cultura",
  344 + "image": null
  345 + }
  346 + ],
  347 + "image": {
  348 + "url": "/image_uploads/dialoga/0000/0167/Abertura_Cultura_Viva.jpg"
  349 + },
  350 + "setting": {
  351 + "color": "",
  352 + "allow_members_to_edit": false,
  353 + "moderate_comments": false,
  354 + "comment_paragraph_plugin_activate": false,
  355 + "author_name": "leonardo.merlin"
  356 + },
  357 + "position": null
  358 + },
  359 + {
  360 + "id": 103592,
  361 + "abstract": "<p>Garantir acesso à proteção social.</p>",
  362 + "title": "Assistência Social",
  363 + "categories": [
  364 + {
  365 + "name": "Redução da Pobreza",
  366 + "id": 183,
  367 + "slug": "reducao-da-pobreza",
  368 + "image": null
  369 + }
  370 + ],
  371 + "image": {
  372 + "url": "/image_uploads/dialoga/0000/0122/assistencia_social.jpg"
  373 + },
  374 + "setting": {
  375 + "color": "#a61c00",
  376 + "moderate_comments": false,
  377 + "comment_paragraph_plugin_activate": false,
  378 + "author_name": "Ronald Emerson Scherolt da Costa",
  379 + "allow_members_to_edit": false
  380 + },
  381 + "position": 19
  382 + },
  383 + {
  384 + "id": 103426,
  385 + "abstract": "<p>Da saúde se cuida todos os dias.</p>",
  386 + "title": "Vida saudável",
  387 + "categories": [
  388 + {
  389 + "name": "Saúde",
  390 + "id": 180,
  391 + "slug": "saude",
  392 + "image": null
  393 + }
  394 + ],
  395 + "image": {
  396 + "url": "/image_uploads/dialoga/0000/0046/vida_saudavel.jpg"
  397 + },
  398 + "setting": {
  399 + "color": "#d9d2e9",
  400 + "moderate_comments": false,
  401 + "comment_paragraph_plugin_activate": false,
  402 + "author_name": "Ronald Emerson Scherolt da Costa",
  403 + "allow_members_to_edit": false
  404 + },
  405 + "position": 7
  406 + },
  407 + {
  408 + "id": 103507,
  409 + "abstract": "<p>Tecnologia a serviço da segurança do cidadão.</p>",
  410 + "title": "Sinesp",
  411 + "categories": [
  412 + {
  413 + "name": "Segurança Pública",
  414 + "id": 182,
  415 + "slug": "seguranca-publica",
  416 + "image": null
  417 + }
  418 + ],
  419 + "image": {
  420 + "url": "/image_uploads/dialoga/0000/0098/sinesp.png"
  421 + },
  422 + "setting": {
  423 + "color": "#00ff00",
  424 + "moderate_comments": false,
  425 + "comment_paragraph_plugin_activate": false,
  426 + "author_name": "Ronald Emerson Scherolt da Costa",
  427 + "allow_members_to_edit": false
  428 + },
  429 + "position": 12
  430 + },
  431 + {
  432 + "id": 103359,
  433 + "abstract": "<p>Acesso a exames e consultas com especialistas.</p>",
  434 + "title": "Mais Especialidades",
  435 + "categories": [
  436 + {
  437 + "name": "Saúde",
  438 + "id": 180,
  439 + "slug": "saude",
  440 + "image": null
  441 + }
  442 + ],
  443 + "image": {
  444 + "url": "/image_uploads/dialoga/0000/0083/mais_especialidades1.png"
  445 + },
  446 + "setting": {
  447 + "color": "#ea9999",
  448 + "moderate_comments": false,
  449 + "comment_paragraph_plugin_activate": false,
  450 + "author_name": "Ronald Emerson Scherolt da Costa",
  451 + "allow_members_to_edit": false
  452 + },
  453 + "position": 2
  454 + },
  455 + {
  456 + "id": 103683,
  457 + "abstract": "<p>Saúde não tem preço.</p>",
  458 + "title": "Aqui tem Farmácia Popular",
  459 + "categories": [
  460 + {
  461 + "name": "Saúde",
  462 + "id": 180,
  463 + "slug": "saude",
  464 + "image": null
  465 + }
  466 + ],
  467 + "image": {
  468 + "url": "/image_uploads/dialoga/0000/0019/saude_nao_tem_preco.jpg"
  469 + },
  470 + "setting": {
  471 + "color": "#e69138",
  472 + "moderate_comments": false,
  473 + "comment_paragraph_plugin_activate": false,
  474 + "author_name": "Ronald Emerson Scherolt da Costa",
  475 + "allow_members_to_edit": false
  476 + },
  477 + "position": 5
  478 + },
  479 + {
  480 + "id": 103695,
  481 + "abstract": "<p>Novo modelo de atuação em Segurança Pública.</p>",
  482 + "title": "Segurança Pública Integrada",
  483 + "categories": [
  484 + {
  485 + "name": "Segurança Pública",
  486 + "id": 182,
  487 + "slug": "seguranca-publica",
  488 + "image": null
  489 + }
  490 + ],
  491 + "image": {
  492 + "url": "/image_uploads/dialoga/0000/0152/policiaintegrada.jpg"
  493 + },
  494 + "setting": {
  495 + "color": "#ff00ff",
  496 + "moderate_comments": false,
  497 + "comment_paragraph_plugin_activate": false,
  498 + "author_name": "Ronald Emerson Scherolt da Costa",
  499 + "allow_members_to_edit": false
  500 + },
  501 + "position": 13
  502 + },
  503 + {
  504 + "id": 103379,
  505 + "abstract": "<p>Resgate e atendimento 24 horas, sete dias da semana.</p>",
  506 + "title": "SAMU 192 e UPAs",
  507 + "categories": [
  508 + {
  509 + "name": "Saúde",
  510 + "id": 180,
  511 + "slug": "saude",
  512 + "image": null
  513 + }
  514 + ],
  515 + "image": {
  516 + "url": "/image_uploads/dialoga/0000/0060/SAMU.jpg"
  517 + },
  518 + "setting": {
  519 + "color": "#45818e",
  520 + "moderate_comments": false,
  521 + "comment_paragraph_plugin_activate": false,
  522 + "author_name": "Ronald Emerson Scherolt da Costa",
  523 + "allow_members_to_edit": false
  524 + },
  525 + "position": 4
  526 + },
  527 + {
  528 + "id": 103494,
  529 + "abstract": "<p>Da Educação Infantil ao Ensino Médio.</p>",
  530 + "title": "Educação Básica",
  531 + "categories": [
  532 + {
  533 + "name": "Educação",
  534 + "id": 181,
  535 + "slug": "educacao",
  536 + "image": null
  537 + }
  538 + ],
  539 + "image": {
  540 + "url": "/image_uploads/dialoga/0000/0076/Educa__o_B_sica.jpg"
  541 + },
  542 + "setting": {
  543 + "color": "#fce5cd",
  544 + "moderate_comments": false,
  545 + "comment_paragraph_plugin_activate": false,
  546 + "author_name": "Ronald Emerson Scherolt da Costa",
  547 + "allow_members_to_edit": false
  548 + },
  549 + "position": 8
  550 + },
  551 + {
  552 + "id": 103644,
  553 + "abstract": "<p>Um caminho de oportunidades com o Enem: Sisu, Prouni, Fies, Ciência sem Fronteiras</p>",
  554 + "title": "Ensino Superior",
  555 + "categories": [
  556 + {
  557 + "name": "Educação",
  558 + "id": 181,
  559 + "slug": "educacao",
  560 + "image": null
  561 + }
  562 + ],
  563 + "image": {
  564 + "url": "/image_uploads/dialoga/0000/0128/enem.jpg"
  565 + },
  566 + "setting": {
  567 + "color": "#cfe2f3",
  568 + "moderate_comments": false,
  569 + "comment_paragraph_plugin_activate": false,
  570 + "author_name": "Ronald Emerson Scherolt da Costa",
  571 + "allow_members_to_edit": false
  572 + },
  573 + "position": 9
  574 + },
  575 + {
  576 + "id": 121499,
  577 + "abstract": "<p>Valorização da arte e da cultura em suas múltiplas possibilidades</p>",
  578 + "title": "Política Nacional das Artes",
  579 + "categories": [
  580 + {
  581 + "name": "Cultura",
  582 + "id": 194,
  583 + "slug": "cultura",
  584 + "image": null
  585 + }
  586 + ],
  587 + "image": {
  588 + "url": "/image_uploads/dialoga/0000/0159/Banner_Pol_tica_Nacional_das_Artes.jpg"
  589 + },
  590 + "setting": {
  591 + "color": "",
  592 + "allow_members_to_edit": false,
  593 + "moderate_comments": false,
  594 + "comment_paragraph_plugin_activate": false,
  595 + "author_name": "leonardo.merlin"
  596 + },
  597 + "position": null
  598 + },
  599 + {
  600 + "id": 103472,
  601 + "abstract": "<p>Polícia Federal, Polícia Rodoviária Federal e Força Nacional de Segurança Pública.</p>",
  602 + "title": "Forças Federais de Segurança",
  603 + "categories": [
  604 + {
  605 + "name": "Segurança Pública",
  606 + "id": 182,
  607 + "slug": "seguranca-publica",
  608 + "image": null
  609 + }
  610 + ],
  611 + "image": {
  612 + "url": "/image_uploads/dialoga/0000/0031/federais2.png"
  613 + },
  614 + "setting": {
  615 + "color": "",
  616 + "moderate_comments": false,
  617 + "comment_paragraph_plugin_activate": false,
  618 + "author_name": "Ronald Emerson Scherolt da Costa",
  619 + "allow_members_to_edit": false
  620 + },
  621 + "position": 16
  622 + },
  623 + {
  624 + "id": 121492,
  625 + "abstract": "<p>Apoio ao audiovisual brasileiro: ampliação da produção, da difusão e do acesso</p>",
  626 + "title": "Brasil de Todas as Telas",
  627 + "categories": [
  628 + {
  629 + "name": "Cultura",
  630 + "id": 194,
  631 + "slug": "cultura",
  632 + "image": null
  633 + }
  634 + ],
  635 + "image": {
  636 + "url": "/image_uploads/dialoga/0000/0165/brasil-de-todas-telas-banner.jpg"
  637 + },
  638 + "setting": {
  639 + "color": "",
  640 + "allow_members_to_edit": false,
  641 + "moderate_comments": false,
  642 + "comment_paragraph_plugin_activate": false,
  643 + "author_name": "leonardo.merlin"
  644 + },
  645 + "position": null
  646 + },
  647 + {
  648 + "id": 121521,
  649 + "abstract": "<p>Mais acesso a cultura para trabalhadores e trabalhadoras</p>",
  650 + "title": "Vale-Cultura",
  651 + "categories": [
  652 + {
  653 + "name": "Cultura",
  654 + "id": 194,
  655 + "slug": "cultura",
  656 + "image": null
  657 + }
  658 + ],
  659 + "image": {
  660 + "url": "/image_uploads/dialoga/0000/0175/Abertura_Vale_cultura-v3.jpg"
  661 + },
  662 + "setting": {
  663 + "color": "",
  664 + "allow_members_to_edit": false,
  665 + "moderate_comments": false,
  666 + "comment_paragraph_plugin_activate": false,
  667 + "author_name": "leonardo.merlin"
  668 + },
  669 + "position": null
  670 + },
  671 + {
  672 + "id": 103416,
  673 + "abstract": "<p>Estrutura adequada para atender melhor a população na atenção básica.</p>",
  674 + "title": "Melhorar os Postos de Saúde",
  675 + "categories": [
  676 + {
  677 + "name": "Saúde",
  678 + "id": 180,
  679 + "slug": "saude",
  680 + "image": null
  681 + }
  682 + ],
  683 + "image": {
  684 + "url": "/image_uploads/dialoga/0000/0053/requalif_redim.jpg"
  685 + },
  686 + "setting": {
  687 + "color": "#cc4125",
  688 + "moderate_comments": false,
  689 + "comment_paragraph_plugin_activate": false,
  690 + "author_name": "Ronald Emerson Scherolt da Costa",
  691 + "allow_members_to_edit": false
  692 + },
  693 + "position": 3
  694 + },
  695 + {
  696 + "id": 121501,
  697 + "abstract": "<p>Preservação do patrimônio e qualidade de vida para os cidadãos</p>",
  698 + "title": "PAC Cidades Históricas",
  699 + "categories": [
  700 + {
  701 + "name": "Cultura",
  702 + "id": 194,
  703 + "slug": "cultura",
  704 + "image": null
  705 + }
  706 + ],
  707 + "image": {
  708 + "url": "/image_uploads/dialoga/0000/0168/Abertura__PAC_Cidades_Historicas-v3.JPG"
  709 + },
  710 + "setting": {
  711 + "color": "",
  712 + "allow_members_to_edit": false,
  713 + "moderate_comments": false,
  714 + "comment_paragraph_plugin_activate": false,
  715 + "author_name": "leonardo.merlin"
  716 + },
  717 + "position": null
  718 + }
  719 + ]
  720 + }
  721 + };
  722 + data.articles.push(articleHome);
  723 +
  724 + data.articles.push({
  725 + "id":103521,
  726 + "article":{"id":103521,"body":"\u003Cdiv class=\"container\"\u003E\r\n\u003Cdiv class=\"row\"\u003E\r\n\u003Cdiv class=\"col-md-12\"\u003E\r\n\u003Ch2\u003EMais M\u00e9dicos\u003Csmall\u003E Mais atendimento nos munic\u00edpios, mais sa\u00fade para quem mais precisa.\u003C/small\u003E\u003C/h2\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003Cdiv class=\"row\"\u003E\r\n\u003Cdiv class=\"col-md-6\"\u003E\u003Cimg class=\"center-block img-responsive\" src=\"http://dialoga.gov.br/dialoga/dialoga-brasil/mais-medicos/imagens/mais-medicos-foto1.jpg\" alt=\"Foto colorida mostra um M\u00e9dico examinando uma menina. Ele est\u00e1 com uma lanterna na m\u00e3o e ela est\u00e1 com a l\u00edngua para fora.\" width=\"640\" height=\"373\" /\u003E\u003C/div\u003E\r\n\u003Cdiv class=\"col-md-6\"\u003E\r\n\u003Cp\u003EEste programa garante m\u00e9dicos nos postos de sa\u00fade de todo o Pa\u00eds. O\u00a0Mais M\u00e9dicos come\u00e7ou em 2013 e j\u00e1 mostra resultados positivos: \u00e9 muito bem avaliado por 95% dos usu\u00e1rios, segundo pesquisa feita pela UFMG / Ipespe, em 2014.\u003C/p\u003E\r\n\u003Cp\u003EO programa veio para enfrentar uma car\u00eancia hist\u00f3rica de m\u00e9dicos em muitos munic\u00edpios do Brasil. Antes do lan\u00e7amento do Mais M\u00e9dicos, 22 estados tinham um n\u00famero de m\u00e9dicos abaixo da m\u00e9dia nacional. Cinco desses estados tinham menos de 1 m\u00e9dico para cada mil habitantes.\u003C/p\u003E\r\n\u003Cp\u003EEntre 2013 e 2014, o governo federal selecionou e levou 14.462 m\u00e9dicos para 3.785 munic\u00edpios. Assim, garantiu atendimento para 50 milh\u00f5es de pessoas que precisavam se deslocar a outras cidades, nem sempre pr\u00f3ximas, para ter atendimento m\u00e9dico.\u003C/p\u003E\r\n\u003Cp\u003EEm 2015, chegamos a 18 mil vagas para m\u00e9dicos no programa. Beneficiamos 63 milh\u00f5es de pessoas, em mais de 4 mil munic\u00edpios. N\u00e3o h\u00e1 um \u00fanico munic\u00edpio brasileiro sem atendimento m\u00e9dico.\u003C/p\u003E\r\n\u003Cp\u003EOs m\u00e9dicos brasileiros se destacaram, em 2015: 92% dos m\u00e9dicos que aderiram ao programa s\u00e3o brasileiros.\u003C/p\u003E\r\n\u003Cp\u003ETodos os m\u00e9dicos rec\u00e9m-formados que participam do Mais M\u00e9dicos recebem um b\u00f4nus de 10% em sua nota na prova de resid\u00eancia, como incentivo a sua atua\u00e7\u00e3o nesta tarefa de levar atendimento \u00e0 sa\u00fade a nossa popula\u00e7\u00e3o.\u003C/p\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003Cdiv class=\"row\"\u003E\r\n\u003Cdiv class=\"col-md-12\"\u003E\r\n\u003Cdiv class=\"text-center\"\u003E\u003Cimg class=\"img-responsive center-block\" src=\"http://dialoga.gov.br/dialoga/dialoga-brasil/mais-medicos/imagens/mais-medicos-foto2.jpg\" alt=\"Infogr\u00e1fico mostra a aceita\u00e7\u00e3o do Mais M\u00e9dico de 95% dos usu\u00e1rios.\" width=\"501\" height=\"135\" /\u003E\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003Cdiv class=\"container\"\u003E\r\n\u003Cdiv class=\"row\"\u003E\r\n\u003Cdiv class=\"col-md-12\"\u003E\r\n\u003Ch3\u003EEvolu\u00e7\u00e3o do programa\u003C/h3\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003Cdiv class=\"row\"\u003E\r\n\u003Cdiv class=\"col-md-12\"\u003E\u003Cimg class=\"center-block img-responsive\" src=\"http://dialoga.gov.br/dialoga/dialoga-brasil/mais-medicos/imagens/mais-medicos-foto3.jpg\" alt=\"Dois mapas do Brasil mostrando a evolu\u00e7\u00e3o do programa, um com o n\u00famero de m\u00e9dicos do programa em 2013 com 1.136 m\u00e9dicos e o outro em 2015 com 18.247 m\u00e9dicos.\" width=\"752\" height=\"548\" /\u003E\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003Cdiv class=\"row bloco-destaque\"\u003E\r\n\u003Cdiv class=\"col-md-12\"\u003E\r\n\u003Ch4\u003EForam criadas 4.600 vagas de gradua\u00e7\u00e3o e 2.586 vagas de resid\u00eancia\u003C/h4\u003E\r\n\u003Cdiv class=\"row\"\u003E\r\n\u003Cdiv class=\"col-md-5 col-sm-5\"\u003E\r\n\u003Cp\u003EO Programa Mais M\u00e9dicos leva para o interior novas vagas em cursos de medicina, investindo na qualidade da forma\u00e7\u00e3o de m\u00e9dicos no Brasil e aumentando o n\u00famero de novos profissionais.\u003C/p\u003E\r\n\u003Cp\u003ES\u00e3o oferecidas, tamb\u00e9m, mais vagas de resid\u00eancia m\u00e9dica na rede de sa\u00fade, para formar especialistas que atendam \u00e0s necessidades de todas as regi\u00f5es do pa\u00eds.\u003Cimg class=\"center-block img-responsive\" src=\"http://dialoga.gov.br/dialoga/dialoga-brasil/mais-medicos/imagens/mais-medicos-foto5.jpg\" alt=\"Gr\u00e1fico de barra, com duas colunas. Uma mostra o crescimento de bolsas em outras especialidades de sa\u00fade. Em 2010 o n\u00famero de 499 e 2.875 em 2015. A outra barra mostra o crescimento de bolsas em resid\u00eancia. 788 vagas de resid\u00eancia em 2010 e 4.952 bolsas em 2015. Ao lado do gr\u00e1fico tem o texto : A cada ano, o Minist\u00e9rio da Sa\u00fade financia um n\u00famero maior de bolsas para forma\u00e7\u00e3o e especializa\u00e7\u00e3o. Ao lado foto mostra quatro m\u00e9dicos, duas mulheres e dois homens de jaleco branco e estetosc\u00f3pio no pesco\u00e7o e sorrindo.\" width=\"756\" height=\"397\" /\u003E\u003C/p\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003Cdiv class=\"row\"\u003E\r\n\u003Cdiv class=\"col-md-12\"\u003E\r\n\u003Ch3 class=\"titulo-destaque\"\u003EHoje, das 22.344 vagas em cursos de medicina, 52% est\u00e3o localizados no interior.\u003C/h3\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003Cdiv class=\"row\"\u003E\r\n\u003Cdiv class=\"col-md-12\"\u003E\u003Cimg class=\"center-block img-responsive\" src=\"http://dialoga.gov.br/dialoga/dialoga-brasil/mais-medicos/imagens/maismedicos-graficointeriorv3.jpg\" alt=\"Gr\u00e1fico de linha mostra a evolu\u00e7\u00e3o no n\u00famero de vagas nos cursos de medicina. A linha cinza mostra que em 1994 tinha 4.884 vagas na capital e 10.637 vagas em 2015. A linha azul mostra 3.878 vagas no interior em 1994 e 14.522 em 2015\" width=\"748\" height=\"435\" /\u003E\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003Cdiv class=\"container\"\u003E\r\n\u003Cdiv class=\"row\"\u003E\r\n\u003Cdiv class=\"col-md-12\"\u003E\r\n\u003Ch3\u003ECompromissos\u003C/h3\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003Cdiv class=\"row\"\u003E\r\n\u003Cdiv class=\"col-md-6 col-sm-6\"\u003E\u003Cimg class=\"center-block img-responsive\" src=\"http://dialoga.gov.br/dialoga/dialoga-brasil/mais-medicos/imagens/mais-medicos-foto7.png\" alt=\"Foto mostra uma m\u00e3o de mulher segurando um Estetosc\u00f3pio com a sigla do SUS (Sistema \u00danico de Sa\u00fade).\" width=\"327\" height=\"327\" /\u003E\u003C/div\u003E\r\n\u003Cdiv class=\"col-md-6 col-sm-6\"\u003E\r\n\u003Cul class=\"list-unstyled\"\u003E\r\n\u003Cli\u003ELevar atendimento m\u00e9dico a 70 milh\u00f5es de pessoas at\u00e9 2018.\u003C/li\u003E\r\n\u003Cli\u003EAt\u00e9 2017, criar mais 6,8 mil novas vagas em faculdades de medicina, chegando a 11,5 mil.\u003C/li\u003E\r\n\u003Cli\u003EAt\u00e9 2018, criar mais 9,8 mil vagas de resid\u00eancia m\u00e9dica chegando a 12,4 mil.\u003C/li\u003E\r\n\u003C/ul\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E"}
  727 + });
  728 + data.articles.push({
  729 + id: 103507,
  730 + "article": {"id":103507,"body":"\u003Cdiv class=\"container\"\u003E\r\n\u003Cdiv class=\"row\"\u003E\r\n\u003Cdiv class=\"col-md-12\"\u003E\r\n\u003Ch2\u003ESINESP\u003Csmall\u003ETecnologia a servi\u00e7o da seguran\u00e7a do cidad\u00e3o.\u003C/small\u003E\u003C/h2\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003Cdiv class=\"container\"\u003E\r\n\u003Cdiv class=\"row\"\u003E\r\n\u003Cdiv class=\"col-md-6 col-sm-6\"\u003E\u003Cimg class=\"img-responsive center-block\" src=\"http://dialoga.gov.br/dialoga/dialoga-brasil/sinesp/imagens/grafico-sinesp-2.jpg\" alt=\"Infogr\u00e1fico com o mapa do Brasil ligado por pontilhados a um monitor com o texto: base de dados. Outro pontilhado liga o monitor a cinco pictogramas, o primeiro a figura de uma engrenagem com o texto: pain\u00e9is gerenciais; o segundo um gr\u00e1fico de barras com o texto: gr\u00e1ficos anal\u00edticos; o terceiro uma folha de papel com escrito e o texto: relat\u00f3rios; a quarta um mapa do Brasil com o texto: mapas estat\u00edsticos e o quinto com tr\u00eas pessoas e o texto: planos de a\u00e7\u00e3o. Ao lado desse infogr\u00e1fico o texto: Sinesp \u2013 Sistema Nacional de Informa\u00e7\u00f5es de Seguran\u00e7a P\u00fablica, Prisionais e sobre Drogas. Atendimentos a emerg\u00eancias municipais, estaduais e federais (190, 191, 192, 193 e 197). Dados centralizados e consolidados. Atualiza\u00e7\u00e3o em tempo real. Sincroniza\u00e7\u00e3o das bases. Boletins de ocorr\u00eancia. Inqu\u00e9ritos policiais civis estaduais e federais. \" width=\"784\" height=\"598\" /\u003E\u003C/div\u003E\r\n\u003Cdiv class=\"col-md-6 col-sm-6\"\u003E\r\n\u003Cp\u003EO \u003Cstrong\u003ESINESP - Sistema Nacional de Informa\u00e7\u00f5es de Seguran\u00e7a P\u00fablica, Prisionais e sobre Drogas\u003C/strong\u003E \u00e9 um servi\u00e7o in\u00e9dito no Brasil. Re\u00fane, sistematiza, analisa e coloca \u00e0 disposi\u00e7\u00e3o dos cidad\u00e3os informa\u00e7\u00f5es sobre seguran\u00e7a p\u00fablica, justi\u00e7a, drogas e sistema prisional.\u003C/p\u003E\r\n\u003Cp\u003EImplementado pelo governo federal, em parceria com os 26 estados e o Distrito Federal, o sistema est\u00e1 ajudando a \u003Cstrong\u003Emelhorar a qualidade dos servi\u00e7os prestados \u003C/strong\u003E pela seguran\u00e7a p\u00fablica.\u003C/p\u003E\r\n\u003Cp\u003EO SINESP ajuda gestores a planejar e executar a\u00e7\u00f5es integradas contra o crime e a viol\u00eancia. Al\u00e9m disso, d\u00e1 mais \u003Cstrong\u003Etranspar\u00eancia\u003C/strong\u003E aos \u00edndices de criminalidade para toda a sociedade, pois os relat\u00f3rios com todas as\u00a0 informa\u00e7\u00f5es dispon\u00edveis no SINESP podem ser lidos e consultados pela popula\u00e7\u00e3o via \u003Cem\u003Einternet\u003C/em\u003E.\u003C/p\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003Cdiv class=\"container\"\u003E\r\n\u003Cdiv class=\"row\"\u003E\r\n\u003Cdiv class=\"col-md-6 col-sm-6\"\u003E\r\n\u003Ch3\u003ESINESP Cidad\u00e3o\u003C/h3\u003E\r\n\u003Cp\u003EDispon\u00edvel para qualquer pessoa, \u00e9 um aplicativo de consulta r\u00e1pida via \u003Cem\u003Einternet \u003C/em\u003Eque oferece informa\u00e7\u00f5es sobre \u003Cstrong\u003Eve\u00edculos roubados ou furtados, pessoas desaparecidas ou com mandatos de pris\u00e3o expedidos contra elas.\u003C/strong\u003E\u003C/p\u003E\r\n\u003Cp\u003EA ferramenta pode ser acessada, \u003Cstrong\u003Egratuitamente\u003C/strong\u003E, pelo endere\u00e7o \u003Cstrong\u003Ewww.sinesp.gov.br\u003C/strong\u003E e nas lojas de aplicativos, tanto para IOS, Android e Windows Phone.\u003C/p\u003E\r\n\u003Cp\u003EEm breve, um novo m\u00f3dulo ser\u00e1 disponibilizado no aplicativo: a localiza\u00e7\u00e3o de unidades policiais pr\u00f3ximas do usu\u00e1rio.\u003C/p\u003E\r\n\u003C/div\u003E\r\n\u003Cdiv class=\"col-md-6 col-sm-6\"\u003E\u003Cimg class=\"img-responsive center-block\" src=\"http://dialoga.gov.br/dialoga/dialoga-brasil/sinesp/imagens/tecnologia-sinesp-imagem2.jpg\" alt=\"Foto mostra m\u00e3o de uma pessoa com celular na m\u00e3o acessando o aplicativo. Ao fundo carros passando na rua. \" width=\"326\" height=\"327\" /\u003E\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003Cdiv class=\"container\"\u003E\r\n\u003Cdiv class=\"row\"\u003E\r\n\u003Cdiv class=\"col-md-12 col-sm-12\"\u003E\u003Cimg class=\"img-responsive center-block\" src=\"http://dialoga.gov.br/dialoga/dialoga-brasil/sinesp/imagens/tecnologia-sinesp-imagem3.jpg\" alt=\"Tr\u00eas pictogramas um ao lado do outro. O primeiro uma nuvem com uma seta para baixo com o texto: mais de 4,5 milh\u00f5es de downloads. O segundo uma lupa e o texto: mais de 150 milh\u00f5es de consulta. E o terceiro um carro com o texto: mais de 100 mil ve\u00edculos recuperados. \" width=\"773\" height=\"176\" /\u003E\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E"}
  731 + });
  732 + data.articles.push({
  733 + id: 121521,
  734 + "article":{"id":121521,"body":"\u003Cdiv class=\"col-xs-12\"\u003E\r\n\u003Cdiv class=\"row\"\u003E\r\n\u003Cdiv class=\"col-md-12\"\u003E\r\n\u003Ch2\u003EVale-Cultura\u003Csmall\u003EMais acesso \u00e0 cultura para trabalhadores e trabalhadoras\u003C/small\u003E\u003C/h2\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003Cdiv class=\"row\"\u003E\r\n\u003Cdiv class=\"col-md-12\"\u003E\r\n\u003Ch3\u003ELivros, shows e espet\u00e1culos para todos.\u003C/h3\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003Cdiv class=\"row\"\u003E\r\n\u003Cdiv class=\"col-md-6 col-sm-6 vcenter\"\u003E\u003Cimg class=\"img-responsive\" src=\"http://gestao.dialoga.gov.br/dialoga/dialoga-brasil/vale-cultura/imagens/vale-cultura1.jpg\" alt=\"\" /\u003E\u003C/div\u003E\r\n\u003Cdiv class=\"col-md-6 col-sm-6 vcenter\"\u003E\r\n\u003Cp\u003EO Vale-Cultura incentiva as empresas a oferecer aos seus funcion\u00e1rios acesso a livros, revistas, ingressos para cinemas, teatros, shows, instrumentos musicais e cursos de arte e cultura.\u003C/p\u003E\r\n\u003Cp\u003EO benef\u00edcio \u00e9 garantido por meio de um cart\u00e3o magn\u00e9tico pr\u00e9-pago, v\u00e1lido em todo os pa\u00eds. Mensalmente, esse cart\u00e3o recebe cr\u00e9dito de R$ 50, que pode ser acumulado para despesas maiores.\u003C/p\u003E\r\n\u003Cp\u003EA ades\u00e3o das empresas \u00e9 facultativa e os custos s\u00e3o livres de encargos sociais e trabalhistas. Aquelas que t\u00eam lucro real podem deduzir at\u00e9 1% do Imposto de Renda devido.\u003C/p\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003Cbr /\u003E\r\n\u003Cdiv class=\"row\"\u003E\r\n\u003Cdiv class=\"col-md-6 col-sm-6 vcenter\"\u003E\r\n\u003Cblockquote\u003E\r\n\u003Cp class=\"text-center\"\u003EEm pouco mais de um ano, o Vale-Cultura j\u00e1 mobiliza mais de R$140 milh\u00f5es e beneficia cerca de 420 mil trabalhadores e trabalhadoras.\u003C/p\u003E\r\n\u003C/blockquote\u003E\r\n\u003C/div\u003E\r\n\u003Cdiv class=\"col-md-6 col-sm-6 vcenter\"\u003E\r\n\u003Cdiv class=\"embed-responsive embed-responsive-16by9\"\u003E\u003Ciframe src=\"https://www.youtube.com/embed/KKmZh5T46g8?rel=0\" frameborder=\"0\" width=\"560\" height=\"315\"\u003E\u003C/iframe\u003E\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003Cdiv class=\"row\"\u003E\r\n\u003Cdiv class=\"col-md-12\"\u003E\r\n\u003Ch3\u003ECompromissos\u003C/h3\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003Cdiv class=\"row\"\u003E\r\n\u003Cdiv class=\"col-md-6 col-sm-6 vcenter\"\u003E\u003Cimg class=\"img-responsive\" src=\"http://gestao.dialoga.gov.br/dialoga/dialoga-brasil/vale-cultura/imagens/vale-cultura3.jpg\" alt=\"\" /\u003E\u003C/div\u003E\r\n\u003Cdiv class=\"col-md-6 col-sm-6 vcenter\"\u003E\r\n\u003Cul class=\"list-unstyled\"\u003E\r\n\u003Cli class=\"bullet\"\u003E\u003Cstrong\u003EAmpliar a ades\u00e3o de empresas e trabalhadores\u003C/strong\u003E\u003C/li\u003E\r\n\u003Cli class=\"bullet\"\u003E\u003Cstrong\u003EAmpliar a rede de estabelecimentos que recebem o Vale-Cultura.\u003C/strong\u003E\u003C/li\u003E\r\n\u003C/ul\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E\r\n\u003C/div\u003E"}
  735 + });
  736 +
  737 + return data;
  738 +};
... ...
e2e/.jshintrc
1 1 {
2 2 "extends": "../.jshintrc",
3 3 "globals": {
  4 + "require": false,
4 5 "browser": false,
5 6 "element": false,
6 7 "by": false,
... ...
e2e/main.po.js
... ... @@ -1,15 +0,0 @@
1   -/**
2   - * This file uses the Page Object pattern to define the main page for tests
3   - * https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ
4   - */
5   -
6   -'use strict';
7   -
8   -var MainPage = function() {
9   - this.jumbEl = element(by.css('.jumbotron'));
10   - this.h1El = this.jumbEl.element(by.css('h1'));
11   - this.imgEl = this.jumbEl.element(by.css('img'));
12   - this.thumbnailEls = element(by.css('body')).all(by.repeater('awesomeThing in main.awesomeThings'));
13   -};
14   -
15   -module.exports = new MainPage();
e2e/main.spec.js
... ... @@ -1,21 +0,0 @@
1   -'use strict';
2   -
3   -describe('The main view', function () {
4   - var page;
5   -
6   - beforeEach(function () {
7   - browser.get('/index.html');
8   - page = require('./main.po');
9   - });
10   -
11   - it('should include jumbotron with correct data', function() {
12   - expect(page.h1El.getText()).toBe('\'Allo, \'Allo!');
13   - expect(page.imgEl.getAttribute('src')).toMatch(/assets\/images\/yeoman.png$/);
14   - expect(page.imgEl.getAttribute('alt')).toBe('I\'m Yeoman');
15   - });
16   -
17   - it('should list more than 5 awesome things', function () {
18   - expect(page.thumbnailEls.count()).toBeGreaterThan(5);
19   - });
20   -
21   -});
e2e/pages/article.spec.js 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +(function(){
  2 + 'use strict';
  3 +
  4 + describe('The index page', function () {
  5 + var page = browser.get('/');
  6 +
  7 + // beforeEach(function () {
  8 + // browser.get('/');
  9 + // });
  10 +
  11 + describe('Common layout', function (){
  12 + require('./layout.js')();
  13 + });
  14 +
  15 + });
  16 +})();
... ...
e2e/pages/inicio.po.js 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +module.exports = (function() {
  2 + 'use strict';
  3 +
  4 + var PageObject = function() {
  5 + this.video = element(by.css('.video-player'));
  6 +
  7 + this.agenda = element(by.css('.event-list'));
  8 + };
  9 +
  10 + return (new PageObject());
  11 +})();
... ...
e2e/pages/inicio.spec.js 0 → 100644
... ... @@ -0,0 +1,124 @@
  1 +/* global require */
  2 +(function(){
  3 + 'use strict';
  4 +
  5 + describe('The index page', function () {
  6 + var page = require('./inicio.po.js');
  7 + // beforeEach(function () {
  8 + // browser.get('/');
  9 + // });
  10 +
  11 + describe('Common layout', function (){
  12 + require('./layout.js')();
  13 + });
  14 +
  15 + describe('Component: Main Video', function(){
  16 + it('should have a thumb background image (for async)', function() {
  17 + expect(page.video.element(by.css('.video-thumbnail'))).toBeDefined();
  18 + expect(page.video.element(by.css('.video-thumbnail')).getCssValue('background-image')).toContain('youtube-background.png');
  19 + expect(page.video.element(by.css('.video-thumbnail')).getAttribute('aria-hidden')).toBe('true');
  20 + });
  21 +
  22 + it('should have a button play trigger', function() {
  23 + expect(page.video.element(by.css('.video-play-button'))).toBeDefined();
  24 + expect(page.video.element(by.css('.video-play-button')).getAttribute('aria-label')).toBeDefined();
  25 + });
  26 + });
  27 +
  28 + describe('Component: Agenda', function(){
  29 + it('should have a tab-trigger', function() {
  30 + expect(page.agenda.element(by.css('.event-tab--trigger'))).toBeDefined();
  31 + expect(page.agenda.element(by.css('.event-tab--title'))).toBeDefined();
  32 + expect(page.agenda.element(by.css('.event-tab--icon'))).toBeDefined();
  33 + expect(page.agenda.element(by.css('.event-tab--icon')).element(by.css('.glyphicon'))).toBeDefined();
  34 + expect(page.agenda.element(by.css('.event-tab--icon')).element(by.css('.glyphicon')).getAttribute('aria-hidden')).toBe('true');
  35 + expect(page.agenda.element(by.css('.event-tab--button'))).toBeDefined();
  36 + expect(page.agenda.element(by.css('.event-tab--total-scheduled'))).toBeDefined();
  37 + expect(page.agenda.element(by.css('.event-tab--total-scheduled'))).toMatch(/(\d)*/);
  38 + });
  39 +
  40 + describe('Component: Agenda / Open-panel', function(){
  41 + it('should have a header', function() {
  42 + // the 2 lines below need to open panel and make elements visibles
  43 + expect(page.agenda.element(by.model('eventListCtrl.isListVisible'))).toBeDefined();
  44 + page.agenda.element(by.css('.event-tab--trigger')).click();
  45 +
  46 + expect(page.agenda.element(by.css('.event-list--title'))).toBeDefined();
  47 + expect(page.agenda.element(by.css('.event-list--title')).getText()).toEqual('Bate-papo com ministr@s');
  48 + expect(page.agenda.element(by.css('.event-list--icon'))).toBeDefined();
  49 + expect(page.agenda.element(by.css('.event-list--icon')).element(by.css('.glyphicon'))).toBeDefined();
  50 + expect(page.agenda.element(by.css('.event-list--icon')).element(by.css('.glyphicon')).getAttribute('aria-hidden')).toBe('true');
  51 + expect(page.agenda.element(by.css('.event-list--minimize'))).toBeDefined();
  52 + expect(page.agenda.element(by.css('.event-list--minimize')).element(by.css('.glyphicon'))).toBeDefined();
  53 + expect(page.agenda.element(by.css('.event-list--minimize')).element(by.css('.glyphicon')).getAttribute('aria-hidden')).toBe('true');
  54 + });
  55 +
  56 + it('should have a table with content', function() {
  57 + // date/time
  58 + expect(page.agenda.element(by.css('.event-list--minimize')).element(by.css('.glyphicon')).getAttribute('aria-hidden')).toBe('true');
  59 + // title
  60 + // subscribe button
  61 + // total of subscribers
  62 + // show only 5 itens
  63 + });
  64 + // it('should have the title of scheduled chat', function() {});
  65 + // it('should have a subscribe button to scheduled chat', function() {});
  66 + // it('should show the number of subscribers on each item', function() {});
  67 + // it('should show 5 itens at most', function() {});
  68 + // it('should be accessible', function() {});
  69 + });
  70 +
  71 + describe('Component: Agenda / with Hangout', function(){
  72 + it('should have a title', function() {});
  73 + it('should have a thumb background image (for async)', function() {});
  74 + it('should have a button trigger to start the video', function() {});
  75 + it('should have a description', function() {
  76 + // PATTERN: %DATETIME - %TITLE, %CATEGORY, ?
  77 + // Get it from the endpoint or assembly-it ?
  78 + });
  79 + it('should have a open trigger', function() {
  80 + // with:
  81 + // - total of scheduled events
  82 + // - icon: arrow down
  83 + });
  84 + });
  85 + });
  86 +
  87 + describe('Component: Category List', function(){
  88 + it('should have a title', function() {});
  89 + it('should have list of category', function() {});
  90 + it('should have the icon of each category', function() {});
  91 + it('should have the name of each category', function() {});
  92 + it('should be accessible', function() {});
  93 + // what expect on hover or focus? Material Desgn likes?
  94 + //
  95 + });
  96 +
  97 + describe('Component: Article List | Box (each) ', function(){
  98 + it('should have a category label', function() {});
  99 + it('should have a banner image', function() {});
  100 + it('should have a alternatve text for the banner image', function() {});
  101 + it('should have a title', function() {});
  102 + it('should have 50 letters at most on title', function() {});
  103 + it('should have a abstract', function() {});
  104 + it('should have 200 letters at most on abstract', function() {});
  105 + it('should have the number of sent proposals', function() {});
  106 + it('should have a call-to-action button', function() {});
  107 + it('should have the same color of the category-color at call-to-action button', function() {});
  108 + it('should be accessible', function() {});
  109 + // what colors on what?
  110 + // what are links/clickable/focusable
  111 + });
  112 +
  113 + describe('Component: Search ', function(){
  114 + it('should have a hidden label', function() {});
  115 + it('should have a html5 search input', function() {});
  116 + it('should have be focusable by a11y link', function() {});
  117 + it('should have a more filters?', function() {});
  118 + it('should be accessible', function() {});
  119 + // what behaviours?
  120 + // more filters? ordering by alphabet: name, category, random.
  121 + // show results at another page
  122 + });
  123 + });
  124 +})();
... ...
e2e/pages/layout.js 0 → 100644
... ... @@ -0,0 +1,80 @@
  1 +module.exports = function(){
  2 + 'use strict';
  3 +
  4 + describe('The common layout', function () {
  5 +
  6 + var page = require('./layout.po.js');
  7 +
  8 + describe('Accessibility (a11y) top bar', function(){
  9 + it('should have a "skip-to-content" anchor', function() {
  10 + expect(page.skipToContent.getText()).toEqual('Ir para o conteúdo 1');
  11 + });
  12 + it('should have a "skip-to-navigation" anchor', function() {
  13 + expect(page.skipToNavigation.getText()).toEqual('Ir para o menu 2');
  14 + });
  15 + it('should have a "skip-to-search" anchor', function() {
  16 + expect(page.skipToSearch.getText()).toEqual('Ir para a busca 3');
  17 + });
  18 + it('should have a "skip-to-footer" anchor', function() {
  19 + expect(page.skipToFooter.getText()).toEqual('Ir para o rodapé 4');
  20 + });
  21 +
  22 + it('should have a accessibility anchor', function() {
  23 + expect(page.actionAccessibility.getText()).toEqual('Acessibilidade');
  24 + });
  25 + it('should have a adjust contrast anchor', function() {
  26 + expect(page.actionContrast.getText()).toEqual('Alto Contraste');
  27 + });
  28 + it('should have a sitemap anchor', function() {
  29 + expect(page.actionSitemap.getText()).toEqual('Mapa do Site');
  30 + });
  31 + });
  32 +
  33 + describe('Header', function(){
  34 + it('should have a logo', function() {});
  35 + it('should have a navigation', function() {});
  36 + it('should have a social share area', function() {});
  37 + it('should have a "CADASTRAR" anchor', function() {});
  38 + it('should have a "ENTRAR" anchor', function() {});
  39 + it('should have a "Veja mais" area', function() {});
  40 + it('should have a valid ARIA', function() {});
  41 +
  42 + describe('Header / Navigation', function(){
  43 + it('should have a "SOBRE" anchor', function() {});
  44 + it('should have a "PROGRAMAS" anchor', function() {});
  45 + it('should have a "PROPOSTAS" anchor', function() {});
  46 + it('should have a "DÚVIDAS" anchor', function() {});
  47 + it('should be condensed on mobile', function() {});
  48 + it('should have a valid ARIA', function() {});
  49 + // it('should have a "ENTRAR?" anchor on MOBILE?', function() {});
  50 + // it('should have a "RANKING?" anchor on MOBILE?', function() {});
  51 + // it('should have a "RESPOSTAS?" anchor on MOBILE?', function() {});
  52 + // it('should have a "PARTICIPE?" anchor on MOBILE?', function() {});
  53 + });
  54 +
  55 + describe('Header / Social Share', function(){
  56 + it('should have a facebook share button', function() {});
  57 + it('should have a twitter share button', function() {});
  58 + it('should have a gplus share button', function() {});
  59 + it('should have a whatsapp share button', function() {});
  60 + it('should be condensed on mobile', function() {});
  61 + it('should have a email share button', function() {});
  62 + it('should have a valid ARIA', function() {});
  63 + // what to do when on mobile?
  64 + // too small on mobile? point issues
  65 + });
  66 +
  67 + describe('Header / "Veja mais"', function(){
  68 + it('should have a youtube link', function() {});
  69 + // it('should have a flicker? link', function() {});
  70 + it('should have a valid ARIA', function() {});
  71 + // what to do when on mobile?
  72 + });
  73 + });
  74 +
  75 + describe('Footer', function(){
  76 + it('should have a ?', function() {});
  77 + it('should have a valid ARIA', function() {});
  78 + });
  79 + });
  80 +};
... ...
e2e/pages/layout.po.js 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +module.exports = (function() {
  2 + 'use strict';
  3 +
  4 + var PageObject = function() {
  5 + this.skipToContent = element(by.id('skip-to-content'));
  6 + this.skipToNavigation = element(by.id('skip-to-navigation'));
  7 + this.skipToSearch = element(by.id('skip-to-search'));
  8 + this.skipToFooter = element(by.id('skip-to-footer'));
  9 +
  10 + this.actionAccessibility = element(by.id('siteaction-accessibility'));
  11 + this.actionContrast = element(by.id('siteaction-contrast'));
  12 + this.actionSitemap = element(by.id('siteaction-sitemap'));
  13 + };
  14 +
  15 + return (new PageObject());
  16 +})();
... ...
e2e/pages/progama.spec.js 0 → 100644
... ... @@ -0,0 +1,55 @@
  1 +(function(){
  2 + 'use strict';
  3 +
  4 + describe('The "Programa" page', function () {
  5 + var page = browser.get('/');
  6 +
  7 + // beforeEach(function () {
  8 + // browser.get('/');
  9 + // });
  10 +
  11 + describe('Common layout', function (){
  12 + require('./layout.js')();
  13 + });
  14 +
  15 + describe('Component: article-preview', function (){});
  16 +
  17 + describe('Component: article-content', function (){});
  18 +
  19 + // describe('Component: article-template-1', function (){});
  20 +
  21 + describe('Component: proposal-random', function (){
  22 + it('should have a loading state', function() {});
  23 + it('should have a breadcrumb', function() {});
  24 + it('should have the text-content of proposal', function() {});
  25 + it('should have a vote up button', function() {});
  26 + it('should have a vote skip button', function() {});
  27 + it('should have a vote down button', function() {});
  28 + it('should have a social share area', function() {});
  29 + it('should have the ranking position', function() {});
  30 + it('should have a ranking button trigger', function() {});
  31 + it('should be accessible', function() {});
  32 + });
  33 +
  34 + describe('Component: proposal-ranking', function (){
  35 + it('should have a loading state', function() {});
  36 + it('should have a close button trigger', function() {});
  37 + it('should have the ranking position of proposal', function() {});
  38 + it('should have the text-content of proposal', function() {});
  39 + it('should have the number of views', function() {});
  40 + it('should have the number of votes up', function() {});
  41 + it('should have the number of votes down', function() {});
  42 + it('should have a link to proposal', function() {});
  43 + it('should have a link to all proposals', function() {});
  44 + it('should be accessible', function() {});
  45 + });
  46 +
  47 + describe('Component: proposal-maker', function (){
  48 + it('should be accessible', function() {});
  49 + });
  50 +
  51 + describe('Component: proposal-ranking', function (){
  52 + it('should be accessible', function() {});
  53 + });
  54 + });
  55 +})();
... ...
e2e/pages/sobre.spec.js 0 → 100644
... ... @@ -0,0 +1,29 @@
  1 +(function(){
  2 + 'use strict';
  3 +
  4 + describe('The "Sobre" page', function () {
  5 + var page = browser.get('/');
  6 +
  7 + // beforeEach(function () {
  8 + // browser.get('/');
  9 + // });
  10 +
  11 + describe('Common layout', function (){
  12 + require('./layout.js')();
  13 + });
  14 +
  15 + describe('Breadcrumb', function(){
  16 + it('should have two itens', function() {});
  17 + });
  18 +
  19 + describe('Content', function(){
  20 + it('should have a main video', function() {});
  21 + it('should have a main video thumb image', function() {});
  22 + it('should have a main video thumb image alternative text', function() {});
  23 +
  24 + it('should have a "Programas" description', function() {});
  25 + it('should have a "Propostas" tutorial', function() {});
  26 + it('should be accessible', function() {});
  27 + });
  28 + });
  29 +})();
... ...
gulp/build.js
... ... @@ -48,6 +48,7 @@ gulp.task(&#39;html&#39;, [&#39;inject&#39;, &#39;partials&#39;], function () {
48 48 .pipe(jsFilter.restore())
49 49 .pipe(cssFilter)
50 50 .pipe($.replace('../../bower_components/bootstrap-sass-official/assets/fonts/bootstrap/', '../fonts/'))
  51 + .pipe($.replace('../../bower_components/open-sans-fontface/fonts/', '../fonts/'))
51 52 .pipe($.csso())
52 53 .pipe(cssFilter.restore())
53 54 .pipe(assets.restore())
... ... @@ -68,7 +69,10 @@ gulp.task(&#39;html&#39;, [&#39;inject&#39;, &#39;partials&#39;], function () {
68 69 // Only applies for fonts from bower dependencies
69 70 // Custom fonts are handled by the "other" task
70 71 gulp.task('fonts', function () {
71   - return gulp.src($.mainBowerFiles().concat('bower_components/bootstrap-sass-official/assets/fonts/bootstrap/*'))
  72 + return gulp.src([
  73 + $.mainBowerFiles().concat('bower_components/bootstrap-sass-official/assets/fonts/bootstrap/*'),
  74 + $.mainBowerFiles().concat('bower_components/open-sans-fontface/fonts/*')
  75 + ])
72 76 .pipe($.filter('**/*.{eot,svg,ttf,woff,woff2}'))
73 77 .pipe($.flatten())
74 78 .pipe(gulp.dest(path.join(conf.paths.dist, '/fonts/')));
... ...
gulp/images.js 0 → 100644
... ... @@ -0,0 +1,24 @@
  1 +'use strict';
  2 +
  3 +var path = require('path');
  4 +var gulp = require('gulp');
  5 +var conf = require('./conf');
  6 +
  7 +var gulpif = require('gulp-if');
  8 +var sprity = require('sprity');
  9 +
  10 +gulp.task('sprites', function () {
  11 + var src = [
  12 + path.join(conf.paths.src, '/assets/images/icons/*.png'),
  13 + path.join('!' + conf.paths.src, '/assets/images/icons/sprite.png')
  14 + ];
  15 + var destCss = path.join(conf.paths.tmp, '/serve/app/');
  16 + var destImg = path.join(conf.paths.src, '/assets/images/icons');
  17 +
  18 + return sprity.src({
  19 + src: src,
  20 + style: 'sprite.css',
  21 + cssPath: '../assets/images/icons/'
  22 + })
  23 + .pipe(gulpif('*.png', gulp.dest(destImg), gulp.dest(destCss)));
  24 +});
... ...
gulp/inject.js
... ... @@ -9,7 +9,7 @@ var $ = require(&#39;gulp-load-plugins&#39;)();
9 9 var wiredep = require('wiredep').stream;
10 10 var _ = require('lodash');
11 11  
12   -gulp.task('inject', ['scripts', 'styles'], function () {
  12 +gulp.task('inject', ['scripts', 'styles', 'sprites'], function () {
13 13 var injectStyles = gulp.src([
14 14 path.join(conf.paths.tmp, '/serve/app/**/*.css'),
15 15 path.join('!' + conf.paths.tmp, '/serve/app/vendor.css')
... ...
gulp/server.js
... ... @@ -8,6 +8,7 @@ var browserSync = require(&#39;browser-sync&#39;);
8 8 var browserSyncSpa = require('browser-sync-spa');
9 9  
10 10 var util = require('util');
  11 +var gutil = require('gulp-util');
11 12  
12 13 var proxyMiddleware = require('http-proxy-middleware');
13 14  
... ... @@ -33,7 +34,25 @@ function browserSyncInit(baseDir, browser) {
33 34 *
34 35 * For more details and option, https://github.com/chimurai/http-proxy-middleware/blob/v0.0.5/README.md
35 36 */
36   - // server.middleware = proxyMiddleware('/users', {target: 'http://jsonplaceholder.typicode.com', proxyHost: 'jsonplaceholder.typicode.com'});
  37 + if(gutil.env.target) {
  38 + server.middleware = proxyMiddleware('/api', {target: gutil.env.target});
  39 + } else {
  40 + // no target! Point to localhost
  41 + server.middleware = proxyMiddleware('/api', {
  42 + target: 'http://0.0.0.0:9000/',
  43 + pathRewrite: {
  44 + // rewrite paths
  45 + '^/api/v1/articles' : '/articles'
  46 + },
  47 + proxyTable: {
  48 + // when request.headers.host == 'dev.localhost:3000',
  49 + // override target 'http://www.example.org' to 'http://localhost:8000'
  50 + // 'dev.localhost:3000' : 'http://localhost:8000'
  51 + 'hom.dialoga.gov.br' : 'http://localhost:9000',
  52 + 'login.dialoga.gov.br' : 'http://localhost:9000'
  53 + }
  54 + });
  55 + }
37 56  
38 57 browserSync.instance = browserSync.init({
39 58 startPath: '/',
... ...
gulp/styles.js
... ... @@ -39,7 +39,10 @@ gulp.task(&#39;styles&#39;, function () {
39 39 .pipe(wiredep(_.extend({}, conf.wiredep)))
40 40 .pipe($.sourcemaps.init())
41 41 .pipe($.sass(sassOptions)).on('error', conf.errorHandler('Sass'))
42   - .pipe($.autoprefixer()).on('error', conf.errorHandler('Autoprefixer'))
  42 + .pipe($.autoprefixer({
  43 + browsers: ['last 3 versions', 'ie >= 9', 'ff > 20', 'Chrome > 30', 'Android', 'Edge', 'Opera', 'Safari', 'iOS'],
  44 + cascade: false
  45 + })).on('error', conf.errorHandler('Autoprefixer'))
43 46 .pipe($.sourcemaps.write())
44 47 .pipe(gulp.dest(path.join(conf.paths.tmp, '/serve/app/')))
45 48 .pipe(browserSync.reload({ stream: true }));
... ...
gulp/watch.js
... ... @@ -25,6 +25,16 @@ gulp.task(&#39;watch&#39;, [&#39;inject&#39;], function () {
25 25 }
26 26 });
27 27  
  28 + gulp.watch([
  29 + path.join(conf.paths.src, '/assets/images/icons/*.png')
  30 + ], function(event) {
  31 + if(isOnlyChange(event)) {
  32 + gulp.start('sprites');
  33 + } else {
  34 + gulp.start('inject');
  35 + }
  36 + });
  37 +
28 38 gulp.watch(path.join(conf.paths.src, '/app/**/*.js'), function(event) {
29 39 if(isOnlyChange(event)) {
30 40 gulp.start('scripts');
... ...
package.json
... ... @@ -6,47 +6,49 @@
6 6 "test": "gulp test"
7 7 },
8 8 "devDependencies": {
  9 + "browser-sync": "~2.7.12",
  10 + "browser-sync-spa": "~1.0.2",
  11 + "chalk": "~1.0.0",
  12 + "concat-stream": "~1.5.0",
  13 + "del": "~1.2.0",
9 14 "gulp": "~3.9.0",
10   - "gulp-autoprefixer": "~2.3.1",
  15 + "gulp-angular-filesort": "~1.1.1",
11 16 "gulp-angular-templatecache": "~1.6.0",
12   - "del": "~1.2.0",
13   - "lodash": "~3.9.3",
  17 + "gulp-autoprefixer": "~2.3.1",
14 18 "gulp-csso": "~1.0.0",
15 19 "gulp-filter": "~2.0.2",
16 20 "gulp-flatten": "~0.0.4",
  21 + "gulp-if": "^1.2.5",
  22 + "gulp-inject": "~1.3.1",
17 23 "gulp-jshint": "~1.11.0",
18 24 "gulp-load-plugins": "~0.10.0",
19   - "gulp-size": "~1.2.1",
20   - "gulp-uglify": "~1.2.0",
21   - "gulp-useref": "~1.2.0",
22   - "gulp-util": "~3.0.5",
  25 + "gulp-minify-html": "~1.0.3",
23 26 "gulp-ng-annotate": "~1.0.0",
24   - "gulp-replace": "~0.5.3",
  27 + "gulp-protractor": "~1.0.0",
25 28 "gulp-rename": "~1.2.2",
  29 + "gulp-replace": "~0.5.3",
26 30 "gulp-rev": "~5.0.0",
27 31 "gulp-rev-replace": "~0.4.2",
28   - "gulp-minify-html": "~1.0.3",
29   - "gulp-inject": "~1.3.1",
30   - "gulp-protractor": "~1.0.0",
31   - "gulp-sourcemaps": "~1.5.2",
32 32 "gulp-sass": "~2.0.1",
33   - "gulp-angular-filesort": "~1.1.1",
34   - "main-bower-files": "~2.8.0",
35   - "merge-stream": "~0.1.7",
  33 + "gulp-size": "~1.2.1",
  34 + "gulp-sourcemaps": "~1.5.2",
  35 + "gulp-uglify": "~1.2.0",
  36 + "gulp-useref": "~1.2.0",
  37 + "gulp-util": "~3.0.5",
  38 + "http-proxy-middleware": "^0.7.0",
36 39 "jshint-stylish": "~2.0.0",
37   - "wiredep": "~2.2.2",
38 40 "karma": "~0.12.36",
39   - "karma-jasmine": "~0.3.5",
40   - "karma-phantomjs-launcher": "~0.2.0",
41 41 "karma-angular-filesort": "~0.1.0",
  42 + "karma-jasmine": "~0.3.5",
42 43 "karma-ng-html2js-preprocessor": "~0.1.2",
43   - "concat-stream": "~1.5.0",
  44 + "karma-phantomjs-launcher": "~0.2.0",
  45 + "lodash": "~3.10.1",
  46 + "main-bower-files": "~2.8.0",
  47 + "merge-stream": "^1.0.0",
44 48 "require-dir": "~0.3.0",
45   - "browser-sync": "~2.7.12",
46   - "browser-sync-spa": "~1.0.2",
47   - "http-proxy-middleware": "~0.0.5",
48   - "chalk": "~1.0.0",
  49 + "sprity": "^1.0.7",
49 50 "uglify-save-license": "~0.4.1",
  51 + "wiredep": "~2.2.2",
50 52 "wrench": "~1.5.8"
51 53 },
52 54 "engines": {
... ...
protractor.conf.js
1   -'use strict';
2   -
3   -var paths = require('./.yo-rc.json')['generator-gulp-angular'].props.paths;
4   -
5   -// An example configuration file.
6   -exports.config = {
7   - // The address of a running selenium server.
8   - //seleniumAddress: 'http://localhost:4444/wd/hub',
9   - //seleniumServerJar: deprecated, this should be set on node_modules/protractor/config.json
10   -
11   - // Capabilities to be passed to the webdriver instance.
12   - capabilities: {
13   - 'browserName': 'chrome'
14   - },
15   -
16   - baseUrl: 'http://localhost:3000',
17   -
18   - // Spec patterns are relative to the current working directly when
19   - // protractor is called.
20   - specs: [paths.e2e + '/**/*.js'],
21   -
22   - // Options to be passed to Jasmine-node.
23   - jasmineNodeOpts: {
24   - showColors: true,
25   - defaultTimeoutInterval: 30000
26   - }
27   -};
  1 +/* globals require, exports*/
  2 +(function(){
  3 + 'use strict';
  4 +
  5 + var paths = require('./.yo-rc.json')['generator-gulp-angular'].props.paths;
  6 +
  7 + // An example configuration file.
  8 + exports.config = {
  9 + // The address of a running selenium server.
  10 + //seleniumAddress: 'http://0.0.0.0:4444/wd/hub',
  11 + //seleniumServerJar: deprecated, this should be set on node_modules/protractor/config.json
  12 +
  13 + // Capabilities to be passed to the webdriver instance.
  14 + capabilities: {
  15 + 'browserName': 'chrome'
  16 + },
  17 +
  18 + chromeOnly: true,
  19 +
  20 + onPrepare: function() {
  21 + /* global angular: false, browser: false */
  22 +
  23 + // Disable animations so e2e tests run more quickly
  24 + var disableNgAnimate = function() {
  25 + angular.module('disableNgAnimate', []).run(['$animate', function($animate) {
  26 + $animate.enabled(false);
  27 + }]);
  28 + };
  29 +
  30 + browser.addMockModule('disableNgAnimate', disableNgAnimate);
  31 +
  32 + // Disable debug info
  33 + // var disableDebugInfo = function() {
  34 + // angular.module('disableDebugInfo', []).run(['$compileProvider', function($compileProvider) {
  35 + // $compileProvider.debugInfoEnabled(false);
  36 + // }]);
  37 + // };
  38 + // browser.addMockModule('disableDebugInfo', disableDebugInfo);
  39 +
  40 + // Store the name of the browser that's currently being used.
  41 + browser.getCapabilities().then(function(caps) {
  42 + browser.params.browser = caps.get('browserName');
  43 + });
  44 +
  45 + browser.driver.manage().window().setSize(1400, 400);
  46 + },
  47 +
  48 + baseUrl: 'http://0.0.0.0:3000',
  49 +
  50 + rootElement: '[ng-app]',
  51 +
  52 + // The timeout in milliseconds for each script run on the browser. This should
  53 + // be longer than the maximum time your application needs to stabilize between
  54 + // tasks.
  55 + allScriptsTimeout: 15000,
  56 +
  57 + // How long to wait for a page to load.
  58 + getPageTimeout: 12000,
  59 +
  60 + // Spec patterns are relative to the current working directly when
  61 + // protractor is called.
  62 + specs: [paths.e2e + '/**/*.js'],
  63 +
  64 + // Options to be passed to Jasmine-node.
  65 + 'framework': 'jasmine2',
  66 + jasmineNodeOpts: {
  67 + showColors: true,
  68 + defaultTimeoutInterval: 30000
  69 + },
  70 +
  71 + plugins: [{
  72 + path: 'node_modules/gulp-protractor/node_modules/protractor/plugins/accessibility',
  73 + chromeA11YDevTools: {
  74 + treatWarningsAsFailures: true
  75 + }
  76 + }, {
  77 + path: 'node_modules/gulp-protractor/node_modules/protractor/plugins/ngHint'
  78 + }]
  79 + };
  80 +})();
... ...
src/app/components/a11y-bar/a11y-bar.html 0 → 100644
... ... @@ -0,0 +1,48 @@
  1 +<div class="a11y-bar">
  2 + <div class="container">
  3 + <div class="row">
  4 + <div class="col-sm-6">
  5 + <ul class="skip-links list-inline list-unstyled">
  6 + <li>
  7 + <a accesskey="1" href="#content" id="skip-to-content" ng-click="skipToContent($event)">
  8 + Ir para o conteúdo
  9 + <span>1</span>
  10 + </a>
  11 + </li>
  12 + <li>
  13 + <a accesskey="2" href="#navigation" id="skip-to-navigation" ng-click="skipToNavigation($event)">
  14 + Ir para o menu
  15 + <span>2</span>
  16 + </a>
  17 + </li>
  18 + <li>
  19 + <a accesskey="3" href="#search" id="skip-to-search" ng-click="skipToSearch($event)">
  20 + Ir para a busca
  21 + <span>3</span>
  22 + </a>
  23 + </li>
  24 + <li>
  25 + <a accesskey="4" href="#footer" id="skip-to-footer" ng-click="skipToFooter($event)">
  26 + Ir para o rodapé
  27 + <span>4</span>
  28 + </a>
  29 + </li>
  30 + </ul>
  31 + </div>
  32 +
  33 + <div class="col-sm-6">
  34 + <ul class="action-links list-inline list-unstyled pull-right">
  35 + <li>
  36 + <a id="siteaction-accessibility" href="#" title="Acessibilidade" accesskey="5" ng-click="actionAccessibility()">Acessibilidade</a>
  37 + </li>
  38 + <li>
  39 + <a id="siteaction-contrast" href="#" title="Alto Contraste" accesskey="6" ng-click="actionContrast()">Alto Contraste</a>
  40 + </li>
  41 + <li>
  42 + <a id="siteaction-sitemap" ui-sref="mapa-do-site" title="Mapa do Site" accesskey="7" ng-click="actionSitemap()">Mapa do Site</a>
  43 + </li>
  44 + </ul>
  45 + </div>
  46 + </div>
  47 + </div>
  48 +</div>
... ...
src/app/components/a11y-bar/a11y-bar.scss 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +.a11y-bar {
  2 + font-size: 12px;
  3 + padding: 5px 0;
  4 + span {
  5 + background-color: #eee;
  6 + padding: 0 3px;
  7 + }
  8 +}
... ...
src/app/components/a11y-bar/a11yBar.directive.js 0 → 100644
... ... @@ -0,0 +1,19 @@
  1 +(function() {
  2 + 'use strict';
  3 +
  4 + angular
  5 + .module('dialoga')
  6 + .directive('a11yBar', a11yBar);
  7 +
  8 + /** @ngInject */
  9 + function a11yBar() {
  10 + var directive = {
  11 + restrict: 'E',
  12 + templateUrl: 'app/components/a11y-bar/a11y-bar.html'
  13 + };
  14 +
  15 + return directive;
  16 +
  17 + }
  18 +
  19 +})();
... ...
src/app/components/article-bar/article-bar.directive.js 0 → 100644
... ... @@ -0,0 +1,68 @@
  1 +(function() {
  2 + 'use strict';
  3 +
  4 + angular
  5 + .module('dialoga')
  6 + .directive('articleBar', articleBar);
  7 +
  8 + /** @ngInject */
  9 + function articleBar() {
  10 + var directive = {
  11 + restrict: 'E',
  12 + templateUrl: 'app/components/article-bar/article-bar.html',
  13 + scope: {
  14 + category: '=',
  15 + categories: '='
  16 + },
  17 + controller: ArticleBarController,
  18 + controllerAs: 'vm',
  19 + bindToController: true
  20 + };
  21 +
  22 + return directive;
  23 +
  24 + /** @ngInject */
  25 + function ArticleBarController($scope, $rootScope, $state, $log) {
  26 + $log.debug('ArticleBarController');
  27 +
  28 + var vm = this;
  29 +
  30 + vm.$scope = $scope;
  31 + vm.$rootScope = $rootScope;
  32 + vm.$state = $state;
  33 + vm.theme = 'blue';
  34 +
  35 + // if(!vm.category) {
  36 + // throw 'article bar without category';
  37 + // }
  38 +
  39 + // if(!vm.categories) {
  40 + // throw 'article bar without categories list';
  41 + // }
  42 +
  43 + vm.currentCategory = vm.category;
  44 +
  45 + vm.$scope.$watch('vm.currentCategory', function(newValue, oldValue){
  46 + if(newValue !== oldValue){
  47 + vm.$state.go('inicio', {
  48 + tema: newValue.slug
  49 + }, {
  50 + location: true
  51 + });
  52 + }
  53 + });
  54 +
  55 + vm.goBack = function (){
  56 + var vm = this;
  57 + var prevState = vm.$rootScope.$previousState;
  58 + if(prevState && prevState.state.name){
  59 + vm.$state.go(prevState.state.name, prevState.params);
  60 + } else {
  61 + vm.$state.go('inicio');
  62 + }
  63 + };
  64 + }
  65 +
  66 + }
  67 +
  68 +})();
... ...
src/app/components/article-bar/article-bar.html 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +<div class="article-bar" ng-class="vm.theme">
  2 + <div class="navbar">
  3 + <div class="navbar-header">
  4 + <button class="article-bar--item btn btn-link" ng-click="vm.goBack()">
  5 + <!-- <span class="glyphicon glyphicon-share-alt" aria-hidden="true"></span> -->
  6 + <span class="glyphicon glyphicon-arrow-left" aria-hidden="true"></span>
  7 + Voltar
  8 + </button>
  9 + </div>
  10 + <div class="navbar-left" ng-if="vm.category">
  11 + <button class="article-bar--item article-bar--category-button btn btn-link">
  12 + <span class="icon" ng-class="'icon-tema-' + vm.category.slug"></span>
  13 + <span class="category-name">{{::vm.category.name}}</span>
  14 + </button>
  15 + </div>
  16 + <div class="navbar-right" ng-if="vm.categories">
  17 + <label for="selectCategory" class="control-label sr-only" title="Selecione uma opção para acessar os programas do tema">Temas:</label>
  18 + <select id="selectCategory" name="selectCategory" class="article-bar--item form-control" ng-model="vm.currentCategory" ng-options="category.name for category in vm.categories track by category.slug">
  19 + </select>
  20 + </div>
  21 + </div>
  22 + </div>
  23 +</div>
... ...
src/app/components/article-bar/article-bar.scss 0 → 100644
... ... @@ -0,0 +1,52 @@
  1 +.article-bar {
  2 + position: relative;
  3 + background-color: #0042b1;
  4 +
  5 + .btn {
  6 + color: #fff;
  7 + font-weight: bold;
  8 + }
  9 +
  10 + &--item {
  11 + margin: 8px 0;
  12 +
  13 + @media (max-width: $screen-xs) {
  14 + margin: 8px;
  15 + }
  16 +
  17 + }
  18 +
  19 + &--category-button {
  20 + position: relative;
  21 + width: 125px;
  22 + text-align: right;
  23 + margin-left: 10px;
  24 + font-size: 24px;
  25 + line-height: 20px;
  26 + font-family: 'Open Sans';
  27 +
  28 + .icon {
  29 + display: inline-block;
  30 + margin: -40px -35px -40px -50px;
  31 + transform: scale(.37);
  32 + }
  33 + }
  34 +
  35 + .navbar {
  36 + margin-bottom: 0;
  37 + }
  38 +
  39 + .navbar-right {
  40 + margin-right: 15px;
  41 + }
  42 +
  43 + @each $category, $color in $categories {
  44 + &.#{$category} {
  45 + background-color: $color;
  46 + }
  47 + }
  48 +
  49 + .contraste & {
  50 + background-color: #262626;
  51 + }
  52 +}
... ...
src/app/components/article-box/article-box.directive.js 0 → 100644
... ... @@ -0,0 +1,84 @@
  1 +(function() {
  2 + 'use strict';
  3 +
  4 + angular
  5 + .module('dialoga')
  6 + .directive('articleBox', articleBox);
  7 +
  8 + /** @ngInject */
  9 + function articleBox($rootScope) {
  10 +
  11 + /** @ngInject */
  12 + function ArticleBoxController(ArticleService, $scope, $state, Slug, $log) {
  13 + $log.debug('ArticleBoxController');
  14 +
  15 + var vm = this;
  16 + vm.ArticleService = ArticleService;
  17 + vm.$scope = $scope;
  18 + vm.$state = $state;
  19 + vm.Slug = Slug;
  20 + vm.$log = $log;
  21 +
  22 + vm.init();
  23 + }
  24 +
  25 + ArticleBoxController.prototype.init = function () {
  26 + var vm = this;
  27 +
  28 + if(!vm.article.slug){
  29 + vm.article.slug = vm.Slug.slugify(vm.article.title);
  30 + }
  31 +
  32 + if(!vm.category){
  33 + vm.category = vm.article.categories[0];
  34 + }
  35 +
  36 + if(!vm.banner){
  37 + vm.banner = {
  38 + src: $rootScope.basePath + vm.article.image.url,
  39 + alt: 'Imagem de destaque do conteúdo'
  40 + };
  41 + }
  42 +
  43 + // if(vm.article.color && !vm.article.bgColor){
  44 + // // 15% more darker
  45 + // vm.article.colorDarker = window.ColorLuminance(vm.article.color, 0.15);
  46 + // }
  47 + };
  48 +
  49 + ArticleBoxController.prototype.showContent = function () {
  50 + var vm = this;
  51 +
  52 + vm.$state.go('programa-conheca', {
  53 + slug: vm.article.slug
  54 + }, {
  55 + location: true
  56 + });
  57 + };
  58 +
  59 + ArticleBoxController.prototype.showPreview = function () {
  60 + var vm = this;
  61 +
  62 + vm.$state.go('programa', {
  63 + slug: vm.article.slug
  64 + }, {
  65 + location: true
  66 + });
  67 + };
  68 +
  69 + var directive = {
  70 + restrict: 'E',
  71 + templateUrl: 'app/components/article-box/article-box.html',
  72 + scope: {
  73 + article: '='
  74 + },
  75 + controller: ArticleBoxController,
  76 + controllerAs: 'vm',
  77 + bindToController: true
  78 + };
  79 +
  80 +
  81 + return directive;
  82 + }
  83 +
  84 +})();
... ...
src/app/components/article-box/article-box.html 0 → 100644
... ... @@ -0,0 +1,18 @@
  1 +<article class="article-box" ng-click="vm.showPreview()" ng-class="vm.category.slug">
  2 + <div>
  3 + <h2 class="article-box--category">{{vm.category.name}}</h2>
  4 + <div class="article-box--image-wrapper">
  5 + <!-- <img class="article-box--image img-responsive" ng-src="{{vm.banner.src}}" alt="{{vm.banner.alt}}" /> -->
  6 + <div class="article-box--image" ng-style="{'background-image':'url( {{vm.banner.src}} )'}"></div>
  7 + </div>
  8 + <div class="article-box--title">
  9 + <h1>{{::vm.article.title}}</h1>
  10 + </div>
  11 + <div class="article-box--abstract" ng-bind-html="vm.article.abstract"></div>
  12 + <div class="button--themed">
  13 + <button class="btn btn-block">
  14 + Participe
  15 + </button>
  16 + </div>
  17 + </div>
  18 +</article>
... ...
src/app/components/article-box/article-box.scss 0 → 100644
... ... @@ -0,0 +1,146 @@
  1 +$article-box-space: 20px;
  2 +
  3 +.article-box {
  4 + cursor: pointer;
  5 + background-color: #fff;
  6 + margin-top: $article-box-space;
  7 + margin-bottom: $article-box-space;
  8 + border-radius: 3px;
  9 + overflow: hidden;
  10 +
  11 + .contraste & {
  12 + color: #fff;
  13 + background-color: #262626;
  14 + }
  15 +
  16 + &--category {
  17 + font-size: 14px;
  18 + font-weight: bold;
  19 + text-transform: uppercase;
  20 + line-height: 22px;
  21 + display: block;
  22 + height: 30px;
  23 + margin: 0;
  24 + padding: 5px $article-box-space;
  25 + color: #ffffff;
  26 +
  27 + @each $category, $color in $categories {
  28 + .#{$category} & {
  29 + background-color: $color;
  30 + }
  31 + }
  32 +
  33 + .contraste & {
  34 + background-color: #262626;
  35 + }
  36 + }
  37 +
  38 + &--title {
  39 +
  40 + padding: 0 $article-box-space;
  41 +
  42 + h1 {
  43 + font-size: 18px;
  44 + font-weight: bold;
  45 + margin: 0 0 $article-box-space 0;
  46 + display: table-cell;
  47 + vertical-align: middle;
  48 +
  49 + // Altura das linhas do abstract
  50 + $hLine: 20px;
  51 + // default
  52 + height: $hLine * 2;
  53 +
  54 + @media (max-width: $screen-xs) {
  55 + // height: $hLine * 3;
  56 + height: auto;
  57 + }
  58 +
  59 + @media (min-width: $screen-xs + 1) {
  60 + // height: $hLine * 2;
  61 + height: auto;
  62 + }
  63 +
  64 + @media (min-width: $screen-sm + 1) {
  65 + height: $hLine * 2;
  66 + }
  67 +
  68 + @media (min-width: $screen-md + 1) {
  69 + height: $hLine * 2;
  70 + }
  71 + }
  72 + }
  73 +
  74 + &--abstract {
  75 + padding: 0 $article-box-space;
  76 + display: table-cell;
  77 + vertical-align: middle;
  78 +
  79 + // Altura das linhas do abstract
  80 + $pLine: 20px;
  81 + // 1 linha: 19px -> 20
  82 + // 2 linhas: 38px -> 40
  83 + // 3 linhas: 57px -> 60
  84 + // 4 linhas: 76px -> 80
  85 +
  86 + height: $pLine * 2; // default
  87 +
  88 + @media (max-width: $screen-xs) {
  89 + // height: $pLine * 4;
  90 + height: auto;
  91 + }
  92 +
  93 + @media (min-width: $screen-xs + 1) {
  94 + // height: $pLine * 3;
  95 + height: auto;
  96 + }
  97 +
  98 + @media (min-width: $screen-sm + 1) {
  99 + height: $pLine * 4;
  100 + }
  101 +
  102 + @media (min-width: $screen-md + 1) {
  103 + height: $pLine * 3;
  104 + }
  105 +
  106 + p { margin: 0; }
  107 + }
  108 +
  109 + &--image-wrapper {
  110 + position: relative;
  111 + // width: 100%;
  112 + // width: 370px;
  113 + // height: 170px;
  114 +
  115 + overflow: hidden;
  116 + // text-align: center;
  117 + min-height: 170px;
  118 + }
  119 +
  120 + &--image {
  121 + min-height: 170px;
  122 + background-position: center;
  123 + background-size: cover;
  124 + background-repeat: no-repeat;
  125 +
  126 + -webkit-transition: all $time ease-in-out;
  127 + -moz-transition: all $time ease-in-out;
  128 + -o-transition: all $time ease-in-out;
  129 + transition: all $time ease-in-out;
  130 + }
  131 +
  132 + &:hover {
  133 + background-color: #d9d9d9;
  134 +
  135 + .article-box--image {
  136 + -webkit-transform: scale($scale); /* prefixo para browsers webkit */
  137 + -moz-transform: scale($scale); /* prefixo para browsers gecko */
  138 + -o-transform: scale($scale); /* prefixo para opera */
  139 + transform: scale($scale);
  140 + }
  141 +
  142 + .contraste & {
  143 + background-color: #262626;
  144 + }
  145 + }
  146 +}
... ...
src/app/components/article-content/article-content.directive.js 0 → 100644
src/app/components/article-content/article-content.scss 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +.article-content {
  2 + h2 {
  3 + font-size: 38px;
  4 + font-weight: 500;
  5 + margin-bottom: 40px;
  6 + padding-bottom: 20px;
  7 +
  8 + small {
  9 + display: block;
  10 + font-size: 16px;
  11 + padding-top: 5px;
  12 + text-transform: none;
  13 + }
  14 + }
  15 +}
... ...
src/app/components/article-grid/article-grid.directive.js 0 → 100644
... ... @@ -0,0 +1,322 @@
  1 +(function() {
  2 + 'use strict';
  3 +
  4 + angular
  5 + .module('dialoga')
  6 + .directive('articleGrid', articleGrid);
  7 +
  8 + /** @ngInject */
  9 + function articleGrid() {
  10 +
  11 + /** @ngInject */
  12 + function ArticleGridController($scope, $rootScope, $element, ArticleService, $location, $filter, $log) {
  13 + $log.debug('ArticleGridController');
  14 +
  15 + // alias
  16 + var vm = this;
  17 +
  18 + // dependencies
  19 + vm.$scope = $scope;
  20 + vm.$rootScope = $rootScope;
  21 + vm.$element = $element;
  22 + vm.ArticleService = ArticleService;
  23 + vm.$location = $location;
  24 + vm.$filter = $filter;
  25 + vm.$log = $log;
  26 + vm.defaultLimit = 6;
  27 +
  28 + // initialization
  29 + vm.init();
  30 + }
  31 +
  32 + ArticleGridController.prototype.init = function() {
  33 + var vm = this;
  34 +
  35 + vm.ArticleService.getPrograms(function(programs){
  36 + vm.articles = programs;
  37 + });
  38 +
  39 + vm.ArticleService.getCategories(function(categories){
  40 + vm.categories = categories;
  41 + });
  42 +
  43 + vm.orderCriteries = [
  44 + { label: 'Título', name: 'titulo' },
  45 + { label: 'Tema', name: 'tema' },
  46 + { label: 'Aleatório', name: 'aleatorio' }
  47 + ];
  48 +
  49 + vm.filtredArticleList = vm.getFiltredArticles();
  50 + vm.search = vm.$location.search();
  51 +
  52 + // Add initial values for the filter
  53 + vm.query = (vm.search && vm.search.filtro) ? vm.search.filtro : null;
  54 + vm.limitTo = (vm.search && vm.search.limite) ? parseInt(vm.search.limite, 10) : vm.defaultLimit;
  55 + vm.orderCriteria = (vm.search && vm.search.ordem) ? { name: vm.search.ordem } : null;
  56 + vm.reverse = (vm.search && vm.search.reverso) ? true : false;
  57 +
  58 + // vm.selectedCategory = (vm.search && vm.search.tema) ? vm.getCategoryBySlug(vm.search.tema) : null;
  59 + if (vm.search && vm.search.tema) {
  60 + var slug = vm.search.tema;
  61 + vm.ArticleService.getCategoryBySlug(slug, function(category){
  62 + vm.selectedCategory = category;
  63 + }, function(error){
  64 + vm.$log.error('Error when try to "getCategoryBySlug"', error);
  65 + });
  66 + }
  67 +
  68 + if (!angular.equals({}, vm.search)) {
  69 + var $el = vm.$element;
  70 + angular.element('body').animate({scrollTop: $el.offset().top}, 'slow');
  71 + }
  72 +
  73 + // update window location params
  74 + vm.$scope.$on('change-selectedCategory', function(event, selectedCategory){
  75 + vm.selectedCategory = selectedCategory;
  76 + });
  77 +
  78 + vm.$scope.$watch('vm.query', function(newValue/*, oldValue*/) {
  79 + vm.search.filtro = newValue ? newValue : null;
  80 + vm.$location.search('filtro', vm.search.filtro);
  81 + if(vm.search.filtro){
  82 + vm.limitTo = vm.articles.length;
  83 + }else{
  84 + vm.limitTo = vm.defaultLimit;
  85 + }
  86 + vm.filtredArticleList = vm.getFiltredArticles();
  87 + });
  88 +
  89 + vm.$scope.$watch('vm.limitTo', function(newValue/*, oldValue*/) {
  90 + vm.search.limite = (newValue && newValue !== vm.defaultLimit) ? newValue : null;
  91 + vm.$location.search('limite', vm.search.limite);
  92 + vm.filtredArticleList = vm.getFiltredArticles();
  93 + });
  94 +
  95 + vm.$scope.$watch('vm.selectedCategory', function(newValue/*, oldValue*/) {
  96 + vm.search.tema = newValue ? newValue.slug : null;
  97 + vm.$location.search('tema', vm.search.tema);
  98 + if(vm.search.tema){
  99 + vm.limitTo = vm.articles.length;
  100 + }else{
  101 + vm.limitTo = vm.defaultLimit;
  102 + }
  103 + vm.filtredArticleList = vm.getFiltredArticles();
  104 + });
  105 +
  106 + vm.$scope.$watch('vm.orderCriteria', function(newValue/*, oldValue*/) {
  107 + vm.search.ordem = (newValue && newValue.name) ? newValue.name : null;
  108 + vm.$location.search('ordem', vm.search.ordem);
  109 + vm.filtredArticleList = vm.getFiltredArticles();
  110 + });
  111 +
  112 + vm.$scope.$watch('vm.reverse', function(newValue/*, oldValue*/) {
  113 + vm.search.reverso = newValue ? newValue : null;
  114 + vm.$location.search('reverso', vm.search.reverso);
  115 + vm.filtredArticleList = vm.getFiltredArticles();
  116 + });
  117 +
  118 + };
  119 +
  120 + ArticleGridController.prototype.resetFilterValues = function() {
  121 + var vm = this;
  122 +
  123 + vm.query = null;
  124 + vm.limitTo = vm.defaultLimit;
  125 + vm.selectedCategory = null;
  126 + vm.orderCriteria = null;
  127 + };
  128 +
  129 + ArticleGridController.prototype.getIconClasses = function(category) {
  130 + var vm = this;
  131 +
  132 + vm.$log.debug('[TODO] getIconClasses of category:', category);
  133 + return 'glyphicon glyphicon-exclamation-sign';
  134 + };
  135 +
  136 + ArticleGridController.prototype.getCategoryBySlug = function(categorySlug) {
  137 + var vm = this;
  138 + var result = null;
  139 +
  140 + angular.forEach(vm.categories, function(value/*, key*/) {
  141 + if (value.slug === categorySlug) {
  142 + result = value;
  143 + }
  144 + });
  145 +
  146 + return result;
  147 + };
  148 +
  149 + ArticleGridController.prototype.showAll = function($event) {
  150 + var vm = this;
  151 +
  152 + $event.stopPropagation();
  153 +
  154 + vm.resetFilterValues();
  155 + vm.limitTo = vm.articles.length;
  156 + };
  157 +
  158 + ArticleGridController.prototype.getFiltredArticles = function() {
  159 + var vm = this;
  160 +
  161 + if(!vm.articles){
  162 + vm.$log.warn('No articles loaded yet. Abort.');
  163 + return null;
  164 + }
  165 +
  166 + var input = vm.articles;
  167 + var output = input;
  168 + var query = vm.query;
  169 + var selectedCategory = vm.selectedCategory;
  170 + var orderCriteria = vm.orderCriteria ? vm.orderCriteria : { name : 'aleatorio'};
  171 + var filter = vm.$filter('filter');
  172 + var orderBy = vm.$filter('orderBy');
  173 + var limitTo = vm.$filter('limitTo');
  174 + var limit = vm.limitTo ? vm.limitTo : 4;
  175 +
  176 + if (selectedCategory) {
  177 + output = _filterByCategory(output, selectedCategory);
  178 + }
  179 +
  180 + if (query) {
  181 + output = filter(output, query, false);
  182 + }
  183 +
  184 + switch (orderCriteria.name) {
  185 + case 'titulo':
  186 + output = orderBy(output, 'title', vm.reverse);
  187 + break;
  188 + case 'tema':
  189 + output = orderBy(output, 'categories[0].name', vm.reverse);
  190 + break;
  191 + case 'more_participants':
  192 + vm.$log.info('Criteria not handled yet: ', orderCriteria);
  193 + break;
  194 + case 'aleatorio':
  195 + // shuffling
  196 + // if (!vm._isShuffled){
  197 + output = vm.filterShuffle(output);
  198 + // vm._isShuffled = true;
  199 + // }
  200 +
  201 + if (vm.reverse) {
  202 + output = output.slice().reverse();
  203 + }
  204 +
  205 + break;
  206 + default:
  207 + vm.$log.warn('Criteria not matched: ', orderCriteria);
  208 + break;
  209 + }
  210 +
  211 + output = limitTo(output, limit);
  212 +
  213 + return output;
  214 + };
  215 +
  216 + ArticleGridController.prototype.filterShuffle = function(input) {
  217 + var result = [];
  218 + var resultByCategory = {};
  219 +
  220 + // divide by categories
  221 + for (var i = 0; i < input.length; i++) {
  222 + var program = input[i];
  223 + var categorySlug = program.categories[0].slug;
  224 +
  225 + if (!resultByCategory[categorySlug]) {
  226 + resultByCategory[categorySlug] = [];
  227 + }
  228 +
  229 + resultByCategory[categorySlug].push(program);
  230 + }
  231 +
  232 + // shuffle each array
  233 + var prop = null;
  234 + var categoryWithPrograms = null;
  235 + for (prop in resultByCategory) {
  236 + if (resultByCategory.hasOwnProperty(prop)) {
  237 + categoryWithPrograms = resultByCategory[prop];
  238 + resultByCategory[prop] = shuffle(categoryWithPrograms);
  239 + }
  240 + }
  241 +
  242 + // Concat all into result array
  243 + // > while has program at Lists on resultByCategory
  244 + var hasProgram = true;
  245 + while (hasProgram) {
  246 +
  247 + var foundProgram = false;
  248 + // each categoryList with array of program
  249 + prop = null;
  250 + categoryWithPrograms = null;
  251 + for (prop in resultByCategory) {
  252 +
  253 + if (resultByCategory.hasOwnProperty(prop)) {
  254 + categoryWithPrograms = resultByCategory[prop];
  255 +
  256 + if (categoryWithPrograms.length > 0) {
  257 + var pivotProgram = categoryWithPrograms.pop();
  258 + result.push(pivotProgram);
  259 + foundProgram = true;
  260 + }
  261 + }
  262 + }
  263 +
  264 + if (!foundProgram) {
  265 + hasProgram = false;
  266 + }
  267 + }
  268 +
  269 + return result;
  270 + };
  271 +
  272 + var directive = {
  273 + restrict: 'E',
  274 + templateUrl: 'app/components/article-grid/article-grid.html',
  275 + controller: ArticleGridController,
  276 + controllerAs: 'vm',
  277 + bindToController: true
  278 + };
  279 +
  280 + return directive;
  281 + }
  282 +
  283 + function _filterByCategory (input, category) {
  284 + input = input || [];
  285 +
  286 + if (!category) {
  287 + // no filter
  288 + return input;
  289 + }
  290 +
  291 + var out = [];
  292 + for (var i = 0; i < input.length; i++) {
  293 + var program = input[i];
  294 + if (program.categories[0].slug === category.slug) {
  295 + out.push(program);
  296 + }
  297 + }
  298 +
  299 + return out;
  300 + }
  301 +
  302 + // -> Fisher–Yates shuffle algorithm
  303 + function shuffle (array) {
  304 + var currentIndex = array.length, temporaryValue, randomIndex ;
  305 +
  306 + // While there remain elements to shuffle...
  307 + while (0 !== currentIndex) {
  308 +
  309 + // Pick a remaining element...
  310 + randomIndex = Math.floor(Math.random() * currentIndex);
  311 + currentIndex -= 1;
  312 +
  313 + // And swap it with the current element.
  314 + temporaryValue = array[currentIndex];
  315 + array[currentIndex] = array[randomIndex];
  316 + array[randomIndex] = temporaryValue;
  317 + }
  318 +
  319 + return array;
  320 + }
  321 +
  322 +})();
... ...
src/app/components/article-grid/article-grid.html 0 → 100644
... ... @@ -0,0 +1,50 @@
  1 +<article class="article-grid">
  2 + <header class="header">
  3 + <h2>Conheça os programas <span class="small">({{vm.filtredArticleList.length}}/{{vm.articles.length}})</span></h2>
  4 + <button type="button" class="btn btn-link" ng-click="vm.showAll($event)">
  5 + <span class="glyphicon glyphicon-chevron-right"></span> Ver todos os {{vm.articles.length}} programas
  6 + </button>
  7 + </header>
  8 + <div>
  9 + <div class="col-sm-12">
  10 + <aside class="form-inline">
  11 + <div class="row">
  12 + <div class="col-xs-6 col-sm-7 col-md-9">
  13 + <label for="articleQueryFilter" class="control-label sr-only">Filtrar programas:</label>
  14 + <input id="articleQueryFilter" type="search" class="form-control" ng-model="vm.query" placeholder="Filtrar programas" aria-label="Filtrar programas" >
  15 + </div>
  16 +
  17 + <!-- <label for="selectCategoryFilter" class="control-label sr-only">Filtrar por tema:</label>
  18 + <select id="selectCategoryFilter" name="selectCategoryFilter" class="form-control" ng-model="vm.categoryFilter" ng-options="category.name for category in vm.categories track by category.slug">
  19 + <option value="">-- Filtrar por tema --</option>
  20 + </select> -->
  21 +
  22 + <div class="col-xs-6 col-sm-5 col-md-3">
  23 + <label for="articleOrderByFilter" class="control-label sr-only">Ordernar por:</label>
  24 + <select id="articleOrderByFilter" name="articleOrderByFilter" class="form-control pull-right" ng-model="vm.orderCriteria" ng-options="orderCriteria.label for orderCriteria in vm.orderCriteries">
  25 + <option value="">-- Ordernar por: --</option>
  26 + </select>
  27 + </div>
  28 + <!-- <div class="checkbox">
  29 + <label>
  30 + <input type="checkbox" ng-model="vm.reverse">
  31 + Reverso
  32 + </label>
  33 + </div> -->
  34 +
  35 + <!-- <input id="articleLimitFilter" type="number" class="form-control input-sm" size="4" step="2" ng-model="vm.limitTo" aria-label="Limitar" >
  36 + <label for="articleLimitFilter" class="control-label">Limite</label> -->
  37 +
  38 + </div>
  39 + </aside>
  40 + </div>
  41 +
  42 + <div ng-repeat="article in vm.filtredArticleList as results">
  43 + <article-box article="article" class="col-xs-12 col-sm-6"></article-box>
  44 + <div ng-if="$odd" class="clearfix"></div>
  45 + </div>
  46 + <div class="animate-repeat" ng-if="results.length == 0">
  47 + Nenhum programa encontrado.
  48 + </div>
  49 + </div>
  50 +</article>
... ...
src/app/components/article-grid/article-grid.scss 0 → 100644
... ... @@ -0,0 +1,20 @@
  1 +.article-grid {
  2 + .header {
  3 + position: relative;
  4 + height: 40px;
  5 + margin-bottom: 10px;
  6 +
  7 + button {
  8 + position: absolute;
  9 + right: 0;
  10 + top: 2px;
  11 + }
  12 + }
  13 +
  14 + .form-inline {
  15 + input,
  16 + select {
  17 + width: 100%;
  18 + }
  19 + }
  20 +}
... ...
src/app/components/article-preview/article-preview.directive.js 0 → 100644
... ... @@ -0,0 +1,74 @@
  1 +(function() {
  2 + 'use strict';
  3 +
  4 + angular
  5 + .module('dialoga')
  6 + .directive('articlePreview', articlePreview);
  7 +
  8 + /** @ngInject */
  9 + function articlePreview($rootScope) {
  10 +
  11 + /** @ngInject */
  12 + function ArticlePreviewController(ArticleService, $scope, $state, Slug, $log) {
  13 + $log.debug('ArticlePreviewController');
  14 +
  15 + var vm = this;
  16 + vm.ArticleService = ArticleService;
  17 + vm.$scope = $scope;
  18 + vm.$state = $state;
  19 + vm.Slug = Slug;
  20 + vm.$log = $log;
  21 +
  22 + vm.init();
  23 + }
  24 +
  25 + ArticlePreviewController.prototype.init = function () {
  26 + var vm = this;
  27 +
  28 + if(!vm.article.slug){
  29 + vm.article.slug = vm.Slug.slugify(vm.article.title);
  30 + }
  31 +
  32 + if(!vm.category){
  33 + vm.category = vm.article.categories[0];
  34 + }
  35 +
  36 + if(!vm.banner){
  37 + vm.banner = {
  38 + src: $rootScope.basePath + vm.article.image.url,
  39 + alt: 'Imagem de destaque do programa'
  40 + };
  41 + }
  42 +
  43 + // if(vm.article.color && !vm.article.bgColor){
  44 + // // 15% more darker
  45 + // vm.article.colorDarker = window.ColorLuminance(vm.article.color, 0.15);
  46 + // }
  47 + };
  48 +
  49 + ArticlePreviewController.prototype.showContent = function () {
  50 + var vm = this;
  51 +
  52 + vm.$state.go('conheca-o-programa', {
  53 + slug: vm.article.slug
  54 + }, {
  55 + location: true
  56 + });
  57 + };
  58 +
  59 + var directive = {
  60 + restrict: 'E',
  61 + templateUrl: 'app/components/article-preview/article-preview.html',
  62 + scope: {
  63 + article: '='
  64 + },
  65 + controller: ArticlePreviewController,
  66 + controllerAs: 'vm',
  67 + bindToController: true
  68 + };
  69 +
  70 +
  71 + return directive;
  72 + }
  73 +
  74 +})();
... ...
src/app/components/article-preview/article-preview.html 0 → 100644
... ... @@ -0,0 +1,101 @@
  1 +<article class="article-preview" ng-class="vm.category.slug">
  2 + <header class="article-banner">
  3 + <img class="article-banner--image" ng-src="{{vm.banner.src}}" alt="{{vm.banner.alt}}">
  4 + <div class="article-banner--strip">
  5 + <h1 class="article-banner--title">{{::vm.article.title}}</h1>
  6 + <p class="article-banner--abstract" ng-bind-html="vm.article.abstract"></p>
  7 + </div>
  8 + </header>
  9 +
  10 + <section class="call-to-action--section">
  11 + <div class="row show-content-row">
  12 + <div class="col-xs-10 col-xs-offset-1 col-md-8 col-md-offset-2 col-lg-6 col-lg-offset-3">
  13 + <div class="button--themed">
  14 + <button class="btn btn-block" ng-click="vm.showContent()">Conheça o programa</button>
  15 + </div>
  16 + </div>
  17 + </div>
  18 + <div class="row proposal-row">
  19 + <div class="row-height">
  20 + <div class="col-md-6 col-height">
  21 + <div class="inside-full-height">
  22 + <div class="proposal-box make-proposal">
  23 + <h2 class="proposal-box--title">Faça uma proposta</h2>
  24 + <p class="proposal-box--text">Qual a sua sugestão para melhorar este programa?</p>
  25 + <div class="row">
  26 + <div class="col-xs-8 col-xs-offset-2">
  27 + <div class="button--themed">
  28 + <button class="btn btn-block" ng-click="vm.goSendProposal()">
  29 + Envie sua proposta
  30 + </button>
  31 + </div>
  32 + </div>
  33 + </div>
  34 + </div>
  35 + </div>
  36 + </div>
  37 + <div class="col-md-6 col-height">
  38 + <div class="inside-full-height">
  39 + <div class="proposal-box support-proposal">
  40 + <h2 class="proposal-box--title">Apoie outras propostas</h2>
  41 + <p class="proposal-box--text">
  42 + Lorem qual a sua sugestão para melhorar este programa
  43 + Lorem qual a sua sugestão para melhorar este programa
  44 + Lorem qual a sua sugestão para melhorar este programa
  45 + Lorem qual a sua sugestão para melhorar este programa
  46 + Lorem qual a sua sugestão para melhorar este programa
  47 + Lorem qual a sua sugestão para melhorar este programa?
  48 + </p>
  49 + <div class="col-lg-12">
  50 + <div class="col-xs-8 col-xs-offset-2 col-sm-10 col-sm-offset-1 col-md-8 col-md-offset-2">
  51 + <div class="button--themed vote-buttons">
  52 + <button class="btn btn-circle vote-buttons-up" ng-click="vm.vote(1)">
  53 + <span class="sr-only">Eu <b>apoio</b> esta proposta.</span>
  54 + <span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
  55 + </button>
  56 +
  57 + <button class="btn btn-circle vote-buttons-down" ng-click="vm.vote(-1)">
  58 + <span class="sr-only">Eu <b>não apoio</b> esta proposta.</span>
  59 + <span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
  60 + </button>
  61 +
  62 + <button class="btn btn-block vote-buttons-skip" ng-click="vm.vote(0)">
  63 + <span class="sr-only">Pular esta proposta.</span>
  64 + <span class="icon" aria-hidden="true"></span>
  65 + Pular
  66 + </button>
  67 + </div>
  68 + </div>
  69 + </div>
  70 + <div class="col-lg-12">
  71 + <div class="col-xs-8 col-xs-offset-2 col-sm-10 col-sm-offset-1 col-md-8 col-md-offset-2">
  72 + <div class="text-center">
  73 + <button class="btn btn-link" ng-click="vm.showResults()">Resultados</button>
  74 + </div>
  75 + </div>
  76 + </div>
  77 + <div class="col-md-12">
  78 + <div class="col-xs-12">
  79 + <div class="text-center">
  80 + <span>Compartilhe esta proposta</span>
  81 + <social-share></social-share>
  82 + </div>
  83 + </div>
  84 + </div>
  85 + <div class="clearfix"></div>
  86 + </div>
  87 + </div>
  88 + </div>
  89 + </div>
  90 + </div>
  91 + <div class="talk-proposal row proposal-row">
  92 + <div class="row-height">
  93 + <div class="col-md-12 col-height">
  94 + <div class="">
  95 + <h2>Bate-papo virtual com ministr@s</h2>
  96 + </div>
  97 + </div>
  98 + </div>
  99 + </div>
  100 + </section>
  101 +</article>
... ...
src/app/components/article-preview/article-preview.scss 0 → 100644
... ... @@ -0,0 +1,111 @@
  1 +.article-preview {
  2 + .article-banner {
  3 + position: relative;
  4 + }
  5 +
  6 + .article-banner--image {
  7 + width: 100%;
  8 + }
  9 +
  10 + .article-banner--strip {
  11 + color: #fff;
  12 + position: absolute;
  13 + bottom: 15%;
  14 + right: 0;
  15 + width: 50%;
  16 + text-align: center;
  17 +
  18 + @each $category, $color in $categories {
  19 + .#{$category} & {
  20 + background-color: $color;
  21 + }
  22 + }
  23 +
  24 + @media (max-width: $screen-sm){
  25 + position: relative;
  26 + width: 100%;
  27 + }
  28 + }
  29 +
  30 + .article-banner--title {
  31 + font-size: 32px;
  32 + text-transform: uppercase;
  33 + margin-top: 0;
  34 + padding-top: 20px;
  35 + }
  36 + .article-banner--title,
  37 + .article-banner--abstract {
  38 + font-weight: bold;
  39 + }
  40 + .article-banner--abstract {
  41 + padding-bottom: 10px;
  42 + }
  43 +
  44 + .show-content-row {
  45 + .button--themed {
  46 + .btn {
  47 + font-size: 38px;
  48 +
  49 + @media (max-width: $screen-sm){
  50 + font-size: 20px;
  51 + }
  52 + }
  53 + }
  54 + }
  55 +
  56 + .talk-proposal {
  57 + margin-top: -20px;
  58 + }
  59 +
  60 + .proposal-box {
  61 +
  62 + // padding: 10px 20px;
  63 +
  64 + .proposal-box--title {
  65 + font-size: 38px;
  66 + font-weight: 400;
  67 + text-align: center;
  68 +
  69 + margin-bottom: 20px;
  70 + }
  71 +
  72 + .proposal-box--text {
  73 + font-size: 24px;
  74 + font-weight: 700;
  75 + line-height: 1.2;
  76 + margin-bottom: 20px;
  77 + }
  78 +
  79 + @each $category, $color in $categories {
  80 + .#{$category} & {
  81 + border-color: $color;
  82 +
  83 + .proposal-box--title {
  84 + color: $color;
  85 + }
  86 + }
  87 + }
  88 + }
  89 +
  90 + .row-height {
  91 + border-spacing: 20px;
  92 + }
  93 +
  94 + .col-height {
  95 +
  96 + border: 1px solid #000;
  97 + border-radius: 3px;
  98 +
  99 + @each $category, $color in $categories {
  100 + .#{$category} & {
  101 + border-color: $color;
  102 + }
  103 + }
  104 +
  105 + @media (max-width: $screen-sm){
  106 + display: block;
  107 + border: none;
  108 + }
  109 +
  110 + }
  111 +}
... ...
src/app/components/auth/auth.service.js
... ... @@ -8,7 +8,7 @@
8 8 .factory('AuthInterceptor', AuthInterceptor);
9 9  
10 10 /** @ngInject */
11   - function AuthService($http, $rootScope, Session, AUTH_EVENTS, api, $log) {
  11 + function AuthService($http, $rootScope, Session, AUTH_EVENTS, API, $log) {
12 12  
13 13 var service = {
14 14 login: login,
... ... @@ -21,7 +21,7 @@
21 21 return service;
22 22  
23 23 function login (credentials) {
24   - var url = api.host + '/api/v1/login';
  24 + var url = API.host + '/api/v1/login';
25 25 var encodedData = 'login=' + credentials.username + '&password=' + credentials.password;
26 26  
27 27 return $http
... ...
src/app/components/category-list/category-list.directive.js 0 → 100644
... ... @@ -0,0 +1,77 @@
  1 +(function() {
  2 + 'use strict';
  3 +
  4 + angular
  5 + .module('dialoga')
  6 + .directive('categoryList', categoryList);
  7 +
  8 + /** @ngInject */
  9 + function categoryList() {
  10 +
  11 + /** @ngInject */
  12 + function CategoryListController($rootScope, ArticleService, $location, $log) {
  13 + $log.debug('CategoryListController');
  14 +
  15 + // alias
  16 + var vm = this;
  17 +
  18 + // dependencies
  19 + vm.$rootScope = $rootScope;
  20 + vm.ArticleService = ArticleService;
  21 + vm.$location = $location;
  22 + vm.$log = $log;
  23 + vm.defaultLimit = 6;
  24 +
  25 + // initialization
  26 + vm.init();
  27 + }
  28 +
  29 + CategoryListController.prototype.init = function() {
  30 + var vm = this;
  31 +
  32 + vm.selectedCategory = null;
  33 + vm.ArticleService.getCategories(function(categories){
  34 + vm.categories = categories;
  35 +
  36 + });
  37 +
  38 + vm.search = vm.$location.search();
  39 + if (vm.search && vm.search.tema) {
  40 + var slug = vm.search.tema;
  41 + vm.ArticleService.getCategoryBySlug(slug, function(category){
  42 + vm.selectedCategory = category;
  43 + }, function(error){
  44 + vm.$log.error('Error when try to "getCategoryBySlug"', error);
  45 + });
  46 + }
  47 + };
  48 +
  49 + CategoryListController.prototype.selectCategory = function(category, $event) {
  50 + var vm = this;
  51 +
  52 + // prevent glitch
  53 + $event.stopPropagation();
  54 +
  55 + if (category !== vm.selectedCategory) {
  56 + // selected new filter
  57 + vm.selectedCategory = category;
  58 + } else {
  59 + vm.selectedCategory = null;
  60 + }
  61 +
  62 + // send event to all controllers
  63 + vm.$rootScope.$broadcast('change-selectedCategory', vm.selectedCategory);
  64 + };
  65 +
  66 + var directive = {
  67 + restrict: 'E',
  68 + templateUrl: 'app/components/category-list/category-list.html',
  69 + controller: CategoryListController,
  70 + controllerAs: 'categoryListCtrl',
  71 + bindToController: true
  72 + };
  73 +
  74 + return directive;
  75 + }
  76 +
  77 +})();
... ...
src/app/components/category-list/category-list.html 0 → 100644
... ... @@ -0,0 +1,17 @@
  1 +<div class="category-list">
  2 + <nav class="navigation">
  3 + <h3 class="category-list--title"><b>Programas</b> por Tema</h3>
  4 + <div class="list-group category-list" ng-class="categoryListCtrl.selectedCategory.slug">
  5 + <button type="button" class="list-group-item category-list--item"
  6 + ng-repeat="category in categoryListCtrl.categories"
  7 + ng-class="{active: categoryListCtrl.selectedCategory.slug === category.slug}"
  8 + ng-click="categoryListCtrl.selectCategory(category, $event)">
  9 +
  10 + <span class="category-list--icon-circle" aria-hidden="true" ng-class="category.slug"></span>
  11 + <span class="category-list--icon icon" aria-hidden="true" ng-class="'icon-tema-' + category.slug"></span>
  12 + <span class="category-list--label">{{::category.name}}</span>
  13 + <span class="category-list--icon--right glyphicon glyphicon-chevron-right"></span>
  14 + </button>
  15 + </div>
  16 + </nav>
  17 +</div>
... ...
src/app/components/category-list/category-list.scss 0 → 100644
... ... @@ -0,0 +1,111 @@
  1 +.category-list {
  2 + .category-list--title {
  3 + color: #ffffff;
  4 + font-size: 16px;
  5 + margin: 0;
  6 + padding: 20px;
  7 + background-color: #484848;
  8 + border-top-left-radius: 5px;
  9 + border-top-right-radius: 5px;
  10 + overflow: hidden;
  11 + }
  12 +
  13 +
  14 + .category-list--group {
  15 + }
  16 +
  17 + .category-list--item {
  18 + position: relative;
  19 + text-transform: uppercase;
  20 + font-weight: bold;
  21 + padding: 0;
  22 + height: 68px;
  23 + overflow: hidden;
  24 + }
  25 +
  26 + .category-list--label {
  27 + margin-left: 70px;
  28 + margin-right: 30px;
  29 + display: inline-block;
  30 + z-index: 99999;
  31 + }
  32 +
  33 + &--icon-circle {
  34 + width: 48px;
  35 + height: 48px;
  36 + position: absolute;
  37 + top: 10px;
  38 + left: 10px;
  39 + // border: 1px solid #fff;
  40 + border-radius: 48px;
  41 +
  42 + -webkit-transition: -webkit-transform 0.2s ease-in-out;
  43 + -moz-transition: -moz-transform 0.2s ease-in-out;
  44 + -o-transition: -o-transform 0.2s ease-in-out;
  45 + transition: transform 0.2s ease-in-out;
  46 +
  47 + // -webkit-transition: all 0.2s ease-in-out;
  48 + // -moz-transition: all 0.2s ease-in-out;
  49 + // -o-transition: all 0.2s ease-in-out;
  50 + // transition: all 0.2s ease-in-out;
  51 +
  52 + z-index: 0;
  53 +
  54 + .active & {
  55 + z-index: -1;
  56 +
  57 + @media (max-width: $screen-xs) {
  58 + transform: scale(20);
  59 + }
  60 +
  61 + @media (min-width: $screen-xs + 1) {
  62 + transform: scale(40);
  63 + }
  64 +
  65 + @media (min-width: $screen-sm + 1) {
  66 + transform: scale(20);
  67 + }
  68 +
  69 + // @media (min-width: $screen-md + 1) {
  70 + // transform: scale(20);
  71 + // }
  72 + }
  73 +
  74 + @each $category, $color in $categories {
  75 + &.#{$category} {
  76 + background-color: $color;
  77 + }
  78 + }
  79 + }
  80 +
  81 + .category-list--icon {
  82 + position: absolute;
  83 + top: -16px;
  84 + left: -14px;
  85 + transform: scale(0.35);
  86 + }
  87 +
  88 + .category-list--icon--right {
  89 + position: absolute;
  90 + right: 9px;
  91 + top: 50%;
  92 + margin-top: -9px;
  93 + transform: scale(1.4);
  94 + }
  95 +
  96 + .list-group-item.active,
  97 + .list-group-item.active:hover,
  98 + .list-group-item.active:focus {
  99 + background-color: #f5f5f5;
  100 + }
  101 +
  102 + // @each $category, $color in $categories {
  103 + // &.#{$category} {
  104 + // .list-group-item.active,
  105 + // .list-group-item.active:hover,
  106 + // .list-group-item.active:focus {
  107 + // background-color: $color;
  108 + // }
  109 + // }
  110 + // }
  111 +}
... ...
src/app/components/event-list/event-list.directive.js 0 → 100644
... ... @@ -0,0 +1,53 @@
  1 +(function() {
  2 + 'use strict';
  3 +
  4 + angular
  5 + .module('dialoga')
  6 + .directive('eventList', eventList);
  7 +
  8 + /** @ngInject */
  9 + function eventList() {
  10 + /** @ngInject */
  11 + function EventListController($scope, $rootScope, $state, $log) {
  12 + $log.debug('EventListController');
  13 +
  14 + var vm = this;
  15 +
  16 + vm.$scope = $scope;
  17 + vm.$rootScope = $rootScope;
  18 + vm.$state = $state;
  19 + vm.$log = $log;
  20 +
  21 + vm.init();
  22 + }
  23 +
  24 + EventListController.prototype.init = function () {
  25 + var vm = this;
  26 +
  27 + vm.eventList = [];
  28 + vm.isListVisible = false;
  29 + };
  30 +
  31 + EventListController.prototype.toggleView = function () {
  32 + var vm = this;
  33 + vm.isListVisible = !vm.isListVisible;
  34 + };
  35 +
  36 + EventListController.prototype.subscribe = function (data) {
  37 + var vm = this;
  38 +
  39 + vm.$log.debug('data', data);
  40 + };
  41 +
  42 + var directive = {
  43 + restrict: 'E',
  44 + templateUrl: 'app/components/event-list/event-list.html',
  45 + controller: EventListController,
  46 + controllerAs: 'eventListCtrl',
  47 + bindToController: true
  48 + };
  49 +
  50 + return directive;
  51 +
  52 + }
  53 +})();
... ...
src/app/components/event-list/event-list.html 0 → 100644
... ... @@ -0,0 +1,109 @@
  1 +<div class="event-list">
  2 + <div class="event-tab--trigger" ng-show="!eventListCtrl.isListVisible" ng-click="eventListCtrl.toggleView()">
  3 + <div class="event-tab--header">
  4 + <div class="event-tab--icon">
  5 + <span class="glyphicon glyphicon-calendar" aria-hidden="true"></span>
  6 + </div>
  7 + <div class="event-tab--title">Bate-Papo com ministr@s</div>
  8 + </div>
  9 + <button class="btn btn-link event-tab--button">
  10 + <span class="event-tab--total-scheduled">18</span>
  11 + <span>bate-papos agendados</span>
  12 + <span class="glyphicon glyphicon-triangle-bottom" aria-hidden="true"></span>
  13 + </button>
  14 + </div>
  15 +
  16 + <div class="event-list--panel ng-hide" ng-show="eventListCtrl.isListVisible">
  17 + <div class="event-list--header">
  18 + <div class="event-list--icon">
  19 + <div class="glyphicon glyphicon-calendar" aria-hidden="true"></div>
  20 + </div>
  21 + <h2 class="event-list--title">Bate-papo com ministr@s</h2>
  22 + <div class="event-list--minimize">
  23 + <button type="button" class="btn btn-link" ng-click="eventListCtrl.toggleView()">
  24 + <span>Minimizar</span>
  25 + <span class="glyphicon glyphicon-triangle-top" aria-hidden="true"></span>
  26 + </button>
  27 + </div>
  28 + </div>
  29 + <div class="event-list--table-wrapper">
  30 + <div class="table-responsive">
  31 + <table class="table event-list--table">
  32 + <!-- <thead></thead> -->
  33 + <tbody>
  34 + <tr>
  35 + <td>
  36 + <span class="date">dd/mm/aaaa</span>
  37 + <span class="separator">-</span>
  38 + <span class="time">HH:mm</span>
  39 + <span class="separator">-</span>
  40 + <span class="description">Mais médicos, Segurança Nacional, SAMU</span>
  41 + <button type="button" class="btn" ng-click="eventListCtrl.subscribe('EVENT_ID')">
  42 + Inscreva-se
  43 + <span class="sr-only">no bate-papo com (ministro) no dia (date) as (hh:mm) horas</span>
  44 + </button>
  45 + <span class="subscribers">123 inscritos</span>
  46 + </td>
  47 + </tr>
  48 + <tr>
  49 + <td>
  50 + <span class="date">dd/mm/aaaa</span>
  51 + <span class="separator">-</span>
  52 + <span class="time">HH:mm</span>
  53 + <span class="separator">-</span>
  54 + <span class="description">Mais médicos, Segurança Nacional, SAMU</span>
  55 + <button type="button" class="btn">Inscreva-se</button>
  56 + <span class="subscribers">123 inscritos</span>
  57 + </td>
  58 + </tr>
  59 + <tr>
  60 + <td>
  61 + <span class="date">dd/mm/aaaa</span>
  62 + <span class="separator">-</span>
  63 + <span class="time">HH:mm</span>
  64 + <span class="separator">-</span>
  65 + <span class="description">Mais médicos, Segurança Nacional, SAMU</span>
  66 + <button type="button" class="btn">Inscreva-se</button>
  67 + <span class="subscribers">123 inscritos</span>
  68 + </td>
  69 + </tr>
  70 + <tr>
  71 + <td>
  72 + <span class="date">dd/mm/aaaa</span>
  73 + <span class="separator">-</span>
  74 + <span class="time">HH:mm</span>
  75 + <span class="separator">-</span>
  76 + <span class="description">Mais médicos, Segurança Nacional, SAMU</span>
  77 + <button type="button" class="btn">Inscreva-se</button>
  78 + <span class="subscribers">123 inscritos</span>
  79 + </td>
  80 + </tr>
  81 + <tr>
  82 + <td>
  83 + <span class="date">dd/mm/aaaa</span>
  84 + <span class="separator">-</span>
  85 + <span class="time">HH:mm</span>
  86 + <span class="separator">-</span>
  87 + <span class="description">Mais médicos, Segurança Nacional, SAMU</span>
  88 + <button type="button" class="btn">Inscreva-se</button>
  89 + <span class="subscribers">123 inscritos</span>
  90 + </td>
  91 + </tr>
  92 + <tr>
  93 + <td>
  94 + <span class="date">dd/mm/aaaa</span>
  95 + <span class="separator">-</span>
  96 + <span class="time">HH:mm</span>
  97 + <span class="separator">-</span>
  98 + <span class="description">Mais médicos, Segurança Nacional, SAMU</span>
  99 + <button type="button" class="btn">Inscreva-se</button>
  100 + <span class="subscribers">123 inscritos</span>
  101 + </td>
  102 + </tr>
  103 + </tbody>
  104 + <!-- <tfooter></tfooter> -->
  105 + </table>
  106 + </div>
  107 + </div>
  108 + </div>
  109 +</div>
... ...
src/app/components/event-list/event-list.scss 0 → 100644
... ... @@ -0,0 +1,82 @@
  1 +.event-list {
  2 + position: relative;
  3 + background-color: #eeeeee;
  4 +
  5 + .event-list--panel {
  6 + height: 310px;
  7 + border: 1px solid #333333;
  8 + padding: 20px;
  9 + margin: 20px 0;
  10 + line-height: 20px;
  11 + transition: .3s linear all;
  12 +
  13 + &.ng-hide {
  14 + height: 0px;
  15 + line-height: 0px;
  16 + }
  17 +
  18 + .event-list--header {
  19 + border-bottom: 1px solid #333333;
  20 + }
  21 +
  22 + .event-list--icon {
  23 + font-size: 25px;
  24 + display: inline-block;
  25 + }
  26 +
  27 + .event-list--title {
  28 + margin: 0 10px;
  29 + display: inline-block;
  30 + }
  31 +
  32 + .event-list--minimize {
  33 + display: inline-block;
  34 + float: right;
  35 + width: 100px;
  36 + }
  37 + }
  38 +
  39 + .event-tab--trigger {
  40 + $event-tab-height: 130px;
  41 + width: 150px;
  42 + height: $event-tab-height;
  43 + position: absolute;
  44 + right: 0;
  45 + top: $event-tab-height * (-1);
  46 + padding: 5px;
  47 + background-color: #eeeeee;
  48 + border: 1px solid #333333;
  49 + text-align: center;
  50 + line-height: 20px;
  51 + cursor: pointer;
  52 + transition: .3s linear all;
  53 + overflow: hidden;
  54 + z-index: 100;
  55 +
  56 + &.ng-hide {
  57 + height: 0px;
  58 + line-height: 0px;
  59 + top: -1px;
  60 + }
  61 + }
  62 +
  63 + .table-responsive {
  64 + height: 250px;
  65 + overflow-y: scroll;
  66 + }
  67 +
  68 + .event-tab--icon {
  69 + font-size: 25px;
  70 + }
  71 + .event-tab--title {
  72 + font-weight: bold;
  73 + }
  74 +
  75 + .event-tab--button {
  76 + font-size: 12px;
  77 + margin: 10px 0 0 0;
  78 + padding: 0;
  79 + width: 100%;
  80 + white-space: normal;
  81 + }
  82 +}
... ...
src/app/components/navbar/navbar.directive.js
... ... @@ -11,7 +11,7 @@
11 11 restrict: 'E',
12 12 templateUrl: 'app/components/navbar/navbar.html',
13 13 scope: {
14   - creationDate: '='
  14 + creationDate: '='
15 15 },
16 16 controller: NavbarController,
17 17 controllerAs: 'vm',
... ... @@ -23,11 +23,15 @@
23 23 /** @ngInject */
24 24 function NavbarController($log) {
25 25 $log.debug('NavbarController');
26   - // var vm = this;
27 26  
28   - // "vm.creation" is avaible by directive option "bindToController: true"
29   - // vm.relativeDate = moment(vm.creationDate).fromNow();
  27 + var vm = this;
  28 +
  29 + vm.scrollTo = function(hash) {
  30 + var $el = angular.element('#' + hash);
  31 + angular.element('body').animate({scrollTop: $el.offset().top}, 'slow');
  32 + };
30 33 }
  34 +
31 35 }
32 36  
33 37 })();
... ...
src/app/components/navbar/navbar.html
1   -<nav class="navbar navbar-static-top">
  1 +<nav id="navigation" class="header-navbar navbar navbar-static-top" role="navigation">
2 2 <div class="container-fluid">
3 3 <div class="navbar-header">
4 4 <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse" aria-expanded="false">
5 5 <span class="sr-only">Alternar menu de navegação</span>
6   - <span class="icon-bar"></span>
7   - <span class="icon-bar"></span>
8   - <span class="icon-bar"></span>
  6 + <span class="icon-bar" aria-hidden="true"></span>
  7 + <span class="icon-bar" aria-hidden="true"></span>
  8 + <span class="icon-bar" aria-hidden="true"></span>
9 9 </button>
10 10 <a class="navbar-brand" ui-sref="inicio">
11 11 <img src="/assets/images/logo.png" alt="Dialoga Brasil | O país fica melhor quando você participa" />
... ... @@ -16,7 +16,7 @@
16 16 <div id="navbar-collapse" class="collapse navbar-collapse">
17 17 <ul class="nav navbar-nav">
18 18 <li><a ui-sref="sobre">Sobre</a></li>
19   - <li><a ui-sref="programas">Programas</a></li>
  19 + <li><a ui-sref="inicio({'#':'lista-de-programas'})" ng-click="vm.scrollTo('lista-de-programas')">Programas</a></li>
20 20 <!-- <li><a ui-sref="ranking">Ranking</a></li> -->
21 21 <!-- <li><a ui-sref="duvidas">Dúvidas</a></li> -->
22 22 <!-- <li><a ui-sref="respostas">Respostas</a></li> -->
... ...
src/app/components/navbar/navbar.scss
1   -.navbar-brand {
2   - height: auto;
3   -}
  1 +.header-navbar {
4 2  
5   -.navbar-nav > li > a {
6   - padding-top: 30px;
7   - padding-bottom: 30px;
8   -}
  3 + .navbar-brand {
  4 + height: auto;
  5 + }
  6 +
  7 + .navbar-nav a {
  8 + padding-top: 30px;
  9 + padding-bottom: 30px;
  10 + text-transform: uppercase;
  11 + color: #03316f;
  12 +
  13 + -webkit-transition: all 0.2s ease-in-out;
  14 + -moz-transition: all 0.2s ease-in-out;
  15 + -o-transition: all 0.2s ease-in-out;
  16 + transition: all 0.2s ease-in-out;
  17 +
  18 + .contraste & {
  19 + color: #fff;
  20 + }
  21 + }
9 22  
10   -.navbar-toggle .icon-bar {
11   - background-color: #333;
  23 + .navbar-toggle .icon-bar {
  24 + background-color: #333;
  25 + }
12 26 }
... ...
src/app/components/programa/programa.directive.js
... ... @@ -1,73 +0,0 @@
1   -(function() {
2   - 'use strict';
3   -
4   - angular
5   - .module('dialoga')
6   - .directive('programaBox', programaBox);
7   -
8   - /** @ngInject */
9   - function programaBox(api) {
10   -
11   - /** @ngInject */
12   - function ProgramaController($log) {
13   - $log.debug('ProgramaController');
14   -
15   - var vm = this;
16   - vm.$log = $log;
17   -
18   - vm.init();
19   - }
20   -
21   - ProgramaController.prototype.init = function () {
22   -
23   - };
24   -
25   - ProgramaController.prototype.getCategory = function () {
26   - var vm = this;
27   -
28   - return vm.program.categories[0];
29   - };
30   -
31   - ProgramaController.prototype.getCategoryName = function () {
32   - return this.getCategory().name;
33   - };
34   -
35   - ProgramaController.prototype.getCategorySlug = function () {
36   - return this.getCategory().slug;
37   - };
38   -
39   - ProgramaController.prototype.getImageUrl = function () {
40   - var vm = this;
41   -
42   - return api.host + vm.program.image.url;
43   - };
44   -
45   - ProgramaController.prototype.getImageAlt = function () {
46   - var vm = this;
47   -
48   - vm.$log.warn('image is not accessible.');
49   - return 'TODO: create image alt on server-side.';
50   - };
51   -
52   - ProgramaController.prototype.showContent = function () {
53   - var vm = this;
54   -
55   - vm.$log.debug('TODO: showContent()', vm.program);
56   - };
57   -
58   - var directive = {
59   - restrict: 'E',
60   - templateUrl: 'app/components/programa/programa.html',
61   - scope: {
62   - program: '='
63   - },
64   - controller: ProgramaController,
65   - controllerAs: 'vm',
66   - bindToController: true
67   - };
68   -
69   -
70   - return directive;
71   - }
72   -
73   -})();
src/app/components/programa/programa.html
... ... @@ -1,8 +0,0 @@
1   -<article class="program-box {{::vm.getCategorySlug()}}" ng-if="vm.program" ng-click="vm.showContent()">
2   - <h2 class="category-name">{{::vm.getCategoryName()}}</h2>
3   - <div class="image-wrapper">
4   - <img class="img-responsive" ng-src="{{::vm.getImageUrl()}}" alt="{{::vm.getImageAlt()}}" />
5   - </div>
6   - <h1 class="program-title">{{::vm.program.title}}</h1>
7   - <div class="program-abstract" ng-bind-html="vm.program.abstract"></div>
8   -</article>
src/app/components/programa/programa.scss
... ... @@ -1,39 +0,0 @@
1   -// Variables
2   -$scale: 1.1;
3   -$time: .3s;
4   -
5   -// sandbox
6   -.program-box {
7   - cursor: pointer;
8   - .category-name {
9   - font-size: 14px;
10   - font-weight: bold;
11   - line-height: 30px;
12   - display: block;
13   - height: 30px;
14   - margin-bottom: 0;
15   - color: #ffffff;
16   - background-color: #000000;
17   - }
18   - .image-wrapper {
19   - position: relative;
20   - // width: 100%;
21   - // width: 370px;
22   - // height: 170px;
23   -
24   - overflow: hidden;
25   - text-align: center;
26   - }
27   - .img-responsive {
28   - -webkit-transition: all $time ease-in-out;
29   - -moz-transition: all $time ease-in-out;
30   - -o-transition: all $time ease-in-out;
31   - transition: all $time ease-in-out;
32   - }
33   - &:hover .img-responsive {
34   - -webkit-transform: scale($scale); /* prefixo para browsers webkit */
35   - -moz-transform: scale($scale); /* prefixo para browsers gecko */
36   - -o-transform: scale($scale); /* prefixo para opera */
37   - transform: scale($scale);
38   - }
39   -}
src/app/components/programas/programas.directive.js
... ... @@ -3,15 +3,13 @@
3 3  
4 4 angular
5 5 .module('dialoga')
6   - .filter('filterByCategory', filterByCategory)
7   - .filter('filterByCriteria', filterByCriteria)
8 6 .directive('programaList', programaList);
9 7  
10 8 /** @ngInject */
11 9 function programaList() {
12 10  
13 11 /** @ngInject */
14   - function ProgramaListController($scope, $location, $log) {
  12 + function ProgramaListController($scope, $element, $location, $filter, $log) {
15 13 $log.debug('ProgramaListController');
16 14  
17 15 // alias
... ... @@ -19,115 +17,248 @@
19 17  
20 18 // dependencies
21 19 vm.$scope = $scope;
  20 + vm.$element = $element;
22 21 vm.$location = $location;
  22 + vm.$filter = $filter;
23 23 vm.$log = $log;
  24 + vm.defaultLimit = 6;
24 25  
25 26 // initialization
26 27 vm.init();
27 28 }
28 29  
29   - ProgramaListController.prototype.init = function () {
  30 + ProgramaListController.prototype.init = function() {
30 31 var vm = this;
31 32  
32   - if(!vm.article){
  33 + if (!vm.article) {
33 34 vm.$log.warn('no article to display. Tip: use a ng-if before use this directive');
34 35 return;
35 36 }
36 37  
37 38 vm.categories = vm.article.categories;
38 39 vm.programs = vm.article.children;
39   - vm.filtredProgramList = [];
40 40 vm.orderCriteries = [
41   - { label: 'Título', name: 'title' },
42   - { label: 'Tema', name: 'category' }
43   - // , { label: 'Mais participações', name: 'more_participants' }
  41 + { label: 'Título', name: 'titulo' },
  42 + { label: 'Tema', name: 'tema' },
  43 + { label: 'Aleatório', name: 'aleatorio' }
44 44 ];
45 45  
  46 + vm.filtredProgramList = vm.getFiltredPrograms();
46 47 vm.search = vm.$location.search();
47 48  
48 49 // Add initial values for the filter
49 50 vm.query = (vm.search && vm.search.filtro) ? vm.search.filtro : null;
50   - vm.limitTo = (vm.search && vm.search.limite) ? parseInt(vm.search.limite, 10) : 4;
51   - vm.categoryFilter = (vm.search && vm.search.tema) ? vm.filterByCategorySlug(vm.search.tema) : null;
  51 + vm.limitTo = (vm.search && vm.search.limite) ? parseInt(vm.search.limite, 10) : vm.defaultLimit;
  52 + vm.categoryFilter = (vm.search && vm.search.tema) ? vm.getCategoryBySlug(vm.search.tema) : null;
  53 + vm.orderCriteria = (vm.search && vm.search.ordem) ? { name: vm.search.ordem } : null;
  54 + vm.reverse = (vm.search && vm.search.reverso) ? true : false;
  55 +
  56 + if (!angular.equals({}, vm.search)) {
  57 + var $el = vm.$element;
  58 + angular.element('body').animate({scrollTop: $el.offset().top}, 'slow');
  59 + }
52 60  
53 61 // update window location params
54   - vm.$scope.$watch('vm.query', function(newValue, oldValue){
55   - vm.search.filtro = newValue;
56   - vm.$location.search(vm.search);
  62 + vm.$scope.$watch('vm.query', function(newValue/*, oldValue*/) {
  63 + vm.search.filtro = newValue ? newValue : null;
  64 + vm.$location.search('filtro', vm.search.filtro);
  65 + if(vm.search.filtro){
  66 + vm.limitTo = vm.programs.length;
  67 + }else{
  68 + vm.limitTo = vm.defaultLimit;
  69 + }
  70 + vm.filtredProgramList = vm.getFiltredPrograms();
57 71 });
58 72  
59   - vm.$scope.$watch('vm.limitTo', function(newValue, oldValue){
60   - vm.search.limite = newValue;
61   - vm.$location.search(vm.search);
  73 + vm.$scope.$watch('vm.limitTo', function(newValue/*, oldValue*/) {
  74 + vm.search.limite = (newValue && newValue !== vm.defaultLimit) ? newValue : null;
  75 + vm.$location.search('limite', vm.search.limite);
  76 + vm.filtredProgramList = vm.getFiltredPrograms();
  77 + });
  78 +
  79 + vm.$scope.$watch('vm.categoryFilter', function(newValue/*, oldValue*/) {
  80 + vm.search.tema = newValue ? newValue.slug : null;
  81 + vm.$location.search('tema', vm.search.tema);
  82 + if(vm.search.tema){
  83 + vm.limitTo = vm.programs.length;
  84 + }
  85 + vm.filtredProgramList = vm.getFiltredPrograms();
62 86 });
63 87  
64   - vm.$scope.$watch('vm.categoryFilter', function(newValue, oldValue){
65   - vm.search.tema = newValue ? newValue.slug : '';
66   - vm.$location.search(vm.search);
  88 + vm.$scope.$watch('vm.orderCriteria', function(newValue/*, oldValue*/) {
  89 + vm.search.ordem = (newValue && newValue.name) ? newValue.name : null;
  90 + vm.$location.search('ordem', vm.search.ordem);
  91 + vm.filtredProgramList = vm.getFiltredPrograms();
  92 + });
  93 +
  94 + vm.$scope.$watch('vm.reverse', function(newValue/*, oldValue*/) {
  95 + vm.search.reverso = newValue ? newValue : null;
  96 + vm.$location.search('reverso', vm.search.reverso);
  97 + vm.filtredProgramList = vm.getFiltredPrograms();
67 98 });
68 99  
69 100 };
70 101  
71   - ProgramaListController.prototype.resetFilterValues = function () {
  102 + ProgramaListController.prototype.resetFilterValues = function() {
72 103 var vm = this;
73 104  
74 105 vm.query = null;
75   - vm.limitTo = 4;
  106 + vm.limitTo = vm.defaultLimit;
76 107 vm.categoryFilter = null;
  108 + vm.orderCriteria = null;
77 109 };
78 110  
79   - ProgramaListController.prototype.getIconClasses = function (category) {
  111 + ProgramaListController.prototype.getIconClasses = function(category) {
80 112 var vm = this;
81 113  
82 114 vm.$log.debug('[TODO] getIconClasses of category:', category);
83 115 return 'glyphicon glyphicon-exclamation-sign';
84 116 };
85 117  
86   - ProgramaListController.prototype.filterByCategorySlug = function (categorySlug) {
  118 + ProgramaListController.prototype.getCategoryBySlug = function(categorySlug) {
87 119 var vm = this;
88 120 var result = null;
89 121  
90   - angular.forEach(vm.categories, function (value, key){
91   - if(value.slug === categorySlug){
  122 + angular.forEach(vm.categories, function(value/*, key*/) {
  123 + if (value.slug === categorySlug) {
92 124 result = value;
93 125 }
94   - })
  126 + });
  127 +
95 128 return result;
96   - }
  129 + };
97 130  
98   - ProgramaListController.prototype.filterByCategory = function (category, $event) {
  131 + ProgramaListController.prototype.filterByCategory = function(category, $event) {
99 132 var vm = this;
100 133  
101 134 $event.stopPropagation();
102 135  
103   - if(category !== vm.categoryFilter){
  136 + if (category !== vm.categoryFilter) {
104 137  
105 138 // selected new filter
106 139 vm.categoryFilter = category;
107   - }else{
108   - // already selected. Unselect.
109   - vm.showAll();
  140 + } else {
  141 + vm.categoryFilter = null;
110 142 }
111 143 };
112 144  
113   - ProgramaListController.prototype.showAll = function ($event) {
  145 + ProgramaListController.prototype.showAll = function($event) {
114 146 var vm = this;
115 147  
116 148 $event.stopPropagation();
117 149  
118 150 vm.resetFilterValues();
  151 + vm.limitTo = vm.programs.length;
  152 + };
  153 +
  154 + ProgramaListController.prototype.getFiltredPrograms = function() {
  155 + var vm = this;
  156 +
  157 + var input = vm.programs;
  158 + var output = input;
  159 + var query = vm.query;
  160 + var categoryFilter = vm.categoryFilter;
  161 + var orderCriteria = vm.orderCriteria ? vm.orderCriteria : { name : 'aleatorio'};
  162 + var filter = vm.$filter('filter');
  163 + var orderBy = vm.$filter('orderBy');
  164 + var limitTo = vm.$filter('limitTo');
  165 + var limit = vm.limitTo ? vm.limitTo : 4;
  166 +
  167 + if (categoryFilter) {
  168 + output = _filterByCategory(output, categoryFilter);
  169 + }
  170 +
  171 + if (query) {
  172 + output = filter(output, query, false);
  173 + }
  174 +
  175 + switch (orderCriteria.name) {
  176 + case 'titulo':
  177 + output = orderBy(output, 'title', vm.reverse);
  178 + break;
  179 + case 'tema':
  180 + output = orderBy(output, 'categories[0].name', vm.reverse);
  181 + break;
  182 + case 'more_participants':
  183 + vm.$log.info('Criteria not handled yet: ', orderCriteria);
  184 + break;
  185 + case 'aleatorio':
  186 + // shuffling
  187 + // if (!vm._isShuffled){
  188 + output = vm.filterShuffle(output);
  189 + // vm._isShuffled = true;
  190 + // }
  191 +
  192 + if (vm.reverse) {
  193 + output = output.slice().reverse();
  194 + }
  195 +
  196 + break;
  197 + default:
  198 + vm.$log.warn('Criteria not matched: ', orderCriteria);
  199 + break;
  200 + }
  201 +
  202 + output = limitTo(output, limit);
  203 +
  204 + return output;
119 205 };
120 206  
121   - // function ProgramaListLinker (scope, element, attrs) {
  207 + ProgramaListController.prototype.filterShuffle = function(input) {
  208 + var result = [];
  209 + var resultByCategory = {};
122 210  
123   - // scope.$watch('article', function(newValue, oldValue){
124   - // if(!newValue){
125   - // return;
126   - // }
127   - // scope.vm.categories = scope.vm.article.categories;
128   - // scope.vm.programs = scope.vm.article.children;
129   - // });
130   - // }
  211 + // divide by categories
  212 + for (var i = 0; i < input.length; i++) {
  213 + var program = input[i];
  214 + var categorySlug = program.categories[0].slug;
  215 +
  216 + if (!resultByCategory[categorySlug]) {
  217 + resultByCategory[categorySlug] = [];
  218 + }
  219 +
  220 + resultByCategory[categorySlug].push(program);
  221 + }
  222 +
  223 + // shuffle each array
  224 + var prop = null;
  225 + var categoryWithPrograms = null;
  226 + for (prop in resultByCategory) {
  227 + if (resultByCategory.hasOwnProperty(prop)) {
  228 + categoryWithPrograms = resultByCategory[prop];
  229 + resultByCategory[prop] = shuffle(categoryWithPrograms);
  230 + }
  231 + }
  232 +
  233 + // Concat all into result array
  234 + // > while has program at Lists on resultByCategory
  235 + var hasProgram = true;
  236 + while (hasProgram) {
  237 +
  238 + var foundProgram = false;
  239 + // each categoryList with array of program
  240 + prop = null;
  241 + categoryWithPrograms = null;
  242 + for (prop in resultByCategory) {
  243 +
  244 + if (resultByCategory.hasOwnProperty(prop)) {
  245 + categoryWithPrograms = resultByCategory[prop];
  246 +
  247 + if (categoryWithPrograms.length > 0) {
  248 + var pivotProgram = categoryWithPrograms.pop();
  249 + result.push(pivotProgram);
  250 + foundProgram = true;
  251 + }
  252 + }
  253 + }
  254 +
  255 + if (!foundProgram) {
  256 + hasProgram = false;
  257 + }
  258 + }
  259 +
  260 + return result;
  261 + };
131 262  
132 263 var directive = {
133 264 restrict: 'E',
... ... @@ -137,76 +268,49 @@
137 268 },
138 269 controller: ProgramaListController,
139 270 controllerAs: 'vm',
140   - bindToController: true,
141   - // link: ProgramaListLinker
  271 + bindToController: true
142 272 };
143 273  
144   -
145 274 return directive;
146 275 }
147 276  
148   - function filterByCategory(){
149   - return function (input, category){
150   - input = input || [];
  277 + function _filterByCategory (input, category) {
  278 + input = input || [];
151 279  
152   - if(!category){
153   - // no filter
154   - return input;
155   - }
  280 + if (!category) {
  281 + // no filter
  282 + return input;
  283 + }
156 284  
157   - var out = [];
158   - for (var i = 0; i < input.length; i++) {
159   - var program = input[i];
160   - if(program.categories[0].slug === category.slug){
161   - out.push(program);
162   - }
  285 + var out = [];
  286 + for (var i = 0; i < input.length; i++) {
  287 + var program = input[i];
  288 + if (program.categories[0].slug === category.slug) {
  289 + out.push(program);
163 290 }
  291 + }
164 292  
165   - return out;
166   - };
  293 + return out;
167 294 }
168 295  
169   - /** @ngInject */
170   - function filterByCriteria($filter, $log){
171   - var orderBy = $filter('orderBy');
172   -
173   - return function (input, criteria, reverse){
174   - input = input || [];
175   - criteria = criteria || {};
176   - reverse = reverse || false;
  296 + // -> Fisher–Yates shuffle algorithm
  297 + function shuffle (array) {
  298 + var currentIndex = array.length, temporaryValue, randomIndex ;
177 299  
178   - var out = [];
179   - // for (var i = 0; i < input.length; i++) {
180   - // var program = input[i];
  300 + // While there remain elements to shuffle...
  301 + while (0 !== currentIndex) {
181 302  
182   - // // todo ordering
183   - // out.push(program);
184   - // }
185   -
186   - switch(criteria.name){
187   - case 'title':
188   - out = orderBy(input, 'title', reverse);
189   - break;
190   - case 'category':
191   - out = orderBy(input, 'categories[0].name', reverse);
192   - break;
193   - case 'more_participants':
194   - // break;
195   - default:
196   - $log.info('Criteria not handled yet: ', criteria);
197   -
198   - if(reverse){
199   - out = input.slice().reverse();
200   - }else{
201   - out = input;
202   - }
203   - break;
204   - }
  303 + // Pick a remaining element...
  304 + randomIndex = Math.floor(Math.random() * currentIndex);
  305 + currentIndex -= 1;
205 306  
  307 + // And swap it with the current element.
  308 + temporaryValue = array[currentIndex];
  309 + array[currentIndex] = array[randomIndex];
  310 + array[randomIndex] = temporaryValue;
  311 + }
206 312  
207   - return out;
208   - };
  313 + return array;
209 314 }
210 315  
211   -
212 316 })();
... ...
src/app/components/programas/programas.directive.spec.js 0 → 100644
... ... @@ -0,0 +1,32 @@
  1 +(function() {
  2 + 'use strict';
  3 +
  4 + describe('program directive', function() {
  5 + var compile, scope, directiveElem;
  6 +
  7 + beforeEach(function(){
  8 + module('dialoga');
  9 +
  10 + inject(function($compile, $rootScope){
  11 + compile = $compile;
  12 + scope = $rootScope.$new();
  13 + // mock article
  14 + scope.article = {};
  15 + });
  16 +
  17 + directiveElem = getCompiledElement();
  18 + });
  19 +
  20 + function getCompiledElement(){
  21 + var element = compile(angular.element('<programa-list></programa-list>'))(scope);
  22 + var compiledElement = compile(element)(scope);
  23 + scope.$digest();
  24 + return compiledElement;
  25 + }
  26 +
  27 + it('ensure exist only one id "lista-de-programas"', function() {});
  28 +
  29 + it('should show default programs, one each category', function() {});
  30 +
  31 + });
  32 +})();
... ...
src/app/components/programas/programas.html
... ... @@ -1,68 +0,0 @@
1   -<div class="row">
2   - <div class="col-sm-3">
3   - <div class="category-list">
4   - <nav class="navigation">
5   - <h3 class="title"><b>Programas</b> por Tema</h3>
6   - <div class="list-group category-list">
7   - <button type="button" class="list-group-item category-item"
8   - ng-repeat="category in vm.categories"
9   - ng-class="{active: vm.categoryFilter.slug === category.slug}"
10   - ng-click="vm.filterByCategory(category, $event)">
11   -
12   - <span ng-class="[category.iconClass]"></span>
13   - <span>{{::category.name}}</span>
14   - <span class="glyphicon glyphicon-chevron-right pull-right"></span>
15   -
16   - </button>
17   - </div>
18   - </nav>
19   - </div>
20   - </div>
21   -
22   - <div class="col-sm-9">
23   - <article class="program-list">
24   - <header class="header">
25   - <h2>Programas</h2>
26   - <button type="button" class="btn btn-link" ng-click="vm.showAll($event)">
27   - <span class="glyphicon glyphicon-chevron-right"></span> Ver todos os programas
28   - </button>
29   - </header>
30   - <div>
31   - <div class="col-sm-12">
32   - <aside class="form-inline">
33   - <div class="form-group">
34   - <label for="programListFilter" class="control-label sr-only">Filtrar programas:</label>
35   - <input id="programListFilter" type="search" class="form-control" ng-model="vm.query" placeholder="Filtrar programas" aria-label="Filtrar programas" >
36   -
37   - <select class="form-control" ng-model="vm.categoryFilter" ng-options="category.name for category in vm.categories track by category.slug">
38   - <option value="">-- Filtrar por tema --</option>
39   - </select>
40   -
41   - <select class="form-control" ng-model="vm.orderCriteria" ng-options="orderCriteria.label for orderCriteria in vm.orderCriteries">
42   - <option value="">-- Ordernar por: --</option>
43   - </select>
44   -
45   - <div class="checkbox">
46   - <label>
47   - <input type="checkbox" ng-model="orderReverse">
48   - Reverso
49   - </label>
50   - </div>
51   -
52   - <input id="programListLimit" type="number" class="form-control input-sm" size="4" step="2" ng-model="vm.limitTo" aria-label="Limitar" >
53   - <label for="programListLimit" class="control-label">Limite</label>
54   -
55   - </div>
56   - </aside>
57   - </div>
58   - <div ng-repeat="program in vm.programs | filterByCategory:vm.categoryFilter | filterByCriteria:vm.orderCriteria:orderReverse | filter:vm.query | limitTo:vm.limitTo as results">
59   - <programa-box program="program" class="col-sm-12 col-md-6"></programa-box>
60   - <div ng-if="$odd" class="clearfix"></div>
61   - </div>
62   - <div class="animate-repeat" ng-if="results.length == 0">
63   - Nenhum programa encontrado.
64   - </div>
65   - </div>
66   - </article>
67   - </div>
68   -</div>
src/app/components/programas/programas.scss
... ... @@ -1,14 +0,0 @@
1   -.program-list {
2   -
3   - .header {
4   - position: relative;
5   - height: 40px;
6   - margin-bottom: 10px;
7   -
8   - button {
9   - position: absolute;
10   - right: 0;
11   - top: 2px;
12   - }
13   - }
14   -}
src/app/components/socialShare/socialShare.directive.js 0 → 100644
... ... @@ -0,0 +1,30 @@
  1 +(function() {
  2 + 'use strict';
  3 +
  4 + angular
  5 + .module('dialoga')
  6 + .directive('socialShare', socialShare);
  7 +
  8 + /** @ngInject */
  9 + function socialShare() {
  10 + var directive = {
  11 + restrict: 'E',
  12 + templateUrl: 'app/components/socialShare/socialShare.html',
  13 + scope: {
  14 + },
  15 + controller: SocialShareController,
  16 + controllerAs: 'vm',
  17 + bindToController: true
  18 + };
  19 +
  20 + return directive;
  21 +
  22 + /** @ngInject */
  23 + function SocialShareController($log) {
  24 + $log.debug('SocialShareController');
  25 +
  26 + var vm = this;
  27 + }
  28 + }
  29 +
  30 +})();
... ...
src/app/components/socialShare/socialShare.html 0 → 100644
... ... @@ -0,0 +1,35 @@
  1 +<div class="social-share">
  2 + <ul>
  3 + <li>
  4 + <a social-facebook custom-url="http://dialoga.gov.br">
  5 + <span class="icon icon-social-facebook"></span>
  6 + <span class="sr-only">Compartilhar no Facebook</span>
  7 + </a>
  8 + </li>
  9 + <li>
  10 + <a social-twitter custom-url="http://dialoga.gov.br" status="This status is #{{ ctrl.coolWord }}">
  11 + <span class="icon icon-social-twitter"></span>
  12 + <span class="sr-only">Compartilhar no Twitter</span>
  13 + </a>
  14 + </li>
  15 + <li>
  16 + <a social-gplus custom-url="http://dialoga.gov.br">
  17 + <span class="icon icon-social-google-plus"></span>
  18 + <span class="sr-only">Compartilhar no Google Plus</span>
  19 + </a>
  20 + </li>
  21 + <li>
  22 + <a href="whatsapp://send?text=Apoio ao audiovisual brasileiro: ampliação da produção, da difusão e do acesso http%3A%2F%2Fdialoga.gov.br%2F%23%2Fprogramas%2F121492%2Fsobre-o-programa" target="_blank">
  23 + <span class="icon icon-social-whatsapp"></span>
  24 + <span class="sr-only">Compartilhar no WhatsApp</span>
  25 + </a>
  26 + </li>
  27 + </ul>
  28 +</div>
  29 +
  30 +<!-- <ul>
  31 + <li><a href="http://dialoga.gov.br/#/programas/121492/sobre-o-programa" class="fb-share icon icon-facebook" data-caption="Brasil de Todas as Telas" data-description="Apoio ao audiovisual brasileiro: ampliação da produção, da difusão e do acesso"><span class="fa fa-facebook"></span><span class="sr-only">Compartilhar no Facebook</span></a></li>
  32 + <li><a href="https://twitter.com/intent/tweet?url=http%3A%2F%2Fdialoga.gov.br%2F%23%2Fprogramas%2F121492%2Fsobre-o-programa&amp;text=Apoio ao audiovisual brasileiro: ampliação da produção, da difusão e do acesso" target="_blank" class="tw-share icon icon-twitter popup"><span class="fa fa-twitter"></span><span class="sr-only">Compartilhar no Twitter</span></a></li>
  33 + <li><a href="https://plus.google.com/share?url=http%3A%2F%2Fdialoga.gov.br%2F%23%2Fprogramas%2F121492%2Fsobre-o-programa" target="_blank" class="gp-share icon icon-gplus popup"><span class="fa fa-google-plus"></span><span class="sr-only">Compartilhar no Google Plus</span></a></li>
  34 + <li><a href="whatsapp://send?text=Apoio ao audiovisual brasileiro: ampliação da produção, da difusão e do acesso http%3A%2F%2Fdialoga.gov.br%2F%23%2Fprogramas%2F121492%2Fsobre-o-programa" target="_blank" class="ws-share icon icon-whatsapp"><span class="fa fa-whatsapp"></span><span class="sr-only">Compartilhar no WhatsApp</span></a></li>
  35 +</ul> -->
... ...
src/app/components/socialShare/socialShare.scss 0 → 100644
... ... @@ -0,0 +1,28 @@
  1 +.social-share {
  2 + ul {
  3 + display: inline-block;
  4 + vertical-align: middle;
  5 + list-style: none;
  6 + padding-left: 0;
  7 + }
  8 +
  9 + li{
  10 + display: inline-block;
  11 + padding: 0 2px !important;
  12 + vertical-align: top;
  13 + }
  14 +
  15 + .social-share--description {
  16 + display: inline-block;
  17 + color: #000;
  18 + font-size: 12px;
  19 + font-weight: 300;
  20 + padding-right: 10px;
  21 + text-align: right;
  22 + vertical-align: middle;
  23 + }
  24 +
  25 + .icon {
  26 + display: block;
  27 + }
  28 +}
... ...
src/app/index.config.js
... ... @@ -4,6 +4,7 @@
4 4 angular
5 5 .module('dialoga')
6 6 .config(configAuthInterceptor)
  7 + .config(configLocationProvider)
7 8 .config(config);
8 9  
9 10 /** @ngInject */
... ... @@ -27,7 +28,13 @@
27 28 return $injector.get('AuthInterceptor');
28 29 }
29 30 ]);
  31 + }
30 32  
  33 + /** @ngInject */
  34 + function configLocationProvider ($locationProvider, Modernizr) {
  35 + if (Modernizr.history) {
  36 + $locationProvider.html5Mode(true);
  37 + }
31 38 }
32 39  
33 40 /** @ngInject */
... ...
src/app/index.constants.js
... ... @@ -4,12 +4,15 @@
4 4  
5 5 angular
6 6 .module('dialoga')
7   - .constant('api', {
  7 + .constant('API', {
8 8 token: null,
9   - host: 'http://hom.login.dialoga.gov.br',
10   - // host: 'http://www.participa.br',
  9 + hostDev: '',
  10 + hostHom: 'http://hom.dialoga.gov.br',
  11 + hostProd: 'http://login.dialoga.gov.br',
11 12 articleId: {
12   - home: 103358
  13 + home: '103358',
  14 + about: '108073',
  15 + terms: '107880'
13 16 }
14 17 })
15 18 .constant('AUTH_EVENTS', {
... ...
src/app/index.module.js
... ... @@ -2,6 +2,6 @@
2 2 'use strict';
3 3  
4 4 angular
5   - .module('dialoga', ['ngAnimate', 'ngCookies', 'ngTouch', 'ngSanitize', 'ui.router']);
  5 + .module('dialoga', ['ngAnimate', 'ngCookies', 'ngTouch', 'ngSanitize', 'ui.router', 'socialLinks', 'slugifier']);
6 6  
7 7 })();
... ...
src/app/index.route.js
... ... @@ -9,76 +9,89 @@
9 9 function routeConfig($stateProvider, $urlRouterProvider) {
10 10 $stateProvider
11 11 .state('inicio', {
12   - url: '/',
  12 + url: '/?limite&tema',
  13 + reloadOnSearch: false,
13 14 views: {
14   - 'header': { templateUrl: 'app/partials/header/header.html' },
  15 + 'header': { templateUrl: 'app/pages/header/header.html' },
15 16 'main': {
16   - templateUrl: 'app/partials/inicio/inicio.html',
17   - controller: 'InicioController',
18   - controllerAs: 'inicio'
  17 + templateUrl: 'app/pages/inicio/inicio.html',
  18 + controller: 'InicioPageController',
  19 + controllerAs: 'pageInicio'
19 20 },
20   - 'footer': { templateUrl: 'app/partials/footer/footer.html' }
  21 + 'footer': { templateUrl: 'app/pages/footer/footer.html' }
21 22 }
22 23 })
23 24 .state('entrar', {
24 25 url: '/entrar',
25 26 views: {
26   - 'header': { templateUrl: 'app/partials/header/header.html' },
  27 + 'header': { templateUrl: 'app/pages/header/header.html' },
27 28 'main': {
28   - templateUrl: 'app/partials/auth/signin.html',
29   - controller: 'AuthController',
30   - controllerAs: 'signin'
  29 + templateUrl: 'app/pages/auth/signin.html',
  30 + controller: 'AuthPageController',
  31 + controllerAs: 'pageSignin'
31 32 },
32   - 'footer': { templateUrl: 'app/partials/footer/footer.html' }
  33 + 'footer': { templateUrl: 'app/pages/footer/footer.html' }
33 34 }
34 35 })
35 36 .state('cadastrar', {
36 37 url: '/cadastrar',
37 38 views: {
38   - 'header': { templateUrl: 'app/partials/header/header.html' },
  39 + 'header': { templateUrl: 'app/pages/header/header.html' },
39 40 'main': {
40   - templateUrl: 'app/partials/auth/signup.html',
41   - controller: 'AuthController',
42   - controllerAs: 'signup'
  41 + templateUrl: 'app/pages/auth/signup.html',
  42 + controller: 'AuthPageController',
  43 + controllerAs: 'pageSignup'
43 44 },
44   - 'footer': { templateUrl: 'app/partials/footer/footer.html' }
  45 + 'footer': { templateUrl: 'app/pages/footer/footer.html' }
45 46 }
46 47 })
47   - .state('programas', {
48   - url: '/programas',
  48 + .state('programa', {
  49 + url: '/programa/:slug',
49 50 views: {
50   - 'header': { templateUrl: 'app/partials/header/header.html' },
  51 + 'header': { templateUrl: 'app/pages/header/header.html' },
51 52 'main': {
52   - templateUrl: 'app/partials/programas/programas.html',
53   - controller: 'ProgramasController',
54   - controllerAs: 'programas'
  53 + templateUrl: 'app/pages/programas/programa.html',
  54 + controller: 'ProgramaPageController',
  55 + controllerAs: 'pagePrograma'
55 56 },
56   - 'footer': { templateUrl: 'app/partials/footer/footer.html' }
  57 + 'footer': { templateUrl: 'app/pages/footer/footer.html' }
  58 + }
  59 + })
  60 + .state('conheca-o-programa', {
  61 + url: '/programa/:slug/conheca-o-programa',
  62 + views: {
  63 + 'header': { templateUrl: 'app/pages/header/header.html' },
  64 + 'main': {
  65 + templateUrl: 'app/pages/programas/conheca-o-programa.html',
  66 + controller: 'ProgramaContentPageController',
  67 + controllerAs: 'pageProgramaContent'
  68 + },
  69 + 'footer': { templateUrl: 'app/pages/footer/footer.html' }
57 70 }
58 71 })
59 72 .state('sobre', {
60 73 url: '/sobre',
61 74 views: {
62   - 'header': { templateUrl: 'app/partials/header/header.html' },
  75 + 'header': { templateUrl: 'app/pages/header/header.html' },
63 76 'main': {
64   - templateUrl: 'app/partials/article/article.html',
65   - controller: 'ArticleController',
66   - controllerAs: 'article'
  77 + templateUrl: 'app/pages/article/article.html',
  78 + controller: 'ArticlePageController',
  79 + controllerAs: 'pageArticle'
67 80 },
68   - 'footer': { templateUrl: 'app/partials/footer/footer.html' }
  81 + 'footer': { templateUrl: 'app/pages/footer/footer.html' }
69 82 }
70 83 })
71 84 .state('termos-de-uso', {
72 85 url: '/termos-de-uso',
73   - controller: 'ArticleController',
  86 + controller: 'ArticlePageController',
74 87 views: {
75   - 'header': { templateUrl: 'app/partials/header/header.html' },
  88 + 'header': { templateUrl: 'app/pages/header/header.html' },
76 89 'main': {
77   - templateUrl: 'app/partials/article/article.html',
78   - controller: 'ArticleController',
79   - controllerAs: 'article'
  90 + templateUrl: 'app/pages/article/article.html',
  91 + controller: 'ArticlePageController',
  92 + controllerAs: 'pageArticle'
80 93 },
81   - 'footer': { templateUrl: 'app/partials/footer/footer.html' }
  94 + 'footer': { templateUrl: 'app/pages/footer/footer.html' }
82 95 }
83 96 })
84 97 ;
... ...
src/app/index.run.js
... ... @@ -6,15 +6,19 @@
6 6 .module('dialoga')
7 7 .run(runAuth)
8 8 .run(runAccessibility)
  9 + .run(runHistory)
  10 + .run(runPath)
  11 + .run(runColorUtils)
9 12 .run(runBlock);
10 13  
11 14 /** @ngInject */
12   - function runAuth($rootScope, $cookies, USER_ROLES, AUTH_EVENTS, AuthService, $log){
  15 + function runAuth($rootScope, $cookies, USER_ROLES, AUTH_EVENTS, AuthService, $log) {
13 16  
14 17 // Listner url/state changes, and check permission
15   - $rootScope.$on('$stateChangeStart', function (event, next) {
16   - if(!next.data || !next.data.authorizedRoles){
17   - $log.debug('public url/state');
  18 + $rootScope.$on('$stateChangeStart', function(event, next) {
  19 +
  20 + if (!next.data || !next.data.authorizedRoles) {
  21 + $log.debug('[RUN] Auth: public url/state');
18 22 return;
19 23 }
20 24  
... ... @@ -33,48 +37,111 @@
33 37 }
34 38 });
35 39  
36   - $log.debug('runAuth end.');
  40 + $log.debug('[RUN] Auth end.');
37 41 }
38 42  
39 43 /** @ngInject */
40 44 function runAccessibility($rootScope, $timeout, $cookies, $log) {
41 45  
42   - var contrast = $cookies.get('dialoga_contraste') === "true";
  46 + var contrast = $cookies.get('dialoga_contraste') === 'true';
43 47 adjustContrast(contrast);
44 48  
45   - function adjustContrast(state){
  49 + function adjustContrast(state) {
46 50 var bodyEl = angular.element(document).find('body');
47 51 angular.element(bodyEl).toggleClass('contraste', !!state);
48 52 }
49 53  
50   - $rootScope.toggleContrast = function () {
  54 + $rootScope.skipToContent = function() {
  55 + angular.element('#content').attr('tabIndex', -1).focus();
  56 + };
  57 +
  58 + $rootScope.skipToNavigation = function() {
  59 + angular.element('#navigation').attr('tabIndex', -1).focus();
  60 + };
  61 +
  62 + $rootScope.skipToSearch = function() {
  63 + // angular.element('#search').attr('tabIndex', -1).focus();
  64 + angular.element('#articleQueryFilter').attr('tabIndex', -1).focus();
  65 + };
  66 +
  67 + $rootScope.skipToFooter = function() {
  68 + angular.element('#footer').attr('tabIndex', -1).focus();
  69 + };
  70 +
  71 + $rootScope.actionContrast = function() {
  72 + // toggle contrast
51 73 contrast = !contrast;
52 74 $cookies.put('dialoga_contraste', contrast);
53 75 adjustContrast(contrast);
54 76 };
55 77  
56   - $rootScope.focusMainContent = function ($event) {
  78 + $rootScope.focusMainContent = function($event) {
57 79  
58 80 // prevent skip link from redirecting
59 81 if ($event) { $event.preventDefault(); }
60 82  
61 83 var mainContentArea = document.querySelector('[role="main"]');
62 84  
63   - if ( mainContentArea ) {
64   - $timeout(function(){
65   - mainContentArea.focus();
66   - },90);
67   - }else{
  85 + if (mainContentArea) {
  86 + $timeout(function() {
  87 + var $el = angular.element(mainContentArea);
  88 +
  89 + angular.element('body').animate({scrollTop: $el.offset().top}, 'slow');
  90 + }, 90);
  91 + } else {
68 92 $log.warn('role="main" not found.');
69 93 }
70 94 };
71 95  
72   - $log.debug('runAccessibility end.');
  96 + $log.debug('[RUN] Accessibility end.');
  97 + }
  98 +
  99 + /** @ngInject */
  100 + function runHistory($rootScope) {
  101 + $rootScope.$on('$stateChangeSuccess', function(event, toState, toStateParams, fromState, fromStateParams) {
  102 + $rootScope.$previousState = { state: fromState, params: fromStateParams};
  103 + });
  104 + }
  105 +
  106 + /** @ngInject */
  107 + function runPath($rootScope, API, $window, $log) {
  108 + var isProd = (/^http:\/\/dialoga\.gov\.br\//.test($window.location.href));
  109 + var isHom = (/^http:\/\/hom.dialoga\.gov\.br\//.test($window.location.href));
  110 + $rootScope.basePath = isProd ? API.hostProd : (isHom ? API.hostHom : API.hostDev);
  111 +
  112 + $log.debug('[RUN] Path end.');
  113 + }
  114 +
  115 + /** @ngInject */
  116 + function runColorUtils($window) {
  117 +
  118 + $window.ColorLuminance = function(hex, lum) {
  119 +
  120 + // validate hex string
  121 + hex = String(hex).replace(/[^0-9a-f]/gi, '');
  122 + if (hex.length < 6) {
  123 + hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
  124 + }
  125 + lum = lum || 0;
  126 +
  127 + // convert to decimal and change luminosity
  128 + var rgb = '#';
  129 + var c;
  130 + var i;
  131 +
  132 + for (i = 0; i < 3; i++) {
  133 + c = parseInt(hex.substr(i * 2, 2), 16);
  134 + c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16);
  135 + rgb += ('00' + c).substr(c.length);
  136 + }
  137 +
  138 + return rgb;
  139 + };
73 140 }
74 141  
75 142 /** @ngInject */
76 143 function runBlock($log) {
77   - $log.debug('runBlock end.');
  144 + $log.debug('[RUN] Block end.');
78 145 }
79 146  
80 147 })();
... ...
src/app/index.scss
... ... @@ -5,6 +5,7 @@
5 5 // $navbar-inverse-link-color: #5AADBB;
6 6 $icon-font-path: "../../bower_components/bootstrap-sass-official/assets/fonts/bootstrap/";
7 7  
  8 +
8 9 /**
9 10 * Do not remove this comments bellow. It's the markers used by wiredep to inject
10 11 * sass dependencies when defined in the bower.json of your dependencies
... ... @@ -20,53 +21,115 @@ $gray: #f1f1f1;
20 21  
21 22 // -------------
22 23  
  24 +// 1.4 - dicionarios
  25 +$categories: (saude: #3449b7, seguranca-publica: #e34748, educacao: #f39720, reducao-da-pobreza: #3ebb8f, cultura: #a63738);
  26 +$categories-descriptions: (saude: "Saúde é direito de todos e dever do Estado. O Sistema Único de Saúde (SUS) é universal, integral e de responsabilidade do Governo Federal, estados e municípios. Atende a todos os brasileiros.", seguranca-publica: "A segurança pública é um direito fundamental dos cidadãos. A proteção da vida, a disseminação da cultura da paz e a integração dos órgãos e instituições municipais, estaduais e federais são os maiores compromissos dessa política pública.", educacao: "Uma pátria educadora se faz com oportunidades para todos. Nos últimos anos, o Brasil criou esse caminho de oportunidades. Ampliamos o acesso à educação em todos os níveis de ensino – da creche à pós-graduação – e para todos os brasileiros, independentemente de sua classe social. E ainda há muito a fazer. O Plano Nacional de Educação (PNE) estabelece novas metas para que o governo federal trabalhe em parceria com a sociedade, com os estados e os municípios na construção de um futuro melhor. Queremos agora um salto na qualidade do ensino.", reducao-da-pobreza: "Com o esforço do Brasil para reduzir a pobreza e a desigualdade, 36 milhões de pessoas superaram a miséria na última década e o país saiu do Mapa da Fome das Nações Unidas.", cultura: "O que nos singulariza no conjunto das nações é, em última instância, nossa cultura. É por ela que nos identificamos como brasileiros de norte a sul deste país. Uma grande nação precisa ter um desenvolvimento cultural à altura de sua grandeza, contemplando as dimensões simbólica, econômica e cidadã da cultura, que são parte central do projeto de um país democrático e plural. A pluralidade é nossa singularidade.");
23 27  
24   -// -------------
25   -// Paleta de Cores
26   -// -------------
27   -$cinza1: #f1f1f1;
28   -$cinza2: #eaeaea;
29   -$cinza3: #dadada;
30   -$cinza4: #989898;
31   -$cinza5: #606060;
32   -$cinza6: #484848;
  28 +// Programs
  29 +$scale: 1.1;
  30 +$time: .2s;
  31 +$darken: 15%;
33 32  
34 33  
35 34 // -------------
36   -// Tipografia
37   -// -------------
38   -// $open-sans-regular:
39   -// $open-sans-bold:
40   -$titulo1-size: 32pt;
41   -$titulo1-line-height: 36pt;
42   -
43   -$titulo2-size: 26pt;
44   -$titulo2-line-height: 30pt;
45 35  
46   -$titulo3-size: 22pt;
47   -$titulo3-line-height: 26pt;
48   -
49   -$titulo4-size: 18pt;
50   -$titulo4-line-height: 22pt;
51   -
52   -$titulo5-size: 14pt;
53   -$titulo5-line-height: 18pt;
54   -
55   -$paragraph-size: 12pt;
56   -$paragraph-line-height: 16pt;
57   -
58   -// -------------
59   -.skip-links a:focus {
60   - background-color: #fff !important;
61   - opacity: 1;
62   - z-index: 2;
  36 +body {
  37 + font-family: "Open Sans", sans-serif;
  38 + &.contraste {
  39 + color: #fff;
  40 + background-color: #000;
  41 +
  42 + a,
  43 + .btn {
  44 + color: #fff;
  45 + background-color: #000;
  46 + }
  47 + }
63 48 }
64 49  
65   -.browsehappy {
66   - margin: 0.2em 0;
67   - background: #ccc;
68   - color: #000;
69   - padding: 0.2em 0;
  50 +// Commons
  51 +.button--themed {
  52 + padding: 20px;
  53 + .btn {
  54 + color: #fff;
  55 + font-weight: bold;
  56 + padding: 15px 0;
  57 + border-left: 0;
  58 + border-right: 0;
  59 + border-top: 0;
  60 + border-radius: 6px;
  61 +
  62 + -webkit-transition: all $time ease-in-out;
  63 + -moz-transition: all $time ease-in-out;
  64 + -o-transition: all $time ease-in-out;
  65 + transition: all $time ease-in-out;
  66 +
  67 + @each $category, $color in $categories {
  68 + .#{$category} & {
  69 + background-color: $color;
  70 + border-bottom: 3px solid darken($color, $darken);
  71 + }
  72 + }
  73 +
  74 + &:hover,
  75 + &:focus {
  76 + @each $category, $color in $categories {
  77 + .#{$category} & {
  78 + background-color: darken($color, $darken);
  79 + }
  80 + }
  81 + }
  82 +
  83 + .contraste & {
  84 + color: #262626;
  85 + background-color: #fff;
  86 + }
  87 + }
  88 +
  89 + .btn-circle {
  90 + width: 64px;
  91 + height: 64px;
  92 + border-radius: 100%;
  93 + }
  94 +
  95 + // &.vote-buttons {
  96 + // padding-bottom: 40px;
  97 + // }
  98 +
  99 + .btn.vote-buttons-up {
  100 + float: right;
  101 + margin-right: 10px;
  102 + background-color: #32dbb5;
  103 + border-bottom: 3px solid #1da485;
  104 +
  105 + &:hover,
  106 + &:focus {
  107 + background-color: #1da485;
  108 + }
  109 + }
  110 +
  111 + .btn.vote-buttons-down {
  112 + float: left;
  113 + margin-left: 10px;
  114 + background-color: #db4127;
  115 + border-bottom: 3px solid #9c2d1a;
  116 +
  117 + &:hover,
  118 + &:focus {
  119 + background-color: #9c2d1a;
  120 + }
  121 +
  122 +
  123 + // @media (max-width: $screen-sm) {
  124 + // margin-left:
  125 + // }
  126 + }
  127 +
  128 + .vote-buttons-up,
  129 + .vote-buttons-down {
  130 + font-size: 30px;
  131 + margin-bottom: 20px;
  132 + }
70 133 }
71 134  
72 135 // Hack to fix "Barra do Brasil"
... ...
src/app/layout.scss 0 → 100644
... ... @@ -0,0 +1,54 @@
  1 +.row-height {
  2 + display: table;
  3 + table-layout: fixed;
  4 + height: 100%;
  5 + width: 100%;
  6 +
  7 + @media (max-width: $screen-sm) {
  8 + display: block;
  9 + }
  10 +
  11 + // @media (min-width: $screen-sm + 1) {
  12 + // height: $hLine * 2;
  13 + // }
  14 +
  15 + // @media (min-width: $screen-md + 1) {
  16 + // height: $hLine * 2;
  17 + // }
  18 +}
  19 +
  20 +.col-height {
  21 + display: table-cell;
  22 + float: none;
  23 + height: 100%;
  24 + vertical-align: top;
  25 +}
  26 +
  27 +.col-height--align-bottom {
  28 + vertical-align: bottom;
  29 +}
  30 +
  31 +.inside {
  32 + margin-top: 20px;
  33 + margin-bottom: 20px;
  34 +}
  35 +
  36 +.inside-full-height {
  37 + height: 100%;
  38 + margin-top: 0;
  39 + margin-bottom: 0;
  40 +
  41 +
  42 + @media (max-width: $screen-sm) {
  43 + border: 1px solid;
  44 + border-radius: 3px;
  45 + padding: 20px;
  46 + margin: 10px 0;
  47 +
  48 + @each $category, $color in $categories {
  49 + .#{$category} & {
  50 + border-color: $color;
  51 + }
  52 + }
  53 + }
  54 +}
... ...
src/app/pages/article/article.controller.js 0 → 100644
... ... @@ -0,0 +1,50 @@
  1 +(function() {
  2 + 'use strict';
  3 +
  4 + angular
  5 + .module('dialoga')
  6 + .controller('ArticlePageController', ArticlePageController);
  7 +
  8 + /** @ngInject */
  9 + function ArticlePageController(ArticleService, $state, $sce, $log) {
  10 + $log.debug('ArticlePageController');
  11 +
  12 + var vm = this;
  13 + vm.ArticleService = ArticleService;
  14 + vm.$state = $state;
  15 + vm.$sce = $sce;
  16 + vm.$log = $log;
  17 +
  18 + vm.init();
  19 + }
  20 +
  21 + ArticlePageController.prototype.init = function() {
  22 + var vm = this;
  23 +
  24 + vm.page = vm.$state.current.name;
  25 + vm.article = null;
  26 + vm.loading = true;
  27 + switch (vm.page){
  28 + case 'sobre':
  29 + vm.ArticleService.getAbout(handleSuccess, handleError);
  30 + break;
  31 + case 'termos-de-uso':
  32 + vm.ArticleService.getTerms(handleSuccess, handleError);
  33 + break;
  34 + default:
  35 + vm.$log.warn('Page not handled:', vm.page);
  36 + break;
  37 + }
  38 +
  39 + function handleSuccess (data) {
  40 + vm.loading = false;
  41 + vm.article = data.article;
  42 + // vm.article.body = vm.$sce.trustAsHtml(vm.article.body);
  43 + }
  44 +
  45 + function handleError (error) {
  46 + vm.loading = false;
  47 + vm.error = error;
  48 + }
  49 + };
  50 +})();
... ...
src/app/pages/article/article.controller.spec.js 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +(function() {
  2 + 'use strict';
  3 +
  4 + describe('controllers', function(){
  5 +
  6 + beforeEach(module('dialoga'));
  7 +
  8 + it('should define more than 5 awesome things', inject(function($controller) {
  9 + var vm = $controller('ArticlePageController');
  10 +
  11 + vm.init();
  12 + expect(vm.page).toBeDefined();
  13 + }));
  14 + });
  15 +})();
... ...
src/app/pages/article/article.html 0 → 100644
... ... @@ -0,0 +1,25 @@
  1 +<div class="container" role="main">
  2 +
  3 + <article-bar></article-bar>
  4 +
  5 + <div ng-if="pageArticle.loading">
  6 + <div class="alert alert-info">
  7 + Carregando conteúdo...
  8 + </div>
  9 + </div>
  10 +
  11 + <div ng-if="pageArticle.error">
  12 + <div class="alert alert-info">
  13 + Erro ao carregar conteúdo.
  14 + </div>
  15 + </div>
  16 +
  17 + <div ng-if="pageArticle.article">
  18 + <article>
  19 + <header>
  20 + <h1>{{::pageArticle.article.title}}</h1>
  21 + </header>
  22 + <section ng-bind-html="pageArticle.article.body"></section>
  23 + </article>
  24 + </div>
  25 +</div>
... ...
src/app/pages/article/article.service.js 0 → 100644
... ... @@ -0,0 +1,173 @@
  1 +(function() {
  2 + 'use strict';
  3 +
  4 + angular
  5 + .module('dialoga')
  6 + .factory('ArticleService', ArticleService);
  7 +
  8 + /** @ngInject */
  9 + function ArticleService($http, $q, $rootScope, API, UtilService, Slug, $log) {
  10 + $log.debug('ArticleService');
  11 +
  12 + var idArticleHome = API.articleId.home;
  13 + var idArticleAbout = API.articleId.about;
  14 + var idArticleTerms = API.articleId.terms;
  15 +
  16 + var _savedAbstract = null;
  17 +
  18 + var service = {
  19 + apiArticles: $rootScope.basePath + '/api/v1/articles/',
  20 + getHome: getHome,
  21 + getAbout: getAbout,
  22 + getTerms: getTerms,
  23 + getArticleById: getArticleById,
  24 + getArticleBySlug: getArticleBySlug,
  25 + getCategories: getCategories,
  26 + getCategoryBySlug: getCategoryBySlug,
  27 + getPrograms: getPrograms,
  28 + getContentById: getContentById,
  29 + setHomeAbstract: setHomeAbstract,
  30 + getHomeAbstract: getHomeAbstract
  31 + };
  32 +
  33 + var CACHE = {}; // cache by article id
  34 +
  35 + return service;
  36 +
  37 + function loadArticleById (articleId, params, cbSuccess, cbError) {
  38 +
  39 + var url = service.apiArticles + articleId;
  40 + var paramsExtended = angular.extend({}, params);
  41 +
  42 + UtilService.get(url, {params: paramsExtended}).then(function(data){
  43 + CACHE[articleId] = data;
  44 + cbSuccess(data);
  45 + }, function(error){
  46 + cbError(error);
  47 + });
  48 + }
  49 +
  50 + function getArticleById (articleId, params, cbSuccess, cbError) {
  51 + var cachedArticle = CACHE[articleId];
  52 +
  53 + if(cachedArticle){
  54 + cbSuccess(cachedArticle);
  55 + }else{
  56 + loadArticleById(articleId, params, cbSuccess, cbError);
  57 + }
  58 + }
  59 +
  60 + function getArticleBySlug (slug, cbSuccess, cbError) {
  61 + var vm = this;
  62 +
  63 + /**
  64 + * XXX: get from home article util we have a endpoint to do-it.
  65 + */
  66 + vm.getHome(function (data) {
  67 + var mainArticle = data.article;
  68 + var programList = mainArticle.children;
  69 + var categories = mainArticle.categories;
  70 +
  71 + $rootScope._CATEGORIES = $rootScope._CATEGORIES ? $rootScope._CATEGORIES : categories;
  72 +
  73 + var result = null;
  74 + for (var i = programList.length - 1; i >= 0; i--) {
  75 + var program = programList[i];
  76 +
  77 + if(!program.slug){
  78 + program.slug = Slug.slugify(program.title);
  79 + }
  80 +
  81 + if(program.slug === slug){
  82 + result = program;
  83 + break;
  84 + }
  85 + }
  86 +
  87 + if(result){
  88 + cbSuccess(result);
  89 + }else{
  90 + cbError('None program with slug "' + slug + '"" was found.');
  91 + }
  92 + }, cbError);
  93 + }
  94 +
  95 + function getCategories (cbSuccess, cbError) {
  96 + return getHome(function(data){
  97 + cbSuccess(data.article.categories);
  98 + }, cbError);
  99 + }
  100 +
  101 + function getCategoryBySlug (slug, cbSuccess, cbError) {
  102 + return getHome(function (data){
  103 + var result = null;
  104 +
  105 + for (var i = data.article.categories.length - 1; i >= 0; i--) {
  106 + var category = data.article.categories[i];
  107 + if (category.slug === slug) {
  108 + result = category;
  109 + break;
  110 + }
  111 + }
  112 +
  113 + cbSuccess(result);
  114 + }, cbError);
  115 + }
  116 +
  117 + function getPrograms (cbSuccess, cbError) {
  118 + return getHome(function(data){
  119 + cbSuccess(data.article.children);
  120 + }, cbError);
  121 + }
  122 +
  123 + function getContentById (contentId, cbSuccess, cbError) {
  124 + return getArticleById(contentId, {
  125 + fields: 'id,body&content_type=ProposalsDiscussionPlugin::Topic'
  126 + }, cbSuccess, cbError);
  127 + }
  128 +
  129 + function getHome (cbSuccess, cbError) {
  130 + return getArticleById(idArticleHome, {
  131 + fields: 'id,children,categories,abstract,title,image,url,setting,position',
  132 + private_token: 'null'
  133 + }, _handleCategory(cbSuccess), cbError);
  134 + }
  135 +
  136 + function getAbout (cbSuccess, cbError) {
  137 + return getArticleById(idArticleAbout, {}, cbSuccess, cbError);
  138 + }
  139 +
  140 + function getTerms (cbSuccess, cbError) {
  141 + return getArticleById(idArticleTerms, {}, cbSuccess, cbError);
  142 + }
  143 +
  144 + function _handleCategory (cbSuccess) {
  145 + // var darkFactor = 0.15;
  146 +
  147 + return function (data) {
  148 + if(data.article.categories){
  149 + // var categories = data.article.categories;
  150 +
  151 + // Handle Category Data
  152 +
  153 + // Handle Category Colors
  154 + // for (var i = categories.length - 1; i >= 0; i--) {
  155 + // var category = categories[i];
  156 + // if(category.color && !category.bgColor){
  157 + // category.colorDarker = $window.ColorLuminance(category.color, 0.15);
  158 + // }
  159 + // };
  160 + }
  161 + cbSuccess(data);
  162 + };
  163 + }
  164 +
  165 + function setHomeAbstract (newAbstract) {
  166 + _savedAbstract = newAbstract;
  167 + }
  168 +
  169 + function getHomeAbstract () {
  170 + return _savedAbstract;
  171 + }
  172 + }
  173 +})();
... ...
src/app/pages/article/article.service.spec.js 0 → 100644
... ... @@ -0,0 +1,67 @@
  1 +(function() {
  2 + 'use strict';
  3 +
  4 + describe('article services', function() {
  5 + var ArticleService, httpBackend;
  6 +
  7 + beforeEach(module('dialoga'));
  8 +
  9 + beforeEach(inject(function(_ArticleService_, $httpBackend) {
  10 + ArticleService = _ArticleService_;
  11 + httpBackend = $httpBackend;
  12 + }));
  13 +
  14 + it('should return the main article', function() {
  15 + var url = 'http://login.dialoga.gov.br/api/v1/articles/103358?fields=id,children,categories,abstract,title,image,url,setting,position&private_token=null';
  16 + httpBackend.whenGET(url).respond({
  17 + 'article':{'id':103358,'abstract':'\u003Cp style=\"text-align: center;\"\u003E\u003Ciframe src=\"https://www.youtube.com/embed/kpAdrO-emV0?rel=0\u0026amp;showinfo=0\u0026amp;iv_load_policy=3\u0026amp;controls=1\" style=\"max-width: 1000px; left: 5%;\" width=\"275\" height=\"200\"\u003E\u003C/iframe\u003E\u003C/p\u003E','title':'Dialoga Brasil','categories':[{'name':'Sa\u00fade','id':180,'slug':'saude','image':null},{'name':'Seguran\u00e7a P\u00fablica','id':182,'slug':'seguranca-publica','image':null},{'name':'Educa\u00e7\u00e3o','id':181,'slug':'educacao','image':null},{'name':'Redu\u00e7\u00e3o da Pobreza','id':183,'slug':'reducao-da-pobreza','image':null}],'image':null,'setting':{'custom_body_label':'Corpo','phase':'proposals','allow_topics':true,'moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Leandro Nunes dos Santos','moderate_proposals':true,'allow_members_to_edit':false},'position':null,'children':[{'id':103644,'abstract':'\u003Cp\u003EUm caminho de oportunidades com o Enem: Sisu, Prouni, Fies, Ci\u00eancia sem Fronteiras\u003C/p\u003E','title':'Ensino Superior','categories':[{'name':'Educa\u00e7\u00e3o','id':181,'slug':'educacao','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0128/enem.jpg'},'setting':{'color':'#cfe2f3','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':9},{'id':103673,'abstract':'\u003Cp\u003EA melhor escolha \u00e9 se informar.\u003C/p\u003E','title':'Incentivo ao Parto Normal','categories':[{'name':'Sa\u00fade','id':180,'slug':'saude','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0092/parto-normal.jpg'},'setting':{'color':'#ff0000','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':6},{'id':103397,'abstract':'\u003Cp\u003ERenda, inclus\u00e3o produtiva e acesso a servi\u00e7os.\u003C/p\u003E','title':'Brasil Sem Mis\u00e9ria','categories':[{'name':'Redu\u00e7\u00e3o da Pobreza','id':183,'slug':'reducao-da-pobreza','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0116/bsm_redim.jpg'},'setting':{'color':'','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':18},{'id':103379,'abstract':'\u003Cp\u003EResgate e atendimento 24 horas, sete dias da semana.\u003C/p\u003E','title':'SAMU 192 e UPAs','categories':[{'name':'Sa\u00fade','id':180,'slug':'saude','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0060/SAMU.jpg'},'setting':{'color':'#45818e','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':4},{'id':103521,'abstract':'\u003Cp\u003EMais atendimento nos munic\u00edpios, mais sa\u00fade para quem mais precisa.\u003C/p\u003E','title':'Mais M\u00e9dicos','categories':[{'name':'Sa\u00fade','id':180,'slug':'saude','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0025/Mais_M_dicos.jpg'},'setting':{'color':'#ffe599','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':1},{'id':103390,'abstract':'\u003Cp\u003EPreven\u00e7\u00e3o, tratamento e enfrentamento ao tr\u00e1fico.\u003C/p\u003E','title':'Crack, \u00e9 poss\u00edvel vencer!','categories':[{'name':'Seguran\u00e7a P\u00fablica','id':182,'slug':'seguranca-publica','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0104/crack.jpg'},'setting':{'color':'#00ff00','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':14},{'id':103592,'abstract':'\u003Cp\u003EGarantir acesso \u00e0 prote\u00e7\u00e3o social.\u003C/p\u003E','title':'Assist\u00eancia Social','categories':[{'name':'Redu\u00e7\u00e3o da Pobreza','id':183,'slug':'reducao-da-pobreza','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0122/assistencia_social.jpg'},'setting':{'color':'#a61c00','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':19},{'id':103426,'abstract':'\u003Cp\u003EDa sa\u00fade se cuida todos os dias.\u003C/p\u003E','title':'Vida saud\u00e1vel','categories':[{'name':'Sa\u00fade','id':180,'slug':'saude','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0046/vida_saudavel.jpg'},'setting':{'color':'#d9d2e9','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':7},{'id':103695,'abstract':'\u003Cp\u003ENovo modelo de atua\u00e7\u00e3o em Seguran\u00e7a P\u00fablica.\u003C/p\u003E','title':'Seguran\u00e7a P\u00fablica Integrada','categories':[{'name':'Seguran\u00e7a P\u00fablica','id':182,'slug':'seguranca-publica','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0152/policiaintegrada.jpg'},'setting':{'color':'#ff00ff','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':13},{'id':103663,'abstract':'\u003Cp\u003EMais educa\u00e7\u00e3o profissional e tecnol\u00f3gica, mais desenvolvimento\u003C/p\u003E','title':'Ensino T\u00e9cnico','categories':[{'name':'Educa\u00e7\u00e3o','id':181,'slug':'educacao','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0134/Ensino_tecnico.jpg'},'setting':{'color':'#d0e0e3','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':10},{'id':103472,'abstract':'\u003Cp\u003EPol\u00edcia Federal, Pol\u00edcia Rodovi\u00e1ria Federal e For\u00e7a Nacional de Seguran\u00e7a P\u00fablica.\u003C/p\u003E','title':'For\u00e7as Federais de Seguran\u00e7a','categories':[{'name':'Seguran\u00e7a P\u00fablica','id':182,'slug':'seguranca-publica','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0031/federais2.png'},'setting':{'color':'','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':16},{'id':103612,'abstract':'\u003Cp\u003EGarantir \u00e1gua para beber e produzir.\u003C/p\u003E','title':'Cisternas','categories':[{'name':'Redu\u00e7\u00e3o da Pobreza','id':183,'slug':'reducao-da-pobreza','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0039/cisterna_redim.jpg'},'setting':{'color':'#0000ff','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':20},{'id':103442,'abstract':'\u003Cp\u003EComplemento \u00e0 renda e acompanhamento em educa\u00e7\u00e3o e sa\u00fade.\u003C/p\u003E','title':'Bolsa Fam\u00edlia','categories':[{'name':'Redu\u00e7\u00e3o da Pobreza','id':183,'slug':'reducao-da-pobreza','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0013/bolsa_familia_redim.jpg'},'setting':{'color':'#ff9900','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':17},{'id':103507,'abstract':'\u003Cp\u003ETecnologia a servi\u00e7o da seguran\u00e7a do cidad\u00e3o.\u003C/p\u003E','title':'Sinesp','categories':[{'name':'Seguran\u00e7a P\u00fablica','id':182,'slug':'seguranca-publica','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0098/sinesp.png'},'setting':{'color':'#00ff00','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':12},{'id':103683,'abstract':'\u003Cp\u003ESa\u00fade n\u00e3o tem pre\u00e7o.\u003C/p\u003E','title':'Aqui tem Farm\u00e1cia Popular','categories':[{'name':'Sa\u00fade','id':180,'slug':'saude','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0019/saude_nao_tem_preco.jpg'},'setting':{'color':'#e69138','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':5},{'id':103457,'abstract':'\u003Cp\u003EA\u00e7\u00e3o conjunta e coopera\u00e7\u00e3o transfronteiri\u00e7a.\u003C/p\u003E','title':'Prote\u00e7\u00e3o das Fronteiras','categories':[{'name':'Seguran\u00e7a P\u00fablica','id':182,'slug':'seguranca-publica','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0110/fronteira_redim.jpg'},'setting':{'color':'#a64d79','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':15},{'id':103494,'abstract':'\u003Cp\u003EDa Educa\u00e7\u00e3o Infantil ao Ensino M\u00e9dio.\u003C/p\u003E','title':'Educa\u00e7\u00e3o B\u00e1sica','categories':[{'name':'Educa\u00e7\u00e3o','id':181,'slug':'educacao','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0076/Educa__o_B_sica.jpg'},'setting':{'color':'#fce5cd','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':8},{'id':103359,'abstract':'\u003Cp\u003EAcesso a exames e consultas com especialistas.\u003C/p\u003E','title':'Mais Especialidades','categories':[{'name':'Sa\u00fade','id':180,'slug':'saude','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0083/mais_especialidades1.png'},'setting':{'color':'#ea9999','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':2},{'id':103485,'abstract':'\u003Cp\u003ECaminho para uma educa\u00e7\u00e3o de qualidade.\u003C/p\u003E','title':'Valoriza\u00e7\u00e3o dos Professores','categories':[{'name':'Educa\u00e7\u00e3o','id':181,'slug':'educacao','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0140/valorizacao_professor.jpg'},'setting':{'color':'#ffff00','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':11},{'id':103416,'abstract':'\u003Cp\u003EEstrutura adequada para atender melhor a popula\u00e7\u00e3o na aten\u00e7\u00e3o b\u00e1sica.\u003C/p\u003E','title':'Melhorar os Postos de Sa\u00fade','categories':[{'name':'Sa\u00fade','id':180,'slug':'saude','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0053/requalif_redim.jpg'},'setting':{'color':'#cc4125','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':3}]}});
  18 +
  19 + ArticleService.getHome(function(result){
  20 + expect(result.article).toBeDefined();
  21 + expect(result.article.title).toEqual('Dialoga Brasil');
  22 + expect(result.article.categories).toBeDefined();
  23 + });
  24 +
  25 + httpBackend.flush();
  26 + });
  27 +
  28 + // it('should return a list of articles', function() {
  29 +
  30 + // httpBackend.whenGET('http://login.dialoga.gov.br/api/v1/articles').respond({
  31 + // "articles": [
  32 + // {
  33 + // abstract: "Que exista educação continuada permanente dos profissionais!!",
  34 + // author: null,
  35 + // body: "",
  36 + // categories: [],
  37 + // children: [],
  38 + // created_at: "2015/08/04 16:36:13",
  39 + // end_date: null,
  40 + // hits: 0,
  41 + // id: 120568,
  42 + // image: null,
  43 + // parent: {id: 103379,…},
  44 + // position: null,
  45 + // profile: {identifier: "dialoga", name: "dialoga", id: 19195, created_at: "2015/04/15 09:38:36", image: null},
  46 + // setting: {comment_paragraph_plugin_activate: false, author_name: "estacio"},
  47 + // start_date: null,
  48 + // tag_list: [],
  49 + // title: "article_f4f4601c-0f36-e90e-d01a-9871f0bd126b",
  50 + // votes_against: 0,
  51 + // votes_for: 0,
  52 + // }
  53 + // ]
  54 + // });
  55 +
  56 + // ArticleService.getList().then(function(result) {
  57 + // console.log('result', result);
  58 +
  59 + // expect(result.data.article).toBeDefined();
  60 + // expect(result.data.article.title).toEqual('Dialoga Brasil');
  61 +
  62 + // });
  63 +
  64 + // httpBackend.flush();
  65 + // });
  66 + });
  67 +})();
... ...
src/app/pages/auth/auth.controller.js 0 → 100644
... ... @@ -0,0 +1,44 @@
  1 +(function () {
  2 + 'use strict';
  3 +
  4 + angular
  5 + .module('dialoga')
  6 + .controller('AuthPageController', AuthPageController);
  7 +
  8 + /** @ngInject */
  9 + function AuthPageController($rootScope, AUTH_EVENTS, AuthService, Session, $log) {
  10 + $log.debug('AuthPageController');
  11 +
  12 + var vm = this;
  13 +
  14 + vm.$rootScope = $rootScope;
  15 + vm.AUTH_EVENTS = AUTH_EVENTS;
  16 + vm.AuthService = AuthService;
  17 + vm.Session = Session;
  18 + vm.$log = $log;
  19 +
  20 + vm.init();
  21 + }
  22 +
  23 + AuthPageController.prototype.init = function() {
  24 + var vm = this;
  25 +
  26 + // init variables
  27 + vm.credentials = {};
  28 +
  29 + // attach events
  30 +
  31 + // ...
  32 + };
  33 +
  34 + AuthPageController.prototype.login = function(credentials) {
  35 + var vm = this;
  36 +
  37 + vm.AuthService.login(credentials).then(function(/*user*/) {
  38 + // handle view
  39 + }, function() {
  40 + // handle view
  41 + });
  42 + };
  43 +
  44 +})();
... ...
src/app/pages/auth/auth.scss 0 → 100644
... ... @@ -0,0 +1,63 @@
  1 +.auth-content{
  2 +
  3 + .btn-social {
  4 + color: #fff;
  5 + font-weight: bold;
  6 +
  7 + &:hover,
  8 + &:focus {color: #fff;}
  9 +
  10 + &.btn-facebook {
  11 + background-color: #33477a;
  12 + &:hover,
  13 + &:focus {background-color: #304373; }
  14 + &:active {background-color: #33477a; }
  15 + }
  16 + &.btn-google-plus {
  17 + background-color: #b92d25;
  18 + &:hover,
  19 + &:focus {background-color: #b12b23; }
  20 + &:active {background-color: #b92d25; }
  21 + }
  22 + }
  23 +
  24 + .btn {
  25 + .contraste & {
  26 + color: #fff;
  27 + }
  28 + }
  29 + .btn-primary {
  30 + .contraste & {
  31 + background-color: #262626;
  32 + border-color: #666;
  33 + }
  34 + }
  35 +
  36 + .glyphicon {
  37 + &.icon-white {
  38 + fill: white;
  39 + }
  40 + }
  41 +
  42 + .separator-or {
  43 + border-top: 2px solid #d8d8d8;
  44 + text-align: center;
  45 + font-weight: bold;
  46 +
  47 + &:after {
  48 + content: "ou";
  49 + position: absolute;
  50 + top: 4px;
  51 + left: 50%;
  52 + margin-left: -26px;
  53 + font-size: 30px;
  54 + line-height: 30px;
  55 + padding: 0 0.25em;
  56 + background: $gray;
  57 +
  58 + .contraste & {
  59 + background: #000;
  60 + }
  61 + }
  62 + }
  63 +}
... ...
src/app/pages/auth/signin.html 0 → 100644
... ... @@ -0,0 +1,38 @@
  1 +<section role="main" class="section-gray auth-content">
  2 + <div class="container">
  3 + <div class="row">
  4 + <div class="col-sm-8 col-sm-offset-2">
  5 + <h2>Identifique-se</h2>
  6 + <form name="loginForm" ng-submit="pageSignin.login(pageSignin.credentials)">
  7 + <div class="form-group">
  8 + <label for="inputUsername" class="sr-only">E-mail:</label>
  9 + <div class="input-group">
  10 + <div class="input-group-addon"><span class="glyphicon glyphicon-user"></span></div>
  11 + <input type="text" id="inputUsername" class="form-control" placeholder="E-mail" required="" autofocus="" ng-model="pageSignin.credentials.username">
  12 + </div>
  13 + </div>
  14 + <div class="form-group">
  15 + <label for="inputPassword" class="sr-only">Senha:</label>
  16 + <div class="input-group">
  17 + <div class="input-group-addon"><span class="glyphicon glyphicon-lock"></span></div>
  18 + <input type="password" id="inputPassword" class="form-control" placeholder="Senha" required="" ng-model="pageSignin.credentials.password">
  19 + </div>
  20 + </div>
  21 + <div class="form-group">
  22 + <button class="btn btn-lg btn-primary btn-block" type="submit">Entrar</button>
  23 + </div>
  24 + </form>
  25 + </div>
  26 + </div>
  27 + <div class="row">
  28 + <div class="col-sm-8 col-sm-offset-2">
  29 + <hr class="separator-or"></hr>
  30 + </div>
  31 + </div>
  32 + <div class="row">
  33 + <div class="col-sm-8 col-sm-offset-2">
  34 + <button class="btn btn-lg btn-link btn-block" type="button" ui-sref="cadastrar">Cadastre-se</button>
  35 + </div>
  36 + </div>
  37 + </div>
  38 +</section>
... ...
src/app/pages/auth/signup.html 0 → 100644
... ... @@ -0,0 +1,58 @@
  1 +<!-- Facebook -->
  2 +<!-- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33 33" width="25" height="25"><path d="M18 32L12 32 12 16l-4 0 0-5.5 4 0 0-3.2C12 2.7 13.2 0 18.5 0l4.4 0 0 5.5 -2.8 0c-2.1 0-2.2 0.8-2.2 2.2l0 2.8 5 0 -0.6 5.5L18 16 18 32z"/></svg> -->
  3 +<!-- Twitter -->
  4 +<!-- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33 33" width="25" height="25"><path d="M32 6.1c-1.2 0.5-2.4 0.9-3.8 1 1.4-0.8 2.4-2.1 2.9-3.6 -1.3 0.8-2.7 1.3-4.2 1.6 -1.2-1.3-2.9-2.1-4.8-2.1 -3.6 0-6.6 2.9-6.6 6.6 0 0.5 0.1 1 0.2 1.5 -5.5-0.3-10.3-2.9-13.5-6.9 -0.6 1-0.9 2.1-0.9 3.3 0 2.3 1.2 4.3 2.9 5.5 -1.1 0-2.1-0.3-3-0.8 0 0 0 0.1 0 0.1 0 3.2 2.3 5.8 5.3 6.4 -0.6 0.2-1.1 0.2-1.7 0.2 -0.4 0-0.8 0-1.2-0.1 0.8 2.6 3.3 4.5 6.1 4.6 -2.2 1.8-5.1 2.8-8.2 2.8 -0.5 0-1.1 0-1.6-0.1 2.9 1.9 6.4 3 10.1 3 12.1 0 18.7-10 18.7-18.7 0-0.3 0-0.6 0-0.8C30 8.5 31.1 7.4 32 6.1z"/></svg> -->
  5 +<!-- Google Plus -->
  6 +<!-- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33 33" width="25" height="25"><path d="M17.5 2c0 0-6.3 0-8.4 0C5.3 2 1.8 4.8 1.8 8.1c0 3.4 2.6 6.1 6.4 6.1 0.3 0 0.5 0 0.8 0 -0.2 0.5-0.4 1-0.4 1.6 0 0.9 0.5 1.7 1.1 2.3 -0.5 0-0.9 0-1.5 0C3.6 18.1 0 21.1 0 24.1c0 3 3.9 4.9 8.6 4.9 5.3 0 8.2-3 8.2-6 0-2.4-0.7-3.9-2.9-5.4 -0.8-0.5-2.2-1.8-2.2-2.6 0-0.9 0.3-1.3 1.6-2.4 1.4-1.1 2.4-2.6 2.4-4.4 0-2.1-0.9-4.2-2.7-4.8l2.7 0L17.5 2zM14.5 22.5c0.1 0.3 0.1 0.6 0.1 0.9 0 2.4-1.6 4.4-6.1 4.4 -3.2 0-5.5-2-5.5-4.5 0-2.4 2.9-4.4 6.1-4.4 0.8 0 1.4 0.1 2.1 0.3C12.9 20.4 14.2 21.1 14.5 22.5zM9.4 13.4c-2.2-0.1-4.2-2.4-4.6-5.2 -0.4-2.8 1.1-5 3.2-4.9 2.2 0.1 4.2 2.3 4.6 5.2C13 11.2 11.6 13.4 9.4 13.4zM26 8L26 2 24 2 24 8 18 8 18 10 24 10 24 16 26 16 26 10 32 10 32 8z"/></svg> -->
  7 +
  8 +<section>
  9 + <div class="container">
  10 + <div class="row">
  11 + <div class="col-sm-12">
  12 + <h1>Cadastro</h1>
  13 + <p>Cadastre-se para fazer parte do Dialoga Brasil, interagir com as propostas e enviar as suas!</p>
  14 + </div>
  15 + </div>
  16 + </div>
  17 +</section>
  18 +<section role="main" class="section-gray auth-content">
  19 + <div class="container">
  20 + <div class="row">
  21 + <div class="col-sm-8 col-sm-offset-2">
  22 + <h2>Conecte-se por redes sociais</h2>
  23 + <div class="col-sm-6">
  24 + <button type="button" class="btn btn-lg btn-block btn-social btn-facebook">
  25 + <span class="glyphicon icon-facebook icon-white" aria-hidden="true">
  26 + <!-- Facebook -->
  27 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33 33" width="25" height="25"><path d="M18 32L12 32 12 16l-4 0 0-5.5 4 0 0-3.2C12 2.7 13.2 0 18.5 0l4.4 0 0 5.5 -2.8 0c-2.1 0-2.2 0.8-2.2 2.2l0 2.8 5 0 -0.6 5.5L18 16 18 32z"/></svg>
  28 + </span>
  29 + <span class="text">
  30 + Conectar pelo Facebook
  31 + </span>
  32 + </button>
  33 + </div>
  34 + <div class="col-sm-6">
  35 + <button type="button" class="btn btn-lg btn-block btn-social btn-google-plus">
  36 + <span class="glyphicon icon-google-plus icon-white" aria-hidden="true">
  37 + <!-- Google Plus -->
  38 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33 33" width="25" height="25"><path d="M17.5 2c0 0-6.3 0-8.4 0C5.3 2 1.8 4.8 1.8 8.1c0 3.4 2.6 6.1 6.4 6.1 0.3 0 0.5 0 0.8 0 -0.2 0.5-0.4 1-0.4 1.6 0 0.9 0.5 1.7 1.1 2.3 -0.5 0-0.9 0-1.5 0C3.6 18.1 0 21.1 0 24.1c0 3 3.9 4.9 8.6 4.9 5.3 0 8.2-3 8.2-6 0-2.4-0.7-3.9-2.9-5.4 -0.8-0.5-2.2-1.8-2.2-2.6 0-0.9 0.3-1.3 1.6-2.4 1.4-1.1 2.4-2.6 2.4-4.4 0-2.1-0.9-4.2-2.7-4.8l2.7 0L17.5 2zM14.5 22.5c0.1 0.3 0.1 0.6 0.1 0.9 0 2.4-1.6 4.4-6.1 4.4 -3.2 0-5.5-2-5.5-4.5 0-2.4 2.9-4.4 6.1-4.4 0.8 0 1.4 0.1 2.1 0.3C12.9 20.4 14.2 21.1 14.5 22.5zM9.4 13.4c-2.2-0.1-4.2-2.4-4.6-5.2 -0.4-2.8 1.1-5 3.2-4.9 2.2 0.1 4.2 2.3 4.6 5.2C13 11.2 11.6 13.4 9.4 13.4zM26 8L26 2 24 2 24 8 18 8 18 10 24 10 24 16 26 16 26 10 32 10 32 8z"/></svg>
  39 + </span>
  40 + <span class="text">
  41 + Conectar pelo Google+
  42 + </span>
  43 + </button>
  44 + </div>
  45 + </div>
  46 + </div>
  47 + <div class="row">
  48 + <div class="col-sm-8 col-sm-offset-2">
  49 + <hr class="separator-or"></hr>
  50 + </div>
  51 + </div>
  52 + <div class="row">
  53 + <div class="col-sm-8 col-sm-offset-2">
  54 + <h2>Faça o cadastro abaixo</h2>
  55 + </div>
  56 + </div>
  57 + </div>
  58 +</section>
... ...
src/app/pages/footer/footer.html 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +<div id="footer">
  2 + <div class="container">
  3 + <div class="row">
  4 + <div class="col-xs-12 text-center">
  5 + <a id="termos-de-uso" ui-sref="termos-de-uso">Termos de uso</a>
  6 + </div>
  7 + </div>
  8 + </div>
  9 +</div>
... ...
src/app/pages/footer/footer.scss 0 → 100644
... ... @@ -0,0 +1,21 @@
  1 +$barra-theme: ("green": #00420c, "yellow": #2c66ce, "blue": #0042b1);
  2 +
  3 +#footer-brasil {
  4 + background: none repeat scroll 0% 0% map-get($barra-theme, "blue");
  5 + padding: 1em 0px;
  6 + max-width: 100%;
  7 +}
  8 +
  9 +#footer {
  10 + padding: 20px 0;
  11 + a {
  12 + margin: 10px auto;
  13 + }
  14 +
  15 + .contraste & {
  16 + background-color: #000;
  17 + a {
  18 + color: #fff;
  19 + }
  20 + }
  21 +}
... ...
src/app/pages/header/header.html 0 → 100644
... ... @@ -0,0 +1,26 @@
  1 +<header class="container">
  2 +
  3 + <div class="row">
  4 + <div class="col-sm-12">
  5 +
  6 + <div class="accessibility-wrapper">
  7 +
  8 + <button type="button" class="btn btn-link pull-right" ui-sref="entrar">
  9 + <span class="icon icon-user" aria-hidden="true"></span>
  10 + Entrar
  11 + </button>
  12 + </div>
  13 + </div>
  14 + </div>
  15 +
  16 + <div class="row">
  17 + <app-navbar></app-navbar>
  18 + </div>
  19 +
  20 + <!-- TODO: breadcrumb -->
  21 + <!-- <ol class="breadcrumb">
  22 + <li><a href="#">Home</a></li>
  23 + <li><a href="#">Library</a></li>
  24 + <li class="active">Data</li>
  25 + </ol> -->
  26 +</header>
... ...
src/app/pages/header/header.scss 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +.accessibility-wrapper {
  2 + .icon-user {
  3 + display: inline-block;
  4 + vertical-align: middle;
  5 + width: 26px;
  6 + height: 26px;
  7 + border: 1px solid #ccc;
  8 + border-radius: 100%;
  9 + background-position: 1px 0px;
  10 +
  11 + .contraste & {
  12 + // XXX: chage for dinamic handler
  13 + background-position: -0px -24px;
  14 + }
  15 + }
  16 +}
... ...
src/app/pages/inicio/inicio.controller.js 0 → 100644
... ... @@ -0,0 +1,152 @@
  1 +/* globals document:true, window:true */
  2 +(function() {
  3 + 'use strict';
  4 +
  5 + angular
  6 + .module('dialoga')
  7 + .controller('InicioPageController', InicioPageController);
  8 +
  9 + /** @ngInject */
  10 + function InicioPageController(ArticleService, $rootScope, $sce, $log) {
  11 + var vm = this;
  12 +
  13 + // aliases
  14 + vm.ArticleService = ArticleService;
  15 + vm.$sce = $sce;
  16 + vm.$log = $log;
  17 +
  18 + vm.init();
  19 + vm.$log.debug('InicioPageController');
  20 + }
  21 +
  22 + InicioPageController.prototype.init = function() {
  23 + var vm = this;
  24 +
  25 + vm.error = null;
  26 + vm.loading = true;
  27 + vm.loadHomeArticle();
  28 + };
  29 +
  30 + InicioPageController.prototype.loadHomeArticle = function() {
  31 + var vm = this;
  32 +
  33 + vm.content = vm.ArticleService.getHomeAbstract();
  34 + vm.isCached = !!vm.content;
  35 +
  36 + if (vm.isCached) {
  37 + hideBackground(2000);
  38 + }
  39 +
  40 + vm.ArticleService.getHome(function(data) {
  41 + vm.loading = false;
  42 + vm.article = data.article;
  43 + }, function(error) {
  44 + vm.$log.error('Error on getHome article.', error);
  45 + vm.error = 'Erro ao carregar o conteúdo principal.';
  46 + });
  47 + };
  48 +
  49 + InicioPageController.prototype.showVideo = function() {
  50 + var vm = this;
  51 +
  52 + // we need handle home content
  53 + if (vm.isCached) {
  54 + hideBackground(0); // force to hide
  55 + vm.$log.warn('The content already cached. Aborting.');
  56 + return;
  57 + }
  58 +
  59 + vm.content = vm.handleHomeAbstract(vm.article.abstract);
  60 + vm.ArticleService.setHomeAbstract(vm.content);
  61 +
  62 + // inject dependencies
  63 + injectIframeApiJs();
  64 + window.onYouTubeIframeAPIReady = window.onYouTubeIframeAPIReady || onYouTubeIframeAPIReady;
  65 + window.onYouTubePlayerReady = window.onYouTubePlayerReady || onYouTubePlayerReady;
  66 + };
  67 +
  68 + InicioPageController.prototype.handleHomeAbstract = function(abstract) {
  69 + var vm = this;
  70 +
  71 + abstract = forceIframeParams(abstract);
  72 + abstract = removeStylefromIframe(abstract);
  73 +
  74 + return vm.$sce.trustAsHtml(abstract);
  75 + };
  76 +
  77 + function injectIframeApiJs() {
  78 + var tag = document.createElement('script');
  79 + tag.src = 'https://www.youtube.com/iframe_api';
  80 +
  81 + var firstScriptTag = document.getElementsByTagName('script')[0];
  82 + firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
  83 + }
  84 +
  85 + function onYouTubeIframeAPIReady() {
  86 + var ytIframe = angular.element.find('.js-iframe iframe');
  87 + var YTPlayer = window.YT.Player;
  88 + new YTPlayer(ytIframe[0], {
  89 + events: {
  90 + 'onReady': onYouTubePlayerReady
  91 + }
  92 + });
  93 + }
  94 +
  95 + function onYouTubePlayerReady (event) {
  96 + event.target.playVideo();
  97 + hideBackground(1000);
  98 + }
  99 +
  100 + function hideBackground (ms) {
  101 + var $elBg = angular.element.find('.video-background');
  102 + angular.element($elBg).fadeOut(ms || 100);
  103 + // angular.element($elBg).hide();
  104 + }
  105 +
  106 + function forceIframeParams(abstract) {
  107 + var patternIframe = '<iframe src="';
  108 + var indexOfIframe = abstract.indexOf(patternIframe);
  109 +
  110 + if (indexOfIframe === -1) {
  111 + return abstract;
  112 + }
  113 +
  114 + var startSrcUrl = indexOfIframe + patternIframe.length;
  115 + var endSrcUrl = abstract.indexOf('"', startSrcUrl);
  116 + var srcUrl = abstract.substring(startSrcUrl , endSrcUrl);
  117 + var resultUrl = srcUrl;
  118 + var c = (srcUrl.indexOf('?') !== -1) ? '&' : ''; // already have url params. So, append-it
  119 +
  120 + // enable js api
  121 + if (srcUrl.indexOf('enablejsapi=1') === -1) {
  122 + resultUrl += c + 'enablejsapi=1';
  123 + c = '&'; // force to always use '&' after here
  124 + }
  125 +
  126 + // set opaque mode
  127 + if (srcUrl.indexOf('wmode=opaque') === -1) {
  128 + resultUrl += c + 'wmode=opaque';
  129 + // c = '&'; // force to always use '&' after here
  130 + }
  131 +
  132 + abstract = abstract.replace(srcUrl, resultUrl);
  133 +
  134 + return abstract;
  135 + }
  136 +
  137 + function removeStylefromIframe (abstract) {
  138 + var patternIframe = 'style="';
  139 + var indexOfIframe = abstract.indexOf('<iframe');
  140 + var indexOfStyleOnIframe = abstract.indexOf('style="', indexOfIframe);
  141 +
  142 + if (indexOfStyleOnIframe === -1) {
  143 + return abstract;
  144 + }
  145 +
  146 + var startStyleContent = indexOfStyleOnIframe + patternIframe.length;
  147 + var endStyleContent = abstract.indexOf('"', startStyleContent);
  148 + var style = abstract.substring(startStyleContent , endStyleContent);
  149 +
  150 + return abstract.replace(style, '');
  151 + }
  152 +})();
... ...
src/app/pages/inicio/inicio.controller.spec.js 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +(function() {
  2 + 'use strict';
  3 +
  4 + describe('controllers', function(){
  5 +
  6 + beforeEach(module('dialoga'));
  7 +
  8 + // it('should define more than 5 awesome things', inject(function($controller) {
  9 + // var vm = $controller('InicioPageController');
  10 +
  11 + // expect(angular.isArray(vm.awesomeThings)).toBeTruthy();
  12 + // expect(vm.awesomeThings.length > 5).toBeTruthy();
  13 + // }));
  14 + });
  15 +})();
... ...
src/app/pages/inicio/inicio.html 0 → 100644
... ... @@ -0,0 +1,50 @@
  1 +<section class="container" role="main">
  2 + <div class="row">
  3 + <div class="col-sm-10 col-sm-offset-1">
  4 + <div class="video-wrapper">
  5 + <div class="video-player js-youtube">
  6 + <div class="embed-responsive embed-responsive-16by9">
  7 + <div class="js-iframe" ng-show="pageInicio.content" ng-bind-html="pageInicio.content"></div>
  8 + <div class="video-background" ng-click="pageInicio.showVideo()">
  9 + <div class="video-thumbnail" aria-hidden="true" style="background-image:url(/assets/images/youtube-background.png)"></div>
  10 + <button class="video-play-button" aria-live="assertive" aria-label="Assistir o vídeo tutorial Dialoga Brasil">
  11 + <svg height="100%" version="1.1" viewBox="0 0 68 48" width="100%"><path class="ytp-play-button-bg" d="m .66,37.62 c 0,0 .66,4.70 2.70,6.77 2.58,2.71 5.98,2.63 7.49,2.91 5.43,.52 23.10,.68 23.12,.68 .00,-1.3e-5 14.29,-0.02 23.81,-0.71 1.32,-0.15 4.22,-0.17 6.81,-2.89 2.03,-2.07 2.70,-6.77 2.70,-6.77 0,0 .67,-5.52 .67,-11.04 l 0,-5.17 c 0,-5.52 -0.67,-11.04 -0.67,-11.04 0,0 -0.66,-4.70 -2.70,-6.77 C 62.03,.86 59.13,.84 57.80,.69 48.28,0 34.00,0 34.00,0 33.97,0 19.69,0 10.18,.69 8.85,.84 5.95,.86 3.36,3.58 1.32,5.65 .66,10.35 .66,10.35 c 0,0 -0.55,4.50 -0.66,9.45 l 0,8.36 c .10,4.94 .66,9.45 .66,9.45 z" fill="#1f1f1e" fill-opacity="0.9"></path><path d="m 26.96,13.67 18.37,9.62 -18.37,9.55 -0.00,-19.17 z" fill="#fff"></path><path d="M 45.02,23.46 45.32,23.28 26.96,13.67 43.32,24.34 45.02,23.46 z" fill="#ccc"></path></svg>
  12 + </button>
  13 + </div>
  14 + </div>
  15 + </div>
  16 + </div>
  17 + </div>
  18 + </div>
  19 + <!-- <div class="js-event-wrapper hide" ng-show="inicio.eventListIsVisible"> -->
  20 + <div class="js-event-wrapper">
  21 + <event-list></event-list>
  22 + </div>
  23 +</section>
  24 +
  25 +<section class="info-section" ng-if="pageInicio.loading || pageInicio.error">
  26 + <div class="container">
  27 + <div class="col-md-12">
  28 + <div ng-if="pageInicio.loading && !pageInicio.error">
  29 + <div class="alert alert-info">Carregando conteúdo...</div>
  30 + </div>
  31 +
  32 + <div ng-if="pageInicio.error">
  33 + <div class="alert alert-danger">{{pageInicio.error}}</div>
  34 + </div>
  35 + </div>
  36 + </div>
  37 +</section>
  38 +
  39 +<section class="section-gray section-space-up" ng-if="pageInicio.article">
  40 + <div class="container">
  41 + <div id="lista-de-programas" class="row">
  42 + <div class="col-sm-4 col-md-3">
  43 + <category-list></category-list>
  44 + </div>
  45 + <div class="col-sm-8 col-md-9">
  46 + <article-grid></article-grid>
  47 + </div>
  48 + </div>
  49 + </div>
  50 +</section>
... ...
src/app/pages/inicio/inicio.scss 0 → 100644
... ... @@ -0,0 +1,89 @@
  1 +.section-gray {
  2 + background-color: $gray;
  3 +
  4 + .contraste & {
  5 + color: #fff;
  6 + background-color: #000;
  7 + }
  8 +}
  9 +
  10 +.section-space-up {
  11 + padding-top: 30px;
  12 +}
  13 +
  14 +.video-wrapper {
  15 + // margin-bottom: 30px;
  16 +}
  17 +
  18 +.video-player {
  19 + position: relative;
  20 + border: 1px solid #333;
  21 +
  22 + .video-background {
  23 + text-align: center;
  24 + cursor: pointer;
  25 + }
  26 +
  27 + .video-thumbnail {
  28 + position: absolute;
  29 + width: 100%;
  30 + height: 100%;
  31 + top: 0;
  32 + left: 0;
  33 + z-index: 10;
  34 + background-position: center;
  35 + background-repeat: no-repeat;
  36 + -moz-transition: opacity .5s cubic-bezier(0.0,0.0,0.2,1);
  37 + -webkit-transition: opacity .5s cubic-bezier(0.0,0.0,0.2,1);
  38 + transition: opacity .5s cubic-bezier(0.0,0.0,0.2,1);
  39 + background-size: cover;
  40 + -moz-background-size: cover;
  41 + -webkit-background-size: cover;
  42 + }
  43 +
  44 + .video-play-button {
  45 + border: none;
  46 + outline: 0;
  47 + color: inherit;
  48 + text-align: inherit;
  49 + font-size: 100%;
  50 + font-family: inherit;
  51 + cursor: pointer;
  52 + line-height: inherit;
  53 + background: transparent;
  54 + padding: 0;
  55 +
  56 + position: absolute;
  57 + top: 50%;
  58 + left: 50%;
  59 + width: 68px;
  60 + height: 48px;
  61 + margin-left: -34px;
  62 + margin-top: -24px;
  63 + z-index: 15;
  64 +
  65 + -moz-transition: opacity .25s cubic-bezier(0.0,0.0,0.2,1);
  66 + -webkit-transition: opacity .25s cubic-bezier(0.0,0.0,0.2,1);
  67 + transition: opacity .25s cubic-bezier(0.0,0.0,0.2,1);
  68 + }
  69 +
  70 + .ytp-play-button-bg {
  71 + -moz-transition: fill .1s cubic-bezier(0.4,0.0,1,1),opacity .1s cubic-bezier(0.4,0.0,1,1);
  72 + -webkit-transition: fill .1s cubic-bezier(0.4,0.0,1,1),opacity .1s cubic-bezier(0.4,0.0,1,1);
  73 + transition: fill .1s cubic-bezier(0.4,0.0,1,1),opacity .1s cubic-bezier(0.4,0.0,1,1);
  74 + fill: #1f1f1f;
  75 + opacity: .9;
  76 + }
  77 +
  78 + &:hover {
  79 + .ytp-play-button-bg {
  80 + fill: #cc181e;
  81 + opacity: 1;
  82 + }
  83 + }
  84 +
  85 + @media screen and (min-width: 992px) {
  86 + width: 80%;
  87 + margin: 0 auto;
  88 + }
  89 +}
... ...
src/app/pages/programas/conheca-o-programa.html 0 → 100644
... ... @@ -0,0 +1,31 @@
  1 +<div class="container page--conheca-o-programa">
  2 + <div ng-if="pageProgramaContent.article && pageProgramaContent.categories">
  3 + <article-bar category="pageProgramaContent.article.categories[0]" categories="pageProgramaContent.categories"></article-bar>
  4 + </div>
  5 +
  6 + <div ng-if="!pageProgramaContent.article.body">
  7 + <div ng-if="!pageProgramaContent.error" class="alert alert-info" role="alert">Carregando detalhes sobre o progama...</div>
  8 + <div ng-if="pageProgramaContent.error" class="alert alert-warning" role="alert">{{pageProgramaContent}}</div>
  9 + </div>
  10 +
  11 + <div ng-if="pageProgramaContent.article.body">
  12 + <article class="program-content">
  13 + <div>
  14 + <section ng-bind-html="pageProgramaContent.article.body"></section>
  15 + </div>
  16 + </article>
  17 + <aside class="program--aside"ng-class="pageProgramaContent.article.categories[0].slug">
  18 + <div class="col-sm-6" >
  19 + <div class="button--themed">
  20 + <button class="btn btn-block" ng-click="pageProgramaContent.goToPreview()">
  21 + <span class="glyphicon glyphicon-arrow-left" aria-hidden="true"></span>
  22 + Participe
  23 + </button>
  24 + </div>
  25 + </div>
  26 + <div class="col-sm-6">
  27 + <social-share></social-share>
  28 + </div>
  29 + </aside>
  30 + </div>
  31 +</div>
... ...
src/app/pages/programas/programa-content.controller.js 0 → 100644
... ... @@ -0,0 +1,81 @@
  1 +(function() {
  2 + 'use strict';
  3 +
  4 + angular
  5 + .module('dialoga')
  6 + .controller('ProgramaContentPageController', ProgramaContentPageController);
  7 +
  8 + /** @ngInject */
  9 + function ProgramaContentPageController(ArticleService, $state, $location, $scope, $rootScope, $log) {
  10 + $log.debug('ProgramaContentPageController');
  11 +
  12 + var vm = this;
  13 +
  14 + vm.ArticleService = ArticleService;
  15 + vm.$state = $state;
  16 + vm.$location = $location;
  17 + vm.$scope = $scope;
  18 + vm.$rootScope = $rootScope;
  19 + vm.$log = $log;
  20 +
  21 + vm.init();
  22 + }
  23 +
  24 + ProgramaContentPageController.prototype.init = function () {
  25 + var vm = this;
  26 +
  27 + var params = vm.$state.params;
  28 + var slug = params.slug;
  29 +
  30 + vm.article = null;
  31 + vm.categories = null;
  32 + vm.currentCategory = null;
  33 + vm.loading = true;
  34 + vm.error = false;
  35 +
  36 + vm.ArticleService.getCategories(function(categories){
  37 + vm.categories = categories;
  38 + }, function (error) {
  39 + vm.error = error;
  40 + vm.$log.error(error);
  41 + });
  42 +
  43 + vm.ArticleService.getArticleBySlug(slug, function(article){
  44 + vm.article = article;
  45 + vm.currentCategory = vm.article.categories[0];
  46 +
  47 + vm.loadContent();
  48 +
  49 + }, function (error) {
  50 + vm.$log.error(error);
  51 + vm.$log.info('Rollback to home page.');
  52 + vm.$state.go('inicio', {}, {location: true});
  53 + });
  54 + };
  55 +
  56 + ProgramaContentPageController.prototype.loadContent = function () {
  57 + var vm = this;
  58 +
  59 + vm.loading = true;
  60 + if(!vm.article.body){
  61 + vm.ArticleService.getContentById(vm.article.id, function (data) {
  62 + vm.article.body = data.article.body;
  63 + vm.loading = false;
  64 + }, function (error) {
  65 + vm.loading = false;
  66 + vm.error = error;
  67 + });
  68 + }
  69 + vm.loading = false;
  70 + };
  71 +
  72 + ProgramaContentPageController.prototype.goToPreview = function () {
  73 + var vm = this;
  74 +
  75 + vm.$state.go('programa', {
  76 + slug: vm.article.slug
  77 + }, {
  78 + location: true
  79 + });
  80 + };
  81 +})();
... ...
src/app/pages/programas/programa.controller.js 0 → 100644
... ... @@ -0,0 +1,68 @@
  1 +(function() {
  2 + 'use strict';
  3 +
  4 + angular
  5 + .module('dialoga')
  6 + .controller('ProgramaPageController', ProgramaPageController);
  7 +
  8 + /** @ngInject */
  9 + function ProgramaPageController(ArticleService, $state, $location, $scope, $rootScope, $log) {
  10 + $log.debug('ProgramaPageController');
  11 +
  12 + var vm = this;
  13 +
  14 + vm.ArticleService = ArticleService;
  15 + vm.$state = $state;
  16 + vm.$location = $location;
  17 + vm.$scope = $scope;
  18 + vm.$rootScope = $rootScope;
  19 + vm.$log = $log;
  20 +
  21 + vm.init();
  22 + }
  23 +
  24 + ProgramaPageController.prototype.init = function () {
  25 + var vm = this;
  26 +
  27 + var params = vm.$state.params;
  28 + var slug = params.slug;
  29 +
  30 + vm.article = null;
  31 + vm.categories = null;
  32 + vm.currentCategory = null;
  33 + vm.loading = true;
  34 + vm.error = false;
  35 +
  36 + vm.ArticleService.getCategories(function(categories){
  37 + vm.categories = categories;
  38 + }, function (error) {
  39 + vm.error = error;
  40 + vm.$log.error(error);
  41 + });
  42 +
  43 + vm.ArticleService.getArticleBySlug(slug, function(article){
  44 + vm.article = article;
  45 + vm.currentCategory = vm.article.categories[0];
  46 +
  47 + // load proposals
  48 + // vm.ArticleService.getRandomProposal(program.id, function(proposal){
  49 + // vm.article.proposal = proposal;
  50 + // }, function (error){
  51 + // vm.$log.error(error);
  52 + // });
  53 +
  54 + // load events
  55 + // vm.ArticleService.getEvents(program.id, function(proposal){
  56 + // vm.article.proposal = proposal;
  57 + // }, function (error){
  58 + // vm.$log.error(error);
  59 + // });
  60 +
  61 + }, function (error) {
  62 + vm.error = error;
  63 + vm.$log.error(error);
  64 + vm.$log.info('Rollback to home page.');
  65 + vm.$state.go('inicio', {}, {location: true});
  66 + });
  67 + };
  68 +})();
... ...
src/app/pages/programas/programa.controller.spec.js 0 → 100644
... ... @@ -0,0 +1,52 @@
  1 +(function() {
  2 + 'use strict';
  3 +
  4 + describe('Controller: ProgramaPageController', function(){
  5 + var $rootScope, $scope, $location, $controller, httpBackend, programaPageController;
  6 + var ENDPOINT_ARTICLE_HOME = 'http://login.dialoga.gov.br/api/v1/articles/103358?fields=id,children,categories,abstract,title,image,url,setting,position&private_token=null';
  7 +
  8 + beforeEach(module('dialoga'));
  9 + beforeEach( inject(function(_$rootScope_, _$controller_, _$location_, $httpBackend) {
  10 + $rootScope = _$rootScope_;
  11 + $controller = _$controller_;
  12 + $location = _$location_;
  13 + $scope = $rootScope.$new();
  14 + httpBackend = $httpBackend;
  15 +
  16 + programaPageController = $controller('ProgramaPageController', {
  17 + '$rootScope': $rootScope,
  18 + '$scope': $scope
  19 + });
  20 +
  21 + httpBackend.whenGET(ENDPOINT_ARTICLE_HOME).respond({
  22 + 'article':{'id':103358,'abstract':'\u003Cp style=\"text-align: center;\"\u003E\u003Ciframe src=\"https://www.youtube.com/embed/kpAdrO-emV0?rel=0\u0026amp;showinfo=0\u0026amp;iv_load_policy=3\u0026amp;controls=1\" style=\"max-width: 1000px; left: 5%;\" width=\"275\" height=\"200\"\u003E\u003C/iframe\u003E\u003C/p\u003E','title':'Dialoga Brasil','categories':[{'name':'Sa\u00fade','id':180,'slug':'saude','image':null},{'name':'Seguran\u00e7a P\u00fablica','id':182,'slug':'seguranca-publica','image':null},{'name':'Educa\u00e7\u00e3o','id':181,'slug':'educacao','image':null},{'name':'Redu\u00e7\u00e3o da Pobreza','id':183,'slug':'reducao-da-pobreza','image':null}],'image':null,'setting':{'custom_body_label':'Corpo','phase':'proposals','allow_topics':true,'moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Leandro Nunes dos Santos','moderate_proposals':true,'allow_members_to_edit':false},'position':null,'children':[{'id':103644,'abstract':'\u003Cp\u003EUm caminho de oportunidades com o Enem: Sisu, Prouni, Fies, Ci\u00eancia sem Fronteiras\u003C/p\u003E','title':'Ensino Superior','categories':[{'name':'Educa\u00e7\u00e3o','id':181,'slug':'educacao','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0128/enem.jpg'},'setting':{'color':'#cfe2f3','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':9},{'id':103673,'abstract':'\u003Cp\u003EA melhor escolha \u00e9 se informar.\u003C/p\u003E','title':'Incentivo ao Parto Normal','categories':[{'name':'Sa\u00fade','id':180,'slug':'saude','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0092/parto-normal.jpg'},'setting':{'color':'#ff0000','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':6},{'id':103397,'abstract':'\u003Cp\u003ERenda, inclus\u00e3o produtiva e acesso a servi\u00e7os.\u003C/p\u003E','title':'Brasil Sem Mis\u00e9ria','categories':[{'name':'Redu\u00e7\u00e3o da Pobreza','id':183,'slug':'reducao-da-pobreza','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0116/bsm_redim.jpg'},'setting':{'color':'','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':18},{'id':103379,'abstract':'\u003Cp\u003EResgate e atendimento 24 horas, sete dias da semana.\u003C/p\u003E','title':'SAMU 192 e UPAs','categories':[{'name':'Sa\u00fade','id':180,'slug':'saude','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0060/SAMU.jpg'},'setting':{'color':'#45818e','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':4},{'id':103521,'abstract':'\u003Cp\u003EMais atendimento nos munic\u00edpios, mais sa\u00fade para quem mais precisa.\u003C/p\u003E','title':'Mais M\u00e9dicos','categories':[{'name':'Sa\u00fade','id':180,'slug':'saude','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0025/Mais_M_dicos.jpg'},'setting':{'color':'#ffe599','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':1},{'id':103390,'abstract':'\u003Cp\u003EPreven\u00e7\u00e3o, tratamento e enfrentamento ao tr\u00e1fico.\u003C/p\u003E','title':'Crack, \u00e9 poss\u00edvel vencer!','categories':[{'name':'Seguran\u00e7a P\u00fablica','id':182,'slug':'seguranca-publica','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0104/crack.jpg'},'setting':{'color':'#00ff00','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':14},{'id':103592,'abstract':'\u003Cp\u003EGarantir acesso \u00e0 prote\u00e7\u00e3o social.\u003C/p\u003E','title':'Assist\u00eancia Social','categories':[{'name':'Redu\u00e7\u00e3o da Pobreza','id':183,'slug':'reducao-da-pobreza','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0122/assistencia_social.jpg'},'setting':{'color':'#a61c00','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':19},{'id':103426,'abstract':'\u003Cp\u003EDa sa\u00fade se cuida todos os dias.\u003C/p\u003E','title':'Vida saud\u00e1vel','categories':[{'name':'Sa\u00fade','id':180,'slug':'saude','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0046/vida_saudavel.jpg'},'setting':{'color':'#d9d2e9','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':7},{'id':103695,'abstract':'\u003Cp\u003ENovo modelo de atua\u00e7\u00e3o em Seguran\u00e7a P\u00fablica.\u003C/p\u003E','title':'Seguran\u00e7a P\u00fablica Integrada','categories':[{'name':'Seguran\u00e7a P\u00fablica','id':182,'slug':'seguranca-publica','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0152/policiaintegrada.jpg'},'setting':{'color':'#ff00ff','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':13},{'id':103663,'abstract':'\u003Cp\u003EMais educa\u00e7\u00e3o profissional e tecnol\u00f3gica, mais desenvolvimento\u003C/p\u003E','title':'Ensino T\u00e9cnico','categories':[{'name':'Educa\u00e7\u00e3o','id':181,'slug':'educacao','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0134/Ensino_tecnico.jpg'},'setting':{'color':'#d0e0e3','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':10},{'id':103472,'abstract':'\u003Cp\u003EPol\u00edcia Federal, Pol\u00edcia Rodovi\u00e1ria Federal e For\u00e7a Nacional de Seguran\u00e7a P\u00fablica.\u003C/p\u003E','title':'For\u00e7as Federais de Seguran\u00e7a','categories':[{'name':'Seguran\u00e7a P\u00fablica','id':182,'slug':'seguranca-publica','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0031/federais2.png'},'setting':{'color':'','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':16},{'id':103612,'abstract':'\u003Cp\u003EGarantir \u00e1gua para beber e produzir.\u003C/p\u003E','title':'Cisternas','categories':[{'name':'Redu\u00e7\u00e3o da Pobreza','id':183,'slug':'reducao-da-pobreza','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0039/cisterna_redim.jpg'},'setting':{'color':'#0000ff','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':20},{'id':103442,'abstract':'\u003Cp\u003EComplemento \u00e0 renda e acompanhamento em educa\u00e7\u00e3o e sa\u00fade.\u003C/p\u003E','title':'Bolsa Fam\u00edlia','categories':[{'name':'Redu\u00e7\u00e3o da Pobreza','id':183,'slug':'reducao-da-pobreza','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0013/bolsa_familia_redim.jpg'},'setting':{'color':'#ff9900','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':17},{'id':103507,'abstract':'\u003Cp\u003ETecnologia a servi\u00e7o da seguran\u00e7a do cidad\u00e3o.\u003C/p\u003E','title':'Sinesp','categories':[{'name':'Seguran\u00e7a P\u00fablica','id':182,'slug':'seguranca-publica','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0098/sinesp.png'},'setting':{'color':'#00ff00','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':12},{'id':103683,'abstract':'\u003Cp\u003ESa\u00fade n\u00e3o tem pre\u00e7o.\u003C/p\u003E','title':'Aqui tem Farm\u00e1cia Popular','categories':[{'name':'Sa\u00fade','id':180,'slug':'saude','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0019/saude_nao_tem_preco.jpg'},'setting':{'color':'#e69138','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':5},{'id':103457,'abstract':'\u003Cp\u003EA\u00e7\u00e3o conjunta e coopera\u00e7\u00e3o transfronteiri\u00e7a.\u003C/p\u003E','title':'Prote\u00e7\u00e3o das Fronteiras','categories':[{'name':'Seguran\u00e7a P\u00fablica','id':182,'slug':'seguranca-publica','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0110/fronteira_redim.jpg'},'setting':{'color':'#a64d79','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':15},{'id':103494,'abstract':'\u003Cp\u003EDa Educa\u00e7\u00e3o Infantil ao Ensino M\u00e9dio.\u003C/p\u003E','title':'Educa\u00e7\u00e3o B\u00e1sica','categories':[{'name':'Educa\u00e7\u00e3o','id':181,'slug':'educacao','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0076/Educa__o_B_sica.jpg'},'setting':{'color':'#fce5cd','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':8},{'id':103359,'abstract':'\u003Cp\u003EAcesso a exames e consultas com especialistas.\u003C/p\u003E','title':'Mais Especialidades','categories':[{'name':'Sa\u00fade','id':180,'slug':'saude','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0083/mais_especialidades1.png'},'setting':{'color':'#ea9999','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':2},{'id':103485,'abstract':'\u003Cp\u003ECaminho para uma educa\u00e7\u00e3o de qualidade.\u003C/p\u003E','title':'Valoriza\u00e7\u00e3o dos Professores','categories':[{'name':'Educa\u00e7\u00e3o','id':181,'slug':'educacao','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0140/valorizacao_professor.jpg'},'setting':{'color':'#ffff00','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':11},{'id':103416,'abstract':'\u003Cp\u003EEstrutura adequada para atender melhor a popula\u00e7\u00e3o na aten\u00e7\u00e3o b\u00e1sica.\u003C/p\u003E','title':'Melhorar os Postos de Sa\u00fade','categories':[{'name':'Sa\u00fade','id':180,'slug':'saude','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0053/requalif_redim.jpg'},'setting':{'color':'#cc4125','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':3}]}
  23 + });
  24 + }));
  25 +
  26 + it('should have a ProgramaPageController controller', function () {
  27 + // console.log('programaPageController', programaPageController);
  28 +
  29 + // expect current path to equal '/programa/:slug'
  30 + $location.path('/programa/bolsa-familia');
  31 + $rootScope.$apply();
  32 + expect($location.path()).toBe('/programa/bolsa-familia');
  33 +
  34 + // expect current scope has a friendly-url to a program
  35 + expect(programaPageController.$state).toBeDefined();
  36 + expect(programaPageController.$state.params).toBeDefined();
  37 + expect(programaPageController.$state.params.slug).toBe('bolsa-familia');
  38 +
  39 + // what to check when user is not logged in here?
  40 + // what to check when user is logged in here?
  41 + });
  42 + it('should be able to go back to "inicio"', function () {});
  43 + it('ensure valid proposal to be sended', function () {});
  44 + it('should be able to send a proposal', function () {});
  45 + it('should be able to vote on proposal', function () {});
  46 + it('should be able to vote on same proposal only once', function () {});
  47 + it('should be able to view a unique proposal by URL', function () {});
  48 + it('should be able to view a table with ranking of all proposals by category', function () {});
  49 + it('should be able to share a proposal on social medias', function () {});
  50 +
  51 + });
  52 +})();
... ...
src/app/pages/programas/programa.html 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +<div class="container">
  2 +
  3 + <div ng-if="pagePrograma.article && pagePrograma.categories">
  4 + <article-bar category="pagePrograma.article.categories[0]" categories="pagePrograma.categories"></article-bar>
  5 + </div>
  6 +
  7 + <div ng-if="!pagePrograma.article">
  8 + <div class="alert alert-info" role="alert">Carregando informações sobre o progama</div>
  9 + </div>
  10 +
  11 + <div ng-if="pagePrograma.article && pagePrograma.categories">
  12 + <article-preview article="pagePrograma.article"></article-preview>
  13 + </div>
  14 +</div>
  15 +
... ...
src/app/pages/programas/programas.scss 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +.program--aside {
  2 + margin-top: 20px;
  3 + padding-top: 20px;
  4 +
  5 + .button--themed {
  6 + padding-top: 0;
  7 + }
  8 +}
  9 +
... ...
src/app/partials/article/article.controller.js
... ... @@ -1,28 +0,0 @@
1   -(function() {
2   - 'use strict';
3   -
4   - angular
5   - .module('dialoga')
6   - .controller('ArticleController', ArticleController);
7   -
8   - /** @ngInject */
9   - function ArticleController($state, $log) {
10   - $log.debug('ArticleController');
11   -
12   - var vm = this;
13   -
14   - vm.page = $state.current.name;
15   -
16   - switch ( $state.current.name ) {
17   - case 'sobre':
18   - break;
19   - case 'termos-de-uso':
20   - break;
21   - default:
22   - $log.debug('$state.current.name', $state.current.name);
23   - break;
24   - }
25   -
26   - // page = $state.is('sobre');
27   - }
28   -})();
src/app/partials/article/article.controller.spec.js
... ... @@ -1,15 +0,0 @@
1   -(function() {
2   - 'use strict';
3   -
4   - describe('controllers', function(){
5   -
6   - beforeEach(module('dialoga'));
7   -
8   - // it('should define more than 5 awesome things', inject(function($controller) {
9   - // var vm = $controller('SobreController');
10   -
11   - // // expect(angular.isArray(vm.awesomeThings)).toBeTruthy();
12   - // // expect(vm.awesomeThings.length > 5).toBeTruthy();
13   - // }));
14   - });
15   -})();
src/app/partials/article/article.html
... ... @@ -1,5 +0,0 @@
1   -<article class="container" role="main">
2   -
3   - Artigo <span>{{article.page}}</span>
4   -
5   -</article>
src/app/partials/article/article.service.js
... ... @@ -1,46 +0,0 @@
1   -(function() {
2   - 'use strict';
3   -
4   - angular
5   - .module('dialoga')
6   - .factory('ArticleService', ArticleService);
7   -
8   - /** @ngInject */
9   - function ArticleService($http, $q, api, UtilService, $log) {
10   - $log.debug('ArticleService');
11   -
12   - var idArticleHome = '103358';
13   - var _savedAbstract = null;
14   -
15   - var service = {
16   - apiArticles: api.host + '/api/v1/articles/',
17   - getHome: getHome,
18   - setHomeAbstract: setHomeAbstract,
19   - getHomeAbstract: getHomeAbstract
20   - };
21   -
22   - return service;
23   -
24   - function getHome () {
25   - return getArticleById(idArticleHome);
26   - }
27   -
28   - function getArticleById (articleId) {
29   - var url = service.apiArticles + articleId;
30   - var params = {
31   - fields: 'id,children,categories,abstract,title,image,url,setting,position',
32   - private_token: 'null'
33   - };
34   -
35   - return UtilService.get(url, {params: params});
36   - }
37   -
38   - function setHomeAbstract (newAbstract) {
39   - _savedAbstract = newAbstract;
40   - }
41   -
42   - function getHomeAbstract () {
43   - return _savedAbstract;
44   - }
45   - }
46   -})();
src/app/partials/article/article.service.spec.js
... ... @@ -1,68 +0,0 @@
1   -(function() {
2   - 'use strict';
3   -
4   - describe('article services', function() {
5   - var ArticleService, httpBackend;
6   -
7   - beforeEach(module('dialoga'));
8   -
9   - beforeEach(inject(function(_ArticleService_, $httpBackend) {
10   - ArticleService = _ArticleService_;
11   - httpBackend = $httpBackend;
12   - }));
13   -
14   - it('should return the main article', function() {
15   - var url = 'http://login.dialoga.gov.br/api/v1/articles/103358?fields=id,children,categories,abstract,title,image,url,setting,position&private_token=null';
16   - httpBackend.whenGET(url).respond({
17   - 'article':{'id':103358,'abstract':'\u003Cp style=\"text-align: center;\"\u003E\u003Ciframe src=\"https://www.youtube.com/embed/kpAdrO-emV0?rel=0\u0026amp;showinfo=0\u0026amp;iv_load_policy=3\u0026amp;controls=1\" style=\"max-width: 1000px; left: 5%;\" width=\"275\" height=\"200\"\u003E\u003C/iframe\u003E\u003C/p\u003E','title':'Dialoga Brasil','categories':[{'name':'Sa\u00fade','id':180,'slug':'saude','image':null},{'name':'Seguran\u00e7a P\u00fablica','id':182,'slug':'seguranca-publica','image':null},{'name':'Educa\u00e7\u00e3o','id':181,'slug':'educacao','image':null},{'name':'Redu\u00e7\u00e3o da Pobreza','id':183,'slug':'reducao-da-pobreza','image':null}],'image':null,'setting':{'custom_body_label':'Corpo','phase':'proposals','allow_topics':true,'moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Leandro Nunes dos Santos','moderate_proposals':true,'allow_members_to_edit':false},'position':null,'children':[{'id':103644,'abstract':'\u003Cp\u003EUm caminho de oportunidades com o Enem: Sisu, Prouni, Fies, Ci\u00eancia sem Fronteiras\u003C/p\u003E','title':'Ensino Superior','categories':[{'name':'Educa\u00e7\u00e3o','id':181,'slug':'educacao','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0128/enem.jpg'},'setting':{'color':'#cfe2f3','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':9},{'id':103673,'abstract':'\u003Cp\u003EA melhor escolha \u00e9 se informar.\u003C/p\u003E','title':'Incentivo ao Parto Normal','categories':[{'name':'Sa\u00fade','id':180,'slug':'saude','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0092/parto-normal.jpg'},'setting':{'color':'#ff0000','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':6},{'id':103397,'abstract':'\u003Cp\u003ERenda, inclus\u00e3o produtiva e acesso a servi\u00e7os.\u003C/p\u003E','title':'Brasil Sem Mis\u00e9ria','categories':[{'name':'Redu\u00e7\u00e3o da Pobreza','id':183,'slug':'reducao-da-pobreza','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0116/bsm_redim.jpg'},'setting':{'color':'','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':18},{'id':103379,'abstract':'\u003Cp\u003EResgate e atendimento 24 horas, sete dias da semana.\u003C/p\u003E','title':'SAMU 192 e UPAs','categories':[{'name':'Sa\u00fade','id':180,'slug':'saude','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0060/SAMU.jpg'},'setting':{'color':'#45818e','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':4},{'id':103521,'abstract':'\u003Cp\u003EMais atendimento nos munic\u00edpios, mais sa\u00fade para quem mais precisa.\u003C/p\u003E','title':'Mais M\u00e9dicos','categories':[{'name':'Sa\u00fade','id':180,'slug':'saude','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0025/Mais_M_dicos.jpg'},'setting':{'color':'#ffe599','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':1},{'id':103390,'abstract':'\u003Cp\u003EPreven\u00e7\u00e3o, tratamento e enfrentamento ao tr\u00e1fico.\u003C/p\u003E','title':'Crack, \u00e9 poss\u00edvel vencer!','categories':[{'name':'Seguran\u00e7a P\u00fablica','id':182,'slug':'seguranca-publica','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0104/crack.jpg'},'setting':{'color':'#00ff00','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':14},{'id':103592,'abstract':'\u003Cp\u003EGarantir acesso \u00e0 prote\u00e7\u00e3o social.\u003C/p\u003E','title':'Assist\u00eancia Social','categories':[{'name':'Redu\u00e7\u00e3o da Pobreza','id':183,'slug':'reducao-da-pobreza','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0122/assistencia_social.jpg'},'setting':{'color':'#a61c00','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':19},{'id':103426,'abstract':'\u003Cp\u003EDa sa\u00fade se cuida todos os dias.\u003C/p\u003E','title':'Vida saud\u00e1vel','categories':[{'name':'Sa\u00fade','id':180,'slug':'saude','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0046/vida_saudavel.jpg'},'setting':{'color':'#d9d2e9','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':7},{'id':103695,'abstract':'\u003Cp\u003ENovo modelo de atua\u00e7\u00e3o em Seguran\u00e7a P\u00fablica.\u003C/p\u003E','title':'Seguran\u00e7a P\u00fablica Integrada','categories':[{'name':'Seguran\u00e7a P\u00fablica','id':182,'slug':'seguranca-publica','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0152/policiaintegrada.jpg'},'setting':{'color':'#ff00ff','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':13},{'id':103663,'abstract':'\u003Cp\u003EMais educa\u00e7\u00e3o profissional e tecnol\u00f3gica, mais desenvolvimento\u003C/p\u003E','title':'Ensino T\u00e9cnico','categories':[{'name':'Educa\u00e7\u00e3o','id':181,'slug':'educacao','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0134/Ensino_tecnico.jpg'},'setting':{'color':'#d0e0e3','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':10},{'id':103472,'abstract':'\u003Cp\u003EPol\u00edcia Federal, Pol\u00edcia Rodovi\u00e1ria Federal e For\u00e7a Nacional de Seguran\u00e7a P\u00fablica.\u003C/p\u003E','title':'For\u00e7as Federais de Seguran\u00e7a','categories':[{'name':'Seguran\u00e7a P\u00fablica','id':182,'slug':'seguranca-publica','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0031/federais2.png'},'setting':{'color':'','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':16},{'id':103612,'abstract':'\u003Cp\u003EGarantir \u00e1gua para beber e produzir.\u003C/p\u003E','title':'Cisternas','categories':[{'name':'Redu\u00e7\u00e3o da Pobreza','id':183,'slug':'reducao-da-pobreza','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0039/cisterna_redim.jpg'},'setting':{'color':'#0000ff','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':20},{'id':103442,'abstract':'\u003Cp\u003EComplemento \u00e0 renda e acompanhamento em educa\u00e7\u00e3o e sa\u00fade.\u003C/p\u003E','title':'Bolsa Fam\u00edlia','categories':[{'name':'Redu\u00e7\u00e3o da Pobreza','id':183,'slug':'reducao-da-pobreza','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0013/bolsa_familia_redim.jpg'},'setting':{'color':'#ff9900','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':17},{'id':103507,'abstract':'\u003Cp\u003ETecnologia a servi\u00e7o da seguran\u00e7a do cidad\u00e3o.\u003C/p\u003E','title':'Sinesp','categories':[{'name':'Seguran\u00e7a P\u00fablica','id':182,'slug':'seguranca-publica','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0098/sinesp.png'},'setting':{'color':'#00ff00','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':12},{'id':103683,'abstract':'\u003Cp\u003ESa\u00fade n\u00e3o tem pre\u00e7o.\u003C/p\u003E','title':'Aqui tem Farm\u00e1cia Popular','categories':[{'name':'Sa\u00fade','id':180,'slug':'saude','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0019/saude_nao_tem_preco.jpg'},'setting':{'color':'#e69138','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':5},{'id':103457,'abstract':'\u003Cp\u003EA\u00e7\u00e3o conjunta e coopera\u00e7\u00e3o transfronteiri\u00e7a.\u003C/p\u003E','title':'Prote\u00e7\u00e3o das Fronteiras','categories':[{'name':'Seguran\u00e7a P\u00fablica','id':182,'slug':'seguranca-publica','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0110/fronteira_redim.jpg'},'setting':{'color':'#a64d79','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':15},{'id':103494,'abstract':'\u003Cp\u003EDa Educa\u00e7\u00e3o Infantil ao Ensino M\u00e9dio.\u003C/p\u003E','title':'Educa\u00e7\u00e3o B\u00e1sica','categories':[{'name':'Educa\u00e7\u00e3o','id':181,'slug':'educacao','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0076/Educa__o_B_sica.jpg'},'setting':{'color':'#fce5cd','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':8},{'id':103359,'abstract':'\u003Cp\u003EAcesso a exames e consultas com especialistas.\u003C/p\u003E','title':'Mais Especialidades','categories':[{'name':'Sa\u00fade','id':180,'slug':'saude','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0083/mais_especialidades1.png'},'setting':{'color':'#ea9999','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':2},{'id':103485,'abstract':'\u003Cp\u003ECaminho para uma educa\u00e7\u00e3o de qualidade.\u003C/p\u003E','title':'Valoriza\u00e7\u00e3o dos Professores','categories':[{'name':'Educa\u00e7\u00e3o','id':181,'slug':'educacao','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0140/valorizacao_professor.jpg'},'setting':{'color':'#ffff00','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':11},{'id':103416,'abstract':'\u003Cp\u003EEstrutura adequada para atender melhor a popula\u00e7\u00e3o na aten\u00e7\u00e3o b\u00e1sica.\u003C/p\u003E','title':'Melhorar os Postos de Sa\u00fade','categories':[{'name':'Sa\u00fade','id':180,'slug':'saude','image':null}],'image':{'url':'/image_uploads/dialoga/0000/0053/requalif_redim.jpg'},'setting':{'color':'#cc4125','moderate_comments':false,'comment_paragraph_plugin_activate':false,'author_name':'Ronald Emerson Scherolt da Costa','allow_members_to_edit':false},'position':3}]}});
18   -
19   - ArticleService.getHome().then(function(result) {
20   -
21   - expect(result.article).toBeDefined();
22   - expect(result.article.title).toEqual('Dialoga Brasil');
23   -
24   - });
25   -
26   - httpBackend.flush();
27   - });
28   -
29   - // it('should return a list of articles', function() {
30   -
31   - // httpBackend.whenGET('http://login.dialoga.gov.br/api/v1/articles').respond({
32   - // "articles": [
33   - // {
34   - // abstract: "Que exista educação continuada permanente dos profissionais!!",
35   - // author: null,
36   - // body: "",
37   - // categories: [],
38   - // children: [],
39   - // created_at: "2015/08/04 16:36:13",
40   - // end_date: null,
41   - // hits: 0,
42   - // id: 120568,
43   - // image: null,
44   - // parent: {id: 103379,…},
45   - // position: null,
46   - // profile: {identifier: "dialoga", name: "dialoga", id: 19195, created_at: "2015/04/15 09:38:36", image: null},
47   - // setting: {comment_paragraph_plugin_activate: false, author_name: "estacio"},
48   - // start_date: null,
49   - // tag_list: [],
50   - // title: "article_f4f4601c-0f36-e90e-d01a-9871f0bd126b",
51   - // votes_against: 0,
52   - // votes_for: 0,
53   - // }
54   - // ]
55   - // });
56   -
57   - // ArticleService.getList().then(function(result) {
58   - // console.log('result', result);
59   -
60   - // expect(result.data.article).toBeDefined();
61   - // expect(result.data.article.title).toEqual('Dialoga Brasil');
62   -
63   - // });
64   -
65   - // httpBackend.flush();
66   - // });
67   - });
68   -})();
src/app/partials/auth/auth.controller.js
... ... @@ -1,44 +0,0 @@
1   -(function() {
2   - 'use strict';
3   -
4   - angular
5   - .module('dialoga')
6   - .controller('AuthController', AuthController);
7   -
8   - /** @ngInject */
9   - function AuthController($rootScope, AUTH_EVENTS, AuthService, Session, $log) {
10   - $log.debug('AuthController');
11   -
12   - var vm = this;
13   -
14   - vm.$rootScope = $rootScope;
15   - vm.AUTH_EVENTS = AUTH_EVENTS;
16   - vm.AuthService = AuthService;
17   - vm.Session = Session;
18   - vm.$log = $log;
19   -
20   - vm.init();
21   - }
22   -
23   - AuthController.prototype.init = function() {
24   - var vm = this;
25   -
26   - // init variables
27   - vm.credentials = {};
28   -
29   - // attach events
30   -
31   - // ...
32   - };
33   -
34   - AuthController.prototype.login = function(credentials) {
35   - var vm = this;
36   -
37   - vm.AuthService.login(credentials).then(function(user) {
38   - // handle view
39   - }, function() {
40   - // handle view
41   - });
42   - };
43   -
44   -})();
src/app/partials/auth/auth.scss
... ... @@ -1,44 +0,0 @@
1   -.btn-social {
2   - color: #fff;
3   - font-weight: bold;
4   -
5   - &:hover,
6   - &:focus {color: #fff;}
7   -
8   - &.btn-facebook {
9   - background-color: #33477a;
10   - &:hover,
11   - &:focus {background-color: #304373; }
12   - &:active {background-color: #33477a; }
13   - }
14   - &.btn-google-plus {
15   - background-color: #b92d25;
16   - &:hover,
17   - &:focus {background-color: #b12b23; }
18   - &:active {background-color: #b92d25; }
19   - }
20   -}
21   -
22   -.glyphicon {
23   - &.icon-white {
24   - fill: white;
25   - }
26   -}
27   -
28   -.separator-or {
29   - border-top: 2px solid #d8d8d8;
30   - text-align: center;
31   - font-weight: bold;
32   -
33   - &:after {
34   - content: "ou";
35   - position: absolute;
36   - top: 4px;
37   - left: 50%;
38   - margin-left: -26px;
39   - font-size: 30px;
40   - line-height: 30px;
41   - padding: 0 0.25em;
42   - background: $gray;
43   - }
44   -}
src/app/partials/auth/signin.html
... ... @@ -1,38 +0,0 @@
1   -<section role="main" class="section-gray">
2   - <div class="container">
3   - <div class="row">
4   - <div class="col-sm-8 col-sm-offset-2">
5   - <h2>Identifique-se</h2>
6   - <form name="loginForm" ng-submit="login.login(login.credentials)">
7   - <div class="form-group">
8   - <label for="inputUsername" class="sr-only">E-mail:</label>
9   - <div class="input-group">
10   - <div class="input-group-addon"><span class="glyphicon glyphicon-user"></span></div>
11   - <input type="text" id="inputUsername" class="form-control" placeholder="E-mail" required="" autofocus="" ng-model="login.credentials.username">
12   - </div>
13   - </div>
14   - <div class="form-group">
15   - <label for="inputPassword" class="sr-only">Senha:</label>
16   - <div class="input-group">
17   - <div class="input-group-addon"><span class="glyphicon glyphicon-lock"></span></div>
18   - <input type="password" id="inputPassword" class="form-control" placeholder="Senha" required="" ng-model="login.credentials.password">
19   - </div>
20   - </div>
21   - <div class="form-group">
22   - <button class="btn btn-lg btn-primary btn-block" type="submit">Entrar</button>
23   - </div>
24   - </form>
25   - </div>
26   - </div>
27   - <div class="row">
28   - <div class="col-sm-8 col-sm-offset-2">
29   - <hr class="separator-or"></hr>
30   - </div>
31   - </div>
32   - <div class="row">
33   - <div class="col-sm-8 col-sm-offset-2">
34   - <button class="btn btn-lg btn-link btn-block" type="button" ui-sref="cadastrar">Cadastre-se</button>
35   - </div>
36   - </div>
37   - </div>
38   -</section>
src/app/partials/auth/signup.html
... ... @@ -1,54 +0,0 @@
1   -<section>
2   - <div class="container">
3   - <div class="row">
4   - <div class="col-sm-12">
5   - <h1>Cadastro</h1>
6   - <p>Cadastre-se para fazer parte do Dialoga Brasil, interagir com as propostas e enviar as suas!</p>
7   - </div>
8   - </div>
9   - </div>
10   -</section>
11   -<section role="main" class="section-gray">
12   - <div class="container">
13   - <div class="row">
14   - <div class="col-sm-8 col-sm-offset-2">
15   - <h2>Conecte-se por redes sociais</h2>
16   - <div class="col-sm-6">
17   - <button type="button" class="btn btn-lg btn-block btn-social btn-facebook">
18   - <span class="glyphicon icon-facebook icon-white" aria-hidden="true">
19   - <!-- Facebook -->
20   - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33 33" width="25" height="25"><path d="M18 32L12 32 12 16l-4 0 0-5.5 4 0 0-3.2C12 2.7 13.2 0 18.5 0l4.4 0 0 5.5 -2.8 0c-2.1 0-2.2 0.8-2.2 2.2l0 2.8 5 0 -0.6 5.5L18 16 18 32z"/></svg>
21   -
22   - <!-- Twitter -->
23   - <!-- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33 33" width="25" height="25"><path d="M32 6.1c-1.2 0.5-2.4 0.9-3.8 1 1.4-0.8 2.4-2.1 2.9-3.6 -1.3 0.8-2.7 1.3-4.2 1.6 -1.2-1.3-2.9-2.1-4.8-2.1 -3.6 0-6.6 2.9-6.6 6.6 0 0.5 0.1 1 0.2 1.5 -5.5-0.3-10.3-2.9-13.5-6.9 -0.6 1-0.9 2.1-0.9 3.3 0 2.3 1.2 4.3 2.9 5.5 -1.1 0-2.1-0.3-3-0.8 0 0 0 0.1 0 0.1 0 3.2 2.3 5.8 5.3 6.4 -0.6 0.2-1.1 0.2-1.7 0.2 -0.4 0-0.8 0-1.2-0.1 0.8 2.6 3.3 4.5 6.1 4.6 -2.2 1.8-5.1 2.8-8.2 2.8 -0.5 0-1.1 0-1.6-0.1 2.9 1.9 6.4 3 10.1 3 12.1 0 18.7-10 18.7-18.7 0-0.3 0-0.6 0-0.8C30 8.5 31.1 7.4 32 6.1z"/></svg> -->
24   - </span>
25   - <span class="text">
26   - Conectar pelo Facebook
27   - </span>
28   - </button>
29   - </div>
30   - <div class="col-sm-6">
31   - <button type="button" class="btn btn-lg btn-block btn-social btn-google-plus">
32   - <span class="glyphicon icon-google-plus icon-white" aria-hidden="true">
33   - <!-- Google + -->
34   - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33 33" width="25" height="25"><path d="M17.5 2c0 0-6.3 0-8.4 0C5.3 2 1.8 4.8 1.8 8.1c0 3.4 2.6 6.1 6.4 6.1 0.3 0 0.5 0 0.8 0 -0.2 0.5-0.4 1-0.4 1.6 0 0.9 0.5 1.7 1.1 2.3 -0.5 0-0.9 0-1.5 0C3.6 18.1 0 21.1 0 24.1c0 3 3.9 4.9 8.6 4.9 5.3 0 8.2-3 8.2-6 0-2.4-0.7-3.9-2.9-5.4 -0.8-0.5-2.2-1.8-2.2-2.6 0-0.9 0.3-1.3 1.6-2.4 1.4-1.1 2.4-2.6 2.4-4.4 0-2.1-0.9-4.2-2.7-4.8l2.7 0L17.5 2zM14.5 22.5c0.1 0.3 0.1 0.6 0.1 0.9 0 2.4-1.6 4.4-6.1 4.4 -3.2 0-5.5-2-5.5-4.5 0-2.4 2.9-4.4 6.1-4.4 0.8 0 1.4 0.1 2.1 0.3C12.9 20.4 14.2 21.1 14.5 22.5zM9.4 13.4c-2.2-0.1-4.2-2.4-4.6-5.2 -0.4-2.8 1.1-5 3.2-4.9 2.2 0.1 4.2 2.3 4.6 5.2C13 11.2 11.6 13.4 9.4 13.4zM26 8L26 2 24 2 24 8 18 8 18 10 24 10 24 16 26 16 26 10 32 10 32 8z"/></svg>
35   - </span>
36   - <span class="text">
37   - Conectar pelo Google+
38   - </span>
39   - </button>
40   - </div>
41   - </div>
42   - </div>
43   - <div class="row">
44   - <div class="col-sm-8 col-sm-offset-2">
45   - <hr class="separator-or"></hr>
46   - </div>
47   - </div>
48   - <div class="row">
49   - <div class="col-sm-8 col-sm-offset-2">
50   - <h2>Faça o cadastro abaixo</h2>
51   - </div>
52   - </div>
53   - </div>
54   -</section>
src/app/partials/footer/footer.html
... ... @@ -1,8 +0,0 @@
1   -<div id="footer" class="container">
2   - <div class="row">
3   - <div class="col-xs-12 text-center">
4   - <a id="termos-de-uso" ui-sref="termos-de-uso">Termos de uso</a>
5   - </div>
6   - </div>
7   -</div>
8   -<div id="footer-brasil"></div>
src/app/partials/footer/footer.scss
... ... @@ -1,11 +0,0 @@
1   -$barra-theme: ("green": #00420c, "yellow": #2c66ce, "blue": #0042b1);
2   -
3   -#footer-brasil {
4   - background: none repeat scroll 0% 0% map-get($barra-theme, "blue");
5   - padding: 1em 0px;
6   - max-width: 100%;
7   -}
8   -
9   -#footer {
10   - margin: 10px auto;
11   -}
src/app/partials/header/header.controller.js
... ... @@ -1,16 +0,0 @@
1   -(function() {
2   - 'use strict';
3   -
4   - angular
5   - .module('dialoga')
6   - .controller('HeaderController', HeaderController);
7   -
8   - /** @ngInject */
9   - function HeaderController($log) {
10   - var vm = this;
11   -
12   - vm.$log = $log;
13   - vm.$log.debug('HeaderController');
14   - }
15   -
16   -})();
src/app/partials/header/header.html
... ... @@ -1,19 +0,0 @@
1   -<header class="container" ng-controller="HeaderController as header">
2   -
3   - <div class="row">
4   - <div class="accessibility-wrapper">
5   - <button type="button" id="display-contrast" class="btn btn-link" ng-click="toggleContrast()">
6   - <span class="glyphicon glyphicon-adjust" aria-hidden="true"></span> Alto Contraste
7   - </button>
8   -
9   - <button type="button" class="btn btn-link pull-right" ui-sref="entrar">
10   - <span class="glyphicon glyphicon-user"></span>
11   - Entrar
12   - </button>
13   - </div>
14   - </div>
15   -
16   - <div class="row">
17   - <app-navbar></app-navbar>
18   - </div>
19   -</header>