diff --git a/Gemfile b/Gemfile
index eea36d384..c0d4b144e 100644
--- a/Gemfile
+++ b/Gemfile
@@ -109,8 +109,8 @@ group :test do
end
group :development, :test do
- gem 'terminal-notifier'
- gem 'terminal-notifier-guard'
+ # gem 'terminal-notifier'
+ # gem 'terminal-notifier-guard'
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug'
diff --git a/Gemfile.lock b/Gemfile.lock
index f51bed510..325952d07 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -561,8 +561,6 @@ GEM
i18n
json (>= 1.4.3)
temple (0.7.6)
- terminal-notifier (1.6.3)
- terminal-notifier-guard (1.6.4)
terminal-table (1.5.2)
therubyracer (0.12.2)
libv8 (~> 3.16.14.0)
@@ -683,8 +681,6 @@ DEPENDENCIES
smart_listing
spring
spring-commands-rspec
- terminal-notifier
- terminal-notifier-guard
therubyracer
timecop
turbolinks
diff --git a/app/assets/images/keywords/faciliter.png b/app/assets/images/keywords/faciliter.png
index 35d0da530..020ba4339 100644
Binary files a/app/assets/images/keywords/faciliter.png and b/app/assets/images/keywords/faciliter.png differ
diff --git a/app/assets/images/keywords/profiter.png b/app/assets/images/keywords/profiter.png
index 682ea1723..0e1f016ba 100644
Binary files a/app/assets/images/keywords/profiter.png and b/app/assets/images/keywords/profiter.png differ
diff --git a/app/assets/images/landing_background.jpg b/app/assets/images/landing_background.jpg
index 3f25fb159..f7ddc8c98 100644
Binary files a/app/assets/images/landing_background.jpg and b/app/assets/images/landing_background.jpg differ
diff --git a/app/assets/javascripts/admin.js b/app/assets/javascripts/admin.js
index 6b66994cc..8cf2e6467 100644
--- a/app/assets/javascripts/admin.js
+++ b/app/assets/javascripts/admin.js
@@ -1,5 +1,10 @@
-$(document).on('page:load', destroy_action);
-$(document).ready(destroy_action);
+$(document).on('page:load', init_admin);
+$(document).ready(init_admin);
+
+function init_admin(){
+ destroy_action();
+ on_change_type_de_champ_select();
+}
function destroy_action(){
$(".delete").on('click', function(){
@@ -15,4 +20,19 @@ function destroy_action(){
$("#liste_gestionnaire #libelle").on('click', function(){
setTimeout(destroy_action, 500);
});
+}
+
+function on_change_type_de_champ_select (){
+
+ $("select.form-control.type_champ").on('change', function(e){
+
+ parent = $(this).parent().parent()
+
+ if (this.value === 'header_section') {
+ parent.addClass('header_section')
+ }
+ else {
+ parent.removeClass('header_section')
+ }
+ })
}
\ No newline at end of file
diff --git a/app/assets/javascripts/admin_procedures_modal.js b/app/assets/javascripts/admin_procedures_modal.js
new file mode 100644
index 000000000..38112328c
--- /dev/null
+++ b/app/assets/javascripts/admin_procedures_modal.js
@@ -0,0 +1,98 @@
+$(document).on('page:load', init_path_modal);
+$(document).ready(init_path_modal);
+
+function init_path_modal() {
+ path_modal_action();
+ path_validation_action();
+ path_type_init();
+ path_validation($("input[id='procedure_path']"));
+}
+
+function path_modal_action() {
+ $('#publishModal').on('show.bs.modal', function (event) {
+ $("#publishModal .modal-body .table .tr_content").hide();
+
+ var button = $(event.relatedTarget) // Button that triggered the modal
+ var modal_title = button.data('modal_title'); // Extract info from data-* attributes
+ var modal_index = button.data('modal_index'); // Extract info from data-* attributes
+
+ var modal = $(this)
+ modal.find('#publishModal_title').html(modal_title);
+ $("#publishModal .modal-body .table #"+modal_index).show();
+ })
+}
+
+function path_validation_action() {
+ $("input[id='procedure_path']").keyup(function (key) {
+ if (key.keyCode != 13)
+ path_validation(this);
+ });
+}
+
+function togglePathMessage(valid, mine) {
+ $('#path_messages .message').hide();
+
+ if (valid === true && mine === true) {
+ $('#path_is_mine').show();
+ } else if (valid === true && mine === false) {
+ $('#path_is_not_mine').show();
+ } else if (valid === false && mine === null) {
+ $('#path_is_invalid').show();
+ }
+
+ if ((valid && mine === null) || mine === true)
+ $('#publishModal #publish').removeAttr('disabled')
+ else
+ $('#publishModal #publish').attr('disabled', 'disabled')
+}
+
+function path_validation(el) {
+ var valid = validatePath($(el).val());
+ toggleErrorClass(el, valid);
+ togglePathMessage(valid, null);
+}
+
+function validatePath(path) {
+ var re = /^[a-z0-9_]{3,30}$/;
+ return re.test(path);
+}
+
+function path_type_init() {
+ display = 'label';
+
+ var bloodhound = new Bloodhound({
+ datumTokenizer: Bloodhound.tokenizers.obj.whitespace(display),
+ queryTokenizer: Bloodhound.tokenizers.whitespace,
+
+ remote: {
+ url: '/admin/procedures/path_list?request=%QUERY',
+ wildcard: '%QUERY'
+ }
+ });
+ bloodhound.initialize();
+
+ $("#procedure_path").typeahead({
+ minLength: 1
+ }, {
+ display: display,
+ source: bloodhound,
+ templates: {
+ empty: 'Ce lien est disponible !',
+ suggestion: Handlebars.compile("
{{label}}
")
+ },
+ limit: 5
+ });
+
+ $('#procedure_path').bind('typeahead:select', function(ev, suggestion) {
+ togglePathMessage(true, suggestion['mine']);
+ });
+}
+
+function transfer_errors_message(show) {
+ if(show){
+ $("#not_found_admin").slideDown(100)
+ }
+ else {
+ $("#not_found_admin").slideUp(100)
+ }
+}
\ No newline at end of file
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index fa22bb903..288d060c0 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -29,6 +29,7 @@
//= require franceconnect
//= require bootstrap-wysihtml5
//= require bootstrap-wysihtml5/locales/fr-FR
+//= require handlebars
//= require typeahead.bundle
$(document).on('page:load', scroll_to);
diff --git a/app/assets/javascripts/carte/carte.js b/app/assets/javascripts/carte/carte.js
index 1e9ba0514..b7ec0ea4b 100644
--- a/app/assets/javascripts/carte/carte.js
+++ b/app/assets/javascripts/carte/carte.js
@@ -156,7 +156,7 @@ function add_event_search_address() {
});
$("#search_by_address input[type='address']").keypress(function (e) {
- if (e.which == 13)
+ if (e.keyCode == 13)
get_address_point($(this).val());
});
}
\ No newline at end of file
diff --git a/app/assets/javascripts/dossiers.js b/app/assets/javascripts/dossiers.js
index 86764fb01..0307b5a63 100644
--- a/app/assets/javascripts/dossiers.js
+++ b/app/assets/javascripts/dossiers.js
@@ -31,4 +31,9 @@ function error_form_siret(invalid_siret){
function reset_form_siret(){
$("input[type='submit']").removeClass('btn-danger').addClass('btn-success').val('Valider');
$("#dossier_siret").removeClass('input-error');
+}
+
+function toggle_etape_1(){
+ $('.row.etape.etape_1 .etapes_menu #logos').toggle(100);
+ $('.row.etape.etape_1 .etapes_informations #description_procedure').toggle(100);
}
\ No newline at end of file
diff --git a/app/assets/stylesheets/admin_procedures_modal.scss b/app/assets/stylesheets/admin_procedures_modal.scss
new file mode 100644
index 000000000..320752d3c
--- /dev/null
+++ b/app/assets/stylesheets/admin_procedures_modal.scss
@@ -0,0 +1,18 @@
+.path_mine_false {
+ color: red
+}
+
+#path_messages {
+ .message {
+ display: none
+ }
+}
+
+#publishModal {
+ .twitter-typeahead {
+ width: 300px;
+ }
+ .tt-menu {
+ width: 300px;
+ }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/admin_type_de_champ.scss b/app/assets/stylesheets/admin_type_de_champ.scss
new file mode 100644
index 000000000..d8b9d1a7b
--- /dev/null
+++ b/app/assets/stylesheets/admin_type_de_champ.scss
@@ -0,0 +1,18 @@
+.header_section{
+ background-color: rgb(245,245,245);
+ margin-top: 20px;
+ margin-bottom: 10px;
+ margin-left: 0;
+ margin-right: 0;
+ text-align:center;
+ padding-bottom: 8px;
+
+ .form-group.description {
+ display: none;
+ }
+
+ .form-group.mandatory {
+ display: none;
+ }
+
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index 92fa141f8..dedae8dcd 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -164,10 +164,6 @@ textarea#description {
width: 100%;
}
-input#nom_projet {
- width: 100%;
-}
-
.logo_fc_small {
max-width: 27px;
}
diff --git a/app/assets/stylesheets/carte.scss b/app/assets/stylesheets/carte.scss
index 274d502ea..f1d7d4dbb 100644
--- a/app/assets/stylesheets/carte.scss
+++ b/app/assets/stylesheets/carte.scss
@@ -132,4 +132,13 @@ table {
.info h4 {
margin: 0 0 5px;
color: #777;
-}
\ No newline at end of file
+}
+
+#search_by_address {
+ .twitter-typeahead {
+ width: 555px;
+ }
+ .tt-menu {
+ width: 555px;
+ }
+}
diff --git a/app/assets/stylesheets/description.scss b/app/assets/stylesheets/description.scss
index 6bef57d7f..6c0845c46 100644
--- a/app/assets/stylesheets/description.scss
+++ b/app/assets/stylesheets/description.scss
@@ -7,6 +7,10 @@
}
}
+.page-header{
+ border-bottom: 1px solid #CCCCCC !important;
+}
+
.input-error {
color: darkred !important;
border-color: darkred !important
@@ -21,11 +25,25 @@
}
}
+.type_champ-header_section {
+ @extend .col-md-12;
+ @extend .col-lg-12;
+
+ margin-bottom: -25px;
+}
+
.type_champ-address {
@extend .col-md-6;
@extend .col-lg-6;
- input[type='address'] {
+ .twitter-typeahead {
+ width: 100%;
+ input {
+ width: 100%;
+ display: block !important;
+ }
+ }
+ .tt-menu {
width: 100%;
}
}
@@ -44,6 +62,11 @@
@extend .col-lg-3;
}
+.type_champ-yes_no {
+ @extend .col-md-3;
+ @extend .col-lg-3;
+}
+
.type_champ-phone {
@extend .col-md-2;
@extend .col-lg-2;
diff --git a/app/assets/stylesheets/typeahead.scss b/app/assets/stylesheets/typeahead.scss
index e29aff51f..8cda8e19b 100644
--- a/app/assets/stylesheets/typeahead.scss
+++ b/app/assets/stylesheets/typeahead.scss
@@ -1,5 +1,5 @@
+
.tt-menu {
- width: 555px;
padding: 8px 0;
background-color: #fff;
border: 1px solid #ccc;
@@ -18,10 +18,6 @@
line-height: 24px;
}
-.twitter-typeahead {
- width: 555px;
-}
-
.tt-suggestion:hover {
cursor: pointer;
color: #fff;
diff --git a/app/controllers/admin/procedures_controller.rb b/app/controllers/admin/procedures_controller.rb
index 2698c8dca..1f6539c6d 100644
--- a/app/controllers/admin/procedures_controller.rb
+++ b/app/controllers/admin/procedures_controller.rb
@@ -7,9 +7,9 @@ class Admin::ProceduresController < AdminController
def index
@procedures = smart_listing_create :procedures,
- current_administrateur.procedures.where(published: true, archived: false).order(created_at: :desc),
- partial: "admin/procedures/list",
- array: true
+ current_administrateur.procedures.where(published: true, archived: false).order(created_at: :desc),
+ partial: "admin/procedures/list",
+ array: true
active_class
end
@@ -36,7 +36,6 @@ class Admin::ProceduresController < AdminController
render 'index'
end
-
def show
@facade = AdminProceduresShowFacades.new @procedure.decorate
end
@@ -87,22 +86,78 @@ class Admin::ProceduresController < AdminController
end
def publish
- change_status({published: true})
+ procedure = current_administrateur.procedures.find(params[:procedure_id])
+
+ new_procedure_path = ProcedurePath.new(
+ {
+ path: params[:procedure_path],
+ procedure: procedure,
+ administrateur: procedure.administrateur
+ })
+ if new_procedure_path.validate
+ new_procedure_path.delete
+ else
+ flash.alert = 'Lien de la procédure invalide'
+ return redirect_to admin_procedures_path
+ end
+
+ procedure_path = ProcedurePath.find_by_path(params[:procedure_path])
+ if procedure_path
+ if procedure_path.administrateur_id == current_administrateur.id
+ procedure_path.procedure.archive
+ else
+ @mine = false
+ return render '/admin/procedures/publish', formats: 'js'
+ end
+ end
+
+ procedure.publish!(params[:procedure_path])
+
+ flash.notice = "Procédure publiée"
+ render js: "window.location = '#{admin_procedures_path}'"
+
+ rescue ActiveRecord::RecordNotFound
+ flash.alert = 'Procédure inéxistante'
+ redirect_to admin_procedures_path
+ end
+
+ def transfer
+ admin = Administrateur.find_by_email(params[:email_admin])
+
+ return render '/admin/procedures/transfer', formats: 'js', status: 404 if admin.nil?
+
+ procedure = current_administrateur.procedures.find(params[:procedure_id])
+ clone_procedure = procedure.clone
+
+ clone_procedure.administrateur = admin
+ clone_procedure.save
+
+ flash.now.notice = "La procédure a correctement été cloné vers le nouvel administrateur."
+
+ render '/admin/procedures/transfer', formats: 'js', status: 200
end
def archive
- change_status({archived: params[:archive]})
+ procedure = current_administrateur.procedures.find(params[:procedure_id])
+ procedure.archive
+
+ flash.notice = "Procédure archivée"
+ redirect_to admin_procedures_path
+
+ rescue ActiveRecord::RecordNotFound
+ flash.alert = 'Procédure inéxistante'
+ redirect_to admin_procedures_path
end
def clone
- @procedure = current_administrateur.procedures.find(params[:procedure_id])
+ procedure = current_administrateur.procedures.find(params[:procedure_id])
- new_procedure = @procedure.clone
+ new_procedure = procedure.clone
if new_procedure
flash.notice = 'Procédure clonée'
redirect_to edit_admin_procedure_path(id: new_procedure.id)
else
- flash.now.alert = @procedure.errors.full_messages.join('
').html_safe
+ flash.now.alert = procedure.errors.full_messages.join('
').html_safe
render 'index'
end
@@ -123,6 +178,12 @@ class Admin::ProceduresController < AdminController
@draft_class = 'active'
end
+ def path_list
+ render json: ProcedurePath.where("path LIKE '%#{params[:request]}%'").pluck(:path, :administrateur_id).inject([]) {
+ |acc, value| acc.push({label: value.first, mine: value.second == current_administrateur.id})
+ }.to_json
+ end
+
private
def create_procedure_params
@@ -132,16 +193,4 @@ class Admin::ProceduresController < AdminController
def create_module_api_carto_params
params.require(:procedure).require(:module_api_carto_attributes).permit(:id, :use_api_carto, :quartiers_prioritaires, :cadastre)
end
-
- def change_status(status_options)
- @procedure = current_administrateur.procedures.find(params[:procedure_id])
- @procedure.update_attributes(status_options)
-
- flash.notice = 'Procédure éditée'
- redirect_to admin_procedures_path
-
- rescue ActiveRecord::RecordNotFound
- flash.alert = 'Procédure inéxistante'
- redirect_to admin_procedures_path
- end
end
diff --git a/app/controllers/backoffice/dossiers_controller.rb b/app/controllers/backoffice/dossiers_controller.rb
index 6f3e8b453..edf67db28 100644
--- a/app/controllers/backoffice/dossiers_controller.rb
+++ b/app/controllers/backoffice/dossiers_controller.rb
@@ -54,12 +54,20 @@ class Backoffice::DossiersController < ApplicationController
render 'show'
end
+ def follow
+ follow = current_gestionnaire.toggle_follow_dossier params[:dossier_id]
+
+ flash.notice = (follow.class == Follow ? 'Dossier suivi' : 'Dossier relaché')
+ redirect_to request.referer
+ end
+
private
def dossiers_to_display
{'a_traiter' => waiting_for_gestionnaire,
'en_attente' => waiting_for_user,
- 'termine' => termine}[@liste]
+ 'termine' => termine,
+ 'suivi' => suivi}[@liste]
end
def waiting_for_gestionnaire
@@ -77,10 +85,16 @@ class Backoffice::DossiersController < ApplicationController
@termine ||= current_gestionnaire.dossiers_filter.termine
end
+ def suivi
+ @suivi_class = (@liste == 'suivi' ? 'active' : '')
+ @suivi ||= current_gestionnaire.dossiers_follow
+ end
+
def total_dossiers_per_state
@dossiers_a_traiter_total = waiting_for_gestionnaire.count
@dossiers_en_attente_total = waiting_for_user.count
@dossiers_termine_total = termine.count
+ @dossiers_suivi_total = suivi.count
end
def create_dossier_facade dossier_id
diff --git a/app/controllers/commentaires_controller.rb b/app/controllers/commentaires_controller.rb
index 4a0b75662..bea003766 100644
--- a/app/controllers/commentaires_controller.rb
+++ b/app/controllers/commentaires_controller.rb
@@ -26,6 +26,10 @@ class CommentairesController < ApplicationController
saved = @commentaire.save unless flash.alert
if is_gestionnaire?
+ unless current_gestionnaire.follow? @commentaire.dossier
+ current_gestionnaire.toggle_follow_dossier @commentaire.dossier
+ end
+
NotificationMailer.new_answer(@commentaire.dossier).deliver_now! if saved
redirect_to url_for(controller: 'backoffice/dossiers', action: :show, id: params['dossier_id'])
elsif current_user.email != @commentaire.dossier.user.email
diff --git a/app/controllers/users/description_controller.rb b/app/controllers/users/description_controller.rb
index dfe9672d3..b3956eaa6 100644
--- a/app/controllers/users/description_controller.rb
+++ b/app/controllers/users/description_controller.rb
@@ -102,6 +102,6 @@ class Users::DescriptionController < UsersController
private
def create_params
- params.permit(:nom_projet)
+ params.permit()
end
end
diff --git a/app/controllers/users/dossiers_controller.rb b/app/controllers/users/dossiers_controller.rb
index 50a5d9c9d..c96ed1cfb 100644
--- a/app/controllers/users/dossiers_controller.rb
+++ b/app/controllers/users/dossiers_controller.rb
@@ -2,7 +2,7 @@ class Users::DossiersController < UsersController
include SmartListing::Helper::ControllerExtensions
helper SmartListing::Helper
- before_action :authenticate_user!
+ before_action :authenticate_user!, except: :commencer
before_action :check_siret, only: :siret_informations
before_action only: [:show] do
@@ -22,6 +22,16 @@ class Users::DossiersController < UsersController
total_dossiers_per_state
end
+ def commencer
+ unless params[:procedure_path].nil?
+ procedure = ProcedurePath.where(path: params[:procedure_path]).first!.procedure
+ end
+
+ redirect_to new_users_dossier_path(procedure_id: procedure.id)
+ rescue ActiveRecord::RecordNotFound
+ error_procedure
+ end
+
def new
procedure = Procedure.where(archived: false, published: true).find(params[:procedure_id])
@@ -49,12 +59,16 @@ class Users::DossiersController < UsersController
update_current_user_siret! siret
- DossierService.new(@facade.dossier, siret, current_user.france_connect_information).dossier_informations!
+ dossier = DossierService.new(@facade.dossier, siret, current_user.france_connect_information).dossier_informations!
+
+ if dossier.entreprise.nil? || dossier.etablissement.nil?
+ return errors_valid_siret
+ end
@facade = facade params[:dossier_id]
render '/dossiers/new_siret', formats: 'js'
- rescue RestClient::ResourceNotFound
+ rescue RestClient::ResourceNotFound, RestClient::BadRequest
errors_valid_siret
rescue ActiveRecord::RecordNotFound
@@ -169,4 +183,5 @@ class Users::DossiersController < UsersController
def facade id = params[:id]
DossierFacades.new id, current_user.email
end
+
end
diff --git a/app/decorators/procedure_decorator.rb b/app/decorators/procedure_decorator.rb
index b0b38bea2..df848570d 100644
--- a/app/decorators/procedure_decorator.rb
+++ b/app/decorators/procedure_decorator.rb
@@ -2,7 +2,7 @@ class ProcedureDecorator < Draper::Decorator
delegate_all
def lien
- h.new_users_dossiers_url(procedure_id: id)
+ h.commencer_url(procedure_path: path) unless path.nil?
end
def created_at_fr
@@ -11,7 +11,7 @@ class ProcedureDecorator < Draper::Decorator
def logo_img
return 'logo-tps.png' if logo.blank?
- logo
+ File.join(STORAGE_URL, File.basename(logo.path))
end
def geographic_information
module_api_carto
diff --git a/app/facades/dossier_facades.rb b/app/facades/dossier_facades.rb
index 55d4728da..2291d608f 100644
--- a/app/facades/dossier_facades.rb
+++ b/app/facades/dossier_facades.rb
@@ -45,4 +45,12 @@ class DossierFacades
def invites
@dossier.invites
end
+
+ def commentaires_files
+ PieceJustificative.where(dossier_id: @dossier.id, type_de_piece_justificative_id: nil)
+ end
+
+ def followers
+ Gestionnaire.joins(:follows).where("follows.dossier_id=#{@dossier.id}")
+ end
end
\ No newline at end of file
diff --git a/app/models/dossier.rb b/app/models/dossier.rb
index 80e212454..4e0f13f8c 100644
--- a/app/models/dossier.rb
+++ b/app/models/dossier.rb
@@ -18,6 +18,7 @@ class Dossier < ActiveRecord::Base
has_many :cadastres, dependent: :destroy
has_many :commentaires, dependent: :destroy
has_many :invites, dependent: :destroy
+ has_many :follows
belongs_to :procedure
belongs_to :user
@@ -29,7 +30,6 @@ class Dossier < ActiveRecord::Base
after_save :build_default_champs, if: Proc.new { procedure_id_changed? }
- validates :nom_projet, presence: true, allow_blank: false, allow_nil: true
validates :user, presence: true
WAITING_FOR_GESTIONNAIRE = %w(initiated updated submitted)
@@ -160,7 +160,6 @@ class Dossier < ActiveRecord::Base
query_string_start_with = "#{word}%"
composed_scope = composed_scope.where(
- dossiers[:nom_projet].matches(query_string).or\
users[:email].matches(query_string).or\
etablissements[:siret].matches(query_string_start_with).or\
entreprises[:raison_sociale].matches(query_string))
@@ -199,4 +198,12 @@ class Dossier < ActiveRecord::Base
update_attributes(autorisation_donnees: false)
end
+
+ def total_follow
+ follows.size
+ end
+
+ def total_commentaire
+ self.commentaires.size
+ end
end
diff --git a/app/models/follow.rb b/app/models/follow.rb
new file mode 100644
index 000000000..d554d8fe6
--- /dev/null
+++ b/app/models/follow.rb
@@ -0,0 +1,6 @@
+class Follow < ActiveRecord::Base
+ belongs_to :gestionnaire
+ belongs_to :dossier
+
+ validates_uniqueness_of :gestionnaire_id, :scope => :dossier_id
+end
\ No newline at end of file
diff --git a/app/models/gestionnaire.rb b/app/models/gestionnaire.rb
index e01fe47a2..128783937 100644
--- a/app/models/gestionnaire.rb
+++ b/app/models/gestionnaire.rb
@@ -7,12 +7,34 @@ class Gestionnaire < ActiveRecord::Base
has_many :assign_to, dependent: :destroy
has_many :procedures, through: :assign_to
has_many :dossiers, through: :procedures
+ has_many :follows
def dossiers_filter
dossiers.where(procedure_id: procedure_filter_list)
end
+ def dossiers_follow
+ dossiers.joins(:follows).where("follows.gestionnaire_id = #{id}")
+ end
+
def procedure_filter_list
procedure_filter.empty? ? procedures.pluck(:id) : procedure_filter
end
+
+ def toggle_follow_dossier dossier_id
+ dossier = dossier_id
+ dossier = Dossier.find(dossier_id) unless dossier_id.class == Dossier
+
+ Follow.create!(dossier: dossier, gestionnaire: self)
+ rescue ActiveRecord::RecordInvalid
+ Follow.where(dossier: dossier, gestionnaire: self).delete_all
+ rescue ActiveRecord::RecordNotFound
+ nil
+ end
+
+ def follow? dossier_id
+ dossier_id = dossier_id.id if dossier_id.class == Dossier
+
+ Follow.where(gestionnaire_id: id, dossier_id: dossier_id).any?
+ end
end
diff --git a/app/models/procedure.rb b/app/models/procedure.rb
index de66b000e..cd90371f7 100644
--- a/app/models/procedure.rb
+++ b/app/models/procedure.rb
@@ -3,6 +3,8 @@ class Procedure < ActiveRecord::Base
has_many :types_de_champ, dependent: :destroy
has_many :dossiers
+ has_one :procedure_path, dependent: :destroy
+
has_one :module_api_carto, dependent: :destroy
belongs_to :administrateur
@@ -21,6 +23,14 @@ class Procedure < ActiveRecord::Base
validates :libelle, presence: true, allow_blank: false, allow_nil: false
validates :description, presence: true, allow_blank: false, allow_nil: false
+ def path
+ procedure_path.path unless procedure_path.nil?
+ end
+
+ def default_path
+ libelle.downcase.gsub(/[^a-z0-9\-_]/,"_").gsub(/_*$/, '').gsub(/_+/, '_')
+ end
+
def types_de_champ_ordered
types_de_champ.order(:order_place)
end
@@ -65,4 +75,17 @@ class Procedure < ActiveRecord::Base
return procedure if procedure.save
end
+ def publish!(path)
+ self.update_attributes!({ published: true, archived: false })
+ ProcedurePath.create!(path: path, procedure: self, administrateur: self.administrateur)
+ end
+
+ def archive
+ self.procedure_path.destroy! if self.path
+ self.update_attributes!({ archived: true })
+ end
+
+ def total_dossier
+ self.dossiers.where.not(state: :draft).size
+ end
end
diff --git a/app/models/procedure_path.rb b/app/models/procedure_path.rb
new file mode 100644
index 000000000..579544c12
--- /dev/null
+++ b/app/models/procedure_path.rb
@@ -0,0 +1,8 @@
+class ProcedurePath < ActiveRecord::Base
+ validates :path, procedure_path_format: true, presence: true, allow_blank: false, allow_nil: false
+ validates :administrateur_id, presence: true, allow_blank: false, allow_nil: false
+ validates :procedure_id, presence: true, allow_blank: false, allow_nil: false
+
+ belongs_to :procedure
+ belongs_to :administrateur
+end
\ No newline at end of file
diff --git a/app/models/type_de_champ.rb b/app/models/type_de_champ.rb
index 3f3bdf1f4..e4df31ea0 100644
--- a/app/models/type_de_champ.rb
+++ b/app/models/type_de_champ.rb
@@ -9,7 +9,9 @@ class TypeDeChamp < ActiveRecord::Base
civilite: 'civilite',
email: 'email',
phone: 'phone',
- address: 'address'
+ address: 'address',
+ yes_no: 'yes_no',
+ header_section: 'header_section'
}
belongs_to :procedure
diff --git a/app/serializers/dossier_serializer.rb b/app/serializers/dossier_serializer.rb
index 90b391f66..3364c8928 100644
--- a/app/serializers/dossier_serializer.rb
+++ b/app/serializers/dossier_serializer.rb
@@ -1,10 +1,11 @@
class DossierSerializer < ActiveModel::Serializer
attributes :id,
- :nom_projet,
:created_at,
:updated_at,
:archived,
- :mandataire_social
+ :mandataire_social,
+ :state,
+ :total_commentaire
has_one :entreprise
has_one :etablissement
diff --git a/app/serializers/dossiers_serializer.rb b/app/serializers/dossiers_serializer.rb
index 2a4f084a1..0179a0667 100644
--- a/app/serializers/dossiers_serializer.rb
+++ b/app/serializers/dossiers_serializer.rb
@@ -1,5 +1,4 @@
class DossiersSerializer < ActiveModel::Serializer
attributes :id,
- :nom_projet,
:updated_at
end
\ No newline at end of file
diff --git a/app/serializers/procedure_serializer.rb b/app/serializers/procedure_serializer.rb
index e21025a37..69d3bf307 100644
--- a/app/serializers/procedure_serializer.rb
+++ b/app/serializers/procedure_serializer.rb
@@ -7,7 +7,8 @@ class ProcedureSerializer < ActiveModel::Serializer
:organisation,
:direction,
:archived,
- :geographic_information
+ :geographic_information,
+ :total_dossier
has_one :geographic_information, serializer: ModuleApiCartoSerializer
diff --git a/app/uploaders/remote_downloader.rb b/app/uploaders/remote_downloader.rb
index 987971f86..6d0d07e1b 100644
--- a/app/uploaders/remote_downloader.rb
+++ b/app/uploaders/remote_downloader.rb
@@ -1,11 +1,9 @@
class RemoteDownloader
- DEST_URL = "https://storage.apientreprise.fr/" + CarrierWave::Uploader::Base.fog_directory + '/'
-
def initialize(filename)
@filename = filename
end
def url
- @url ||= File.join(DEST_URL, @filename)
+ @url ||= File.join(STORAGE_URL, @filename)
end
end
diff --git a/app/validators/procedure_path_format_validator.rb b/app/validators/procedure_path_format_validator.rb
new file mode 100644
index 000000000..2d677c37e
--- /dev/null
+++ b/app/validators/procedure_path_format_validator.rb
@@ -0,0 +1,12 @@
+class ProcedurePathFormatValidator < ActiveModel::Validator
+
+ def path_regex
+ /^[a-z0-9_]{3,30}$/
+ end
+
+ def validate(record)
+ return false if record.path.blank?
+ record.errors[:path] << "Path invalide" unless path_regex.match(record.path)
+ end
+
+end
diff --git a/app/views/admin/procedures/_head.html.haml b/app/views/admin/procedures/_head.html.haml
index 185fd711e..f3ca2c1b7 100644
--- a/app/views/admin/procedures/_head.html.haml
+++ b/app/views/admin/procedures/_head.html.haml
@@ -1,6 +1,6 @@
%h2.text-info
-unless @procedure.logo.blank?
- = image_tag @procedure.logo, style: 'width: 30px'
+ = image_tag @procedure.decorate.logo_img, style: 'width: 30px'
=@procedure.libelle
%br
diff --git a/app/views/admin/procedures/_informations.html.haml b/app/views/admin/procedures/_informations.html.haml
index c71686181..6be1a248f 100644
--- a/app/views/admin/procedures/_informations.html.haml
+++ b/app/views/admin/procedures/_informations.html.haml
@@ -15,7 +15,7 @@
.col-md-6.col-lg-6
%h4 Logo de la procédure
- unless @procedure.logo.blank?
- = image_tag @procedure.logo, {style: 'height: 40px; display: inline; margin-right: 6px', id: 'preview_procedure_logo'}
+ = image_tag @procedure.decorate.logo_img, {style: 'height: 40px; display: inline; margin-right: 6px', id: 'preview_procedure_logo'}
= f.file_field(:logo, accept: 'image/png, image/jpg, image/jpeg', style: 'display:inline')
%div{style:'margin-top:5px'}
diff --git a/app/views/admin/procedures/_list.html.haml b/app/views/admin/procedures/_list.html.haml
index ed729fc6d..459585388 100644
--- a/app/views/admin/procedures/_list.html.haml
+++ b/app/views/admin/procedures/_list.html.haml
@@ -3,7 +3,7 @@
%thead
%th#ID= smart_listing.sortable 'ID', 'id'
%th#libelle= smart_listing.sortable 'Libellé', 'libelle'
- - unless @draft_class
+ - if @active_class
%th#lien Lien
%th#created_at= smart_listing.sortable 'Date création', 'created_at'
%th#lien Actions
@@ -11,10 +11,10 @@
- @procedures.each do |procedure|
- procedure = procedure.decorate
%tr
- %td.col-md-1.col-lg-1= procedure.id
+ %td= procedure.id
%td.col-md-6.col-lg-6
= link_to(procedure.libelle, "/admin/procedures/#{procedure.id}")
- - unless @draft_class
+ - if @active_class
%td= link_to procedure.lien, procedure.lien
%td
= procedure.created_at_fr
diff --git a/app/views/admin/procedures/_modal_publish.html.haml b/app/views/admin/procedures/_modal_publish.html.haml
new file mode 100644
index 000000000..a241ae444
--- /dev/null
+++ b/app/views/admin/procedures/_modal_publish.html.haml
@@ -0,0 +1,48 @@
+#publishModal.modal.fade{"aria-labelledby" => "myModalLabel", :role => "dialog", :tabindex => "-1"}
+ .modal-dialog.modal-lg{:role => "document"}
+ = form_tag admin_procedure_publish_path(procedure_id: @procedure.id), method: :put, remote: true do
+ .modal-content
+ .modal-header
+ %button.close{"aria-label" => "Close", "data-dismiss" => "modal", :type => "button"}
+ %span{"aria-hidden" => "true"} ×
+ %h4#myModalLabel.modal-title
+ =@procedure.archived?? 'Réactiver' : 'Publier'
+ la procédure
+ %span#publishModal_title
+ .modal-body
+ Vous vous apprêtez à
+ =@procedure.archived?? 'republier' : 'publier'
+ votre procédure au public.
+ - unless @procedure.archived?
+ %b
+ Elle ne pourra plus être modifiée à l'issue de cette publication.
+ %br
+ Afin de faciliter l'accès à la procédure, vous êtes invité à personnaliser l'adresse d'accès si vous le souhaitez.
+ %br
+ .form-group
+ %br
+ %h4 Lien de la procédure
+ %p.center
+ ="#{root_url}commencer/"
+ = text_field_tag('procedure_path', @procedure.default_path,
+ id: 'procedure_path',
+ placeholder: 'Chemin vers la procédure',
+ class:'form-control',
+ maxlength: 30,
+ style: 'width: 300px; display: inline')
+ #path_messages
+ #path_is_mine.text-warning.center.message
+ Ce lien est déjà utilisé par une de vos procédure.
+ %br
+ Si vous voulez l'utiliser, l'ancienne procédure sera archivée (plus accessible du public).
+ #path_is_not_mine.text-danger.center.message
+ Ce lien est déjà utilisé par une procédure.
+ %br
+ Vous ne pouvez pas l'utiliser car il appartient à un autre administrateur.
+ #path_is_invalid.text-danger.center.message
+ Ce lien n'est pas valide. Il doit comporter au moins 3 caractères et seuls les caractères a-z, 0-9 et '_' sont autorisés.
+ .modal-footer
+ = submit_tag "#{@procedure.archived?? 'Réactiver' : 'Publier'}", class: %w(btn btn btn-success),
+ id: 'publish',
+ disabled: :disabled
+ = button_tag 'Annuler', class: %w(btn btn btn-default), id: 'cancel', data: { dismiss: 'modal' }
diff --git a/app/views/admin/procedures/_modal_transfer.html.haml b/app/views/admin/procedures/_modal_transfer.html.haml
new file mode 100644
index 000000000..caa28a31e
--- /dev/null
+++ b/app/views/admin/procedures/_modal_transfer.html.haml
@@ -0,0 +1,23 @@
+#transferModal.modal.fade{"aria-labelledby" => "TransferProcedureModal", :role => "dialog", :tabindex => "-1"}
+ .modal-dialog.modal-md{:role => "document"}
+ = form_tag admin_procedure_transfer_path(procedure_id: @procedure.id), method: :post, remote: true do
+ .modal-content
+ .modal-header
+ %button.close{"aria-label" => "Close", "data-dismiss" => "modal", :type => "button"}
+ %span{"aria-hidden" => "true"} ×
+ %h4#myModalLabel.modal-title
+ Petit transfert de procédure entre administrateur
+ .modal-body
+ %p
+ Cette fonctionnalité vous permet de transmettre un clone de votre procédure à un autre administrateur.
+ %div{style:'margin-top:20px'}
+ = text_field_tag :email_admin, '', {class: 'form-control',
+ type: 'email',
+ placeholder: 'Email administrateur cible',
+ maxlength: 30,
+ style: 'width: 300px; margin-left:auto; margin-right:auto'}
+ %div#not_found_admin.center.text-danger{style:'display:none; margin-top: 10px'}
+ Cet administrateur n'existe pas.
+ .modal-footer
+ = submit_tag "Envoyer", class: 'btn btn-success'
+ = button_tag 'Annuler', class: %w(btn btn btn-default), id: 'cancel', data: { dismiss: 'modal' }
diff --git a/app/views/admin/procedures/publish.js.erb b/app/views/admin/procedures/publish.js.erb
new file mode 100644
index 000000000..04a6b2229
--- /dev/null
+++ b/app/views/admin/procedures/publish.js.erb
@@ -0,0 +1 @@
+<%= "togglePathMessage(true, #{@mine})" %>
\ No newline at end of file
diff --git a/app/views/admin/procedures/show.html.haml b/app/views/admin/procedures/show.html.haml
index 8626a87e2..494969bcf 100644
--- a/app/views/admin/procedures/show.html.haml
+++ b/app/views/admin/procedures/show.html.haml
@@ -1,27 +1,31 @@
#procedure_show
=render partial: 'head', locals: {active: 'Informations'}
- -if ! @facade.procedure.published?
- = form_tag admin_procedure_publish_path(procedure_id: @facade.procedure.id, publish: true), method: :put, style:'float: right; margin-top: 10px' do
- %button#archive.btn.btn-small.btn-success.text-info{type: :button}
- %i.fa.fa-eraser
- Publier
- #confirm
- %button#valid.btn.btn-small.btn-success{type: :submit}
- %i.fa.fa-check
- Valider
- %button#cancel.btn.btn-small.btn-danger{type: :button}
- %i.fa.fa-remove
- Annuler
+ -unless @facade.procedure.published?
+ %a#publish.btn.btn-success{"data-target" => "#publishModal", "data-toggle" => "modal", :type => "button", style:'float: right; margin-top: 10px'}
+ %i.fa.fa-eraser
+ Publier
- -else
+ =render partial: '/admin/procedures/modal_publish'
+
+ %a#transfer.btn.btn-small.btn-default{"data-target" => "#transferModal", "data-toggle" => "modal", :type => "button", style:'float: right; margin-top: 10px'}
+ %i.fa.fa-exchange
+ Transférer
+
+ =render partial: '/admin/procedures/modal_transfer'
+
+ -if @facade.procedure.archived?
+ %a#reenable.btn.btn-small.btn-default.text-info{"data-target" => "#publishModal", "data-toggle" => "modal", :type => "button", style:'float: right; margin-top: 10px'}
+ %i.fa.fa-eraser
+ Réactiver
+
+ =render partial: '/admin/procedures/modal_publish'
+
+ -elsif @facade.procedure.published?
= form_tag admin_procedure_archive_path(procedure_id: @facade.procedure.id, archive: !@facade.procedure.archived?), method: :put, style:'float: right; margin-top: 10px' do
%button#archive.btn.btn-small.btn-default.text-info{type: :button}
%i.fa.fa-eraser
- - if @facade.procedure.archived
- = 'Réactiver'
- - else
- = 'Archiver'
+ = 'Archiver'
#confirm
%button#valid.btn.btn-small.btn-success{type: :submit}
%i.fa.fa-check
@@ -38,7 +42,10 @@
%div
%h3 Lien procédure
%div{style:'margin-left:3%'}
- -if @facade.procedure.published?
+ -if @facade.procedure.archived?
+ %b
+ Cette procédure a été archivée et n'est plus accessible par le public.
+ -elsif @facade.procedure.published?
= @facade.procedure.lien
-else
%b
diff --git a/app/views/admin/procedures/transfer.js.erb b/app/views/admin/procedures/transfer.js.erb
new file mode 100644
index 000000000..d57f2f48f
--- /dev/null
+++ b/app/views/admin/procedures/transfer.js.erb
@@ -0,0 +1,11 @@
+<%- if response.status == 404 %>
+ transfer_errors_message(true);
+<%- else %>
+ <% flash.each do |type, message| %>
+ $("#flash_message").html(" <%= message.html_safe %>
")
+ <% end %>
+ <% flash.clear %>
+ transfer_errors_message(false);
+ $("#email_admin").val('');
+ $("button#cancel").click();
+<%- end %>
\ No newline at end of file
diff --git a/app/views/admin/types_de_champ/_fields.html.haml b/app/views/admin/types_de_champ/_fields.html.haml
index 42118cdd3..4103a2329 100644
--- a/app/views/admin/types_de_champ/_fields.html.haml
+++ b/app/views/admin/types_de_champ/_fields.html.haml
@@ -1,15 +1,18 @@
= f.fields_for :types_de_champ, types_de_champ, remote: true do |ff|
- .form-inline
- .form-group
+ .form-inline{class:"#{ff.object.object.type_champ == 'header_section' ? 'header_section' : ''}"}
+ .form-group.libelle
%h4 Libellé
= ff.text_field :libelle, class: 'form-control libelle', placeholder: 'Libellé'
- .form-group
+
+ .form-group.type
%h4 Type
= ff.select :type_champ, TypeDeChamp.type_champs, {}, {class: 'form-control type_champ'}
- .form-group
+
+ .form-group.description
%h4 Description
= ff.text_area :description, class: 'form-control description', placeholder: 'Description'
- .form-group
+
+ .form-group.mandatory
%h4 Obligatoire ?
.center
= ff.check_box :mandatory, placeholder: 'Obligatoire ?'
diff --git a/app/views/admin/types_de_champ/show.js.erb b/app/views/admin/types_de_champ/show.js.erb
index f8e69b515..259d609e3 100644
--- a/app/views/admin/types_de_champ/show.js.erb
+++ b/app/views/admin/types_de_champ/show.js.erb
@@ -1,4 +1,5 @@
<% flash.each do |type, message| %>
$("#flash_message").html(" <%= message.html_safe %>
").children().fadeOut(5000)
<% end %>
-$('#liste_champ').html("<%= escape_javascript(render partial: 'form', locals: { procedure: @procedure, types_de_champ: @types_de_champ } ) %>");
\ No newline at end of file
+$('#liste_champ').html("<%= escape_javascript(render partial: 'form', locals: { procedure: @procedure, types_de_champ: @types_de_champ } ) %>");
+on_change_type_de_champ_select ();
\ No newline at end of file
diff --git a/app/views/backoffice/dossiers/_follow_action.html.haml b/app/views/backoffice/dossiers/_follow_action.html.haml
new file mode 100644
index 000000000..2a87b49eb
--- /dev/null
+++ b/app/views/backoffice/dossiers/_follow_action.html.haml
@@ -0,0 +1,4 @@
+- if current_gestionnaire.follow?(@facade.dossier.id)
+ = link_to('Quitter'.html_safe, backoffice_dossier_follow_path(dossier_id: @facade.dossier.id), 'data-method' => :put, class: 'btn btn-md btn-danger', id: "suivre_dossier_#{@facade.dossier.id}")
+-else
+ = link_to('Suivre', backoffice_dossier_follow_path(dossier_id: @facade.dossier.id), 'data-method' => :put, class: 'btn btn-md btn-primary', id: "suivre_dossier_#{@facade.dossier.id}")
diff --git a/app/views/backoffice/dossiers/_followers.html.haml b/app/views/backoffice/dossiers/_followers.html.haml
new file mode 100644
index 000000000..8274055d4
--- /dev/null
+++ b/app/views/backoffice/dossiers/_followers.html.haml
@@ -0,0 +1,14 @@
+%h3 Personnes suivant l'activité de ce dossier
+
+%br
+.row
+ .col-md-4.col-lg-4
+ - if @facade.followers.size > 0
+ %ul
+ - @facade.followers.each do |follower|
+ %li
+ = follower.email
+ - else
+ Aucune personne ne suit ce dossier
+
+
diff --git a/app/views/backoffice/dossiers/_list.html.haml b/app/views/backoffice/dossiers/_list.html.haml
index 176b093f7..6307fff8c 100644
--- a/app/views/backoffice/dossiers/_list.html.haml
+++ b/app/views/backoffice/dossiers/_list.html.haml
@@ -1,19 +1,28 @@
- unless smart_listing.empty?
%table.table
- %thead.row
- %th.col-md-4.col-lg-4= smart_listing.sortable 'Procédure', 'procedure.libelle'
- %th.col-md-4.col-lg-4= smart_listing.sortable 'Dossier', 'nom_projet'
- %th.col-md-2.col-lg-2= smart_listing.sortable 'État', 'state'
- %th.col-md-2.col-lg-2= smart_listing.sortable 'Date de mise à jour', 'updated_at'
+ %thead
+ %th= smart_listing.sortable 'Procédure', 'procedure.libelle'
+ %th= smart_listing.sortable 'Raison sociale', 'entreprise.raison_sociale'
+ %th= smart_listing.sortable 'État', 'state'
+ %th= smart_listing.sortable 'Date de mise à jour', 'updated_at'
+ %th.center Actions
+ %th.center Abonnés
- @dossiers.each do |dossier|
- dossier = dossier.decorate
%tr
- %td= dossier.procedure.libelle
- %td
- = link_to(dossier.nom_projet, "/backoffice/dossiers/#{dossier.id}")
+ %td.col-md-4.col-lg-4= dossier.procedure.libelle
+ %td.col-md-4.col-lg-4
+ = link_to(dossier.entreprise.raison_sociale, "/backoffice/dossiers/#{dossier.id}")
%td= dossier.display_state
%td= dossier.last_update
+ %td.center
+ - if current_gestionnaire.follow?(dossier.id)
+ = link_to('Quitter'.html_safe, backoffice_dossier_follow_path(dossier_id: dossier.id), 'data-method' => :put, class: 'btn-sm btn-danger', id: "suivre_dossier_#{dossier.id}")
+ -else
+ = link_to('Suivre', backoffice_dossier_follow_path(dossier_id: dossier.id), 'data-method' => :put, class: 'btn-sm btn-primary', id: "suivre_dossier_#{dossier.id}")
+ %td.center{style:"color: #{dossier.total_follow == 0 ? 'red' : ''}"}
+ = dossier.total_follow
= smart_listing.paginate
= smart_listing.pagination_per_page_links
diff --git a/app/views/backoffice/dossiers/_onglets.html.haml b/app/views/backoffice/dossiers/_onglets.html.haml
index 7ee1ae1a3..589b12fce 100644
--- a/app/views/backoffice/dossiers/_onglets.html.haml
+++ b/app/views/backoffice/dossiers/_onglets.html.haml
@@ -17,6 +17,13 @@
.badge.progress-bar-info
=@dossiers_en_attente_total
+ %li{ class: (@suivi_class) }
+ %a{:href => "#{url_for backoffice_dossiers_path(liste: 'suivi')}"}
+ %h5.text-warning
+ ="Suivi"
+ .badge.progress-bar-warning
+ =@dossiers_suivi_total
+
%li{ class: (@termine_class) }
%a{:href => "#{url_for backoffice_dossiers_path(liste: 'termine')}"}
%h5.text-success
diff --git a/app/views/backoffice/dossiers/search.html.haml b/app/views/backoffice/dossiers/search.html.haml
index d55850ae2..9d01e31b5 100644
--- a/app/views/backoffice/dossiers/search.html.haml
+++ b/app/views/backoffice/dossiers/search.html.haml
@@ -8,16 +8,14 @@
%h4
= "Dossier N°#{@dossier.id}"
%tr
- %td.col-md-2.col-lg-1
+ %td.col-md-1.col-lg-1
= @dossier.id
- %td.col-md-4.col-lg-3
- = link_to(@dossier.nom_projet, "/backoffice/dossiers/#{@dossier.id}")
- %td.col-md-2.col-lg-3
- = @dossier.entreprise.raison_sociale
- %td.col-md-4.col-lg-2
- = @dossier.user.email
+ %td.col-md-4.col-lg-4
+ = @dossier.procedure.libelle
+ %td.col-md-4.col-lg-4
+ = link_to(@dossier.entreprise.raison_sociale, "/backoffice/dossiers/#{@dossier.id}")
%td.col-md-2.col-lg-2
- = @dossier.etablissement.siret
+ = @dossier.user.email
%td.col-md-1.col-lg-1{class: @dossier.state_color_class}
= @dossier.display_state
%br
@@ -29,21 +27,18 @@
- elsif !@dossiers_search.empty?
%table.table
%tr
- %th.col-md-2.col-lg-1 ID dossier
- %th.col-md-4.col-lg-3 Dossier
- %th.col-md-2.col-lg-3 Raison Sociale
- %th.col-md-4.col-lg-2 Email contact
- %th.col-md-2.col-lg-2 SIRET
+ %th.col-md-1.col-lg-1 ID dossier
+ %th.col-md-4.col-lg-4 Procédure
+ %th.col-md-4.col-lg-4 Raison Sociale
+ %th.col-md-2.col-lg-2 Email contact
%th.col-md-1.col-lg-1 État
- @dossiers_search.each do |dossier|
%tr
%td= dossier.id
- %td
- = link_to(dossier.nom_projet, "/backoffice/dossiers/#{dossier.id}")
- %td= dossier.entreprise.raison_sociale
+ %td= dossier.procedure.libelle
+ %td= link_to(dossier.entreprise.raison_sociale, "/backoffice/dossiers/#{dossier.id}")
%td= dossier.user.email
- %td= dossier.etablissement.siret
%td{class: dossier.state_color_class}= dossier.display_state
.pagination
diff --git a/app/views/backoffice/dossiers/show.html.haml b/app/views/backoffice/dossiers/show.html.haml
index e24c2b978..caba91adb 100644
--- a/app/views/backoffice/dossiers/show.html.haml
+++ b/app/views/backoffice/dossiers/show.html.haml
@@ -6,6 +6,8 @@
%h3{:class => 'text-success'}
= @facade.dossier.display_state
+ = render partial: 'follow_action'
+
= render partial: '/dossiers/infos_entreprise'
= render partial: '/dossiers/infos_dossier'
@@ -16,17 +18,27 @@
%li{role: "presentation", class: "active"}
%a{href: "#commentaires", 'aria-controls' => "commentaires", role: "tab", 'data-toggle' => "tab"}
Commentaires
+ %li{role: "presentation"}
+ %a{href: "#commentaires_files", 'aria-controls' => "commentaires_files", role: "tab", 'data-toggle' => "tab"}
+ Fichiers
%li{role: "presentation"}
%a{href: "#invites", 'aria-controls' => "invites", role: "tab", 'data-toggle' => "tab"}
Invités
+ %li{role: "presentation"}
+ %a{href: "#followers", 'aria-controls' => "followers", role: "tab", 'data-toggle' => "tab"}
+ Abonnés
%div{class: "tab-content"}
%div{role: "tabpanel", class: "tab-pane fade in active", id:"commentaires"}
%h3 Flux de commentaires
%br
= render partial: '/users/recapitulatif/commentaires_flux'
+ %div{role: "tabpanel", class: "tab-pane fade", id:"commentaires_files"}
+ = render partial: '/dossiers/commentaires_files'
%div{role: "tabpanel", class: "tab-pane fade", id:"invites"}
= render partial: '/dossiers/invites'
+ %div{role: "tabpanel", class: "tab-pane fade", id:"followers"}
+ = render partial: 'followers'
%br
%br
\ No newline at end of file
diff --git a/app/views/dossiers/_commentaires_files.html.haml b/app/views/dossiers/_commentaires_files.html.haml
new file mode 100644
index 000000000..53a22cc06
--- /dev/null
+++ b/app/views/dossiers/_commentaires_files.html.haml
@@ -0,0 +1,23 @@
+%h3 Fichiers des commentaires
+
+%br
+- if @facade.commentaires_files.size > 0
+ %table.table
+ %thead
+ %th.col-md-3
+ Email
+ %th.col-md-2
+ Date
+ %th.col-md-6
+ Fichier
+
+
+ - @facade.commentaires_files.each do |file|
+ %tr
+ %td= file.user.nil? ? 'Accompagnateur' : file.user.email
+ %td= file.created_at.localtime
+ %td= link_to file.original_filename, file.content_url, style:'color: green', target: '_blank'
+- else
+ %h4.text-primary
+ Pas de fichier dans le flux de commentaires.
+
diff --git a/app/views/dossiers/_infos_dossier.html.haml b/app/views/dossiers/_infos_dossier.html.haml
index f916f5dcb..6e814043f 100644
--- a/app/views/dossiers/_infos_dossier.html.haml
+++ b/app/views/dossiers/_infos_dossier.html.haml
@@ -1,9 +1,7 @@
#infos_dossier
%div.row
.col-lg-6.col-md-6
- %h3.text-info
- = @facade.dossier.nom_projet
- %h4
+ %h3
= @facade.dossier.procedure.libelle
- if @facade.dossier.mandataire_social && gestionnaire_signed_in?
diff --git a/app/views/dossiers/_show.html.haml b/app/views/dossiers/_show.html.haml
index 3b273f41d..4874bedb6 100644
--- a/app/views/dossiers/_show.html.haml
+++ b/app/views/dossiers/_show.html.haml
@@ -8,14 +8,7 @@
-#- if @facade.procedure.module_api_carto.use_api_carto?
-# .row.etape.etape_3
- -# .etape.etapes_menu.col-md-3.col-lg-3
- -# %h3
- -# 3 - Ma zone d'intervention
- -# .etape.etapes_informations.col-md-9.col-lg-9
+ -# = render partial: '/dossiers/etapes/etape3'
-#
-#.row.etape.etape_4
- -# .etape.etapes_menu.col-md-3.col-lg-3
- -# %h3
- -# = "#{@facade.procedure.module_api_carto.use_api_carto? ? '4' : '3'} - Mon dossier"
- -# .etape.etapes_informations.col-md-9.col-lg-9
-
+ -# = render partial: '/dossiers/etapes/etape4'
diff --git a/app/views/dossiers/etapes/_etape1.html.haml b/app/views/dossiers/etapes/_etape1.html.haml
index 917e08b0f..9b3a10025 100644
--- a/app/views/dossiers/etapes/_etape1.html.haml
+++ b/app/views/dossiers/etapes/_etape1.html.haml
@@ -2,7 +2,8 @@
%h3
Ma procédure
%br
- .center
+
+ #logos.center{class: (@facade.entreprise.nil? ? '' : 'mask')}
- if @facade.procedure.euro_flag
#euro_flag.flag
=image_tag('drapeau_europe.png')
@@ -15,5 +16,5 @@
%h2#titre_procedure.text-info
= @facade.procedure.libelle
- %p{style:'width: 95%;'}
+ %p#description_procedure{style:'width: 95%;', class: (@facade.entreprise.nil? ? '' : 'mask')}
= h @facade.procedure.description.html_safe
\ No newline at end of file
diff --git a/app/views/dossiers/etapes/_etape2.html.haml b/app/views/dossiers/etapes/_etape2.html.haml
index cb14a694c..2e8f161e9 100644
--- a/app/views/dossiers/etapes/_etape2.html.haml
+++ b/app/views/dossiers/etapes/_etape2.html.haml
@@ -22,6 +22,7 @@
= f.hidden_field :dossier_id, value: @facade.dossier.id
= f.submit 'Valider', class: %w(btn btn-lg btn-success), data: { disable_with: "Recherche en cours ..." }
- else
+ %br
#recap_info_entreprise
= render partial: '/dossiers/infos_entreprise'
diff --git a/app/views/dossiers/etapes/_etape3.html.haml b/app/views/dossiers/etapes/_etape3.html.haml
new file mode 100644
index 000000000..5e5735480
--- /dev/null
+++ b/app/views/dossiers/etapes/_etape3.html.haml
@@ -0,0 +1,6 @@
+.etape.etapes_menu.col-md-3.col-lg-3
+ %h3
+ Ma zone d'intervention
+
+.etape.etapes_informations.col-md-9.col-lg-9
+ .row
diff --git a/app/views/dossiers/etapes/_etape4.html.haml b/app/views/dossiers/etapes/_etape4.html.haml
new file mode 100644
index 000000000..64636c231
--- /dev/null
+++ b/app/views/dossiers/etapes/_etape4.html.haml
@@ -0,0 +1,6 @@
+.etape.etapes_menu.col-md-3.col-lg-3
+ %h3
+ Mon dossier
+
+.etape.etapes_informations.col-md-9.col-lg-9
+ .row
diff --git a/app/views/dossiers/new_siret.js.erb b/app/views/dossiers/new_siret.js.erb
index 803581a3c..c3d7503cf 100644
--- a/app/views/dossiers/new_siret.js.erb
+++ b/app/views/dossiers/new_siret.js.erb
@@ -1,7 +1,14 @@
-$('.row.etape.etape_2').html("<%= escape_javascript(render partial: '/dossiers/etapes/etape2', locals: { facade: @facade } ) %>");
-the_terms();
-
-<% unless flash.empty? %>
+<% if flash.empty? %>
+$('.row.etape.etape_2').hide(300, render_new_siret);
+$('.row.etape.etape_2').slideDown(400, the_terms);
+toggle_etape_1();
+<% else %>
error_form_siret('<%= invalid_siret %>');
<% end %>
-<% flash.clear %>
\ No newline at end of file
+
+<% flash.clear %>
+
+
+function render_new_siret(){
+ $('.row.etape.etape_2').html("<%= escape_javascript(render partial: '/dossiers/etapes/etape2', locals: { facade: @facade } ) %>");
+}
\ No newline at end of file
diff --git a/app/views/gestionnaires/passwords/new.html.haml b/app/views/gestionnaires/passwords/new.html.haml
index 9c15a8ca9..eed941e40 100644
--- a/app/views/gestionnaires/passwords/new.html.haml
+++ b/app/views/gestionnaires/passwords/new.html.haml
@@ -1,5 +1,6 @@
= devise_error_messages!
+%br
#form_login
= image_tag('logo-tps.png')
%br
diff --git a/app/views/invite_mailer/invite_user.text.erb b/app/views/invite_mailer/invite_user.text.erb
index 12d8125c9..57827303c 100644
--- a/app/views/invite_mailer/invite_user.text.erb
+++ b/app/views/invite_mailer/invite_user.text.erb
@@ -1,7 +1,6 @@
Bonjour <%= @invite.email %>
L'utilisateur <%= @invite.email_sender %> souhaite que vous participiez à l'élaboration d'un dossier sur la plateforme TPS.
-Ce dossier se nomme : <%= @invite.dossier.nom_projet %>
Pour le consulter, merci de suivre ce lien : <%= users_dossiers_invite_url(@invite.id) %>
diff --git a/app/views/users/description/_champs.html.haml b/app/views/users/description/_champs.html.haml
index df175b482..3d6d5387f 100644
--- a/app/views/users/description/_champs.html.haml
+++ b/app/views/users/description/_champs.html.haml
@@ -8,6 +8,10 @@
= '*'
%input{type: 'hidden', name:"champs['#{champ.id}']", id: "champs_#{champ.id}", value: ''}
%input{type: 'checkbox', style:'margin-left: 15px;', name:"champs['#{champ.id}']", id: "champs_#{champ.id}", checked: ('checked' if champ.value == 'on')}
+
+ - elsif champ.type_champ == 'header_section'
+ =render partial: 'users/description/champs/header_section', locals: {champ: champ}
+
-else
%h4
= champ.libelle
@@ -23,6 +27,9 @@
- elsif champ.type_champ == 'datetime'
=render partial: 'users/description/champs/datetime', locals: {champ: champ}
+ - elsif champ.type_champ == 'yes_no'
+ =render partial: 'users/description/champs/yes_no', locals: {champ: champ}
+
-else
%input.form-control{name:"champs['#{champ.id}']",
placeholder: champ.libelle,
diff --git a/app/views/users/description/_show.html.haml b/app/views/users/description/_show.html.haml
index c0db91dc6..463ac15e8 100644
--- a/app/views/users/description/_show.html.haml
+++ b/app/views/users/description/_show.html.haml
@@ -3,15 +3,8 @@
= @dossier.procedure.libelle
%h3 Votre dossier
- %br
-
-#TODO use form_for
= form_tag(url_for({controller: 'users/description', action: :create, dossier_id: @dossier.id}), class: 'form-inline', method: 'POST', multipart: true) do
- %div
- .row
- .col-md-12
- %h4 Libellé pour votre dossier *
- = text_field_tag :nom_projet, @dossier.nom_projet, placeholder: 'Nom du projet', class: 'form-control'
#liste_champs
-unless @champs.nil?
diff --git a/app/views/users/description/champs/_header_section.html.haml b/app/views/users/description/champs/_header_section.html.haml
new file mode 100644
index 000000000..5ff3eae62
--- /dev/null
+++ b/app/views/users/description/champs/_header_section.html.haml
@@ -0,0 +1,2 @@
+%h3.text-primary.page-header
+ =champ.libelle
\ No newline at end of file
diff --git a/app/views/users/description/champs/_yes_no.html.haml b/app/views/users/description/champs/_yes_no.html.haml
new file mode 100644
index 000000000..9224f98f5
--- /dev/null
+++ b/app/views/users/description/champs/_yes_no.html.haml
@@ -0,0 +1,7 @@
+%label.radio-inline
+ = radio_button_tag "champs['#{champ.id}']", "true", champ.value == 'true'
+ Oui
+
+%label.radio-inline
+ = radio_button_tag "champs['#{champ.id}']", "false", champ.value == 'false'
+ Non
\ No newline at end of file
diff --git a/app/views/users/dossiers/_list.html.haml b/app/views/users/dossiers/_list.html.haml
index eee042954..3f788cee0 100644
--- a/app/views/users/dossiers/_list.html.haml
+++ b/app/views/users/dossiers/_list.html.haml
@@ -2,7 +2,7 @@
%table.table
%thead
%th.col-md-4.col-lg-4= smart_listing.sortable 'Procédure', 'procedure.libelle'
- %th.col-md-4.col-lg-4= smart_listing.sortable 'Nom du Projet', 'nom_projet'
+ %th.col-md-4.col-lg-4= smart_listing.sortable 'Raison sociale', 'entreprise.raison_sociale'
%th.col-md-2.col-lg-2= smart_listing.sortable 'État', 'state'
%th.col-md-2.col-lg-2= smart_listing.sortable 'Date de mise à jour', 'updated_at'
- @dossiers.each do |dossier|
@@ -15,8 +15,8 @@
%td
= dossier.procedure.libelle
%td
- = link_to(dossier.nom_projet, users_dossiers_invite_path(id: invite.id)) unless invite.nil?
- = link_to(dossier.nom_projet, users_dossier_recapitulatif_path(dossier)) if invite.nil?
+ = link_to(dossier.entreprise.raison_sociale, users_dossiers_invite_path(id: invite.id)) unless invite.nil?
+ = link_to(dossier.entreprise.raison_sociale, users_dossier_recapitulatif_path(dossier)) if invite.nil?
%td{id: "dossier_#{dossier.id}_state"}= dossier.display_state
%td= dossier.last_update
diff --git a/app/views/users/passwords/new.html.haml b/app/views/users/passwords/new.html.haml
index 4ffd7bc17..6504a7295 100644
--- a/app/views/users/passwords/new.html.haml
+++ b/app/views/users/passwords/new.html.haml
@@ -28,6 +28,7 @@
= devise_error_messages!
+%br
#form_login
= image_tag('logo-tps.png')
%br
diff --git a/app/views/welcome_mailer/welcome_email.text.erb b/app/views/welcome_mailer/welcome_email.text.erb
index 59e4ef9e6..57984af05 100644
--- a/app/views/welcome_mailer/welcome_email.text.erb
+++ b/app/views/welcome_mailer/welcome_email.text.erb
@@ -2,12 +2,12 @@ Bienvenue sur la plateforme TPS
Nous vous remercions de vous être inscrit sur TPS. Pour mémoire, voici quelques informations utiles :
- URL : https://tps.apientreprise.fr
+ URL : <%= root_url %>>
Login : <%= @user.email %>
Oubli de mot de passe, pas de problème :
- https://tps.apientreprise.fr/users/password/new
+ <%= new_user_password_url %>
Bonne journée,
diff --git a/config/deploy.rb b/config/deploy.rb
index 82ee49d66..4350ccd30 100644
--- a/config/deploy.rb
+++ b/config/deploy.rb
@@ -72,7 +72,8 @@ set :shared_paths, [
"config/unicorn.rb",
"config/initializers/raven.rb",
'config/france_connect.yml',
- 'config/initializers/mailjet.rb'
+ 'config/initializers/mailjet.rb',
+ 'config/initializers/storage_url.rb'
]
diff --git a/config/environments/development.rb b/config/environments/development.rb
index 0d42d3db7..66984e511 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -36,7 +36,7 @@ Rails.application.configure do
# Raises helpful error messages.
config.assets.raise_runtime_errors = true
- config.action_mailer.delivery_method = :mailjet
+ config.action_mailer.delivery_method = :test
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
# Raises error for missing translations
diff --git a/config/initializers/carrierwave.rb b/config/initializers/carrierwave.rb
index 35813733a..dcb948fc1 100644
--- a/config/initializers/carrierwave.rb
+++ b/config/initializers/carrierwave.rb
@@ -26,6 +26,8 @@ CarrierWave.configure do |config|
if Rails.env.production?
config.fog_directory = "tps"
+ elsif Rails.env.development?
+ config.fog_directory= "test_local"
else
config.fog_directory = "tps_dev"
end
diff --git a/config/initializers/storage_url.rb b/config/initializers/storage_url.rb
new file mode 100644
index 000000000..0a1cf0f93
--- /dev/null
+++ b/config/initializers/storage_url.rb
@@ -0,0 +1 @@
+STORAGE_URL = "https://storage.apientreprise.fr/" + CarrierWave::Uploader::Base.fog_directory + '/'
\ No newline at end of file
diff --git a/config/locales/models/dossier/fr.yml b/config/locales/models/dossier/fr.yml
index 37b811618..6c7eaab74 100644
--- a/config/locales/models/dossier/fr.yml
+++ b/config/locales/models/dossier/fr.yml
@@ -4,8 +4,6 @@ fr:
dossier: 'Dossier'
attributes:
dossier:
- nom_projet: 'Le nom du projet'
- description: 'La description'
montant_projet: 'Le montant du projet'
montant_aide_demande: "Le montant d'aide demandée"
date_previsionnelle: "La date de début prévisionnelle"
diff --git a/config/routes.rb b/config/routes.rb
index 98b331bc3..cc657c43d 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -89,6 +89,7 @@ Rails.application.routes.draw do
get 'sign_in' => '/administrateurs/sessions#new'
get 'procedures/archived' => 'procedures#archived'
get 'procedures/draft' => 'procedures#draft'
+ get 'procedures/path_list' => 'procedures#path_list'
get 'profile' => 'profile#show', as: :profile
resources :procedures do
@@ -103,6 +104,7 @@ Rails.application.routes.draw do
put 'archive' => 'procedures#archive', as: :archive
put 'publish' => 'procedures#publish', as: :publish
+ post 'transfer' => 'procedures#transfer', as: :transfer
put 'clone' => 'procedures#clone', as: :clone
resource :accompagnateurs, only: [:show, :update]
@@ -142,6 +144,8 @@ Rails.application.routes.draw do
post 'close' => 'dossiers#close'
post 'invites' => '/invites#create'
+
+ put 'follow' => 'dossiers#follow'
end
resources :commentaires, only: [:create]
@@ -161,5 +165,9 @@ Rails.application.routes.draw do
end
end
+ namespace :commencer do
+ get '/:procedure_path' => '/users/dossiers#commencer'
+ end
+
apipie
end
diff --git a/db/migrate/20160622081322_add_procedure_path_mapping_table.rb b/db/migrate/20160622081322_add_procedure_path_mapping_table.rb
new file mode 100644
index 000000000..9d3eecc1f
--- /dev/null
+++ b/db/migrate/20160622081322_add_procedure_path_mapping_table.rb
@@ -0,0 +1,18 @@
+class AddProcedurePathMappingTable < ActiveRecord::Migration
+ class ProcedurePath < ActiveRecord::Base
+ end
+
+ def change
+ create_table :procedure_paths do |t|
+ t.string :path, limit: 30, null: true, unique: true, index: true
+ t.integer :procedure_id, unique: true, null: true
+ t.integer :administrateur_id, unique: true, null: true
+ end
+ add_foreign_key :procedure_paths, :procedures
+ add_foreign_key :procedure_paths, :administrateurs
+
+ Procedure.all.each do |procedure|
+ ProcedurePath.create(path: "#{procedure.id}", procedure_id: procedure.id, administrateur_id: procedure.administrateur.id)
+ end
+ end
+end
diff --git a/db/migrate/20160718124741_gestionnaire_can_follow_dossier.rb b/db/migrate/20160718124741_gestionnaire_can_follow_dossier.rb
new file mode 100644
index 000000000..15247e65f
--- /dev/null
+++ b/db/migrate/20160718124741_gestionnaire_can_follow_dossier.rb
@@ -0,0 +1,8 @@
+class GestionnaireCanFollowDossier < ActiveRecord::Migration
+ def change
+ create_table :follows do |t|
+ t.belongs_to :gestionnaire, index: true
+ t.belongs_to :dossier, index: true
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 630778df7..1dacf946f 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20160622081321) do
+ActiveRecord::Schema.define(version: 20160718124741) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -168,6 +168,14 @@ ActiveRecord::Schema.define(version: 20160622081321) do
t.integer "etablissement_id"
end
+ create_table "follows", force: :cascade do |t|
+ t.integer "gestionnaire_id"
+ t.integer "dossier_id"
+ end
+
+ add_index "follows", ["dossier_id"], name: "index_follows_on_dossier_id", using: :btree
+ add_index "follows", ["gestionnaire_id"], name: "index_follows_on_gestionnaire_id", using: :btree
+
create_table "france_connect_informations", force: :cascade do |t|
t.string "gender"
t.string "given_name"
@@ -226,6 +234,14 @@ ActiveRecord::Schema.define(version: 20160622081321) do
add_index "pieces_justificatives", ["type_de_piece_justificative_id"], name: "index_pieces_justificatives_on_type_de_piece_justificative_id", using: :btree
+ create_table "procedure_paths", force: :cascade do |t|
+ t.string "path", limit: 30
+ t.integer "procedure_id"
+ t.integer "administrateur_id"
+ end
+
+ add_index "procedure_paths", ["path"], name: "index_procedure_paths_on_path", using: :btree
+
create_table "procedures", force: :cascade do |t|
t.string "libelle"
t.string "description"
@@ -304,4 +320,6 @@ ActiveRecord::Schema.define(version: 20160622081321) do
add_foreign_key "cerfas", "dossiers"
add_foreign_key "commentaires", "dossiers"
add_foreign_key "dossiers", "users"
+ add_foreign_key "procedure_paths", "administrateurs"
+ add_foreign_key "procedure_paths", "procedures"
end
diff --git a/spec/controllers/admin/procedures_controller_spec.rb b/spec/controllers/admin/procedures_controller_spec.rb
index 6bd380b79..c6ddc9462 100644
--- a/spec/controllers/admin/procedures_controller_spec.rb
+++ b/spec/controllers/admin/procedures_controller_spec.rb
@@ -77,7 +77,7 @@ describe Admin::ProceduresController, type: :controller do
subject
end
- it { expect { subject }.to change{Procedure.count}.by(-1) }
+ it { expect { subject }.to change { Procedure.count }.by(-1) }
end
context 'when procedure is published' do
@@ -263,31 +263,116 @@ describe Admin::ProceduresController, type: :controller do
end
end
+ describe 'PUT #publish' do
+ let(:procedure) { create(:procedure, administrateur: admin) }
+ let(:procedure2) { create(:procedure, :published, administrateur: admin) }
+ let(:procedure3) { create(:procedure, :published) }
+
+ context 'when admin is the owner of the procedure' do
+ before do
+ put :publish, procedure_id: procedure.id, procedure_path: procedure_path
+ procedure.reload
+ procedure2.reload
+ end
+
+ context 'procedure path does not exist' do
+ let(:procedure_path) { 'new_path' }
+
+ it 'publish the given procedure' do
+ expect(procedure.published).to be_truthy
+ expect(procedure.path).to eq(procedure_path)
+ expect(response.status).to eq 200
+ expect(flash[:notice]).to have_content 'Procédure publiée'
+ end
+ end
+
+ context 'procedure path exists and is owned by current administrator' do
+ let(:procedure_path) { procedure2.path }
+
+ it 'publish the given procedure' do
+ expect(procedure.published).to be_truthy
+ expect(procedure.path).to eq(procedure_path)
+ expect(response.status).to eq 200
+ expect(flash[:notice]).to have_content 'Procédure publiée'
+ end
+
+ it 'archive previous procedure' do
+ expect(procedure2.published).to be_truthy
+ expect(procedure2.archived).to be_truthy
+ expect(procedure2.path).to be_nil
+ end
+ end
+
+ context 'procedure path exists and is not owned by current administrator' do
+ let(:procedure_path) { procedure3.path }
+
+ it 'does not publish the given procedure' do
+ expect(procedure.published).to be_falsey
+ expect(procedure.path).to be_nil
+ expect(response.status).to eq 200
+ end
+
+ it 'previous procedure remains published' do
+ expect(procedure2.published).to be_truthy
+ expect(procedure2.archived).to be_falsey
+ expect(procedure2.path).to match(/fake_path/)
+ end
+ end
+
+ context 'procedure path is invalid' do
+ let(:procedure_path) { 'Invalid Procedure Path' }
+
+ it 'does not publish the given procedure' do
+ expect(procedure.published).to be_falsey
+ expect(procedure.path).to be_nil
+ expect(response).to redirect_to :admin_procedures
+ expect(flash[:alert]).to have_content 'Lien de la procédure invalide'
+ end
+ end
+ end
+
+ context 'when admin is not the owner of the procedure' do
+ let(:admin_2) { create(:administrateur) }
+
+ before do
+ sign_out admin
+ sign_in admin_2
+
+ put :publish, procedure_id: procedure.id, procedure_path: 'fake_path'
+ procedure.reload
+ end
+
+ it 'fails' do
+ expect(response).to redirect_to :admin_procedures
+ expect(flash[:alert]).to have_content 'Procédure inéxistante'
+ end
+ end
+ end
+
describe 'PUT #archive' do
let(:procedure) { create(:procedure, administrateur: admin) }
context 'when admin is the owner of the procedure' do
before do
- put :archive, procedure_id: procedure.id, archive: archive
+ put :archive, procedure_id: procedure.id
procedure.reload
end
context 'when owner want archive procedure' do
-
- let(:archive) { true }
-
it { expect(procedure.archived).to be_truthy }
it { expect(response).to redirect_to :admin_procedures }
- it { expect(flash[:notice]).to have_content 'Procédure éditée' }
+ it { expect(flash[:notice]).to have_content 'Procédure archivée' }
end
- context 'when owner want reactive procedure' do
-
- let(:archive) { false }
+ context 'when owner want to re-enable procedure' do
+ before do
+ put :publish, procedure_id: procedure.id, procedure_path: 'fake_path'
+ procedure.reload
+ end
it { expect(procedure.archived).to be_falsey }
- it { expect(response).to redirect_to :admin_procedures }
- it { expect(flash[:notice]).to have_content 'Procédure éditée' }
+ it { expect(response.status).to eq 200 }
+ it { expect(flash[:notice]).to have_content 'Procédure publiée' }
end
end
@@ -337,4 +422,60 @@ describe Admin::ProceduresController, type: :controller do
it { expect(flash[:alert]).to have_content 'Procédure inéxistante' }
end
end
+
+ describe 'GET #path_list' do
+ let!(:procedure) { create(:procedure, :published, administrateur: admin) }
+ let(:admin2) { create(:administrateur) }
+ let!(:procedure2) { create(:procedure, :published, administrateur: admin2) }
+ subject { get :path_list }
+ let(:body) { JSON.parse(response.body) }
+
+ before do
+ subject
+ end
+
+ it { expect(response.status).to eq(200) }
+ it { expect(body.size).to eq(2) }
+ it { expect(body.first['label']).to eq(procedure.path) }
+ it { expect(body.first['mine']).to be_truthy }
+ it { expect(body.second['label']).to eq(procedure2.path) }
+ it { expect(body.second['mine']).to be_falsy }
+
+ context 'filtered' do
+ subject { get :path_list, request: procedure2.path }
+
+ it { expect(response.status).to eq(200) }
+ it { expect(body.size).to eq(1) }
+ it { expect(body.first['label']).to eq(procedure2.path) }
+ it { expect(body.first['mine']).to be_falsy }
+ end
+ end
+
+ describe 'POST transfer' do
+ let!(:procedure) { create :procedure, administrateur: admin }
+
+ subject { post :transfer, email_admin: email_admin, procedure_id: procedure.id }
+
+ context 'when admin is unknow' do
+ let(:email_admin) { 'plop' }
+
+ it { expect(subject.status).to eq 404 }
+ end
+
+ context 'when admin is know' do
+ let(:new_admin) { create :administrateur, email: 'new_admin@admin.com' }
+ let(:email_admin) { new_admin.email }
+
+ it { expect(subject.status).to eq 200 }
+ it { expect {subject}.to change(Procedure, :count).by(1) }
+
+ context {
+ before do
+ subject
+ end
+
+ it { expect(Procedure.last.administrateur).to eq new_admin }
+ }
+ end
+ end
end
diff --git a/spec/controllers/api/v1/dossiers_controller_spec.rb b/spec/controllers/api/v1/dossiers_controller_spec.rb
index 83518f772..6ff404ec4 100644
--- a/spec/controllers/api/v1/dossiers_controller_spec.rb
+++ b/spec/controllers/api/v1/dossiers_controller_spec.rb
@@ -52,9 +52,8 @@ describe API::V1::DossiersController do
describe 'dossier' do
subject { super().first }
it { expect(subject[:id]).to eq(dossier.id) }
- it { expect(subject[:nom_projet]).to eq(dossier.nom_projet) }
it { expect(subject[:updated_at]).to eq("2008-09-01T08:05:00.000Z") }
- it { expect(subject.keys.size).to eq(3) }
+ it { expect(subject.keys.size).to eq(2) }
end
end
@@ -116,18 +115,19 @@ describe API::V1::DossiersController do
let!(:dossier) { Timecop.freeze(date_creation) { create(:dossier, :with_entreprise, procedure: procedure) } }
let(:dossier_id) { dossier.id }
let(:body) { JSON.parse(retour.body, symbolize_names: true) }
- let(:field_list) { [:id, :nom_projet, :created_at, :updated_at, :archived, :mandataire_social, :entreprise, :etablissement, :cerfa, :types_de_piece_justificative, :pieces_justificatives, :champs, :commentaires] }
+ let(:field_list) { [:id, :created_at, :updated_at, :archived, :mandataire_social, :total_commentaire, :entreprise, :etablissement, :cerfa, :types_de_piece_justificative, :pieces_justificatives, :champs, :commentaires, :state] }
subject { body[:dossier] }
it 'return REST code 200', :show_in_doc do
expect(retour.code).to eq('200')
end
it { expect(subject[:id]).to eq(dossier.id) }
- it { expect(subject[:nom_projet]).to eq(dossier.nom_projet) }
+ it { expect(subject[:state]).to eq(dossier.state) }
it { expect(subject[:created_at]).to eq('2008-09-01T08:05:00.000Z') }
it { expect(subject[:updated_at]).to eq('2008-09-01T08:05:00.000Z') }
it { expect(subject[:archived]).to eq(dossier.archived) }
it { expect(subject[:mandataire_social]).to eq(dossier.mandataire_social) }
+ it { expect(subject[:total_commentaire]).to eq(dossier.total_commentaire) }
it { expect(subject.keys).to match_array(field_list) }
@@ -230,7 +230,7 @@ describe API::V1::DossiersController do
it { expect(subject[:libelle]).to eq('Description') }
it { expect(subject[:description]).to eq('description de votre projet') }
it { expect(subject.keys.include?(:order_place)).to be_truthy }
- it { expect(subject[:type]).to eq('textarea') }
+ it { expect(subject[:type]).to eq('text') }
end
end
end
diff --git a/spec/controllers/api/v1/procedures_controller_spec.rb b/spec/controllers/api/v1/procedures_controller_spec.rb
index a4134720a..f478cd5db 100644
--- a/spec/controllers/api/v1/procedures_controller_spec.rb
+++ b/spec/controllers/api/v1/procedures_controller_spec.rb
@@ -35,6 +35,7 @@ describe API::V1::ProceduresController do
it { expect(subject[:direction]).to eq(procedure.direction) }
it { expect(subject[:link]).to eq(procedure.lien_demarche) }
it { expect(subject[:archived]).to eq(procedure.archived) }
+ it { expect(subject[:total_dossier]).to eq(procedure.total_dossier) }
it { is_expected.to have_key(:types_de_champ) }
it { expect(subject[:types_de_champ]).to be_an(Array) }
describe 'type_de_champ' do
diff --git a/spec/controllers/backoffice/commentaires_controller_spec.rb b/spec/controllers/backoffice/commentaires_controller_spec.rb
index a85f0cc99..231f12c69 100644
--- a/spec/controllers/backoffice/commentaires_controller_spec.rb
+++ b/spec/controllers/backoffice/commentaires_controller_spec.rb
@@ -5,6 +5,7 @@ describe Backoffice::CommentairesController, type: :controller do
let(:dossier_id) { dossier.id }
let(:email_commentaire) { 'test@test.com' }
let(:texte_commentaire) { 'Commentaire de test' }
+ let(:gestionnaire) { create(:gestionnaire) }
before do
allow(ClamavService).to receive(:safe_file?).and_return(true)
@@ -12,16 +13,32 @@ describe Backoffice::CommentairesController, type: :controller do
describe '#POST create' do
before do
- sign_in create(:gestionnaire)
+ sign_in gestionnaire
end
+
context "création correct d'un commentaire" do
+ subject { post :create, dossier_id: dossier_id, email_commentaire: email_commentaire, texte_commentaire: texte_commentaire }
+
it 'depuis la page admin' do
- post :create, dossier_id: dossier_id, email_commentaire: email_commentaire, texte_commentaire: texte_commentaire
- expect(response).to redirect_to("/backoffice/dossiers/#{dossier_id}")
+ expect(subject).to redirect_to("/backoffice/dossiers/#{dossier_id}")
+ end
+
+ it 'gestionnaire is automatically affect to follow the dossier' do
+ expect { subject }.to change(Follow, :count).by(1)
+ end
+
+ context 'when gestionnaire already follow dossier' do
+ before do
+ create :follow, gestionnaire_id: gestionnaire.id, dossier_id: dossier_id
+ end
+
+ it 'gestionnaire is automatically affect to follow the dossier' do
+ expect { subject }.to change(Follow, :count).by(0)
+ end
end
end
- context 'when document is upload whith a commentaire', vcr: { cassette_name: 'controllers_backoffice_commentaires_controller_doc_upload_with_comment' } do
+ context 'when document is upload whith a commentaire', vcr: {cassette_name: 'controllers_backoffice_commentaires_controller_doc_upload_with_comment'} do
let(:document_upload) { Rack::Test::UploadedFile.new("./spec/support/files/piece_justificative_0.pdf", 'application/pdf') }
subject do
@@ -80,7 +97,7 @@ describe Backoffice::CommentairesController, type: :controller do
subject { dossier.state }
- it {is_expected.to eq('replied')}
+ it { is_expected.to eq('replied') }
it 'Notification email is send' do
expect(NotificationMailer).to receive(:new_answer).and_return(NotificationMailer)
diff --git a/spec/controllers/backoffice/dossiers_controller_spec.rb b/spec/controllers/backoffice/dossiers_controller_spec.rb
index 895c0e4a5..19d5c280b 100644
--- a/spec/controllers/backoffice/dossiers_controller_spec.rb
+++ b/spec/controllers/backoffice/dossiers_controller_spec.rb
@@ -1,8 +1,12 @@
require 'rails_helper'
describe Backoffice::DossiersController, type: :controller do
+ before do
+ @request.env['HTTP_REFERER'] = TPS::Application::URL
+ end
+
let(:dossier) { create(:dossier, :with_entreprise) }
- let(:dossier_archived) { create(:dossier, :with_entreprise, archived: true) }
+ let(:dossier_archived) { create(:dossier, :with_entreprise, archived: true) }
let(:dossier_id) { dossier.id }
let(:bad_dossier_id) { Dossier.count + 10 }
@@ -128,4 +132,31 @@ describe Backoffice::DossiersController, type: :controller do
expect(dossier.state).to eq('closed')
end
end
+
+ describe 'PUT #toggle_follow' do
+ before do
+ sign_in gestionnaire
+ end
+
+ subject { put :follow, dossier_id: dossier_id }
+
+ it { expect(subject.status).to eq 302 }
+
+ describe 'flash alert' do
+ context 'when dossier is not follow by gestionnaire' do
+ before do
+ subject
+ end
+ it { expect(flash[:notice]).to have_content 'Dossier suivi' }
+ end
+
+ context 'when dossier is follow by gestionnaire' do
+ before do
+ create :follow, gestionnaire_id: gestionnaire.id, dossier_id: dossier.id
+ subject
+ end
+ it { expect(flash[:notice]).to have_content 'Dossier relaché' }
+ end
+ end
+ end
end
diff --git a/spec/controllers/users/description_controller_spec.rb b/spec/controllers/users/description_controller_spec.rb
index bcf08bcbb..58d0f9f2a 100644
--- a/spec/controllers/users/description_controller_spec.rb
+++ b/spec/controllers/users/description_controller_spec.rb
@@ -63,14 +63,13 @@ describe Users::DescriptionController, type: :controller, vcr: {cassette_name: '
describe 'POST #create' do
let(:timestamp) { Time.now }
- let(:nom_projet) { 'Projet de test' }
let(:description) { 'Description de test Coucou, je suis un saut à la ligne Je suis un double saut la ligne.' }
context 'Tous les attributs sont bons' do
describe 'Premier enregistrement des données' do
before do
dossier.draft!
- post :create, dossier_id: dossier_id, nom_projet: nom_projet
+ post :create, dossier_id: dossier_id
dossier.reload
end
@@ -78,8 +77,6 @@ describe Users::DescriptionController, type: :controller, vcr: {cassette_name: '
expect(response).to redirect_to("/users/dossiers/#{dossier_id}/recapitulatif")
end
- it { expect(dossier.nom_projet).to eq nom_projet }
-
it 'etat du dossier est soumis' do
expect(dossier.state).to eq('initiated')
end
@@ -88,7 +85,7 @@ describe Users::DescriptionController, type: :controller, vcr: {cassette_name: '
context 'En train de manipuler un dossier non brouillon' do
before do
dossier.initiated!
- post :create, dossier_id: dossier_id, nom_projet: nom_projet, description: description
+ post :create, dossier_id: dossier_id
dossier.reload
end
@@ -102,28 +99,10 @@ describe Users::DescriptionController, type: :controller, vcr: {cassette_name: '
end
end
- context 'Attribut(s) manquant(s)' do
- subject {
- post :create,
- dossier_id: dossier_id,
- nom_projet: nom_projet,
- description: description
- }
- before { subject }
-
- context 'nom_projet empty' do
- let(:nom_projet) { '' }
- it { is_expected.to render_template(:show) }
- it { expect(flash[:alert]).to be_present }
- end
- end
-
context 'Quand la procédure accepte les CERFA' do
context 'Sauvegarde du CERFA PDF', vcr: {cassette_name: 'controllers_users_description_controller_save_cerfa'} do
before do
post :create, dossier_id: dossier_id,
- nom_projet: nom_projet,
- description: description,
cerfa_pdf: cerfa_pdf
dossier.reload
end
@@ -150,7 +129,7 @@ describe Users::DescriptionController, type: :controller, vcr: {cassette_name: '
let(:cerfas) { Cerfa.where(dossier_id: dossier_id) }
before do
- post :create, dossier_id: dossier_id, nom_projet: nom_projet, description: description, cerfa_pdf: cerfa_pdf
+ post :create, dossier_id: dossier_id, cerfa_pdf: cerfa_pdf
end
it "il y a deux CERFA PDF pour ce dossier" do
@@ -165,8 +144,6 @@ describe Users::DescriptionController, type: :controller, vcr: {cassette_name: '
let!(:procedure) { create(:procedure) }
before do
post :create, dossier_id: dossier_id,
- nom_projet: nom_projet,
- description: description,
cerfa_pdf: cerfa_pdf
dossier.reload
end
@@ -186,8 +163,6 @@ describe Users::DescriptionController, type: :controller, vcr: {cassette_name: '
before do
post :create, {dossier_id: dossier_id,
- nom_projet: nom_projet,
- description: description,
champs: {
"'#{dossier.champs.first.id}'" => dossier_champs_first,
"'#{dossier.champs.second.id}'" => dossier_date_value
@@ -228,8 +203,6 @@ describe Users::DescriptionController, type: :controller, vcr: {cassette_name: '
let(:all_pj_type) { dossier.procedure.type_de_piece_justificative_ids }
before do
post :create, {dossier_id: dossier_id,
- nom_projet: nom_projet,
- description: description,
'piece_justificative_'+all_pj_type[0].to_s => piece_justificative_0,
'piece_justificative_'+all_pj_type[1].to_s => piece_justificative_1}
dossier.reload
@@ -240,8 +213,6 @@ describe Users::DescriptionController, type: :controller, vcr: {cassette_name: '
expect(ClamavService).to receive(:safe_file?).twice
post :create, {dossier_id: dossier_id,
- nom_projet: nom_projet,
- description: description,
'piece_justificative_'+all_pj_type[0].to_s => piece_justificative_0,
'piece_justificative_'+all_pj_type[1].to_s => piece_justificative_1}
end
diff --git a/spec/controllers/users/dossiers_controller_spec.rb b/spec/controllers/users/dossiers_controller_spec.rb
index 4514cf689..8234c3668 100644
--- a/spec/controllers/users/dossiers_controller_spec.rb
+++ b/spec/controllers/users/dossiers_controller_spec.rb
@@ -152,16 +152,25 @@ describe Users::DossiersController, type: :controller do
end
end
+ describe 'GET #commencer' do
+ subject { get :commencer, procedure_path: procedure.path }
+
+ it { expect(subject.status).to eq 302 }
+ it { expect(subject).to redirect_to new_users_dossier_path(procedure_id: procedure.id) }
+ end
+
describe 'POST #siret_informations' do
+ let(:user) { create(:user) }
+
before do
stub_request(:get, "https://api-dev.apientreprise.fr/v2/etablissements/#{siret_not_found}?token=#{SIADETOKEN}")
.to_return(status: 404, body: 'fake body')
stub_request(:get, "https://api-dev.apientreprise.fr/v2/etablissements/#{siret}?token=#{SIADETOKEN}")
- .to_return(status: 200, body: File.read('spec/support/files/etablissement.json'))
+ .to_return(status: status_entreprise_call, body: File.read('spec/support/files/etablissement.json'))
stub_request(:get, "https://api-dev.apientreprise.fr/v2/entreprises/#{siren}?token=#{SIADETOKEN}")
- .to_return(status: 200, body: File.read('spec/support/files/entreprise.json'))
+ .to_return(status: status_entreprise_call, body: File.read('spec/support/files/entreprise.json'))
stub_request(:get, "https://api-dev.apientreprise.fr/v1/etablissements/exercices/#{siret}?token=#{SIADETOKEN}")
.to_return(status: exercices_status, body: exercices_body)
@@ -173,8 +182,7 @@ describe Users::DossiersController, type: :controller do
end
describe 'dossier attributs' do
- let(:user) { create(:user) }
-
+ let(:status_entreprise_call) { 200 }
shared_examples 'with valid siret' do
before do
sign_in user
@@ -315,6 +323,20 @@ describe Users::DossiersController, type: :controller do
it { expect(response.to_a[2]).to be_an_instance_of ActionDispatch::Response::RackBody }
end
end
+
+ context 'when REST error 400 is return' do
+ let(:status_entreprise_call) { 400 }
+
+ subject { post :siret_informations, dossier_id: dossier.id, dossier: {siret: siret} }
+
+ before do
+ sign_in user
+ subject
+ end
+
+ it { expect(response.status).to eq 200 }
+
+ end
end
describe 'PUT #update' do
diff --git a/spec/decorators/procedure_decorator_spec.rb b/spec/decorators/procedure_decorator_spec.rb
new file mode 100644
index 000000000..c730f7c84
--- /dev/null
+++ b/spec/decorators/procedure_decorator_spec.rb
@@ -0,0 +1,29 @@
+require 'spec_helper'
+
+describe ProcedureDecorator do
+ let(:procedure) { create(:procedure, :published, created_at: Time.new(2015, 12, 24, 14, 10)) }
+ subject { procedure.decorate }
+
+ describe 'lien' do
+ subject { super().lien }
+ it { is_expected.to match(/fake_path/) }
+ end
+
+ describe 'created_at_fr' do
+ subject { super().created_at_fr }
+ it { is_expected.to eq('24/12/2015 14:10') }
+ end
+
+ describe 'logo_img' do
+ subject { super().logo_img }
+ it { is_expected.to eq('logo-tps.png') }
+ end
+
+ describe 'geographic_information' do
+ subject { super().geographic_information }
+ it { expect(subject.use_api_carto).to be_falsey }
+ it { expect(subject.quartiers_prioritaires).to be_falsey }
+ it { expect(subject.cadastre).to be_falsey }
+ end
+
+end
\ No newline at end of file
diff --git a/spec/factories/dossier.rb b/spec/factories/dossier.rb
index 3919ecccd..e3f1e3490 100644
--- a/spec/factories/dossier.rb
+++ b/spec/factories/dossier.rb
@@ -1,6 +1,5 @@
FactoryGirl.define do
factory :dossier do
- nom_projet "Demande de subvention dans le cadre d'accompagnement d'enfant à l'étranger"
state 'draft'
association :user, factory: [:user]
diff --git a/spec/factories/follow.rb b/spec/factories/follow.rb
new file mode 100644
index 000000000..9db1f67ce
--- /dev/null
+++ b/spec/factories/follow.rb
@@ -0,0 +1,4 @@
+FactoryGirl.define do
+ factory :follow do
+ end
+end
diff --git a/spec/factories/procedure.rb b/spec/factories/procedure.rb
index 376180656..d8d5dc8c1 100644
--- a/spec/factories/procedure.rb
+++ b/spec/factories/procedure.rb
@@ -1,4 +1,5 @@
FactoryGirl.define do
+ sequence(:published_path) { |n| "fake_path#{n}" }
factory :procedure do
lien_demarche 'http://localhost'
libelle 'Demande de subvention'
@@ -6,6 +7,7 @@ FactoryGirl.define do
organisation "Orga SGMAP"
direction "direction SGMAP"
published false
+ administrateur { create(:administrateur) }
after(:build) do |procedure, _evaluator|
if procedure.module_api_carto.nil?
@@ -55,8 +57,8 @@ FactoryGirl.define do
end
trait :published do
- after(:build) do |procedure, _evaluator|
- procedure.published = true
+ after(:create) do |procedure, _evaluator|
+ procedure.publish!(generate(:published_path))
end
end
end
diff --git a/spec/factories/procedure_path.rb b/spec/factories/procedure_path.rb
new file mode 100644
index 000000000..4620abe6e
--- /dev/null
+++ b/spec/factories/procedure_path.rb
@@ -0,0 +1,5 @@
+FactoryGirl.define do
+ factory :procedure_path do
+ path 'fake_path'
+ end
+end
diff --git a/spec/factories/type_de_champ.rb b/spec/factories/type_de_champ.rb
index 2b26e9ca0..8e348a254 100644
--- a/spec/factories/type_de_champ.rb
+++ b/spec/factories/type_de_champ.rb
@@ -2,7 +2,7 @@ FactoryGirl.define do
factory :type_de_champ do
libelle 'Description'
description 'description de votre projet'
- type_champ 'textarea'
+ type_champ 'text'
order_place 1
mandatory false
end
diff --git a/spec/features/backoffice/navigate_to_dossier_spec.rb b/spec/features/backoffice/navigate_to_dossier_spec.rb
index 41d0944f6..4a3664a99 100644
--- a/spec/features/backoffice/navigate_to_dossier_spec.rb
+++ b/spec/features/backoffice/navigate_to_dossier_spec.rb
@@ -5,7 +5,7 @@ feature 'on backoffice page' do
let(:gestionnaire) { create(:gestionnaire, administrateurs: [administrateur]) }
let(:procedure) { create(:procedure, administrateur: administrateur) }
- let!(:dossier) { create(:dossier, :with_entreprise, procedure: procedure, state: 'initiated') }
+ let!(:dossier) { create(:dossier, :with_entreprise, procedure: procedure, state: 'initiated') }
before do
create :assign_to, gestionnaire: gestionnaire, procedure: procedure
@@ -20,7 +20,7 @@ feature 'on backoffice page' do
end
context 'when he click on first dossier' do
before do
- page.click_on dossier.nom_projet
+ page.click_on dossier.entreprise.raison_sociale
end
scenario 'it redirect to dossier page' do
expect(page).to have_css('#backoffice_dossier_show')
diff --git a/spec/features/backoffice/search_file_spec.rb b/spec/features/backoffice/search_file_spec.rb
index 8d0bb38df..d0db942d7 100644
--- a/spec/features/backoffice/search_file_spec.rb
+++ b/spec/features/backoffice/search_file_spec.rb
@@ -40,13 +40,11 @@ feature 'search file on gestionnaire backoffice' do
context 'when terms input does return result' do
let!(:dossier) { create(:dossier, :with_entreprise, procedure: procedure, state: 'initiated') }
- let!(:dossier_2) { create(:dossier, procedure: procedure, state: 'initiated', nom_projet: 'Projet de test') }
+ let!(:dossier_2) { create(:dossier, procedure: procedure, state: 'initiated') }
- let(:terms) { dossier.nom_projet }
+ let(:terms) { dossier.entreprise.raison_sociale }
- it { expect(page).not_to have_content('Projet de test') }
-
- it { expect(page).to have_content(dossier.nom_projet) }
+ it { expect(page).to have_content(dossier.entreprise.raison_sociale) }
context "when terms is a file's id" do
let(:terms) { dossier.id }
diff --git a/spec/features/description_page/upload_piece_justificative_spec.rb b/spec/features/description_page/upload_piece_justificative_spec.rb
index 89b14e15a..09f97734d 100644
--- a/spec/features/description_page/upload_piece_justificative_spec.rb
+++ b/spec/features/description_page/upload_piece_justificative_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
feature 'user is on description page' do
- let!(:procedure) { create(:procedure, :with_two_type_de_piece_justificative, cerfa_flag: true) }
+ let!(:procedure) { create(:procedure, :with_two_type_de_piece_justificative, :with_type_de_champ, cerfa_flag: true) }
let!(:dossier) { create(:dossier, :with_entreprise, procedure: procedure) }
before do
@@ -21,7 +21,7 @@ feature 'user is on description page' do
context 'he fill description fields' do
before do
- find_by_id('nom_projet').set 'mon nom'
+ find_by_id("champs_#{dossier.champs.first.id}").set 'mon nom'
end
context 'before submit' do
it 'dossier cerfa is empty' do
diff --git a/spec/features/users/complete_demande_spec.rb b/spec/features/users/complete_demande_spec.rb
index c028bd2a2..61f071c0c 100644
--- a/spec/features/users/complete_demande_spec.rb
+++ b/spec/features/users/complete_demande_spec.rb
@@ -2,17 +2,19 @@ require 'spec_helper'
feature 'user path for dossier creation' do
let(:user) { create(:user) }
- let(:procedure) { create(:procedure, :published) }
+ let(:procedure) { create(:procedure, :published, :with_type_de_champ) }
let(:siret) { '53272417600013' }
let(:siren) { siret[0...9] }
context 'user arrives on siret page', js: true do
before do
- visit new_users_dossiers_path(procedure_id: procedure.id)
+ visit commencer_path(procedure_path: procedure.path)
end
scenario 'he is redirected on login page' do
expect(page).to have_css('#login_user')
+ expect(page).to have_css('#logo_procedure')
+ expect(page).to have_css('#titre_procedure')
end
context 'user sign_in' do
@@ -66,7 +68,7 @@ feature 'user path for dossier creation' do
end
context 'user fill and validate description page' do
before do
- page.find_by_id('nom_projet').set 'Mon super projet'
+ page.find_by_id("champs_#{Dossier.last.champs.first.id}").set 'Mon super projet'
page.click_on 'Soumettre mon dossier'
end
scenario 'user is on recap page' do
diff --git a/spec/features/users/list_dossiers_spec.rb b/spec/features/users/list_dossiers_spec.rb
index e9867fe61..22d0c1060 100644
--- a/spec/features/users/list_dossiers_spec.rb
+++ b/spec/features/users/list_dossiers_spec.rb
@@ -3,12 +3,15 @@ require 'spec_helper'
feature 'user access to the list of his dossier' do
let(:user) { create(:user) }
- let!(:last_updated_dossier) { create(:dossier, user: user, state: 'replied')}
- let!(:dossier1) { create(:dossier, user: user, nom_projet: 'mon permier dossier', state: 'replied') }
- let!(:dossier2) { create(:dossier, nom_projet: 'mon deuxième dossier') }
+ let!(:last_updated_dossier) { create(:dossier, :with_entreprise, user: user, state: 'replied')}
+ let!(:dossier1) { create(:dossier, :with_entreprise, user: user, state: 'replied') }
+ let!(:dossier2) { create(:dossier, :with_entreprise) }
before do
- last_updated_dossier.update_attributes(nom_projet: 'salut la compagnie')
+ dossier1.update_column(:updated_at, "19/07/2016 15:35".to_time)
+ dossier1.entreprise.update_column(:raison_sociale, 'PLOP')
+ last_updated_dossier.entreprise.update_column(:raison_sociale, 'PLIP')
+
visit new_user_session_path
within('#new_user') do
page.find_by_id('user_email').set user.email
@@ -17,12 +20,12 @@ feature 'user access to the list of his dossier' do
end
end
scenario 'the list of dossier is displayed' do
- expect(page).to have_content(dossier1.nom_projet)
- expect(page).not_to have_content(dossier2.nom_projet)
+ expect(page).to have_content(dossier1.entreprise.raison_sociale)
+ expect(page).not_to have_content(dossier2.entreprise.raison_sociale)
end
scenario 'the list must be order by last updated' do
- expect(page.body).to match(/#{last_updated_dossier.nom_projet}.*#{dossier1.nom_projet}/m)
+ expect(page.body).to match(/#{last_updated_dossier.entreprise.raison_sociale}.*#{dossier1.entreprise.raison_sociale}/m)
end
scenario 'the state of dossier is displayed' do
@@ -31,7 +34,7 @@ feature 'user access to the list of his dossier' do
context 'when user clicks on a projet in list' do
before do
- page.click_on dossier1.nom_projet
+ page.click_on dossier1.entreprise.raison_sociale
end
scenario 'user is redirected to dossier page' do
expect(page).to have_css('#recap_dossier')
diff --git a/spec/fixtures/cassettes/admin_procedure_edit.yml b/spec/fixtures/cassettes/admin_procedure_edit.yml
new file mode 100644
index 000000000..a4f8431cf
--- /dev/null
+++ b/spec/fixtures/cassettes/admin_procedure_edit.yml
@@ -0,0 +1,1344 @@
+---
+http_interactions:
+- request:
+ method: post
+ uri: https://auth.cloud.ovh.net/v2.0/tokens
+ body:
+ encoding: UTF-8
+ string: '{"auth":{"passwordCredentials":{"username":"ovh_fake_username","password":"ovh_fake_password"},"tenantName":"ovh_fake_tenant_name"}}'
+ headers:
+ User-Agent:
+ - fog/1.38.0 fog-core/1.38.0
+ Content-Type:
+ - application/json
+ response:
+ status:
+ code: 200
+ message: ''
+ headers:
+ Vary:
+ - X-Auth-Token
+ Content-Type:
+ - application/json
+ Content-Length:
+ - '7079'
+ Date:
+ - Thu, 12 May 2016 14:05:17 GMT
+ Connection:
+ - close
+ body:
+ encoding: UTF-8
+ string: '{"access": {"token": {"issued_at": "2016-05-12T14:05:17.214079", "expires":
+ "2016-05-13T14:05:17Z", "id": "ff665d4700654b6d9c94964dfc1a262f", "tenant":
+ {"id": "a24c37ed11a84896914514384898c34b", "enabled": true, "name": "2627898119540674",
+ "description": "apientreprise"}, "audit_ids": ["Y2ixVCRJQe-D6IN-cPQQsw"]},
+ "serviceCatalog": [{"endpoints": [{"adminURL": "https://compute.gra1.cloud.ovh.net/v2/a24c37ed11a84896914514384898c34b",
+ "region": "GRA1", "internalURL": "https://compute.gra1.cloud.ovh.net/v2/a24c37ed11a84896914514384898c34b",
+ "id": "17f6ef1cc63e492ab8d3f2bda8428cb0", "publicURL": "https://compute.gra1.cloud.ovh.net/v2/a24c37ed11a84896914514384898c34b"},
+ {"adminURL": "https://compute.bhs1.cloud.ovh.net/v2/a24c37ed11a84896914514384898c34b",
+ "region": "BHS1", "internalURL": "https://compute.bhs1.cloud.ovh.net/v2/a24c37ed11a84896914514384898c34b",
+ "id": "21fdd202afd04470bbaf84f9396d0dcc", "publicURL": "https://compute.bhs1.cloud.ovh.net/v2/a24c37ed11a84896914514384898c34b"},
+ {"adminURL": "https://compute.sbg1.cloud.ovh.net/v2/a24c37ed11a84896914514384898c34b",
+ "region": "SBG1", "internalURL": "https://compute.sbg1.cloud.ovh.net/v2/a24c37ed11a84896914514384898c34b",
+ "id": "a707bffedf1c4b80a124c585c67c1639", "publicURL": "https://compute.sbg1.cloud.ovh.net/v2/a24c37ed11a84896914514384898c34b"}],
+ "endpoints_links": [], "type": "compute", "name": "nova"}, {"endpoints": [{"adminURL":
+ "https://network.compute.gra1.cloud.ovh.net/", "region": "GRA1", "internalURL":
+ "https://network.compute.gra1.cloud.ovh.net/", "id": "26a339a8c7d5463f89ca937068ebbcd4",
+ "publicURL": "https://network.compute.gra1.cloud.ovh.net/"}, {"adminURL":
+ "https://network.compute.bhs1.cloud.ovh.net/", "region": "BHS1", "internalURL":
+ "https://network.compute.bhs1.cloud.ovh.net/", "id": "3fe2326789ec4e37af2e6b2c80a90876",
+ "publicURL": "https://network.compute.bhs1.cloud.ovh.net/"}, {"adminURL":
+ "https://network.compute.sbg1.cloud.ovh.net/", "region": "SBG1", "internalURL":
+ "https://network.compute.sbg1.cloud.ovh.net/", "id": "075839111e7a41f1bb458926e5f04cec",
+ "publicURL": "https://network.compute.sbg1.cloud.ovh.net/"}], "endpoints_links":
+ [], "type": "network", "name": "neutron"}, {"endpoints": [{"adminURL": "https://volume.compute.gra1.cloud.ovh.net/v2/a24c37ed11a84896914514384898c34b",
+ "region": "GRA1", "internalURL": "https://volume.compute.gra1.cloud.ovh.net/v2/a24c37ed11a84896914514384898c34b",
+ "id": "7231957fdf0346e5adebe860ac5e5e57", "publicURL": "https://volume.compute.gra1.cloud.ovh.net/v2/a24c37ed11a84896914514384898c34b"},
+ {"adminURL": "https://volume.compute.bhs1.cloud.ovh.net/v2/a24c37ed11a84896914514384898c34b",
+ "region": "BHS1", "internalURL": "https://volume.compute.bhs1.cloud.ovh.net/v2/a24c37ed11a84896914514384898c34b",
+ "id": "2f5b68f95d7b4b1fad1a683dac8e8ca3", "publicURL": "https://volume.compute.bhs1.cloud.ovh.net/v2/a24c37ed11a84896914514384898c34b"},
+ {"adminURL": "https://volume.compute.sbg1.cloud.ovh.net/v2/a24c37ed11a84896914514384898c34b",
+ "region": "SBG1", "internalURL": "https://volume.compute.sbg1.cloud.ovh.net/v2/a24c37ed11a84896914514384898c34b",
+ "id": "021b61bd7313479e8f8d77d21c7b434a", "publicURL": "https://volume.compute.sbg1.cloud.ovh.net/v2/a24c37ed11a84896914514384898c34b"}],
+ "endpoints_links": [], "type": "volumev2", "name": "cinderv2"}, {"endpoints":
+ [{"adminURL": "https://image.compute.gra1.cloud.ovh.net/", "region": "GRA1",
+ "internalURL": "https://image.compute.gra1.cloud.ovh.net/", "id": "56795c82f1744e47b7782f1fc2407212",
+ "publicURL": "https://image.compute.gra1.cloud.ovh.net/"}, {"adminURL": "https://image.compute.bhs1.cloud.ovh.net/",
+ "region": "BHS1", "internalURL": "https://image.compute.bhs1.cloud.ovh.net/",
+ "id": "5eaa4cbe80354ea482f2b0477c9c16f0", "publicURL": "https://image.compute.bhs1.cloud.ovh.net/"},
+ {"adminURL": "https://image.compute.sbg1.cloud.ovh.net/", "region": "SBG1",
+ "internalURL": "https://image.compute.sbg1.cloud.ovh.net/", "id": "15758b246d1340e887a2170bd3399071",
+ "publicURL": "https://image.compute.sbg1.cloud.ovh.net/"}], "endpoints_links":
+ [], "type": "image", "name": "glance"}, {"endpoints": [{"adminURL": "https://volume.compute.gra1.cloud.ovh.net/v1/a24c37ed11a84896914514384898c34b",
+ "region": "GRA1", "internalURL": "https://volume.compute.gra1.cloud.ovh.net/v1/a24c37ed11a84896914514384898c34b",
+ "id": "a6936c8876c1490cbf91d0707e78d350", "publicURL": "https://volume.compute.gra1.cloud.ovh.net/v1/a24c37ed11a84896914514384898c34b"},
+ {"adminURL": "https://volume.compute.bhs1.cloud.ovh.net/v1/a24c37ed11a84896914514384898c34b",
+ "region": "BHS1", "internalURL": "https://volume.compute.bhs1.cloud.ovh.net/v1/a24c37ed11a84896914514384898c34b",
+ "id": "43bc107cf78448faa9e5a6b3a5ca48dd", "publicURL": "https://volume.compute.bhs1.cloud.ovh.net/v1/a24c37ed11a84896914514384898c34b"},
+ {"adminURL": "https://volume.compute.sbg1.cloud.ovh.net/v1/a24c37ed11a84896914514384898c34b",
+ "region": "SBG1", "internalURL": "https://volume.compute.sbg1.cloud.ovh.net/v1/a24c37ed11a84896914514384898c34b",
+ "id": "2be04ee1ddb148c19e91d3da5934fa55", "publicURL": "https://volume.compute.sbg1.cloud.ovh.net/v1/a24c37ed11a84896914514384898c34b"}],
+ "endpoints_links": [], "type": "volume", "name": "cinder"}, {"endpoints":
+ [{"adminURL": "https://storage.gra1.cloud.ovh.net", "region": "GRA1", "internalURL":
+ "http://127.0.0.1:8888/v1/AUTH_a24c37ed11a84896914514384898c34b", "id": "c96f61d071a74e36bd3c07e53d241ce3",
+ "publicURL": "https://storage.gra1.cloud.ovh.net/v1/AUTH_a24c37ed11a84896914514384898c34b"},
+ {"adminURL": "https://storage.bhs1.cloud.ovh.net:8888/", "region": "BHS1",
+ "internalURL": "http://127.0.0.1:8888/v1/AUTH_a24c37ed11a84896914514384898c34b",
+ "id": "3327534a1a824389aae5d663b9821d67", "publicURL": "https://storage.bhs1.cloud.ovh.net/v1/AUTH_a24c37ed11a84896914514384898c34b"},
+ {"adminURL": "https://storage.sbg1.cloud.ovh.net", "region": "SBG1", "internalURL":
+ "http://127.0.0.1:8888/v1/AUTH_a24c37ed11a84896914514384898c34b", "id": "2af96b87ad484cb7879a9ea554d5418c",
+ "publicURL": "https://storage.sbg1.cloud.ovh.net/v1/AUTH_a24c37ed11a84896914514384898c34b"}],
+ "endpoints_links": [], "type": "object-store", "name": "swift"}, {"endpoints":
+ [{"adminURL": "https://auth.cloud.ovh.net:35357/v2.0", "region": "GRA1", "internalURL":
+ "http://127.0.0.1:5000/v2.0", "id": "62101e498fc3404dbc18ec80888992cb", "publicURL":
+ "https://auth.cloud.ovh.net/v2.0"}, {"adminURL": "https://auth.cloud.ovh.net:35357/v2.0",
+ "region": "BHS1", "internalURL": "http://127.0.0.1:5000/v2.0", "id": "00e403276b3246c4a5c54dc7133f9f0a",
+ "publicURL": "https://auth.cloud.ovh.net/v2.0"}, {"adminURL": "https://auth.cloud.ovh.net:35357/v2.0",
+ "region": "SBG1", "internalURL": "http://127.0.0.1:5000/v2.0", "id": "6094ef2ed9f240ed9b648dfcc0d9f923",
+ "publicURL": "https://auth.cloud.ovh.net/v2.0"}], "endpoints_links": [], "type":
+ "identity", "name": "keystone"}], "user": {"username": "MhsuDbK4DsPr", "roles_links":
+ [], "id": "43914cf4645747ba90d075c62ebb5018", "roles": [{"name": "_member_"}],
+ "name": "MhsuDbK4DsPr"}, "metadata": {"is_admin": 0, "roles": ["9fe2ff9ee4384b1894a90878d3e92bab"]}}}'
+ http_version:
+ recorded_at: Thu, 12 May 2016 14:05:17 GMT
+- request:
+ method: put
+ uri: https://storage.sbg1.cloud.ovh.net/v1/AUTH_a24c37ed11a84896914514384898c34b/tps_dev/procedure-3dbb3535-5388-4a37-bc2d-778327b9f998.png
+ body:
+ encoding: ASCII-8BIT
+ string: !binary |-
+ iVBORw0KGgoAAAANSUhEUgAAATwAAAFgCAYAAAAmScWKAAAKsWlDQ1BJQ0Mg
+ UHJvZmlsZQAASImVlgdUU1kax+976Y2W0FvovQsEkF4DKEgHUQkJJZQYAkFE
+ bMigAiOKiAioAzoIouCoFBkLIoiFQbGBdUAGAWUdLICKyj5gCTu7Z3fPfu98
+ 7/7Ol/u++383757zB4D8jMXnJ8ESACTz0gQBni70sPAIOu53QAQ4QAAagMZi
+ p/Kd/f19ARKL419j6hGA5sb7RnO9/v33/xqSnJhUNgCQP8LRnFR2MsLnkWxn
+ 8wVpAKAykLrGhjT+HFcgTBMgAhE+M8dxC9wxx9EL3D8/JyjAFeFxAPBkFksQ
+ BwDpE1Knp7PjkD5kOYRNeRwuD2EvhB3Y8SwOwrsQNkxOXj/HiAagG/1PfeL+
+ 0jNa1JPFihPxwrvMB96Nm8pPYm38P7fjf0dyknBxDXUkyfECrwBkVED2rCZx
+ vY+IedEr/RaZy5mfP8/xQq/gRWanukYsMofl5rPIwsRg50VmCZae5aYxgxZZ
+ sD5A1J+XtNJX1D+GKeKYVPfARY7lejAXOTM+KHSR07khKxc5NTHQZ2mOq6gu
+ EAaINMcKPETvmJy6pI3NWlorLT7Ia0lDmEgPJ8bNXVTnBYvm89NcRD35Sf5L
+ +pM8RfXU9EDRs2nIB7bICSxv/6U+/qL9ASHAE5gjlwVy0UEgcAcBgInckVXT
+ YjLS5oS7rudvFHDj4tPozsjJiaEzeWxjQ7q5qZklAHPncOFv/tA/f74gGfxS
+ LeEuALaITmjPUo2zCYDmbuRbHFmq6eQDQBkFoLOFLRSkL9TQczcMcsLFAQ3I
+ AxXklOsCI0SpFbADTohCb+AHgkA4WAvYIB4kAwHYALLAdpAL8sFecACUgaPg
+ GKgBp8FZ0AwugqvgOrgN7oKH4CkYAMPgDZgAU2AGgiAcRIGokDykCmlBBpA5
+ xIAcIHfIFwqAwqEoKA7iQUIoC9oB5UNFUBlUCdVCv0AXoKvQTagXegwNQmPQ
+ e+gLjILJMA1WhrVhE5gBO8M+cBC8Bo6DU+BMOAfeA5fCVfApuAm+Ct+GH8ID
+ 8Bt4EgVQJJQMSg1lhGKgXFF+qAhULEqA2oLKQ5WgqlD1qFZUF+o+agA1jvqM
+ xqKpaDraCG2H9kIHo9noFPQWdAG6DF2DbkJ3oO+jB9ET6O8YCkYJY4CxxTAx
+ YZg4zAZMLqYEU41pxHRiHmKGMVNYLFYGq4O1xnphw7EJ2E3YAuxhbAO2DduL
+ HcJO4nA4eZwBzh7nh2Ph0nC5uEO4U7gruHu4YdwnPAmvijfHe+Aj8Dx8Nr4E
+ fxJ/GX8PP4KfIUgQtAi2BD8Ch7CRUEg4Tmgl3CEME2aIkkQdoj0xiJhA3E4s
+ JdYTO4nPiB9IJJI6yYa0isQlbSOVks6QbpAGSZ/JUmR9sis5kiwk7yGfILeR
+ H5M/UCgUbYoTJYKSRtlDqaVco7ygfBKjihmLMcU4YlvFysWaxO6JvRUniGuJ
+ O4uvFc8ULxE/J35HfFyCIKEt4SrBktgiUS5xQaJPYlKSKmkm6SeZLFkgeVLy
+ puSoFE5KW8pdiiOVI3VM6prUEBVF1aC6UtnUHdTj1E7qMA1L06ExaQm0fNpp
+ Wg9tQlpKepl0iHSGdLn0JekBGZSMtgxTJkmmUOaszCOZL7LKss6yMbK7Zetl
+ 78lOyynKOcnFyOXJNcg9lPsiT5d3l0+U3yffLP9cAa2gr7BKYYPCEYVOhXFF
+ mqKdIlsxT/Gs4hMlWElfKUBpk9IxpW6lSWUVZU9lvvIh5WvK4yoyKk4qCSrF
+ KpdVxlSpqg6qXNVi1Suqr+nSdGd6Er2U3kGfUFNS81ITqlWq9ajNqOuoB6tn
+ qzeoP9cgajA0YjWKNdo1JjRVNVdoZmnWaT7RImgxtOK1Dmp1aU1r62iHau/U
+ btYe1ZHTYepk6tTpPNOl6DrqpuhW6T7Qw+ox9BL1Duvd1Yf1LfXj9cv17xjA
+ BlYGXIPDBr2GGEMbQ55hlWGfEdnI2SjdqM5o0FjG2Nc427jZ+K2JpkmEyT6T
+ LpPvppamSabHTZ+aSZl5m2WbtZq9N9c3Z5uXmz+woFh4WGy1aLF4t8xgWcyy
+ I8v6LamWKyx3WrZbfrOythJY1VuNWWtaR1lXWPcxaAx/RgHjhg3GxsVmq81F
+ m8+2VrZptmdt/7Qzsku0O2k3ulxneczy48uH7NXtWfaV9gMOdIcoh58cBhzV
+ HFmOVY4vnTScOE7VTiPOes4Jzqec37qYughcGl2mXW1dN7u2uaHcPN3y3Hrc
+ pdyD3cvcX3ioe8R51HlMeFp6bvJs88J4+Xjt8+pjKjPZzFrmhLe192bvDh+y
+ T6BPmc9LX31fgW/rCniF94r9K56t1FrJW9nsB/yYfvv9nvvr+Kf4/7oKu8p/
+ VfmqVwFmAVkBXYHUwHWBJwOnglyCCoOeBusGC4PbQ8RDIkNqQ6ZD3UKLQgfC
+ TMI2h90OVwjnhrdE4CJCIqojJle7rz6wejjSMjI38tEanTUZa26uVVibtPbS
+ OvF1rHXnojBRoVEno76y/FhVrMloZnRF9ATblX2Q/YbjxCnmjMXYxxTFjMTa
+ xxbFjsbZx+2PG4t3jC+JH+e6csu47xK8Eo4mTCf6JZ5InE0KTWpIxidHJV/g
+ SfESeR3rVdZnrO/lG/Bz+QMptikHUiYEPoLqVCh1TWpLGg0xPN1CXeEPwsF0
+ h/Ty9E8bQjacy5DM4GV0b9TfuHvjSKZH5s+b0JvYm9qz1LK2Zw1udt5cuQXa
+ Er2lfavG1pytw9s8t9VsJ25P3P5btml2UfbHHaE7WnOUc7blDP3g+UNdrliu
+ ILdvp93Oo7vQu7i7enZb7D60+3seJ+9Wvml+Sf7XAnbBrR/Nfiz9cXZP7J6e
+ QqvCI3uxe3l7H+1z3FdTJFmUWTS0f8X+pmJ6cV7xxwPrDtwsWVZy9CDxoPDg
+ QKlvacshzUN7D30tiy97WO5S3lChVLG7Yvow5/C9I05H6o8qH80/+uUn7k/9
+ lZ6VTVXaVSXHsMfSj706HnK862fGz7XVCtX51d9O8E4M1ATUdNRa19aeVDpZ
+ WAfXCevGTkWeunva7XRLvVF9ZYNMQ/4ZcEZ45vUvUb88Outztv0c41z9ea3z
+ FY3UxrwmqGlj00RzfPNAS3hL7wXvC+2tdq2Nvxr/euKi2sXyS9KXCi8TL+dc
+ nr2SeWWyjd82fjXu6lD7uvan18KuPehY1dHT6dN547rH9Wtdzl1XbtjfuHjT
+ 9uaFW4xbzbetbjd1W3Y3/mb5W2OPVU/THes7LXdt7rb2Lu+9fM/x3tX7bvev
+ P2A+uP1w5cPeR8GP+vsi+wb6Of2jj5Mev3uS/mTm6bZnmGd5zyWel7xQelH1
+ u97vDQNWA5cG3Qa7Xwa+fDrEHnrzR+ofX4dzXlFelYyojtSOmo9eHPMYu/t6
+ 9evhN/w3M+O5f5P8W8Vb3bfn/3T6s3sibGL4neDd7PuCD/IfTnxc9rF90n/y
+ xVTy1Mx03if5TzWfGZ+7voR+GZnZ8BX3tfSb3rfW7z7fn80mz87yWQLWvBVA
+ IQnHxgLw/gTiE8IBoCK+gii24JPnA1rw9vME/hMveOn5sAKgahsAc7YywAlh
+ ZNRuQ3oj7I9kkBOALSxE+Y9IjbUwX+hFakasScns7AfEH+L0APjWNzs70zw7
+ +60aEfsEgLapBX8+FxGID9YznqPeNU8qwb/E3wGtxQeABsYopAAAAAlwSFlz
+ AAALEwAACxMBAJqcGAAAAgVpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4
+ OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhN
+ UCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8v
+ d3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAg
+ PHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1s
+ bnM6ZXhpZj0iaHR0cDovL25zLmFkb2JlLmNvbS9leGlmLzEuMC8iCiAgICAg
+ ICAgICAgIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8x
+ LjAvIj4KICAgICAgICAgPGV4aWY6UGl4ZWxZRGltZW5zaW9uPjc1MzwvZXhp
+ ZjpQaXhlbFlEaW1lbnNpb24+CiAgICAgICAgIDxleGlmOlBpeGVsWERpbWVu
+ c2lvbj4xNjQyPC9leGlmOlBpeGVsWERpbWVuc2lvbj4KICAgICAgICAgPHRp
+ ZmY6T3JpZW50YXRpb24+MTwvdGlmZjpPcmllbnRhdGlvbj4KICAgICAgPC9y
+ ZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CumR
+ lG4AAEAASURBVHgB7F0HYJRF2n42vfdKOhB6k64goKCCHcXe9fT0Ts/T099e
+ r3h3enbPdnqKnh1pKlZAAUV67wRIQnpvm7r5n3c2X9gkm82m7ybfwGa//cp8
+ M+/MPPPO2wbQk04BnQI6BXQK6BTQKaBTQKeATgGdAjoFdAroFNApoFNAp4BO
+ AZ0CjkwBgyMXTi+bc1Kgvr7elSUPLMopiisqLU2CoT7BYDLEw2DwRz18YDBV
+ AIZi1JkyXVxdUkJCQ474Bvmm8plig8Fgcs5a66V2BgrogOcMreQEZSTIuRQU
+ lE7Jzcy7e8v63QsqyiqQuicbaTuyAFM9aktrULm3CjWohbeLG7yHusPN0xXu
+ 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
+ iQ53FUu7ukMZBYqre3lzOkYFeTHOpkFpYNvdGQgSLuTuSuLj7FNUWJZeuAY7
+ ObUBBKUMKjBe/+U7nLLwPlRTgWEQP9v2JAHIKPpQu9Ks5vh6+F96G2If/gP8
+ Rg9TuVgO5vZka/e9ArztJrDduffcjWwLNUk02DhWpB7H8fcWoejh5zjRHeUy
+ dxJCXrqtKvyS8xb4RIZ96WjL3F5rAhLNUGCsPfnLralf3rk5I6iwmBMCAe32
+ wSG49ZREjIy1tKfjDN1rJe25vtQdb5LOKUm4ukrGoFv+815cunQ7AyrUYpK/
+ matrzdrDZnnYHs0VFTbvb36xHYCneWCMqCijB8ZzCNq7lx4YjL5S1YYCo/k7
+ hRQEd0O8D2V7e8iV1CHyv68h6pLzdW6vOa3a+t0M+Iq27ETm8wtR/t4z6knP
+ MRch8smbd0acNfdcg7fj7K3RKzDCQRjx7Z7jn/zz1/SZP2RSTkfinRnli/to
+ ZjKDcjo3Ap+MUxGr636vbfW81q9byuoOpOfjOcrqXttyHKOolBAai7lJZzqA
+ BATIGzQIuaKoMDUE9my9OE2vCMpW2M+laQqMR/dtx4Lnf4sa/7H2KTCavtX8
+ S94d4cljapZFtkduL+bB2+E/doS63u3cnrUyOek5S1qZqqqRSzOW7EdfR83W
+ zzih+MDn8psQ+YfrXgg6ecL9jrDM7Ux/b3cTEejct6cV3f/KL0effDOFcjoO
+ GH+6Kr3OqMNnj41BoLeHytNyoLb7JfoDaskhZNC4uqVr9+LyZRpX56ECc3aI
+ q9NoS25RPCoqGRjgCLdbtFtupz0v3+0EPIYDJTgbUMOZcOmy9zHwu/dQFTAU
+ LmXWjZctX2X1WLg9d3Z/anJNR/cy53xEvP6eku25Bvg1oaHV5/WTFhQga8L2
+ 1MxYqnMLkPP5V8i/9XlOKZsJfL4IfOCRqoibLp/vMyjh695c5vYI4MnyNS23
+ dPoHWzO+vH9Xjr+E9hYH8KfHROCKifGI0eR07MwySHukUBbN1ZcOLSeLfWl5
+ eG7pJryxLQMjgjzpamz2lug0fdlO9e7uSKeiopzfPQF40kbhfG8uZXlXZx/H
+ Hx9/AK6u9MCguZLdCgxrDS12exGcaBkYpDZrA3zPvh6xT96NgAmj1d2WHIy1
+ x/VzFhSQfiFjuEG+V37oKLLf/ghlT73J6SqFYagmI+j1O7bSTe08Q1jYcYsn
+ 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
+ +urJek+brdgC8Ey1NXScbQqZfZU2zeslHJ3G1Rk56y/clonhiw/g/fRSJJGr
+ KyNdsmySs3mObf+uY56yXJYOvIVyvaqkgUquV9+V9nrMXykqgoORGxDgGNxd
+ 26TptjtExC+TmiwT/zdxJsrDToVbYRd5YDTY19WxPT0HRyE6ygc+RQxPVcUN
+ hTjR2L2Etaf20m9EoeHlYbbbo2yvZPbljbK9xiWzvctme97p6Pd42Z62WgBe
+ vUutOVKAo1esi8unyepEvrY7pww3fnEA161Jh+wyGkmu7gi5OjrbdUuSAajs
+ 9bjU2ka5XhbleiGU63maRK7XBUbfzFcUFXmREar8dgnJu6WmjpNpMds5isbI
+ y4PC8Msll9MDY2fnzVSUfR0jRrNB/UdSXudHeV1JPuV3bN/2yOvaQybhTYTb
+ E7u90TNQX1KqZHslD/0FdanpCtSV/E8K1R9SZaXNWrYAPBeTi01LZZu5OdJF
+ Ozkxmfw0rq6MQuG3Nmdg1JID+Oh4meLqjBwY2Xbm1ZnqyysE9NzYMY+bDEil
+ vZ4P7fW82EK1nZHrMU/h7kojIlDq1aCo4Dk9cesJIQPR6P6h45B5yvU0/qUH
+ BhVRHUqN8jra140wy+tcCgh2Iq/rKXLTrRF+DHRKpUbNPx5H8ZALUPnFN2ZD
+ Zg1w+zq35+VlE9lbAB6F6X2Dw7Ojk1nK6rZmluLK5Qfwm3XHEcKZWmR1wtV1
+ hazO3gEkoFcroEeu8jhn7Q1+oTAkJSKE9pB1Yn3f3pFDGpgVFX7IZCgih1BU
+ 2EuMHriPW+0oBUalpze+OO0c5emgBP8doLOS10UFIiIpDEE1dA8rK+deGp1Q
+ TnSk/tLnRZNbQuUIjZXrww0oP28uSh54AnXH0sz9R+rWX7g9KzRsCXj18NUY
+ Gjsww0qWjn/KUlZXVFWLl39Nw3hydcsZ8HQgwwcxMFaXy+raQxWzMoMaPgrW
+ d1CuV51EP1za65nEQp8Z2d0uDQ0pHhWmfq6oaI3+OQSAcIaQeiFmIPZecg08
+ KvZwEyM7uTwBD3JMJiqdvJIiEM1tNf0KKa+jcbFZOaGNpNbe3o3nBfS8zZrc
+ mn/9BcWJ58G4/GvOqJw4+7Imt91LWoPBvKSVUWX3yOrGhuvirC1ldRuOl+DC
+ pftxx69ZiGHIoAgPF6WB7S5ZXXuqwnlaLXFlybVV5Hr0ww2ODoeHkuuZJ2ub
+ +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
+ dMDrlizWuUngi0jPKXpj/eZ982/+PEVtU7tyeiQuPGUSZk4apbapUcCn5Hs6
+ t2cdmttKKoblK7l4gp2EvF/of/H5d5Dz0Jd0w1kD7/gYjL33bIxdvuCPbj4+
+ j7L9R8QxiLZC/57KoQNeT5Sx0n12fKHxrB2/ZL7/6sc/Bz+6jbt/XB1xz8IE
+ nHXyZIyJC1U5qQHCKx34rET44UpGJjAThUR5Tj72bvgEKde9R36ulHI6H4x+
+ YCUmrTttvV90+OVsb54ir4ehooAOeENEaQ4CtU3tm50pzz3/0R6s5zGS0yK8
+ cO2p43HaggkICdB9ww1RUwxaNh3kdFU12L/pG+y9bwOqd6bRqsQTUTcswuSL
+ VhyMmJQscrqDg1YQPeEeKaADXo+kGZwHBD7vwrLqRz76Zt9vnt70C77LrMQ5
+ k4Lx6+VTMH/GGHi4uaiMFZega3MHpxGsnKq0lQThzsWxafq2n/DTE2+h6I1d
+ 3H3TguC1UzDl6jW1o+fNWksNxSbGOybdq1uZ7P1KTge8fpFt4C9xkIw6fKTw
+ nf99tnvKXZsPo6a+GTfSjOXcZVMxZVwsjZUNLuYlJxlIerA9CiigI9a1y+lS
+ sfPl95B5/+csbBO8p8Zgwp/OwLhlC2519/W+n+3YYHu1OLZKpI+kYWxvDhjZ
+ prZ4x97Ud/794U8+T23PRpyXC65bmozVlO+NijK6oRIPt2wpHfiGsbFMsyZH
+ p1zWG8+RKM8txE/rP8Gh6z6knK6ERia+SLz/FEw997T3/KPCL2G7lZi+rl8P
+ HwV0wBs+2rflTODjNrXaazd/d/DBF97/GRsPFuPkUX64dMUkLJ0/Af7aNjXd
+ jKWNZsN10UFOV12LfZ98i133bEANz0Rx5L+Ya+biuEtXpUZPHreKQPfLcJVT
+ z7d7CuiA1z1dhuUugc8/u6D8ufc/37326Y9+wU+Ftbh8RgQuWDkNs6clwpln
+ uUowPRBnWAp6DGaqlq+st+KyuYxN3b4bO599F3kvij0dELQ8CdOuX1M/ZsH0
+ c5xcXTcyni6nU5SxrT864NlWe6jScHCN++Vw9rtvfLhrzP1fpMKXAr1rl4zG
+ 2lOnIXl0hBZHfasBaIN1GClF6gB0rFR+SiZ2vPI+Mu7cwtPByuEzLgoT/0wz
+ kxUL7/D0972P7VE/Uuo+EuuhA56NtioHmmN9ffOKbbtT3nzl3R/dnv8+Bwui
+ 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
+ RK5CYII=
+ headers:
+ User-Agent:
+ - fog/1.38.0 fog-core/1.38.0
+ Content-Type:
+ - image/png
+ Accept:
+ - application/json
+ X-Auth-Token:
+ - fb685ff7f33040b490fd3c2d7592e383
+ Content-Length:
+ - '53915'
+ response:
+ status:
+ code: 201
+ message: ''
+ headers:
+ Last-Modified:
+ - Wed, 29 Jun 2016 14:09:52 GMT
+ Content-Length:
+ - '0'
+ Etag:
+ - 61cf45878a2aa26800cd7d7248e9e5fb
+ Content-Type:
+ - text/html; charset=UTF-8
+ X-Trans-Id:
+ - tx26db11eba1d64a1bbf1c7-005773d6af
+ Date:
+ - Wed, 29 Jun 2016 14:09:51 GMT
+ Connection:
+ - close
+ body:
+ encoding: UTF-8
+ string: ''
+ http_version:
+ recorded_at: Wed, 29 Jun 2016 14:09:51 GMT
+recorded_with: VCR 3.0.1
diff --git a/spec/mailers/welcome_mailer_spec.rb b/spec/mailers/welcome_mailer_spec.rb
index fa9ff057c..f60e24b10 100644
--- a/spec/mailers/welcome_mailer_spec.rb
+++ b/spec/mailers/welcome_mailer_spec.rb
@@ -4,8 +4,8 @@ describe WelcomeMailer, type: :mailer do
describe ".welcome_email" do
let(:user) { create(:user) }
subject(:subject) { described_class.welcome_email(user) }
- it { expect(subject.body).to match('https://tps.apientreprise.fr') }
- it { expect(subject.body).to match('https://tps.apientreprise.fr/users/password/new') }
+ it { expect(subject.body).to match(root_url) }
+ it { expect(subject.body).to match(new_user_password_url) }
it { expect(subject.body).to match(user.email) }
it { expect(subject.body).to match('Bienvenue sur la plateforme TPS') }
it { expect(subject.body).to match('Nous vous remercions de vous être inscrit sur TPS. Pour mémoire, voici quelques informations utiles :')}
diff --git a/spec/models/dossier_spec.rb b/spec/models/dossier_spec.rb
index c9ae004e5..b26b8243e 100644
--- a/spec/models/dossier_spec.rb
+++ b/spec/models/dossier_spec.rb
@@ -2,6 +2,7 @@ require 'spec_helper'
describe Dossier do
let(:user) { create(:user) }
+
describe 'database columns' do
it { is_expected.to have_db_column(:autorisation_donnees) }
it { is_expected.to have_db_column(:nom_projet) }
@@ -24,6 +25,7 @@ describe Dossier do
it { is_expected.to have_one(:entreprise) }
it { is_expected.to belong_to(:user) }
it { is_expected.to have_many(:invites) }
+ it { is_expected.to have_many(:follows) }
end
describe 'delegation' do
@@ -33,14 +35,6 @@ describe Dossier do
it { is_expected.to delegate_method(:types_de_champ).to(:procedure) }
end
- describe 'validation' do
- context 'nom_projet' do
- it { is_expected.to allow_value(nil).for(:nom_projet) }
- it { is_expected.not_to allow_value('').for(:nom_projet) }
- it { is_expected.to allow_value('mon super projet').for(:nom_projet) }
- end
- end
-
describe 'methods' do
let(:dossier) { create(:dossier, :with_entreprise, user: user) }
@@ -82,7 +76,7 @@ describe Dossier do
end
end
- describe '#retrieve_last_piece_justificative_by_type', vcr: { cassette_name: 'models_dossier_retrieve_last_piece_justificative_by_type' } do
+ describe '#retrieve_last_piece_justificative_by_type', vcr: {cassette_name: 'models_dossier_retrieve_last_piece_justificative_by_type'} do
let(:types_de_pj_dossier) { dossier.procedure.types_de_piece_justificative }
subject { dossier.retrieve_last_piece_justificative_by_type types_de_pj_dossier.first }
@@ -121,7 +115,7 @@ describe Dossier do
it 'does not create default champs' do
expect(subject).not_to receive(:build_default_champs)
- subject.update_attributes(nom_projet: 'plop')
+ subject.update_attributes(state: 'initiated')
end
end
end
@@ -390,18 +384,18 @@ describe Dossier do
create :assign_to, gestionnaire: gestionnaire, procedure: procedure_admin
end
- let!(:dossier1) { create(:dossier, procedure: procedure_admin, state: 'draft') }
- let!(:dossier2) { create(:dossier, procedure: procedure_admin, state: 'initiated') } #a_traiter
- let!(:dossier3) { create(:dossier, procedure: procedure_admin, state: 'initiated') } #a_traiter
- let!(:dossier4) { create(:dossier, procedure: procedure_admin, state: 'replied') } #en_attente
- let!(:dossier5) { create(:dossier, procedure: procedure_admin, state: 'updated') } #a_traiter
- let!(:dossier6) { create(:dossier, procedure: procedure_admin_2, state: 'validated') } #en_attente
- let!(:dossier7) { create(:dossier, procedure: procedure_admin_2, state: 'submitted') } #a_traiter
- let!(:dossier8) { create(:dossier, procedure: procedure_admin_2, state: 'closed') } #termine
- let!(:dossier9) { create(:dossier, procedure: procedure_admin, state: 'closed') } #termine
- let!(:dossier10) { create(:dossier, procedure: procedure_admin, state: 'initiated', archived: true) } #a_traiter #archived
- let!(:dossier11) { create(:dossier, procedure: procedure_admin, state: 'replied', archived: true) } #en_attente #archived
- let!(:dossier12) { create(:dossier, procedure: procedure_admin, state: 'closed', archived: true) } #termine #archived
+ let!(:dossier1) { create(:dossier, procedure: procedure_admin, state: 'draft') }
+ let!(:dossier2) { create(:dossier, procedure: procedure_admin, state: 'initiated') } #a_traiter
+ let!(:dossier3) { create(:dossier, procedure: procedure_admin, state: 'initiated') } #a_traiter
+ let!(:dossier4) { create(:dossier, procedure: procedure_admin, state: 'replied') } #en_attente
+ let!(:dossier5) { create(:dossier, procedure: procedure_admin, state: 'updated') } #a_traiter
+ let!(:dossier6) { create(:dossier, procedure: procedure_admin_2, state: 'validated') } #en_attente
+ let!(:dossier7) { create(:dossier, procedure: procedure_admin_2, state: 'submitted') } #a_traiter
+ let!(:dossier8) { create(:dossier, procedure: procedure_admin_2, state: 'closed') } #termine
+ let!(:dossier9) { create(:dossier, procedure: procedure_admin, state: 'closed') } #termine
+ let!(:dossier10) { create(:dossier, procedure: procedure_admin, state: 'initiated', archived: true) } #a_traiter #archived
+ let!(:dossier11) { create(:dossier, procedure: procedure_admin, state: 'replied', archived: true) } #en_attente #archived
+ let!(:dossier12) { create(:dossier, procedure: procedure_admin, state: 'closed', archived: true) } #termine #archived
describe '#waiting_for_gestionnaire' do
subject { gestionnaire.dossiers.waiting_for_gestionnaire }
@@ -442,11 +436,11 @@ describe Dossier do
let(:procedure_1) { create(:procedure, administrateur: administrateur_1) }
let(:procedure_2) { create(:procedure, administrateur: administrateur_2) }
- let!(:dossier_0) { create(:dossier, nom_projet: 'je suis un brouillon', state: 'draft', procedure: procedure_1, user: create(:user, email: 'brouillon@clap.fr')) }
- let!(:dossier_1) { create(:dossier, nom_projet: 'Projet de test', state: 'initiated', procedure: procedure_1, user: create(:user, email: 'contact@test.com')) }
- let!(:dossier_2) { create(:dossier, nom_projet: 'Lili et Marcel', state: 'initiated', procedure: procedure_1, user: create(:user, email: 'plop@gmail.com')) }
- let!(:dossier_3) { create(:dossier, nom_projet: 'Construction projet marcel', state: 'initiated', procedure: procedure_2, user: create(:user, email: 'peace@clap.fr')) }
- let!(:dossier_archived) { create(:dossier, nom_projet: 'je suis un Marcel archivé', state: 'initiated', procedure: procedure_1, archived: true, user: create(:user, email: 'brouillonArchived@clap.fr')) }
+ let!(:dossier_0) { create(:dossier, state: 'draft', procedure: procedure_1, user: create(:user, email: 'brouillon@clap.fr')) }
+ let!(:dossier_1) { create(:dossier, state: 'initiated', procedure: procedure_1, user: create(:user, email: 'contact@test.com')) }
+ let!(:dossier_2) { create(:dossier, state: 'initiated', procedure: procedure_1, user: create(:user, email: 'plop@gmail.com')) }
+ let!(:dossier_3) { create(:dossier, state: 'initiated', procedure: procedure_2, user: create(:user, email: 'peace@clap.fr')) }
+ let!(:dossier_archived) { create(:dossier, state: 'initiated', procedure: procedure_1, archived: true, user: create(:user, email: 'brouillonArchived@clap.fr')) }
let!(:etablissement_1) { create(:etablissement, entreprise: create(:entreprise, raison_sociale: 'OCTO Academy', dossier: dossier_1), dossier: dossier_1, siret: '41636169600051') }
let!(:etablissement_2) { create(:etablissement, entreprise: create(:entreprise, raison_sociale: 'Plop octo', dossier: dossier_2), dossier: dossier_2, siret: '41816602300012') }
@@ -464,12 +458,6 @@ describe Dossier do
it { expect(subject.size).to eq(0) }
end
- describe 'search on file title' do
- let(:terms) { 'Marcel' }
-
- it { expect(subject.size).to eq(1) }
- end
-
describe 'search on contact email' do
let(:terms) { 'clap' }
@@ -511,8 +499,8 @@ describe Dossier do
end
describe '#cerfa_available?' do
- let(:procedure) { create(:procedure, cerfa_flag: cerfa_flag) }
- let(:dossier) { create(:dossier, procedure: procedure)}
+ let(:procedure) { create(:procedure, cerfa_flag: cerfa_flag) }
+ let(:dossier) { create(:dossier, procedure: procedure) }
context 'Procedure accepts CERFA' do
let(:cerfa_flag) { true }
@@ -531,11 +519,10 @@ describe Dossier do
end
describe '#as_csv?' do
- let(:procedure) { create(:procedure) }
+ let(:procedure) { create(:procedure) }
let(:dossier) { create(:dossier, :with_entreprise, user: user, procedure: procedure) }
subject { dossier.as_csv }
- it { expect(subject[:nom_projet]).to eq("Demande de subvention dans le cadre d'accompagnement d'enfant à l'étranger") }
it { expect(subject[:archived]).to be_falsey }
it { expect(subject['etablissement.siret']).to eq('44011762001530') }
it { expect(subject['etablissement.siege_social']).to be_truthy }
@@ -577,11 +564,11 @@ describe Dossier do
it { expect(dossier.entreprise.rna_information).not_to be_nil }
it { expect(dossier.autorisation_donnees).to be_truthy }
- it { expect{subject}.to change(RNAInformation, :count).by(-1) }
- it { expect{subject}.to change(Exercice, :count).by(-1) }
+ it { expect { subject }.to change(RNAInformation, :count).by(-1) }
+ it { expect { subject }.to change(Exercice, :count).by(-1) }
- it { expect{subject}.to change(Entreprise, :count).by(-1) }
- it { expect{subject}.to change(Etablissement, :count).by(-1) }
+ it { expect { subject }.to change(Entreprise, :count).by(-1) }
+ it { expect { subject }.to change(Etablissement, :count).by(-1) }
context 'when method reset! is call' do
before do
@@ -600,7 +587,7 @@ describe Dossier do
let!(:procedure_2) { create :procedure }
let(:dossier_1) { Dossier.new(id: 0, procedure: procedure_1) }
- let(:dossier_2) { Dossier.new(id: 0, procedure: procedure_2) }
+ let(:dossier_2) { Dossier.new(id: 0, procedure: procedure_2) }
before do
create :type_de_champ, libelle: 'type_1_1', order_place: 1, procedure: dossier_1.procedure
@@ -637,4 +624,27 @@ describe Dossier do
end
end
+
+ describe '#total_follow' do
+ let(:dossier) { create(:dossier, :with_entreprise, user: user) }
+ let(:dossier2) { create(:dossier, :with_entreprise, user: user) }
+
+ subject { dossier.total_follow }
+
+ context 'when no body follow dossier' do
+ it { expect(subject).to eq 0 }
+ end
+
+ context 'when 2 people follow dossier' do
+ before do
+ create :follow, dossier_id: dossier.id, gestionnaire_id: (create :gestionnaire).id
+ create :follow, dossier_id: dossier.id, gestionnaire_id: (create :gestionnaire).id
+
+ create :follow, dossier_id: dossier2.id, gestionnaire_id: (create :gestionnaire).id
+ create :follow, dossier_id: dossier2.id, gestionnaire_id: (create :gestionnaire).id
+ end
+
+ it { expect(subject).to eq 2 }
+ end
+ end
end
diff --git a/spec/models/gestionnaire_spec.rb b/spec/models/gestionnaire_spec.rb
index a7aea4737..17a8b55a2 100644
--- a/spec/models/gestionnaire_spec.rb
+++ b/spec/models/gestionnaire_spec.rb
@@ -1,6 +1,17 @@
require 'rails_helper'
describe Gestionnaire, type: :model do
+ let(:admin) { create :administrateur }
+ let!(:procedure) { create :procedure, administrateur: admin }
+ let!(:procedure_2) { create :procedure, administrateur: admin }
+ let(:gestionnaire) { create :gestionnaire, procedure_filter: procedure_filter, administrateurs: [admin] }
+ let(:procedure_filter) { [] }
+
+ before do
+ create :assign_to, gestionnaire: gestionnaire, procedure: procedure
+ create :assign_to, gestionnaire: gestionnaire, procedure: procedure_2
+ end
+
describe 'database column' do
it { is_expected.to have_db_column(:email) }
it { is_expected.to have_db_column(:encrypted_password) }
@@ -20,20 +31,11 @@ describe Gestionnaire, type: :model do
it { is_expected.to have_and_belong_to_many(:administrateurs) }
it { is_expected.to have_many(:procedures) }
it { is_expected.to have_many(:dossiers) }
+ it { is_expected.to have_many(:follows) }
end
describe '#dossiers_filter' do
- let(:admin) { create :administrateur }
- let(:procedure) { create :procedure, administrateur: admin }
- let(:procedure_2) { create :procedure, administrateur: admin }
- let(:gestionnaire) { create :gestionnaire, procedure_filter: procedure_filter, administrateurs: [admin] }
let!(:dossier) { create :dossier, procedure: procedure }
- let(:procedure_filter) { [] }
-
- before do
- create :assign_to, gestionnaire: gestionnaire, procedure: procedure
- create :assign_to, gestionnaire: gestionnaire, procedure: procedure_2
- end
subject { gestionnaire.dossiers_filter }
@@ -49,18 +51,6 @@ describe Gestionnaire, type: :model do
end
describe '#procedure_filter_list' do
- let(:admin) { create :administrateur }
- let!(:procedure) { create :procedure, administrateur: admin }
- let!(:procedure_2) { create :procedure, administrateur: admin }
- let(:gestionnaire) { create :gestionnaire, procedure_filter: procedure_filter, administrateurs: [admin] }
-
- before do
- create :assign_to, gestionnaire: gestionnaire, procedure: procedure
- create :assign_to, gestionnaire: gestionnaire, procedure: procedure_2
- end
-
- let(:procedure_filter) { [] }
-
subject { gestionnaire.procedure_filter_list }
context 'when gestionnaire procedure_filter is empty' do
@@ -73,4 +63,96 @@ describe Gestionnaire, type: :model do
it { expect(subject).to eq [procedure.id] }
end
end
+
+ describe '#toggle_follow_dossier' do
+ let!(:dossier) { create :dossier, procedure: procedure }
+
+ subject { gestionnaire.toggle_follow_dossier dossier_id }
+
+ context 'when dossier id not valid' do
+ let(:dossier_id) { 0 }
+
+ it { expect(subject).to eq nil }
+ end
+
+ context 'when dossier id is valid' do
+ let(:dossier_id) { dossier.id }
+
+ context 'when dossier is not follow by gestionnaire' do
+ it 'value change in database' do
+ expect { subject }.to change(Follow, :count).by(1)
+ end
+
+ it { expect(subject).to be_an_instance_of Follow }
+ end
+
+ context 'when dossier is follow by gestionnaire' do
+ before do
+ create :follow, dossier_id: dossier.id, gestionnaire_id: gestionnaire.id
+ end
+
+ it 'value change in database' do
+ expect { subject }.to change(Follow, :count).by(-1)
+ end
+
+ it { expect(subject).to eq 1 }
+ end
+ end
+
+ context 'when dossier instance is past' do
+ let(:dossier_id) { dossier }
+
+ context 'when dossier is not follow by gestionnaire' do
+ it 'value change in database' do
+ expect { subject }.to change(Follow, :count).by(1)
+ end
+
+ it { expect(subject).to be_an_instance_of Follow }
+ end
+
+ context 'when dossier is follow by gestionnaire' do
+ before do
+ create :follow, dossier_id: dossier.id, gestionnaire_id: gestionnaire.id
+ end
+
+ it 'value change in database' do
+ expect { subject }.to change(Follow, :count).by(-1)
+ end
+
+ it { expect(subject).to eq 1 }
+ end
+ end
+ end
+
+ describe '#follow?' do
+ let!(:dossier) { create :dossier, procedure: procedure }
+
+ subject { gestionnaire.follow? dossier.id }
+
+ context 'when gestionnaire follow a dossier' do
+
+ before do
+ create :follow, dossier_id: dossier.id, gestionnaire_id: gestionnaire.id
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when gestionnaire not follow a dossier' do
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ describe '#dossiers_follow' do
+ let!(:dossier) { create :dossier, procedure: procedure }
+
+ before do
+ create :follow, dossier_id: dossier.id, gestionnaire_id: gestionnaire.id
+ end
+
+ subject { gestionnaire.dossiers_follow }
+
+ it { expect(Follow.all.size).to eq 1 }
+ it { expect(subject.first).to eq dossier }
+ end
end
diff --git a/spec/models/procedure_path_spec.rb b/spec/models/procedure_path_spec.rb
new file mode 100644
index 000000000..eaf75f411
--- /dev/null
+++ b/spec/models/procedure_path_spec.rb
@@ -0,0 +1,38 @@
+require 'spec_helper'
+
+describe ProcedurePath do
+ describe 'assocations' do
+ it { is_expected.to belong_to(:administrateur) }
+ it { is_expected.to belong_to(:procedure) }
+ end
+
+ describe 'attributes' do
+ it { is_expected.to have_db_column(:path) }
+ end
+
+ describe 'validation' do
+ describe 'path' do
+ let(:admin) { create(:administrateur) }
+ let(:procedure) { create(:procedure) }
+ let(:procedure_path) { create(:procedure_path, administrateur: admin, procedure: procedure, path: path) }
+
+ context 'when path is nil' do
+ let(:path) { nil }
+ it { expect{procedure_path}.to raise_error ActiveRecord::RecordInvalid }
+ end
+ context 'when path is empty' do
+ let(:path) { '' }
+ it { expect{procedure_path}.to raise_error ActiveRecord::RecordInvalid }
+ end
+ context 'when path is invalid' do
+ let(:path) { 'Demande de subvention' }
+ it { expect{procedure_path}.to raise_error ActiveRecord::RecordInvalid }
+ end
+ context 'when path is valid' do
+ let(:path) { 'ma_super_procedure' }
+ it { expect{procedure_path}.not_to raise_error }
+ end
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/spec/models/procedure_spec.rb b/spec/models/procedure_spec.rb
index f805f0292..1724ed8d2 100644
--- a/spec/models/procedure_spec.rb
+++ b/spec/models/procedure_spec.rb
@@ -19,6 +19,7 @@ describe Procedure do
it { is_expected.to have_db_column(:logo) }
it { is_expected.to have_db_column(:logo_secure_token) }
it { is_expected.to have_db_column(:cerfa_flag) }
+ it { is_expected.to have_db_column(:published) }
end
describe 'validation' do
@@ -156,10 +157,63 @@ describe Procedure do
describe 'procedure status is reset' do
let(:archived) { true }
let(:published) { true }
- it 'sets published and archived to false' do
+ it 'Not published nor archived' do
expect(subject.archived).to be_falsey
expect(subject.published).to be_falsey
+ expect(subject.path).to be_nil
end
end
end
+
+ describe 'publish' do
+ let(:procedure) { create(:procedure, :published) }
+ let(:procedure_path) { ProcedurePath.find(procedure.procedure_path.id) }
+
+ it 'is available from a valid path' do
+ expect(procedure.path).to match(/fake_path/)
+ expect(procedure.published).to be_truthy
+ end
+
+ it 'is correctly set in ProcedurePath table' do
+ expect(ProcedurePath.count(path: procedure.path)).to eq(1)
+ expect(procedure_path.procedure_id).to eq(procedure.id)
+ expect(procedure_path.administrateur_id).to eq(procedure.administrateur_id)
+ end
+ end
+
+ describe 'archive' do
+ let(:procedure) { create(:procedure, :published) }
+ let(:procedure_path) { ProcedurePath.find(procedure.procedure_path.id) }
+ before do
+ procedure.archive
+ procedure.reload
+ end
+
+ it 'is not available from a valid path anymore' do
+ expect(procedure.path).to be_nil
+ expect(procedure.published).to be_truthy
+ expect(procedure.archived).to be_truthy
+ end
+
+ it 'is not in ProcedurePath table anymore' do
+ expect(ProcedurePath.count(path: procedure.path)).to eq(0)
+ expect(ProcedurePath.find_by_procedure_id(procedure.id)).to be_nil
+ end
+ end
+
+ describe 'total_dossier' do
+
+ let(:procedure) { create :procedure }
+
+ before do
+ create :dossier, procedure: procedure, state: :initiated
+ create :dossier, procedure: procedure, state: :draft
+ create :dossier, procedure: procedure, state: :replied
+ end
+
+ subject { procedure.total_dossier }
+
+ it { is_expected.to eq 2 }
+
+ end
end
diff --git a/spec/views/admin/previsualisations/show.html.haml_spec.rb b/spec/views/admin/previsualisations/show.html.haml_spec.rb
index 4d97de3a8..82263c78b 100644
--- a/spec/views/admin/previsualisations/show.html.haml_spec.rb
+++ b/spec/views/admin/previsualisations/show.html.haml_spec.rb
@@ -21,10 +21,6 @@ describe 'admin/previsualisations/show.html.haml', type: :view do
expect(rendered).to have_selector("form[action='/users/dossiers/#{dossier_id}/description'][method=post]")
end
- it 'Nom du projet' do
- expect(rendered).to have_selector('input[id=nom_projet][name=nom_projet]')
- end
-
it 'Charger votre CERFA (PDF)' do
expect(rendered).to have_selector('input[type=file][name=cerfa_pdf][id=cerfa_pdf]')
end
@@ -66,17 +62,12 @@ describe 'admin/previsualisations/show.html.haml', type: :view do
context 'les valeurs sont réaffichées si elles sont présentes dans la BDD' do
let!(:dossier) do
create(:dossier,
- nom_projet: 'Projet de test',
user: user)
end
before do
render
end
-
- it 'Nom du projet' do
- expect(rendered).to have_selector("input[id=nom_projet][value='#{dossier.nom_projet}']")
- end
end
context 'Champs' do
diff --git a/spec/views/admin/procedures/edit.html.haml_spec.rb b/spec/views/admin/procedures/edit.html.haml_spec.rb
index 44db3875c..ba4492a5c 100644
--- a/spec/views/admin/procedures/edit.html.haml_spec.rb
+++ b/spec/views/admin/procedures/edit.html.haml_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'admin/procedures/edit.html.haml', type: :view do
+describe 'admin/procedures/edit.html.haml', type: :view, vcr: { cassette_name: 'admin_procedure_edit' } do
let(:logo) { Rack::Test::UploadedFile.new("./spec/support/files/logo_test_procedure.png", 'image/png') }
let(:procedure) { create(:procedure, logo: logo) }
diff --git a/spec/views/admin/procedures/show.html.haml_spec.rb b/spec/views/admin/procedures/show.html.haml_spec.rb
index 7e5c272a1..06c716479 100644
--- a/spec/views/admin/procedures/show.html.haml_spec.rb
+++ b/spec/views/admin/procedures/show.html.haml_spec.rb
@@ -2,41 +2,64 @@ require 'spec_helper'
describe 'admin/procedures/show.html.haml', type: :view do
let(:archived) { false }
- let(:published) { false }
- let(:procedure) { create(:procedure, published: published, archived: archived) }
+ let(:procedure) { create(:procedure, archived: archived) }
before do
assign(:facade, AdminProceduresShowFacades.new(procedure.decorate))
assign(:procedure, procedure)
- render
end
- describe 'publish button' do
- it { expect(rendered).to have_content('Publier') }
- end
-
- describe 'archive and unarchive button' do
- let(:published) { true }
-
- context 'when procedure is published' do
- it { expect(rendered).to have_content('Archiver') }
+ describe 'procedure is draft' do
+ before do
+ render
end
- context 'when procedure is archived' do
- let(:archived) { true }
- it { expect(rendered).to have_content('Réactiver') }
+ describe 'publish button is visible' do
+ it { expect(rendered).to have_css('a#publish') }
+ it { expect(rendered).not_to have_css('button#archive') }
+ it { expect(rendered).not_to have_css('a#reenable') }
end
- end
- describe 'procedure link' do
-
- context 'is not present when not published' do
+ describe 'procedure link is not present' do
it { expect(rendered).to have_content('Cette procédure n\'a pas encore été publiée et n\'est donc pas accessible par le public.') }
end
+ end
- context 'is present when already published' do
- let(:published) { true }
- it { expect(rendered).to have_content(new_users_dossiers_url(procedure_id: procedure.id)) }
+ describe 'procedure is published' do
+ before do
+ procedure.publish!('fake_path')
+ procedure.reload
+ render
+ end
+
+ describe 'archive button is visible', js: true do
+ it { expect(rendered).not_to have_css('a#publish') }
+ it { expect(rendered).to have_css('button#archive') }
+ it { expect(rendered).not_to have_css('a#reenable') }
+ end
+
+ describe 'procedure link is present' do
+ it { expect(rendered).to have_content(commencer_url(procedure_path: procedure.path)) }
end
end
+
+ describe 'procedure is archived' do
+ before do
+ procedure.publish!('fake_path')
+ procedure.archive
+ procedure.reload
+ render
+ end
+
+ describe 'Re-enable button is visible' do
+ it { expect(rendered).not_to have_css('a#publish') }
+ it { expect(rendered).not_to have_css('button#archive') }
+ it { expect(rendered).to have_css('a#reenable') }
+ end
+
+ describe 'procedure link is not present' do
+ it { expect(rendered).to have_content('Cette procédure a été archivée et n\'est plus accessible par le public.') }
+ end
+ end
+
end
\ No newline at end of file
diff --git a/spec/views/backoffice/dossiers/index_html.haml_spec.rb b/spec/views/backoffice/dossiers/index_html.haml_spec.rb
index 5cc52453a..a8d59f286 100644
--- a/spec/views/backoffice/dossiers/index_html.haml_spec.rb
+++ b/spec/views/backoffice/dossiers/index_html.haml_spec.rb
@@ -6,12 +6,17 @@ describe 'backoffice/dossiers/index.html.haml', type: :view do
let!(:procedure) { create(:procedure, administrateur: administrateur) }
- let!(:decorate_dossier_initiated) { create(:dossier, procedure: procedure, nom_projet: 'projet initiated', state: 'initiated').decorate }
- let!(:decorate_dossier_replied) { create(:dossier, procedure: procedure, nom_projet: 'projet replied', state: 'replied').decorate }
- let!(:decorate_dossier_closed) { create(:dossier, procedure: procedure, nom_projet: 'projet closed', state: 'closed').decorate }
+ let!(:decorate_dossier_initiated) { create(:dossier, :with_entreprise, procedure: procedure, state: 'initiated').decorate }
+ let!(:decorate_dossier_replied) { create(:dossier, :with_entreprise, procedure: procedure, state: 'replied').decorate }
+ let!(:decorate_dossier_closed) { create(:dossier, :with_entreprise, procedure: procedure, state: 'closed').decorate }
before do
+
+ decorate_dossier_closed.entreprise.update_column(:raison_sociale, 'plip')
+ decorate_dossier_replied.entreprise.update_column(:raison_sociale, 'plop')
+
create :assign_to, gestionnaire: gestionnaire, procedure: procedure
+ sign_in gestionnaire
end
describe 'on tab a_traiter' do
@@ -29,12 +34,14 @@ describe 'backoffice/dossiers/index.html.haml', type: :view do
subject { rendered }
it { is_expected.to have_css('#backoffice_index') }
it { is_expected.to have_content(procedure.libelle) }
- it { is_expected.to have_content(decorate_dossier_initiated.nom_projet) }
+ it { is_expected.to have_content(decorate_dossier_initiated.entreprise.raison_sociale) }
it { is_expected.to have_content(decorate_dossier_initiated.display_state) }
it { is_expected.to have_content(decorate_dossier_initiated.last_update) }
- it { is_expected.not_to have_content(decorate_dossier_replied.nom_projet) }
- it { is_expected.not_to have_content(decorate_dossier_closed.nom_projet) }
+ it { is_expected.not_to have_content(decorate_dossier_replied.entreprise.raison_sociale) }
+ it { is_expected.not_to have_content(decorate_dossier_closed.entreprise.raison_sociale) }
+
+ it { is_expected.to have_css("#suivre_dossier_#{gestionnaire.dossiers.waiting_for_gestionnaire.first.id}") }
describe 'active tab' do
it { is_expected.to have_selector('.active .text-danger') }
@@ -56,18 +63,49 @@ describe 'backoffice/dossiers/index.html.haml', type: :view do
subject { rendered }
it { is_expected.to have_css('#backoffice_index') }
it { is_expected.to have_content(procedure.libelle) }
- it { is_expected.to have_content(decorate_dossier_replied.nom_projet) }
+ it { is_expected.to have_content(decorate_dossier_replied.entreprise.raison_sociale) }
it { is_expected.to have_content(decorate_dossier_replied.display_state) }
it { is_expected.to have_content(decorate_dossier_replied.last_update) }
- it { is_expected.not_to have_content(decorate_dossier_initiated.nom_projet) }
- it { is_expected.not_to have_content(decorate_dossier_closed.nom_projet) }
+ it { is_expected.not_to have_content(decorate_dossier_initiated.entreprise.raison_sociale) }
+ it { is_expected.not_to have_content(decorate_dossier_closed.entreprise.raison_sociale) }
describe 'active tab' do
it { is_expected.to have_selector('.active .text-info') }
end
end
+ describe 'on tab suivi' do
+ before do
+ create :follow, dossier_id: decorate_dossier_replied.id, gestionnaire_id: gestionnaire.id
+
+ assign(:dossiers, (smart_listing_create :dossiers,
+ gestionnaire.dossiers_follow,
+ partial: "backoffice/dossiers/list",
+ array: true))
+ assign(:suivi_class, 'active')
+ assign(:liste, 'suivi')
+ render
+ end
+
+ subject { rendered }
+
+ it { is_expected.to have_css('#backoffice_index') }
+ it { is_expected.to have_content(procedure.libelle) }
+ it { is_expected.to have_content(decorate_dossier_replied.entreprise.raison_sociale) }
+ it { is_expected.to have_content(decorate_dossier_replied.display_state) }
+ it { is_expected.to have_content(decorate_dossier_replied.last_update) }
+
+ it { is_expected.not_to have_content(decorate_dossier_initiated.entreprise.raison_sociale) }
+ it { is_expected.not_to have_content(decorate_dossier_closed.entreprise.raison_sociale) }
+
+ it { is_expected.to have_css("#suivre_dossier_#{gestionnaire.dossiers_follow.first.id}") }
+
+ describe 'active tab' do
+ it { is_expected.to have_selector('.active .text-warning') }
+ end
+ end
+
describe 'on tab termine' do
before do
assign(:dossiers, (smart_listing_create :dossiers,
@@ -83,12 +121,14 @@ describe 'backoffice/dossiers/index.html.haml', type: :view do
it { is_expected.to have_css('#backoffice_index') }
it { is_expected.to have_content(procedure.libelle) }
- it { is_expected.to have_content(decorate_dossier_closed.nom_projet) }
+ it { is_expected.to have_content(decorate_dossier_closed.entreprise.raison_sociale) }
it { is_expected.to have_content(decorate_dossier_closed.display_state) }
it { is_expected.to have_content(decorate_dossier_closed.last_update) }
- it { is_expected.not_to have_content(decorate_dossier_initiated.nom_projet) }
- it { is_expected.not_to have_content(decorate_dossier_replied.nom_projet) }
+ it { is_expected.not_to have_content(decorate_dossier_initiated.entreprise.raison_sociale) }
+ it { is_expected.not_to have_content(decorate_dossier_replied.entreprise.raison_sociale) }
+
+ it { is_expected.to have_css("#suivre_dossier_#{gestionnaire.dossiers.termine.first.id}") }
describe 'active tab' do
it { is_expected.to have_selector('.active .text-success') }
diff --git a/spec/views/users/description/show.html.haml_spec.rb b/spec/views/users/description/show.html.haml_spec.rb
index a6a283dc4..4a44776b7 100644
--- a/spec/views/users/description/show.html.haml_spec.rb
+++ b/spec/views/users/description/show.html.haml_spec.rb
@@ -22,10 +22,6 @@ describe 'users/description/show.html.haml', type: :view do
expect(rendered).to have_selector("form[action='/users/dossiers/#{dossier_id}/description'][method=post]")
end
- it 'Nom du projet' do
- expect(rendered).to have_selector('input[id=nom_projet][name=nom_projet]')
- end
-
it 'Charger votre CERFA (PDF)' do
expect(rendered).to have_selector('input[type=file][name=cerfa_pdf][id=cerfa_pdf]')
end
@@ -64,22 +60,6 @@ describe 'users/description/show.html.haml', type: :view do
end
end
- context 'les valeurs sont réaffichées si elles sont présentes dans la BDD' do
- let!(:dossier) do
- create(:dossier,
- nom_projet: 'Projet de test',
- user: user)
- end
-
- before do
- render
- end
-
- it 'Nom du projet' do
- expect(rendered).to have_selector("input[id=nom_projet][value='#{dossier.nom_projet}']")
- end
- end
-
context 'Champs' do
let(:champs) { dossier.champs }
let(:types_de_champ) { procedure.types_de_champ.where(type_champ: 'datetime').first }
diff --git a/spec/views/users/dossiers/index_html.haml_spec.rb b/spec/views/users/dossiers/index_html.haml_spec.rb
index 6b4a48edd..381e607fe 100644
--- a/spec/views/users/dossiers/index_html.haml_spec.rb
+++ b/spec/views/users/dossiers/index_html.haml_spec.rb
@@ -3,10 +3,17 @@ require 'spec_helper'
describe 'users/dossiers/index.html.haml', type: :view do
let(:user) { create(:user) }
- let!(:dossier) { create(:dossier, user: user, state: 'initiated', nom_projet: 'projet de test').decorate }
- let!(:dossier_2) { create(:dossier, user: user, state: 'replied', nom_projet: 'projet répondu').decorate }
- let!(:dossier_3) { create(:dossier, user: user, state: 'replied', nom_projet: 'projet répondu 2').decorate }
- let!(:dossier_termine) { create(:dossier, user: user, state: 'closed').decorate }
+ let!(:dossier) { create(:dossier, :with_entreprise, user: user, state: 'initiated').decorate }
+ let!(:dossier_2) { create(:dossier, :with_entreprise, user: user, state: 'replied').decorate }
+ let!(:dossier_3) { create(:dossier, :with_entreprise, user: user, state: 'replied').decorate }
+ let!(:dossier_termine) { create(:dossier, :with_entreprise, user: user, state: 'closed').decorate }
+
+ before do
+ dossier_2.entreprise.update_column(:raison_sociale, 'plip')
+ dossier_2.entreprise.update_column(:raison_sociale, 'plop')
+ dossier_3.entreprise.update_column(:raison_sociale, 'plup')
+ dossier_termine.entreprise.update_column(:raison_sociale, 'plap')
+ end
describe 'params liste is a_traiter' do
let(:dossiers_list) { user.dossiers.waiting_for_user('DESC') }
@@ -32,14 +39,14 @@ describe 'users/dossiers/index.html.haml', type: :view do
describe 'dossier replied is present' do
it { is_expected.to have_content(dossier_2.procedure.libelle) }
- it { is_expected.to have_content(dossier_2.nom_projet) }
+ it { is_expected.to have_content(dossier_2.entreprise.raison_sociale) }
it { is_expected.to have_content(dossier_2.display_state) }
it { is_expected.to have_content(dossier_2.last_update) }
end
describe 'dossier initiated and closed are not present' do
- it { is_expected.not_to have_content(dossier.nom_projet) }
- it { is_expected.not_to have_content(dossier_termine.nom_projet) }
+ it { is_expected.not_to have_content(dossier.entreprise.raison_sociale) }
+ it { is_expected.not_to have_content(dossier_termine.entreprise.raison_sociale) }
end
describe 'badges on tabs' do
@@ -69,14 +76,14 @@ describe 'users/dossiers/index.html.haml', type: :view do
describe 'dossier initiated is present' do
it { is_expected.to have_content(dossier.procedure.libelle) }
- it { is_expected.to have_content(dossier.nom_projet) }
+ it { is_expected.to have_content(dossier.entreprise.raison_sociale) }
it { is_expected.to have_content(dossier.display_state) }
it { is_expected.to have_content(dossier.last_update) }
end
describe 'dossier replied and closed are not present' do
- it { is_expected.not_to have_content(dossier_2.nom_projet) }
- it { is_expected.not_to have_content(dossier_termine.nom_projet) }
+ it { is_expected.not_to have_content(dossier_2.entreprise.raison_sociale) }
+ it { is_expected.not_to have_content(dossier_termine.entreprise.raison_sociale) }
end
end
@@ -100,14 +107,14 @@ describe 'users/dossiers/index.html.haml', type: :view do
describe 'dossier termine is present' do
it { is_expected.to have_content(dossier_termine.procedure.libelle) }
- it { is_expected.to have_content(dossier_termine.nom_projet) }
+ it { is_expected.to have_content(dossier_termine.entreprise.raison_sociale) }
it { is_expected.to have_content(dossier_termine.display_state) }
it { is_expected.to have_content(dossier_termine.last_update) }
end
describe 'dossier initiated and replied are not present' do
- it { is_expected.not_to have_content(dossier.nom_projet) }
- it { is_expected.not_to have_content(dossier_2.nom_projet) }
+ it { is_expected.not_to have_content(dossier.entreprise.raison_sociale) }
+ it { is_expected.not_to have_content(dossier_2.entreprise.raison_sociale) }
end
end
end
\ No newline at end of file
diff --git a/vendor/assets/javascripts/handlebars.js b/vendor/assets/javascripts/handlebars.js
new file mode 100644
index 000000000..289ae458a
--- /dev/null
+++ b/vendor/assets/javascripts/handlebars.js
@@ -0,0 +1,4608 @@
+/*!
+
+ handlebars v4.0.5
+
+Copyright (C) 2011-2015 by Yehuda Katz
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+@license
+*/
+(function webpackUniversalModuleDefinition(root, factory) {
+ if(typeof exports === 'object' && typeof module === 'object')
+ module.exports = factory();
+ else if(typeof define === 'function' && define.amd)
+ define([], factory);
+ else if(typeof exports === 'object')
+ exports["Handlebars"] = factory();
+ else
+ root["Handlebars"] = factory();
+})(this, function() {
+return /******/ (function(modules) { // webpackBootstrap
+/******/ // The module cache
+/******/ var installedModules = {};
+
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+
+/******/ // Check if module is in cache
+/******/ if(installedModules[moduleId])
+/******/ return installedModules[moduleId].exports;
+
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = installedModules[moduleId] = {
+/******/ exports: {},
+/******/ id: moduleId,
+/******/ loaded: false
+/******/ };
+
+/******/ // Execute the module function
+/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+
+/******/ // Flag the module as loaded
+/******/ module.loaded = true;
+
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+
+
+/******/ // expose the modules object (__webpack_modules__)
+/******/ __webpack_require__.m = modules;
+
+/******/ // expose the module cache
+/******/ __webpack_require__.c = installedModules;
+
+/******/ // __webpack_public_path__
+/******/ __webpack_require__.p = "";
+
+/******/ // Load entry module and return exports
+/******/ return __webpack_require__(0);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _interopRequireDefault = __webpack_require__(1)['default'];
+
+ exports.__esModule = true;
+
+ var _handlebarsRuntime = __webpack_require__(2);
+
+ var _handlebarsRuntime2 = _interopRequireDefault(_handlebarsRuntime);
+
+ // Compiler imports
+
+ var _handlebarsCompilerAst = __webpack_require__(21);
+
+ var _handlebarsCompilerAst2 = _interopRequireDefault(_handlebarsCompilerAst);
+
+ var _handlebarsCompilerBase = __webpack_require__(22);
+
+ var _handlebarsCompilerCompiler = __webpack_require__(27);
+
+ var _handlebarsCompilerJavascriptCompiler = __webpack_require__(28);
+
+ var _handlebarsCompilerJavascriptCompiler2 = _interopRequireDefault(_handlebarsCompilerJavascriptCompiler);
+
+ var _handlebarsCompilerVisitor = __webpack_require__(25);
+
+ var _handlebarsCompilerVisitor2 = _interopRequireDefault(_handlebarsCompilerVisitor);
+
+ var _handlebarsNoConflict = __webpack_require__(20);
+
+ var _handlebarsNoConflict2 = _interopRequireDefault(_handlebarsNoConflict);
+
+ var _create = _handlebarsRuntime2['default'].create;
+ function create() {
+ var hb = _create();
+
+ hb.compile = function (input, options) {
+ return _handlebarsCompilerCompiler.compile(input, options, hb);
+ };
+ hb.precompile = function (input, options) {
+ return _handlebarsCompilerCompiler.precompile(input, options, hb);
+ };
+
+ hb.AST = _handlebarsCompilerAst2['default'];
+ hb.Compiler = _handlebarsCompilerCompiler.Compiler;
+ hb.JavaScriptCompiler = _handlebarsCompilerJavascriptCompiler2['default'];
+ hb.Parser = _handlebarsCompilerBase.parser;
+ hb.parse = _handlebarsCompilerBase.parse;
+
+ return hb;
+ }
+
+ var inst = create();
+ inst.create = create;
+
+ _handlebarsNoConflict2['default'](inst);
+
+ inst.Visitor = _handlebarsCompilerVisitor2['default'];
+
+ inst['default'] = inst;
+
+ exports['default'] = inst;
+ module.exports = exports['default'];
+
+/***/ },
+/* 1 */
+/***/ function(module, exports) {
+
+ "use strict";
+
+ exports["default"] = function (obj) {
+ return obj && obj.__esModule ? obj : {
+ "default": obj
+ };
+ };
+
+ exports.__esModule = true;
+
+/***/ },
+/* 2 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _interopRequireWildcard = __webpack_require__(3)['default'];
+
+ var _interopRequireDefault = __webpack_require__(1)['default'];
+
+ exports.__esModule = true;
+
+ var _handlebarsBase = __webpack_require__(4);
+
+ var base = _interopRequireWildcard(_handlebarsBase);
+
+ // Each of these augment the Handlebars object. No need to setup here.
+ // (This is done to easily share code between commonjs and browse envs)
+
+ var _handlebarsSafeString = __webpack_require__(18);
+
+ var _handlebarsSafeString2 = _interopRequireDefault(_handlebarsSafeString);
+
+ var _handlebarsException = __webpack_require__(6);
+
+ var _handlebarsException2 = _interopRequireDefault(_handlebarsException);
+
+ var _handlebarsUtils = __webpack_require__(5);
+
+ var Utils = _interopRequireWildcard(_handlebarsUtils);
+
+ var _handlebarsRuntime = __webpack_require__(19);
+
+ var runtime = _interopRequireWildcard(_handlebarsRuntime);
+
+ var _handlebarsNoConflict = __webpack_require__(20);
+
+ var _handlebarsNoConflict2 = _interopRequireDefault(_handlebarsNoConflict);
+
+ // For compatibility and usage outside of module systems, make the Handlebars object a namespace
+ function create() {
+ var hb = new base.HandlebarsEnvironment();
+
+ Utils.extend(hb, base);
+ hb.SafeString = _handlebarsSafeString2['default'];
+ hb.Exception = _handlebarsException2['default'];
+ hb.Utils = Utils;
+ hb.escapeExpression = Utils.escapeExpression;
+
+ hb.VM = runtime;
+ hb.template = function (spec) {
+ return runtime.template(spec, hb);
+ };
+
+ return hb;
+ }
+
+ var inst = create();
+ inst.create = create;
+
+ _handlebarsNoConflict2['default'](inst);
+
+ inst['default'] = inst;
+
+ exports['default'] = inst;
+ module.exports = exports['default'];
+
+/***/ },
+/* 3 */
+/***/ function(module, exports) {
+
+ "use strict";
+
+ exports["default"] = function (obj) {
+ if (obj && obj.__esModule) {
+ return obj;
+ } else {
+ var newObj = {};
+
+ if (obj != null) {
+ for (var key in obj) {
+ if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key];
+ }
+ }
+
+ newObj["default"] = obj;
+ return newObj;
+ }
+ };
+
+ exports.__esModule = true;
+
+/***/ },
+/* 4 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _interopRequireDefault = __webpack_require__(1)['default'];
+
+ exports.__esModule = true;
+ exports.HandlebarsEnvironment = HandlebarsEnvironment;
+
+ var _utils = __webpack_require__(5);
+
+ var _exception = __webpack_require__(6);
+
+ var _exception2 = _interopRequireDefault(_exception);
+
+ var _helpers = __webpack_require__(7);
+
+ var _decorators = __webpack_require__(15);
+
+ var _logger = __webpack_require__(17);
+
+ var _logger2 = _interopRequireDefault(_logger);
+
+ var VERSION = '4.0.5';
+ exports.VERSION = VERSION;
+ var COMPILER_REVISION = 7;
+
+ exports.COMPILER_REVISION = COMPILER_REVISION;
+ var REVISION_CHANGES = {
+ 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it
+ 2: '== 1.0.0-rc.3',
+ 3: '== 1.0.0-rc.4',
+ 4: '== 1.x.x',
+ 5: '== 2.0.0-alpha.x',
+ 6: '>= 2.0.0-beta.1',
+ 7: '>= 4.0.0'
+ };
+
+ exports.REVISION_CHANGES = REVISION_CHANGES;
+ var objectType = '[object Object]';
+
+ function HandlebarsEnvironment(helpers, partials, decorators) {
+ this.helpers = helpers || {};
+ this.partials = partials || {};
+ this.decorators = decorators || {};
+
+ _helpers.registerDefaultHelpers(this);
+ _decorators.registerDefaultDecorators(this);
+ }
+
+ HandlebarsEnvironment.prototype = {
+ constructor: HandlebarsEnvironment,
+
+ logger: _logger2['default'],
+ log: _logger2['default'].log,
+
+ registerHelper: function registerHelper(name, fn) {
+ if (_utils.toString.call(name) === objectType) {
+ if (fn) {
+ throw new _exception2['default']('Arg not supported with multiple helpers');
+ }
+ _utils.extend(this.helpers, name);
+ } else {
+ this.helpers[name] = fn;
+ }
+ },
+ unregisterHelper: function unregisterHelper(name) {
+ delete this.helpers[name];
+ },
+
+ registerPartial: function registerPartial(name, partial) {
+ if (_utils.toString.call(name) === objectType) {
+ _utils.extend(this.partials, name);
+ } else {
+ if (typeof partial === 'undefined') {
+ throw new _exception2['default']('Attempting to register a partial called "' + name + '" as undefined');
+ }
+ this.partials[name] = partial;
+ }
+ },
+ unregisterPartial: function unregisterPartial(name) {
+ delete this.partials[name];
+ },
+
+ registerDecorator: function registerDecorator(name, fn) {
+ if (_utils.toString.call(name) === objectType) {
+ if (fn) {
+ throw new _exception2['default']('Arg not supported with multiple decorators');
+ }
+ _utils.extend(this.decorators, name);
+ } else {
+ this.decorators[name] = fn;
+ }
+ },
+ unregisterDecorator: function unregisterDecorator(name) {
+ delete this.decorators[name];
+ }
+ };
+
+ var log = _logger2['default'].log;
+
+ exports.log = log;
+ exports.createFrame = _utils.createFrame;
+ exports.logger = _logger2['default'];
+
+/***/ },
+/* 5 */
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+ exports.extend = extend;
+ exports.indexOf = indexOf;
+ exports.escapeExpression = escapeExpression;
+ exports.isEmpty = isEmpty;
+ exports.createFrame = createFrame;
+ exports.blockParams = blockParams;
+ exports.appendContextPath = appendContextPath;
+ var escape = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ "'": ''',
+ '`': '`',
+ '=': '='
+ };
+
+ var badChars = /[&<>"'`=]/g,
+ possible = /[&<>"'`=]/;
+
+ function escapeChar(chr) {
+ return escape[chr];
+ }
+
+ function extend(obj /* , ...source */) {
+ for (var i = 1; i < arguments.length; i++) {
+ for (var key in arguments[i]) {
+ if (Object.prototype.hasOwnProperty.call(arguments[i], key)) {
+ obj[key] = arguments[i][key];
+ }
+ }
+ }
+
+ return obj;
+ }
+
+ var toString = Object.prototype.toString;
+
+ exports.toString = toString;
+ // Sourced from lodash
+ // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt
+ /* eslint-disable func-style */
+ var isFunction = function isFunction(value) {
+ return typeof value === 'function';
+ };
+ // fallback for older versions of Chrome and Safari
+ /* istanbul ignore next */
+ if (isFunction(/x/)) {
+ exports.isFunction = isFunction = function (value) {
+ return typeof value === 'function' && toString.call(value) === '[object Function]';
+ };
+ }
+ exports.isFunction = isFunction;
+
+ /* eslint-enable func-style */
+
+ /* istanbul ignore next */
+ var isArray = Array.isArray || function (value) {
+ return value && typeof value === 'object' ? toString.call(value) === '[object Array]' : false;
+ };
+
+ exports.isArray = isArray;
+ // Older IE versions do not directly support indexOf so we must implement our own, sadly.
+
+ function indexOf(array, value) {
+ for (var i = 0, len = array.length; i < len; i++) {
+ if (array[i] === value) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ function escapeExpression(string) {
+ if (typeof string !== 'string') {
+ // don't escape SafeStrings, since they're already safe
+ if (string && string.toHTML) {
+ return string.toHTML();
+ } else if (string == null) {
+ return '';
+ } else if (!string) {
+ return string + '';
+ }
+
+ // Force a string conversion as this will be done by the append regardless and
+ // the regex test will do this transparently behind the scenes, causing issues if
+ // an object's to string has escaped characters in it.
+ string = '' + string;
+ }
+
+ if (!possible.test(string)) {
+ return string;
+ }
+ return string.replace(badChars, escapeChar);
+ }
+
+ function isEmpty(value) {
+ if (!value && value !== 0) {
+ return true;
+ } else if (isArray(value) && value.length === 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ function createFrame(object) {
+ var frame = extend({}, object);
+ frame._parent = object;
+ return frame;
+ }
+
+ function blockParams(params, ids) {
+ params.path = ids;
+ return params;
+ }
+
+ function appendContextPath(contextPath, id) {
+ return (contextPath ? contextPath + '.' : '') + id;
+ }
+
+/***/ },
+/* 6 */
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+
+ var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
+
+ function Exception(message, node) {
+ var loc = node && node.loc,
+ line = undefined,
+ column = undefined;
+ if (loc) {
+ line = loc.start.line;
+ column = loc.start.column;
+
+ message += ' - ' + line + ':' + column;
+ }
+
+ var tmp = Error.prototype.constructor.call(this, message);
+
+ // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work.
+ for (var idx = 0; idx < errorProps.length; idx++) {
+ this[errorProps[idx]] = tmp[errorProps[idx]];
+ }
+
+ /* istanbul ignore else */
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this, Exception);
+ }
+
+ if (loc) {
+ this.lineNumber = line;
+ this.column = column;
+ }
+ }
+
+ Exception.prototype = new Error();
+
+ exports['default'] = Exception;
+ module.exports = exports['default'];
+
+/***/ },
+/* 7 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _interopRequireDefault = __webpack_require__(1)['default'];
+
+ exports.__esModule = true;
+ exports.registerDefaultHelpers = registerDefaultHelpers;
+
+ var _helpersBlockHelperMissing = __webpack_require__(8);
+
+ var _helpersBlockHelperMissing2 = _interopRequireDefault(_helpersBlockHelperMissing);
+
+ var _helpersEach = __webpack_require__(9);
+
+ var _helpersEach2 = _interopRequireDefault(_helpersEach);
+
+ var _helpersHelperMissing = __webpack_require__(10);
+
+ var _helpersHelperMissing2 = _interopRequireDefault(_helpersHelperMissing);
+
+ var _helpersIf = __webpack_require__(11);
+
+ var _helpersIf2 = _interopRequireDefault(_helpersIf);
+
+ var _helpersLog = __webpack_require__(12);
+
+ var _helpersLog2 = _interopRequireDefault(_helpersLog);
+
+ var _helpersLookup = __webpack_require__(13);
+
+ var _helpersLookup2 = _interopRequireDefault(_helpersLookup);
+
+ var _helpersWith = __webpack_require__(14);
+
+ var _helpersWith2 = _interopRequireDefault(_helpersWith);
+
+ function registerDefaultHelpers(instance) {
+ _helpersBlockHelperMissing2['default'](instance);
+ _helpersEach2['default'](instance);
+ _helpersHelperMissing2['default'](instance);
+ _helpersIf2['default'](instance);
+ _helpersLog2['default'](instance);
+ _helpersLookup2['default'](instance);
+ _helpersWith2['default'](instance);
+ }
+
+/***/ },
+/* 8 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+
+ var _utils = __webpack_require__(5);
+
+ exports['default'] = function (instance) {
+ instance.registerHelper('blockHelperMissing', function (context, options) {
+ var inverse = options.inverse,
+ fn = options.fn;
+
+ if (context === true) {
+ return fn(this);
+ } else if (context === false || context == null) {
+ return inverse(this);
+ } else if (_utils.isArray(context)) {
+ if (context.length > 0) {
+ if (options.ids) {
+ options.ids = [options.name];
+ }
+
+ return instance.helpers.each(context, options);
+ } else {
+ return inverse(this);
+ }
+ } else {
+ if (options.data && options.ids) {
+ var data = _utils.createFrame(options.data);
+ data.contextPath = _utils.appendContextPath(options.data.contextPath, options.name);
+ options = { data: data };
+ }
+
+ return fn(context, options);
+ }
+ });
+ };
+
+ module.exports = exports['default'];
+
+/***/ },
+/* 9 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _interopRequireDefault = __webpack_require__(1)['default'];
+
+ exports.__esModule = true;
+
+ var _utils = __webpack_require__(5);
+
+ var _exception = __webpack_require__(6);
+
+ var _exception2 = _interopRequireDefault(_exception);
+
+ exports['default'] = function (instance) {
+ instance.registerHelper('each', function (context, options) {
+ if (!options) {
+ throw new _exception2['default']('Must pass iterator to #each');
+ }
+
+ var fn = options.fn,
+ inverse = options.inverse,
+ i = 0,
+ ret = '',
+ data = undefined,
+ contextPath = undefined;
+
+ if (options.data && options.ids) {
+ contextPath = _utils.appendContextPath(options.data.contextPath, options.ids[0]) + '.';
+ }
+
+ if (_utils.isFunction(context)) {
+ context = context.call(this);
+ }
+
+ if (options.data) {
+ data = _utils.createFrame(options.data);
+ }
+
+ function execIteration(field, index, last) {
+ if (data) {
+ data.key = field;
+ data.index = index;
+ data.first = index === 0;
+ data.last = !!last;
+
+ if (contextPath) {
+ data.contextPath = contextPath + field;
+ }
+ }
+
+ ret = ret + fn(context[field], {
+ data: data,
+ blockParams: _utils.blockParams([context[field], field], [contextPath + field, null])
+ });
+ }
+
+ if (context && typeof context === 'object') {
+ if (_utils.isArray(context)) {
+ for (var j = context.length; i < j; i++) {
+ if (i in context) {
+ execIteration(i, i, i === context.length - 1);
+ }
+ }
+ } else {
+ var priorKey = undefined;
+
+ for (var key in context) {
+ if (context.hasOwnProperty(key)) {
+ // We're running the iterations one step out of sync so we can detect
+ // the last iteration without have to scan the object twice and create
+ // an itermediate keys array.
+ if (priorKey !== undefined) {
+ execIteration(priorKey, i - 1);
+ }
+ priorKey = key;
+ i++;
+ }
+ }
+ if (priorKey !== undefined) {
+ execIteration(priorKey, i - 1, true);
+ }
+ }
+ }
+
+ if (i === 0) {
+ ret = inverse(this);
+ }
+
+ return ret;
+ });
+ };
+
+ module.exports = exports['default'];
+
+/***/ },
+/* 10 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _interopRequireDefault = __webpack_require__(1)['default'];
+
+ exports.__esModule = true;
+
+ var _exception = __webpack_require__(6);
+
+ var _exception2 = _interopRequireDefault(_exception);
+
+ exports['default'] = function (instance) {
+ instance.registerHelper('helperMissing', function () /* [args, ]options */{
+ if (arguments.length === 1) {
+ // A missing field in a {{foo}} construct.
+ return undefined;
+ } else {
+ // Someone is actually trying to call something, blow up.
+ throw new _exception2['default']('Missing helper: "' + arguments[arguments.length - 1].name + '"');
+ }
+ });
+ };
+
+ module.exports = exports['default'];
+
+/***/ },
+/* 11 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+
+ var _utils = __webpack_require__(5);
+
+ exports['default'] = function (instance) {
+ instance.registerHelper('if', function (conditional, options) {
+ if (_utils.isFunction(conditional)) {
+ conditional = conditional.call(this);
+ }
+
+ // Default behavior is to render the positive path if the value is truthy and not empty.
+ // The `includeZero` option may be set to treat the condtional as purely not empty based on the
+ // behavior of isEmpty. Effectively this determines if 0 is handled by the positive path or negative.
+ if (!options.hash.includeZero && !conditional || _utils.isEmpty(conditional)) {
+ return options.inverse(this);
+ } else {
+ return options.fn(this);
+ }
+ });
+
+ instance.registerHelper('unless', function (conditional, options) {
+ return instance.helpers['if'].call(this, conditional, { fn: options.inverse, inverse: options.fn, hash: options.hash });
+ });
+ };
+
+ module.exports = exports['default'];
+
+/***/ },
+/* 12 */
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+
+ exports['default'] = function (instance) {
+ instance.registerHelper('log', function () /* message, options */{
+ var args = [undefined],
+ options = arguments[arguments.length - 1];
+ for (var i = 0; i < arguments.length - 1; i++) {
+ args.push(arguments[i]);
+ }
+
+ var level = 1;
+ if (options.hash.level != null) {
+ level = options.hash.level;
+ } else if (options.data && options.data.level != null) {
+ level = options.data.level;
+ }
+ args[0] = level;
+
+ instance.log.apply(instance, args);
+ });
+ };
+
+ module.exports = exports['default'];
+
+/***/ },
+/* 13 */
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+
+ exports['default'] = function (instance) {
+ instance.registerHelper('lookup', function (obj, field) {
+ return obj && obj[field];
+ });
+ };
+
+ module.exports = exports['default'];
+
+/***/ },
+/* 14 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+
+ var _utils = __webpack_require__(5);
+
+ exports['default'] = function (instance) {
+ instance.registerHelper('with', function (context, options) {
+ if (_utils.isFunction(context)) {
+ context = context.call(this);
+ }
+
+ var fn = options.fn;
+
+ if (!_utils.isEmpty(context)) {
+ var data = options.data;
+ if (options.data && options.ids) {
+ data = _utils.createFrame(options.data);
+ data.contextPath = _utils.appendContextPath(options.data.contextPath, options.ids[0]);
+ }
+
+ return fn(context, {
+ data: data,
+ blockParams: _utils.blockParams([context], [data && data.contextPath])
+ });
+ } else {
+ return options.inverse(this);
+ }
+ });
+ };
+
+ module.exports = exports['default'];
+
+/***/ },
+/* 15 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _interopRequireDefault = __webpack_require__(1)['default'];
+
+ exports.__esModule = true;
+ exports.registerDefaultDecorators = registerDefaultDecorators;
+
+ var _decoratorsInline = __webpack_require__(16);
+
+ var _decoratorsInline2 = _interopRequireDefault(_decoratorsInline);
+
+ function registerDefaultDecorators(instance) {
+ _decoratorsInline2['default'](instance);
+ }
+
+/***/ },
+/* 16 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+
+ var _utils = __webpack_require__(5);
+
+ exports['default'] = function (instance) {
+ instance.registerDecorator('inline', function (fn, props, container, options) {
+ var ret = fn;
+ if (!props.partials) {
+ props.partials = {};
+ ret = function (context, options) {
+ // Create a new partials stack frame prior to exec.
+ var original = container.partials;
+ container.partials = _utils.extend({}, original, props.partials);
+ var ret = fn(context, options);
+ container.partials = original;
+ return ret;
+ };
+ }
+
+ props.partials[options.args[0]] = options.fn;
+
+ return ret;
+ });
+ };
+
+ module.exports = exports['default'];
+
+/***/ },
+/* 17 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+
+ var _utils = __webpack_require__(5);
+
+ var logger = {
+ methodMap: ['debug', 'info', 'warn', 'error'],
+ level: 'info',
+
+ // Maps a given level value to the `methodMap` indexes above.
+ lookupLevel: function lookupLevel(level) {
+ if (typeof level === 'string') {
+ var levelMap = _utils.indexOf(logger.methodMap, level.toLowerCase());
+ if (levelMap >= 0) {
+ level = levelMap;
+ } else {
+ level = parseInt(level, 10);
+ }
+ }
+
+ return level;
+ },
+
+ // Can be overridden in the host environment
+ log: function log(level) {
+ level = logger.lookupLevel(level);
+
+ if (typeof console !== 'undefined' && logger.lookupLevel(logger.level) <= level) {
+ var method = logger.methodMap[level];
+ if (!console[method]) {
+ // eslint-disable-line no-console
+ method = 'log';
+ }
+
+ for (var _len = arguments.length, message = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
+ message[_key - 1] = arguments[_key];
+ }
+
+ console[method].apply(console, message); // eslint-disable-line no-console
+ }
+ }
+ };
+
+ exports['default'] = logger;
+ module.exports = exports['default'];
+
+/***/ },
+/* 18 */
+/***/ function(module, exports) {
+
+ // Build out our basic SafeString type
+ 'use strict';
+
+ exports.__esModule = true;
+ function SafeString(string) {
+ this.string = string;
+ }
+
+ SafeString.prototype.toString = SafeString.prototype.toHTML = function () {
+ return '' + this.string;
+ };
+
+ exports['default'] = SafeString;
+ module.exports = exports['default'];
+
+/***/ },
+/* 19 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _interopRequireWildcard = __webpack_require__(3)['default'];
+
+ var _interopRequireDefault = __webpack_require__(1)['default'];
+
+ exports.__esModule = true;
+ exports.checkRevision = checkRevision;
+ exports.template = template;
+ exports.wrapProgram = wrapProgram;
+ exports.resolvePartial = resolvePartial;
+ exports.invokePartial = invokePartial;
+ exports.noop = noop;
+
+ var _utils = __webpack_require__(5);
+
+ var Utils = _interopRequireWildcard(_utils);
+
+ var _exception = __webpack_require__(6);
+
+ var _exception2 = _interopRequireDefault(_exception);
+
+ var _base = __webpack_require__(4);
+
+ function checkRevision(compilerInfo) {
+ var compilerRevision = compilerInfo && compilerInfo[0] || 1,
+ currentRevision = _base.COMPILER_REVISION;
+
+ if (compilerRevision !== currentRevision) {
+ if (compilerRevision < currentRevision) {
+ var runtimeVersions = _base.REVISION_CHANGES[currentRevision],
+ compilerVersions = _base.REVISION_CHANGES[compilerRevision];
+ throw new _exception2['default']('Template was precompiled with an older version of Handlebars than the current runtime. ' + 'Please update your precompiler to a newer version (' + runtimeVersions + ') or downgrade your runtime to an older version (' + compilerVersions + ').');
+ } else {
+ // Use the embedded version info since the runtime doesn't know about this revision yet
+ throw new _exception2['default']('Template was precompiled with a newer version of Handlebars than the current runtime. ' + 'Please update your runtime to a newer version (' + compilerInfo[1] + ').');
+ }
+ }
+ }
+
+ function template(templateSpec, env) {
+ /* istanbul ignore next */
+ if (!env) {
+ throw new _exception2['default']('No environment passed to template');
+ }
+ if (!templateSpec || !templateSpec.main) {
+ throw new _exception2['default']('Unknown template object: ' + typeof templateSpec);
+ }
+
+ templateSpec.main.decorator = templateSpec.main_d;
+
+ // Note: Using env.VM references rather than local var references throughout this section to allow
+ // for external users to override these as psuedo-supported APIs.
+ env.VM.checkRevision(templateSpec.compiler);
+
+ function invokePartialWrapper(partial, context, options) {
+ if (options.hash) {
+ context = Utils.extend({}, context, options.hash);
+ if (options.ids) {
+ options.ids[0] = true;
+ }
+ }
+
+ partial = env.VM.resolvePartial.call(this, partial, context, options);
+ var result = env.VM.invokePartial.call(this, partial, context, options);
+
+ if (result == null && env.compile) {
+ options.partials[options.name] = env.compile(partial, templateSpec.compilerOptions, env);
+ result = options.partials[options.name](context, options);
+ }
+ if (result != null) {
+ if (options.indent) {
+ var lines = result.split('\n');
+ for (var i = 0, l = lines.length; i < l; i++) {
+ if (!lines[i] && i + 1 === l) {
+ break;
+ }
+
+ lines[i] = options.indent + lines[i];
+ }
+ result = lines.join('\n');
+ }
+ return result;
+ } else {
+ throw new _exception2['default']('The partial ' + options.name + ' could not be compiled when running in runtime-only mode');
+ }
+ }
+
+ // Just add water
+ var container = {
+ strict: function strict(obj, name) {
+ if (!(name in obj)) {
+ throw new _exception2['default']('"' + name + '" not defined in ' + obj);
+ }
+ return obj[name];
+ },
+ lookup: function lookup(depths, name) {
+ var len = depths.length;
+ for (var i = 0; i < len; i++) {
+ if (depths[i] && depths[i][name] != null) {
+ return depths[i][name];
+ }
+ }
+ },
+ lambda: function lambda(current, context) {
+ return typeof current === 'function' ? current.call(context) : current;
+ },
+
+ escapeExpression: Utils.escapeExpression,
+ invokePartial: invokePartialWrapper,
+
+ fn: function fn(i) {
+ var ret = templateSpec[i];
+ ret.decorator = templateSpec[i + '_d'];
+ return ret;
+ },
+
+ programs: [],
+ program: function program(i, data, declaredBlockParams, blockParams, depths) {
+ var programWrapper = this.programs[i],
+ fn = this.fn(i);
+ if (data || depths || blockParams || declaredBlockParams) {
+ programWrapper = wrapProgram(this, i, fn, data, declaredBlockParams, blockParams, depths);
+ } else if (!programWrapper) {
+ programWrapper = this.programs[i] = wrapProgram(this, i, fn);
+ }
+ return programWrapper;
+ },
+
+ data: function data(value, depth) {
+ while (value && depth--) {
+ value = value._parent;
+ }
+ return value;
+ },
+ merge: function merge(param, common) {
+ var obj = param || common;
+
+ if (param && common && param !== common) {
+ obj = Utils.extend({}, common, param);
+ }
+
+ return obj;
+ },
+
+ noop: env.VM.noop,
+ compilerInfo: templateSpec.compiler
+ };
+
+ function ret(context) {
+ var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
+
+ var data = options.data;
+
+ ret._setup(options);
+ if (!options.partial && templateSpec.useData) {
+ data = initData(context, data);
+ }
+ var depths = undefined,
+ blockParams = templateSpec.useBlockParams ? [] : undefined;
+ if (templateSpec.useDepths) {
+ if (options.depths) {
+ depths = context !== options.depths[0] ? [context].concat(options.depths) : options.depths;
+ } else {
+ depths = [context];
+ }
+ }
+
+ function main(context /*, options*/) {
+ return '' + templateSpec.main(container, context, container.helpers, container.partials, data, blockParams, depths);
+ }
+ main = executeDecorators(templateSpec.main, main, container, options.depths || [], data, blockParams);
+ return main(context, options);
+ }
+ ret.isTop = true;
+
+ ret._setup = function (options) {
+ if (!options.partial) {
+ container.helpers = container.merge(options.helpers, env.helpers);
+
+ if (templateSpec.usePartial) {
+ container.partials = container.merge(options.partials, env.partials);
+ }
+ if (templateSpec.usePartial || templateSpec.useDecorators) {
+ container.decorators = container.merge(options.decorators, env.decorators);
+ }
+ } else {
+ container.helpers = options.helpers;
+ container.partials = options.partials;
+ container.decorators = options.decorators;
+ }
+ };
+
+ ret._child = function (i, data, blockParams, depths) {
+ if (templateSpec.useBlockParams && !blockParams) {
+ throw new _exception2['default']('must pass block params');
+ }
+ if (templateSpec.useDepths && !depths) {
+ throw new _exception2['default']('must pass parent depths');
+ }
+
+ return wrapProgram(container, i, templateSpec[i], data, 0, blockParams, depths);
+ };
+ return ret;
+ }
+
+ function wrapProgram(container, i, fn, data, declaredBlockParams, blockParams, depths) {
+ function prog(context) {
+ var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
+
+ var currentDepths = depths;
+ if (depths && context !== depths[0]) {
+ currentDepths = [context].concat(depths);
+ }
+
+ return fn(container, context, container.helpers, container.partials, options.data || data, blockParams && [options.blockParams].concat(blockParams), currentDepths);
+ }
+
+ prog = executeDecorators(fn, prog, container, depths, data, blockParams);
+
+ prog.program = i;
+ prog.depth = depths ? depths.length : 0;
+ prog.blockParams = declaredBlockParams || 0;
+ return prog;
+ }
+
+ function resolvePartial(partial, context, options) {
+ if (!partial) {
+ if (options.name === '@partial-block') {
+ partial = options.data['partial-block'];
+ } else {
+ partial = options.partials[options.name];
+ }
+ } else if (!partial.call && !options.name) {
+ // This is a dynamic partial that returned a string
+ options.name = partial;
+ partial = options.partials[partial];
+ }
+ return partial;
+ }
+
+ function invokePartial(partial, context, options) {
+ options.partial = true;
+ if (options.ids) {
+ options.data.contextPath = options.ids[0] || options.data.contextPath;
+ }
+
+ var partialBlock = undefined;
+ if (options.fn && options.fn !== noop) {
+ options.data = _base.createFrame(options.data);
+ partialBlock = options.data['partial-block'] = options.fn;
+
+ if (partialBlock.partials) {
+ options.partials = Utils.extend({}, options.partials, partialBlock.partials);
+ }
+ }
+
+ if (partial === undefined && partialBlock) {
+ partial = partialBlock;
+ }
+
+ if (partial === undefined) {
+ throw new _exception2['default']('The partial ' + options.name + ' could not be found');
+ } else if (partial instanceof Function) {
+ return partial(context, options);
+ }
+ }
+
+ function noop() {
+ return '';
+ }
+
+ function initData(context, data) {
+ if (!data || !('root' in data)) {
+ data = data ? _base.createFrame(data) : {};
+ data.root = context;
+ }
+ return data;
+ }
+
+ function executeDecorators(fn, prog, container, depths, data, blockParams) {
+ if (fn.decorator) {
+ var props = {};
+ prog = fn.decorator(prog, props, container, depths && depths[0], data, blockParams, depths);
+ Utils.extend(prog, props);
+ }
+ return prog;
+ }
+
+/***/ },
+/* 20 */
+/***/ function(module, exports) {
+
+ /* WEBPACK VAR INJECTION */(function(global) {/* global window */
+ 'use strict';
+
+ exports.__esModule = true;
+
+ exports['default'] = function (Handlebars) {
+ /* istanbul ignore next */
+ var root = typeof global !== 'undefined' ? global : window,
+ $Handlebars = root.Handlebars;
+ /* istanbul ignore next */
+ Handlebars.noConflict = function () {
+ if (root.Handlebars === Handlebars) {
+ root.Handlebars = $Handlebars;
+ }
+ return Handlebars;
+ };
+ };
+
+ module.exports = exports['default'];
+ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
+
+/***/ },
+/* 21 */
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+ var AST = {
+ // Public API used to evaluate derived attributes regarding AST nodes
+ helpers: {
+ // a mustache is definitely a helper if:
+ // * it is an eligible helper, and
+ // * it has at least one parameter or hash segment
+ helperExpression: function helperExpression(node) {
+ return node.type === 'SubExpression' || (node.type === 'MustacheStatement' || node.type === 'BlockStatement') && !!(node.params && node.params.length || node.hash);
+ },
+
+ scopedId: function scopedId(path) {
+ return (/^\.|this\b/.test(path.original)
+ );
+ },
+
+ // an ID is simple if it only has one part, and that part is not
+ // `..` or `this`.
+ simpleId: function simpleId(path) {
+ return path.parts.length === 1 && !AST.helpers.scopedId(path) && !path.depth;
+ }
+ }
+ };
+
+ // Must be exported as an object rather than the root of the module as the jison lexer
+ // must modify the object to operate properly.
+ exports['default'] = AST;
+ module.exports = exports['default'];
+
+/***/ },
+/* 22 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _interopRequireDefault = __webpack_require__(1)['default'];
+
+ var _interopRequireWildcard = __webpack_require__(3)['default'];
+
+ exports.__esModule = true;
+ exports.parse = parse;
+
+ var _parser = __webpack_require__(23);
+
+ var _parser2 = _interopRequireDefault(_parser);
+
+ var _whitespaceControl = __webpack_require__(24);
+
+ var _whitespaceControl2 = _interopRequireDefault(_whitespaceControl);
+
+ var _helpers = __webpack_require__(26);
+
+ var Helpers = _interopRequireWildcard(_helpers);
+
+ var _utils = __webpack_require__(5);
+
+ exports.parser = _parser2['default'];
+
+ var yy = {};
+ _utils.extend(yy, Helpers);
+
+ function parse(input, options) {
+ // Just return if an already-compiled AST was passed in.
+ if (input.type === 'Program') {
+ return input;
+ }
+
+ _parser2['default'].yy = yy;
+
+ // Altering the shared object here, but this is ok as parser is a sync operation
+ yy.locInfo = function (locInfo) {
+ return new yy.SourceLocation(options && options.srcName, locInfo);
+ };
+
+ var strip = new _whitespaceControl2['default'](options);
+ return strip.accept(_parser2['default'].parse(input));
+ }
+
+/***/ },
+/* 23 */
+/***/ function(module, exports) {
+
+ /* istanbul ignore next */
+ /* Jison generated parser */
+ "use strict";
+
+ var handlebars = (function () {
+ var parser = { trace: function trace() {},
+ yy: {},
+ symbols_: { "error": 2, "root": 3, "program": 4, "EOF": 5, "program_repetition0": 6, "statement": 7, "mustache": 8, "block": 9, "rawBlock": 10, "partial": 11, "partialBlock": 12, "content": 13, "COMMENT": 14, "CONTENT": 15, "openRawBlock": 16, "rawBlock_repetition_plus0": 17, "END_RAW_BLOCK": 18, "OPEN_RAW_BLOCK": 19, "helperName": 20, "openRawBlock_repetition0": 21, "openRawBlock_option0": 22, "CLOSE_RAW_BLOCK": 23, "openBlock": 24, "block_option0": 25, "closeBlock": 26, "openInverse": 27, "block_option1": 28, "OPEN_BLOCK": 29, "openBlock_repetition0": 30, "openBlock_option0": 31, "openBlock_option1": 32, "CLOSE": 33, "OPEN_INVERSE": 34, "openInverse_repetition0": 35, "openInverse_option0": 36, "openInverse_option1": 37, "openInverseChain": 38, "OPEN_INVERSE_CHAIN": 39, "openInverseChain_repetition0": 40, "openInverseChain_option0": 41, "openInverseChain_option1": 42, "inverseAndProgram": 43, "INVERSE": 44, "inverseChain": 45, "inverseChain_option0": 46, "OPEN_ENDBLOCK": 47, "OPEN": 48, "mustache_repetition0": 49, "mustache_option0": 50, "OPEN_UNESCAPED": 51, "mustache_repetition1": 52, "mustache_option1": 53, "CLOSE_UNESCAPED": 54, "OPEN_PARTIAL": 55, "partialName": 56, "partial_repetition0": 57, "partial_option0": 58, "openPartialBlock": 59, "OPEN_PARTIAL_BLOCK": 60, "openPartialBlock_repetition0": 61, "openPartialBlock_option0": 62, "param": 63, "sexpr": 64, "OPEN_SEXPR": 65, "sexpr_repetition0": 66, "sexpr_option0": 67, "CLOSE_SEXPR": 68, "hash": 69, "hash_repetition_plus0": 70, "hashSegment": 71, "ID": 72, "EQUALS": 73, "blockParams": 74, "OPEN_BLOCK_PARAMS": 75, "blockParams_repetition_plus0": 76, "CLOSE_BLOCK_PARAMS": 77, "path": 78, "dataName": 79, "STRING": 80, "NUMBER": 81, "BOOLEAN": 82, "UNDEFINED": 83, "NULL": 84, "DATA": 85, "pathSegments": 86, "SEP": 87, "$accept": 0, "$end": 1 },
+ terminals_: { 2: "error", 5: "EOF", 14: "COMMENT", 15: "CONTENT", 18: "END_RAW_BLOCK", 19: "OPEN_RAW_BLOCK", 23: "CLOSE_RAW_BLOCK", 29: "OPEN_BLOCK", 33: "CLOSE", 34: "OPEN_INVERSE", 39: "OPEN_INVERSE_CHAIN", 44: "INVERSE", 47: "OPEN_ENDBLOCK", 48: "OPEN", 51: "OPEN_UNESCAPED", 54: "CLOSE_UNESCAPED", 55: "OPEN_PARTIAL", 60: "OPEN_PARTIAL_BLOCK", 65: "OPEN_SEXPR", 68: "CLOSE_SEXPR", 72: "ID", 73: "EQUALS", 75: "OPEN_BLOCK_PARAMS", 77: "CLOSE_BLOCK_PARAMS", 80: "STRING", 81: "NUMBER", 82: "BOOLEAN", 83: "UNDEFINED", 84: "NULL", 85: "DATA", 87: "SEP" },
+ productions_: [0, [3, 2], [4, 1], [7, 1], [7, 1], [7, 1], [7, 1], [7, 1], [7, 1], [7, 1], [13, 1], [10, 3], [16, 5], [9, 4], [9, 4], [24, 6], [27, 6], [38, 6], [43, 2], [45, 3], [45, 1], [26, 3], [8, 5], [8, 5], [11, 5], [12, 3], [59, 5], [63, 1], [63, 1], [64, 5], [69, 1], [71, 3], [74, 3], [20, 1], [20, 1], [20, 1], [20, 1], [20, 1], [20, 1], [20, 1], [56, 1], [56, 1], [79, 2], [78, 1], [86, 3], [86, 1], [6, 0], [6, 2], [17, 1], [17, 2], [21, 0], [21, 2], [22, 0], [22, 1], [25, 0], [25, 1], [28, 0], [28, 1], [30, 0], [30, 2], [31, 0], [31, 1], [32, 0], [32, 1], [35, 0], [35, 2], [36, 0], [36, 1], [37, 0], [37, 1], [40, 0], [40, 2], [41, 0], [41, 1], [42, 0], [42, 1], [46, 0], [46, 1], [49, 0], [49, 2], [50, 0], [50, 1], [52, 0], [52, 2], [53, 0], [53, 1], [57, 0], [57, 2], [58, 0], [58, 1], [61, 0], [61, 2], [62, 0], [62, 1], [66, 0], [66, 2], [67, 0], [67, 1], [70, 1], [70, 2], [76, 1], [76, 2]],
+ performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$
+ /**/) {
+
+ var $0 = $$.length - 1;
+ switch (yystate) {
+ case 1:
+ return $$[$0 - 1];
+ break;
+ case 2:
+ this.$ = yy.prepareProgram($$[$0]);
+ break;
+ case 3:
+ this.$ = $$[$0];
+ break;
+ case 4:
+ this.$ = $$[$0];
+ break;
+ case 5:
+ this.$ = $$[$0];
+ break;
+ case 6:
+ this.$ = $$[$0];
+ break;
+ case 7:
+ this.$ = $$[$0];
+ break;
+ case 8:
+ this.$ = $$[$0];
+ break;
+ case 9:
+ this.$ = {
+ type: 'CommentStatement',
+ value: yy.stripComment($$[$0]),
+ strip: yy.stripFlags($$[$0], $$[$0]),
+ loc: yy.locInfo(this._$)
+ };
+
+ break;
+ case 10:
+ this.$ = {
+ type: 'ContentStatement',
+ original: $$[$0],
+ value: $$[$0],
+ loc: yy.locInfo(this._$)
+ };
+
+ break;
+ case 11:
+ this.$ = yy.prepareRawBlock($$[$0 - 2], $$[$0 - 1], $$[$0], this._$);
+ break;
+ case 12:
+ this.$ = { path: $$[$0 - 3], params: $$[$0 - 2], hash: $$[$0 - 1] };
+ break;
+ case 13:
+ this.$ = yy.prepareBlock($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0], false, this._$);
+ break;
+ case 14:
+ this.$ = yy.prepareBlock($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0], true, this._$);
+ break;
+ case 15:
+ this.$ = { open: $$[$0 - 5], path: $$[$0 - 4], params: $$[$0 - 3], hash: $$[$0 - 2], blockParams: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 5], $$[$0]) };
+ break;
+ case 16:
+ this.$ = { path: $$[$0 - 4], params: $$[$0 - 3], hash: $$[$0 - 2], blockParams: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 5], $$[$0]) };
+ break;
+ case 17:
+ this.$ = { path: $$[$0 - 4], params: $$[$0 - 3], hash: $$[$0 - 2], blockParams: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 5], $$[$0]) };
+ break;
+ case 18:
+ this.$ = { strip: yy.stripFlags($$[$0 - 1], $$[$0 - 1]), program: $$[$0] };
+ break;
+ case 19:
+ var inverse = yy.prepareBlock($$[$0 - 2], $$[$0 - 1], $$[$0], $$[$0], false, this._$),
+ program = yy.prepareProgram([inverse], $$[$0 - 1].loc);
+ program.chained = true;
+
+ this.$ = { strip: $$[$0 - 2].strip, program: program, chain: true };
+
+ break;
+ case 20:
+ this.$ = $$[$0];
+ break;
+ case 21:
+ this.$ = { path: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 2], $$[$0]) };
+ break;
+ case 22:
+ this.$ = yy.prepareMustache($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0 - 4], yy.stripFlags($$[$0 - 4], $$[$0]), this._$);
+ break;
+ case 23:
+ this.$ = yy.prepareMustache($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0 - 4], yy.stripFlags($$[$0 - 4], $$[$0]), this._$);
+ break;
+ case 24:
+ this.$ = {
+ type: 'PartialStatement',
+ name: $$[$0 - 3],
+ params: $$[$0 - 2],
+ hash: $$[$0 - 1],
+ indent: '',
+ strip: yy.stripFlags($$[$0 - 4], $$[$0]),
+ loc: yy.locInfo(this._$)
+ };
+
+ break;
+ case 25:
+ this.$ = yy.preparePartialBlock($$[$0 - 2], $$[$0 - 1], $$[$0], this._$);
+ break;
+ case 26:
+ this.$ = { path: $$[$0 - 3], params: $$[$0 - 2], hash: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 4], $$[$0]) };
+ break;
+ case 27:
+ this.$ = $$[$0];
+ break;
+ case 28:
+ this.$ = $$[$0];
+ break;
+ case 29:
+ this.$ = {
+ type: 'SubExpression',
+ path: $$[$0 - 3],
+ params: $$[$0 - 2],
+ hash: $$[$0 - 1],
+ loc: yy.locInfo(this._$)
+ };
+
+ break;
+ case 30:
+ this.$ = { type: 'Hash', pairs: $$[$0], loc: yy.locInfo(this._$) };
+ break;
+ case 31:
+ this.$ = { type: 'HashPair', key: yy.id($$[$0 - 2]), value: $$[$0], loc: yy.locInfo(this._$) };
+ break;
+ case 32:
+ this.$ = yy.id($$[$0 - 1]);
+ break;
+ case 33:
+ this.$ = $$[$0];
+ break;
+ case 34:
+ this.$ = $$[$0];
+ break;
+ case 35:
+ this.$ = { type: 'StringLiteral', value: $$[$0], original: $$[$0], loc: yy.locInfo(this._$) };
+ break;
+ case 36:
+ this.$ = { type: 'NumberLiteral', value: Number($$[$0]), original: Number($$[$0]), loc: yy.locInfo(this._$) };
+ break;
+ case 37:
+ this.$ = { type: 'BooleanLiteral', value: $$[$0] === 'true', original: $$[$0] === 'true', loc: yy.locInfo(this._$) };
+ break;
+ case 38:
+ this.$ = { type: 'UndefinedLiteral', original: undefined, value: undefined, loc: yy.locInfo(this._$) };
+ break;
+ case 39:
+ this.$ = { type: 'NullLiteral', original: null, value: null, loc: yy.locInfo(this._$) };
+ break;
+ case 40:
+ this.$ = $$[$0];
+ break;
+ case 41:
+ this.$ = $$[$0];
+ break;
+ case 42:
+ this.$ = yy.preparePath(true, $$[$0], this._$);
+ break;
+ case 43:
+ this.$ = yy.preparePath(false, $$[$0], this._$);
+ break;
+ case 44:
+ $$[$0 - 2].push({ part: yy.id($$[$0]), original: $$[$0], separator: $$[$0 - 1] });this.$ = $$[$0 - 2];
+ break;
+ case 45:
+ this.$ = [{ part: yy.id($$[$0]), original: $$[$0] }];
+ break;
+ case 46:
+ this.$ = [];
+ break;
+ case 47:
+ $$[$0 - 1].push($$[$0]);
+ break;
+ case 48:
+ this.$ = [$$[$0]];
+ break;
+ case 49:
+ $$[$0 - 1].push($$[$0]);
+ break;
+ case 50:
+ this.$ = [];
+ break;
+ case 51:
+ $$[$0 - 1].push($$[$0]);
+ break;
+ case 58:
+ this.$ = [];
+ break;
+ case 59:
+ $$[$0 - 1].push($$[$0]);
+ break;
+ case 64:
+ this.$ = [];
+ break;
+ case 65:
+ $$[$0 - 1].push($$[$0]);
+ break;
+ case 70:
+ this.$ = [];
+ break;
+ case 71:
+ $$[$0 - 1].push($$[$0]);
+ break;
+ case 78:
+ this.$ = [];
+ break;
+ case 79:
+ $$[$0 - 1].push($$[$0]);
+ break;
+ case 82:
+ this.$ = [];
+ break;
+ case 83:
+ $$[$0 - 1].push($$[$0]);
+ break;
+ case 86:
+ this.$ = [];
+ break;
+ case 87:
+ $$[$0 - 1].push($$[$0]);
+ break;
+ case 90:
+ this.$ = [];
+ break;
+ case 91:
+ $$[$0 - 1].push($$[$0]);
+ break;
+ case 94:
+ this.$ = [];
+ break;
+ case 95:
+ $$[$0 - 1].push($$[$0]);
+ break;
+ case 98:
+ this.$ = [$$[$0]];
+ break;
+ case 99:
+ $$[$0 - 1].push($$[$0]);
+ break;
+ case 100:
+ this.$ = [$$[$0]];
+ break;
+ case 101:
+ $$[$0 - 1].push($$[$0]);
+ break;
+ }
+ },
+ table: [{ 3: 1, 4: 2, 5: [2, 46], 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 1: [3] }, { 5: [1, 4] }, { 5: [2, 2], 7: 5, 8: 6, 9: 7, 10: 8, 11: 9, 12: 10, 13: 11, 14: [1, 12], 15: [1, 20], 16: 17, 19: [1, 23], 24: 15, 27: 16, 29: [1, 21], 34: [1, 22], 39: [2, 2], 44: [2, 2], 47: [2, 2], 48: [1, 13], 51: [1, 14], 55: [1, 18], 59: 19, 60: [1, 24] }, { 1: [2, 1] }, { 5: [2, 47], 14: [2, 47], 15: [2, 47], 19: [2, 47], 29: [2, 47], 34: [2, 47], 39: [2, 47], 44: [2, 47], 47: [2, 47], 48: [2, 47], 51: [2, 47], 55: [2, 47], 60: [2, 47] }, { 5: [2, 3], 14: [2, 3], 15: [2, 3], 19: [2, 3], 29: [2, 3], 34: [2, 3], 39: [2, 3], 44: [2, 3], 47: [2, 3], 48: [2, 3], 51: [2, 3], 55: [2, 3], 60: [2, 3] }, { 5: [2, 4], 14: [2, 4], 15: [2, 4], 19: [2, 4], 29: [2, 4], 34: [2, 4], 39: [2, 4], 44: [2, 4], 47: [2, 4], 48: [2, 4], 51: [2, 4], 55: [2, 4], 60: [2, 4] }, { 5: [2, 5], 14: [2, 5], 15: [2, 5], 19: [2, 5], 29: [2, 5], 34: [2, 5], 39: [2, 5], 44: [2, 5], 47: [2, 5], 48: [2, 5], 51: [2, 5], 55: [2, 5], 60: [2, 5] }, { 5: [2, 6], 14: [2, 6], 15: [2, 6], 19: [2, 6], 29: [2, 6], 34: [2, 6], 39: [2, 6], 44: [2, 6], 47: [2, 6], 48: [2, 6], 51: [2, 6], 55: [2, 6], 60: [2, 6] }, { 5: [2, 7], 14: [2, 7], 15: [2, 7], 19: [2, 7], 29: [2, 7], 34: [2, 7], 39: [2, 7], 44: [2, 7], 47: [2, 7], 48: [2, 7], 51: [2, 7], 55: [2, 7], 60: [2, 7] }, { 5: [2, 8], 14: [2, 8], 15: [2, 8], 19: [2, 8], 29: [2, 8], 34: [2, 8], 39: [2, 8], 44: [2, 8], 47: [2, 8], 48: [2, 8], 51: [2, 8], 55: [2, 8], 60: [2, 8] }, { 5: [2, 9], 14: [2, 9], 15: [2, 9], 19: [2, 9], 29: [2, 9], 34: [2, 9], 39: [2, 9], 44: [2, 9], 47: [2, 9], 48: [2, 9], 51: [2, 9], 55: [2, 9], 60: [2, 9] }, { 20: 25, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 36, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 4: 37, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 39: [2, 46], 44: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 4: 38, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 44: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 13: 40, 15: [1, 20], 17: 39 }, { 20: 42, 56: 41, 64: 43, 65: [1, 44], 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 4: 45, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 5: [2, 10], 14: [2, 10], 15: [2, 10], 18: [2, 10], 19: [2, 10], 29: [2, 10], 34: [2, 10], 39: [2, 10], 44: [2, 10], 47: [2, 10], 48: [2, 10], 51: [2, 10], 55: [2, 10], 60: [2, 10] }, { 20: 46, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 47, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 48, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 42, 56: 49, 64: 43, 65: [1, 44], 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 33: [2, 78], 49: 50, 65: [2, 78], 72: [2, 78], 80: [2, 78], 81: [2, 78], 82: [2, 78], 83: [2, 78], 84: [2, 78], 85: [2, 78] }, { 23: [2, 33], 33: [2, 33], 54: [2, 33], 65: [2, 33], 68: [2, 33], 72: [2, 33], 75: [2, 33], 80: [2, 33], 81: [2, 33], 82: [2, 33], 83: [2, 33], 84: [2, 33], 85: [2, 33] }, { 23: [2, 34], 33: [2, 34], 54: [2, 34], 65: [2, 34], 68: [2, 34], 72: [2, 34], 75: [2, 34], 80: [2, 34], 81: [2, 34], 82: [2, 34], 83: [2, 34], 84: [2, 34], 85: [2, 34] }, { 23: [2, 35], 33: [2, 35], 54: [2, 35], 65: [2, 35], 68: [2, 35], 72: [2, 35], 75: [2, 35], 80: [2, 35], 81: [2, 35], 82: [2, 35], 83: [2, 35], 84: [2, 35], 85: [2, 35] }, { 23: [2, 36], 33: [2, 36], 54: [2, 36], 65: [2, 36], 68: [2, 36], 72: [2, 36], 75: [2, 36], 80: [2, 36], 81: [2, 36], 82: [2, 36], 83: [2, 36], 84: [2, 36], 85: [2, 36] }, { 23: [2, 37], 33: [2, 37], 54: [2, 37], 65: [2, 37], 68: [2, 37], 72: [2, 37], 75: [2, 37], 80: [2, 37], 81: [2, 37], 82: [2, 37], 83: [2, 37], 84: [2, 37], 85: [2, 37] }, { 23: [2, 38], 33: [2, 38], 54: [2, 38], 65: [2, 38], 68: [2, 38], 72: [2, 38], 75: [2, 38], 80: [2, 38], 81: [2, 38], 82: [2, 38], 83: [2, 38], 84: [2, 38], 85: [2, 38] }, { 23: [2, 39], 33: [2, 39], 54: [2, 39], 65: [2, 39], 68: [2, 39], 72: [2, 39], 75: [2, 39], 80: [2, 39], 81: [2, 39], 82: [2, 39], 83: [2, 39], 84: [2, 39], 85: [2, 39] }, { 23: [2, 43], 33: [2, 43], 54: [2, 43], 65: [2, 43], 68: [2, 43], 72: [2, 43], 75: [2, 43], 80: [2, 43], 81: [2, 43], 82: [2, 43], 83: [2, 43], 84: [2, 43], 85: [2, 43], 87: [1, 51] }, { 72: [1, 35], 86: 52 }, { 23: [2, 45], 33: [2, 45], 54: [2, 45], 65: [2, 45], 68: [2, 45], 72: [2, 45], 75: [2, 45], 80: [2, 45], 81: [2, 45], 82: [2, 45], 83: [2, 45], 84: [2, 45], 85: [2, 45], 87: [2, 45] }, { 52: 53, 54: [2, 82], 65: [2, 82], 72: [2, 82], 80: [2, 82], 81: [2, 82], 82: [2, 82], 83: [2, 82], 84: [2, 82], 85: [2, 82] }, { 25: 54, 38: 56, 39: [1, 58], 43: 57, 44: [1, 59], 45: 55, 47: [2, 54] }, { 28: 60, 43: 61, 44: [1, 59], 47: [2, 56] }, { 13: 63, 15: [1, 20], 18: [1, 62] }, { 15: [2, 48], 18: [2, 48] }, { 33: [2, 86], 57: 64, 65: [2, 86], 72: [2, 86], 80: [2, 86], 81: [2, 86], 82: [2, 86], 83: [2, 86], 84: [2, 86], 85: [2, 86] }, { 33: [2, 40], 65: [2, 40], 72: [2, 40], 80: [2, 40], 81: [2, 40], 82: [2, 40], 83: [2, 40], 84: [2, 40], 85: [2, 40] }, { 33: [2, 41], 65: [2, 41], 72: [2, 41], 80: [2, 41], 81: [2, 41], 82: [2, 41], 83: [2, 41], 84: [2, 41], 85: [2, 41] }, { 20: 65, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 26: 66, 47: [1, 67] }, { 30: 68, 33: [2, 58], 65: [2, 58], 72: [2, 58], 75: [2, 58], 80: [2, 58], 81: [2, 58], 82: [2, 58], 83: [2, 58], 84: [2, 58], 85: [2, 58] }, { 33: [2, 64], 35: 69, 65: [2, 64], 72: [2, 64], 75: [2, 64], 80: [2, 64], 81: [2, 64], 82: [2, 64], 83: [2, 64], 84: [2, 64], 85: [2, 64] }, { 21: 70, 23: [2, 50], 65: [2, 50], 72: [2, 50], 80: [2, 50], 81: [2, 50], 82: [2, 50], 83: [2, 50], 84: [2, 50], 85: [2, 50] }, { 33: [2, 90], 61: 71, 65: [2, 90], 72: [2, 90], 80: [2, 90], 81: [2, 90], 82: [2, 90], 83: [2, 90], 84: [2, 90], 85: [2, 90] }, { 20: 75, 33: [2, 80], 50: 72, 63: 73, 64: 76, 65: [1, 44], 69: 74, 70: 77, 71: 78, 72: [1, 79], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 72: [1, 80] }, { 23: [2, 42], 33: [2, 42], 54: [2, 42], 65: [2, 42], 68: [2, 42], 72: [2, 42], 75: [2, 42], 80: [2, 42], 81: [2, 42], 82: [2, 42], 83: [2, 42], 84: [2, 42], 85: [2, 42], 87: [1, 51] }, { 20: 75, 53: 81, 54: [2, 84], 63: 82, 64: 76, 65: [1, 44], 69: 83, 70: 77, 71: 78, 72: [1, 79], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 26: 84, 47: [1, 67] }, { 47: [2, 55] }, { 4: 85, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 39: [2, 46], 44: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 47: [2, 20] }, { 20: 86, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 4: 87, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 26: 88, 47: [1, 67] }, { 47: [2, 57] }, { 5: [2, 11], 14: [2, 11], 15: [2, 11], 19: [2, 11], 29: [2, 11], 34: [2, 11], 39: [2, 11], 44: [2, 11], 47: [2, 11], 48: [2, 11], 51: [2, 11], 55: [2, 11], 60: [2, 11] }, { 15: [2, 49], 18: [2, 49] }, { 20: 75, 33: [2, 88], 58: 89, 63: 90, 64: 76, 65: [1, 44], 69: 91, 70: 77, 71: 78, 72: [1, 79], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 65: [2, 94], 66: 92, 68: [2, 94], 72: [2, 94], 80: [2, 94], 81: [2, 94], 82: [2, 94], 83: [2, 94], 84: [2, 94], 85: [2, 94] }, { 5: [2, 25], 14: [2, 25], 15: [2, 25], 19: [2, 25], 29: [2, 25], 34: [2, 25], 39: [2, 25], 44: [2, 25], 47: [2, 25], 48: [2, 25], 51: [2, 25], 55: [2, 25], 60: [2, 25] }, { 20: 93, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 75, 31: 94, 33: [2, 60], 63: 95, 64: 76, 65: [1, 44], 69: 96, 70: 77, 71: 78, 72: [1, 79], 75: [2, 60], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 75, 33: [2, 66], 36: 97, 63: 98, 64: 76, 65: [1, 44], 69: 99, 70: 77, 71: 78, 72: [1, 79], 75: [2, 66], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 75, 22: 100, 23: [2, 52], 63: 101, 64: 76, 65: [1, 44], 69: 102, 70: 77, 71: 78, 72: [1, 79], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 75, 33: [2, 92], 62: 103, 63: 104, 64: 76, 65: [1, 44], 69: 105, 70: 77, 71: 78, 72: [1, 79], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 33: [1, 106] }, { 33: [2, 79], 65: [2, 79], 72: [2, 79], 80: [2, 79], 81: [2, 79], 82: [2, 79], 83: [2, 79], 84: [2, 79], 85: [2, 79] }, { 33: [2, 81] }, { 23: [2, 27], 33: [2, 27], 54: [2, 27], 65: [2, 27], 68: [2, 27], 72: [2, 27], 75: [2, 27], 80: [2, 27], 81: [2, 27], 82: [2, 27], 83: [2, 27], 84: [2, 27], 85: [2, 27] }, { 23: [2, 28], 33: [2, 28], 54: [2, 28], 65: [2, 28], 68: [2, 28], 72: [2, 28], 75: [2, 28], 80: [2, 28], 81: [2, 28], 82: [2, 28], 83: [2, 28], 84: [2, 28], 85: [2, 28] }, { 23: [2, 30], 33: [2, 30], 54: [2, 30], 68: [2, 30], 71: 107, 72: [1, 108], 75: [2, 30] }, { 23: [2, 98], 33: [2, 98], 54: [2, 98], 68: [2, 98], 72: [2, 98], 75: [2, 98] }, { 23: [2, 45], 33: [2, 45], 54: [2, 45], 65: [2, 45], 68: [2, 45], 72: [2, 45], 73: [1, 109], 75: [2, 45], 80: [2, 45], 81: [2, 45], 82: [2, 45], 83: [2, 45], 84: [2, 45], 85: [2, 45], 87: [2, 45] }, { 23: [2, 44], 33: [2, 44], 54: [2, 44], 65: [2, 44], 68: [2, 44], 72: [2, 44], 75: [2, 44], 80: [2, 44], 81: [2, 44], 82: [2, 44], 83: [2, 44], 84: [2, 44], 85: [2, 44], 87: [2, 44] }, { 54: [1, 110] }, { 54: [2, 83], 65: [2, 83], 72: [2, 83], 80: [2, 83], 81: [2, 83], 82: [2, 83], 83: [2, 83], 84: [2, 83], 85: [2, 83] }, { 54: [2, 85] }, { 5: [2, 13], 14: [2, 13], 15: [2, 13], 19: [2, 13], 29: [2, 13], 34: [2, 13], 39: [2, 13], 44: [2, 13], 47: [2, 13], 48: [2, 13], 51: [2, 13], 55: [2, 13], 60: [2, 13] }, { 38: 56, 39: [1, 58], 43: 57, 44: [1, 59], 45: 112, 46: 111, 47: [2, 76] }, { 33: [2, 70], 40: 113, 65: [2, 70], 72: [2, 70], 75: [2, 70], 80: [2, 70], 81: [2, 70], 82: [2, 70], 83: [2, 70], 84: [2, 70], 85: [2, 70] }, { 47: [2, 18] }, { 5: [2, 14], 14: [2, 14], 15: [2, 14], 19: [2, 14], 29: [2, 14], 34: [2, 14], 39: [2, 14], 44: [2, 14], 47: [2, 14], 48: [2, 14], 51: [2, 14], 55: [2, 14], 60: [2, 14] }, { 33: [1, 114] }, { 33: [2, 87], 65: [2, 87], 72: [2, 87], 80: [2, 87], 81: [2, 87], 82: [2, 87], 83: [2, 87], 84: [2, 87], 85: [2, 87] }, { 33: [2, 89] }, { 20: 75, 63: 116, 64: 76, 65: [1, 44], 67: 115, 68: [2, 96], 69: 117, 70: 77, 71: 78, 72: [1, 79], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 33: [1, 118] }, { 32: 119, 33: [2, 62], 74: 120, 75: [1, 121] }, { 33: [2, 59], 65: [2, 59], 72: [2, 59], 75: [2, 59], 80: [2, 59], 81: [2, 59], 82: [2, 59], 83: [2, 59], 84: [2, 59], 85: [2, 59] }, { 33: [2, 61], 75: [2, 61] }, { 33: [2, 68], 37: 122, 74: 123, 75: [1, 121] }, { 33: [2, 65], 65: [2, 65], 72: [2, 65], 75: [2, 65], 80: [2, 65], 81: [2, 65], 82: [2, 65], 83: [2, 65], 84: [2, 65], 85: [2, 65] }, { 33: [2, 67], 75: [2, 67] }, { 23: [1, 124] }, { 23: [2, 51], 65: [2, 51], 72: [2, 51], 80: [2, 51], 81: [2, 51], 82: [2, 51], 83: [2, 51], 84: [2, 51], 85: [2, 51] }, { 23: [2, 53] }, { 33: [1, 125] }, { 33: [2, 91], 65: [2, 91], 72: [2, 91], 80: [2, 91], 81: [2, 91], 82: [2, 91], 83: [2, 91], 84: [2, 91], 85: [2, 91] }, { 33: [2, 93] }, { 5: [2, 22], 14: [2, 22], 15: [2, 22], 19: [2, 22], 29: [2, 22], 34: [2, 22], 39: [2, 22], 44: [2, 22], 47: [2, 22], 48: [2, 22], 51: [2, 22], 55: [2, 22], 60: [2, 22] }, { 23: [2, 99], 33: [2, 99], 54: [2, 99], 68: [2, 99], 72: [2, 99], 75: [2, 99] }, { 73: [1, 109] }, { 20: 75, 63: 126, 64: 76, 65: [1, 44], 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 5: [2, 23], 14: [2, 23], 15: [2, 23], 19: [2, 23], 29: [2, 23], 34: [2, 23], 39: [2, 23], 44: [2, 23], 47: [2, 23], 48: [2, 23], 51: [2, 23], 55: [2, 23], 60: [2, 23] }, { 47: [2, 19] }, { 47: [2, 77] }, { 20: 75, 33: [2, 72], 41: 127, 63: 128, 64: 76, 65: [1, 44], 69: 129, 70: 77, 71: 78, 72: [1, 79], 75: [2, 72], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 5: [2, 24], 14: [2, 24], 15: [2, 24], 19: [2, 24], 29: [2, 24], 34: [2, 24], 39: [2, 24], 44: [2, 24], 47: [2, 24], 48: [2, 24], 51: [2, 24], 55: [2, 24], 60: [2, 24] }, { 68: [1, 130] }, { 65: [2, 95], 68: [2, 95], 72: [2, 95], 80: [2, 95], 81: [2, 95], 82: [2, 95], 83: [2, 95], 84: [2, 95], 85: [2, 95] }, { 68: [2, 97] }, { 5: [2, 21], 14: [2, 21], 15: [2, 21], 19: [2, 21], 29: [2, 21], 34: [2, 21], 39: [2, 21], 44: [2, 21], 47: [2, 21], 48: [2, 21], 51: [2, 21], 55: [2, 21], 60: [2, 21] }, { 33: [1, 131] }, { 33: [2, 63] }, { 72: [1, 133], 76: 132 }, { 33: [1, 134] }, { 33: [2, 69] }, { 15: [2, 12] }, { 14: [2, 26], 15: [2, 26], 19: [2, 26], 29: [2, 26], 34: [2, 26], 47: [2, 26], 48: [2, 26], 51: [2, 26], 55: [2, 26], 60: [2, 26] }, { 23: [2, 31], 33: [2, 31], 54: [2, 31], 68: [2, 31], 72: [2, 31], 75: [2, 31] }, { 33: [2, 74], 42: 135, 74: 136, 75: [1, 121] }, { 33: [2, 71], 65: [2, 71], 72: [2, 71], 75: [2, 71], 80: [2, 71], 81: [2, 71], 82: [2, 71], 83: [2, 71], 84: [2, 71], 85: [2, 71] }, { 33: [2, 73], 75: [2, 73] }, { 23: [2, 29], 33: [2, 29], 54: [2, 29], 65: [2, 29], 68: [2, 29], 72: [2, 29], 75: [2, 29], 80: [2, 29], 81: [2, 29], 82: [2, 29], 83: [2, 29], 84: [2, 29], 85: [2, 29] }, { 14: [2, 15], 15: [2, 15], 19: [2, 15], 29: [2, 15], 34: [2, 15], 39: [2, 15], 44: [2, 15], 47: [2, 15], 48: [2, 15], 51: [2, 15], 55: [2, 15], 60: [2, 15] }, { 72: [1, 138], 77: [1, 137] }, { 72: [2, 100], 77: [2, 100] }, { 14: [2, 16], 15: [2, 16], 19: [2, 16], 29: [2, 16], 34: [2, 16], 44: [2, 16], 47: [2, 16], 48: [2, 16], 51: [2, 16], 55: [2, 16], 60: [2, 16] }, { 33: [1, 139] }, { 33: [2, 75] }, { 33: [2, 32] }, { 72: [2, 101], 77: [2, 101] }, { 14: [2, 17], 15: [2, 17], 19: [2, 17], 29: [2, 17], 34: [2, 17], 39: [2, 17], 44: [2, 17], 47: [2, 17], 48: [2, 17], 51: [2, 17], 55: [2, 17], 60: [2, 17] }],
+ defaultActions: { 4: [2, 1], 55: [2, 55], 57: [2, 20], 61: [2, 57], 74: [2, 81], 83: [2, 85], 87: [2, 18], 91: [2, 89], 102: [2, 53], 105: [2, 93], 111: [2, 19], 112: [2, 77], 117: [2, 97], 120: [2, 63], 123: [2, 69], 124: [2, 12], 136: [2, 75], 137: [2, 32] },
+ parseError: function parseError(str, hash) {
+ throw new Error(str);
+ },
+ parse: function parse(input) {
+ var self = this,
+ stack = [0],
+ vstack = [null],
+ lstack = [],
+ table = this.table,
+ yytext = "",
+ yylineno = 0,
+ yyleng = 0,
+ recovering = 0,
+ TERROR = 2,
+ EOF = 1;
+ this.lexer.setInput(input);
+ this.lexer.yy = this.yy;
+ this.yy.lexer = this.lexer;
+ this.yy.parser = this;
+ if (typeof this.lexer.yylloc == "undefined") this.lexer.yylloc = {};
+ var yyloc = this.lexer.yylloc;
+ lstack.push(yyloc);
+ var ranges = this.lexer.options && this.lexer.options.ranges;
+ if (typeof this.yy.parseError === "function") this.parseError = this.yy.parseError;
+ function popStack(n) {
+ stack.length = stack.length - 2 * n;
+ vstack.length = vstack.length - n;
+ lstack.length = lstack.length - n;
+ }
+ function lex() {
+ var token;
+ token = self.lexer.lex() || 1;
+ if (typeof token !== "number") {
+ token = self.symbols_[token] || token;
+ }
+ return token;
+ }
+ var symbol,
+ preErrorSymbol,
+ state,
+ action,
+ a,
+ r,
+ yyval = {},
+ p,
+ len,
+ newState,
+ expected;
+ while (true) {
+ state = stack[stack.length - 1];
+ if (this.defaultActions[state]) {
+ action = this.defaultActions[state];
+ } else {
+ if (symbol === null || typeof symbol == "undefined") {
+ symbol = lex();
+ }
+ action = table[state] && table[state][symbol];
+ }
+ if (typeof action === "undefined" || !action.length || !action[0]) {
+ var errStr = "";
+ if (!recovering) {
+ expected = [];
+ for (p in table[state]) if (this.terminals_[p] && p > 2) {
+ expected.push("'" + this.terminals_[p] + "'");
+ }
+ if (this.lexer.showPosition) {
+ errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'";
+ } else {
+ errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1 ? "end of input" : "'" + (this.terminals_[symbol] || symbol) + "'");
+ }
+ this.parseError(errStr, { text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected });
+ }
+ }
+ if (action[0] instanceof Array && action.length > 1) {
+ throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol);
+ }
+ switch (action[0]) {
+ case 1:
+ stack.push(symbol);
+ vstack.push(this.lexer.yytext);
+ lstack.push(this.lexer.yylloc);
+ stack.push(action[1]);
+ symbol = null;
+ if (!preErrorSymbol) {
+ yyleng = this.lexer.yyleng;
+ yytext = this.lexer.yytext;
+ yylineno = this.lexer.yylineno;
+ yyloc = this.lexer.yylloc;
+ if (recovering > 0) recovering--;
+ } else {
+ symbol = preErrorSymbol;
+ preErrorSymbol = null;
+ }
+ break;
+ case 2:
+ len = this.productions_[action[1]][1];
+ yyval.$ = vstack[vstack.length - len];
+ yyval._$ = { first_line: lstack[lstack.length - (len || 1)].first_line, last_line: lstack[lstack.length - 1].last_line, first_column: lstack[lstack.length - (len || 1)].first_column, last_column: lstack[lstack.length - 1].last_column };
+ if (ranges) {
+ yyval._$.range = [lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1]];
+ }
+ r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);
+ if (typeof r !== "undefined") {
+ return r;
+ }
+ if (len) {
+ stack = stack.slice(0, -1 * len * 2);
+ vstack = vstack.slice(0, -1 * len);
+ lstack = lstack.slice(0, -1 * len);
+ }
+ stack.push(this.productions_[action[1]][0]);
+ vstack.push(yyval.$);
+ lstack.push(yyval._$);
+ newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
+ stack.push(newState);
+ break;
+ case 3:
+ return true;
+ }
+ }
+ return true;
+ }
+ };
+ /* Jison generated lexer */
+ var lexer = (function () {
+ var lexer = { EOF: 1,
+ parseError: function parseError(str, hash) {
+ if (this.yy.parser) {
+ this.yy.parser.parseError(str, hash);
+ } else {
+ throw new Error(str);
+ }
+ },
+ setInput: function setInput(input) {
+ this._input = input;
+ this._more = this._less = this.done = false;
+ this.yylineno = this.yyleng = 0;
+ this.yytext = this.matched = this.match = '';
+ this.conditionStack = ['INITIAL'];
+ this.yylloc = { first_line: 1, first_column: 0, last_line: 1, last_column: 0 };
+ if (this.options.ranges) this.yylloc.range = [0, 0];
+ this.offset = 0;
+ return this;
+ },
+ input: function input() {
+ var ch = this._input[0];
+ this.yytext += ch;
+ this.yyleng++;
+ this.offset++;
+ this.match += ch;
+ this.matched += ch;
+ var lines = ch.match(/(?:\r\n?|\n).*/g);
+ if (lines) {
+ this.yylineno++;
+ this.yylloc.last_line++;
+ } else {
+ this.yylloc.last_column++;
+ }
+ if (this.options.ranges) this.yylloc.range[1]++;
+
+ this._input = this._input.slice(1);
+ return ch;
+ },
+ unput: function unput(ch) {
+ var len = ch.length;
+ var lines = ch.split(/(?:\r\n?|\n)/g);
+
+ this._input = ch + this._input;
+ this.yytext = this.yytext.substr(0, this.yytext.length - len - 1);
+ //this.yyleng -= len;
+ this.offset -= len;
+ var oldLines = this.match.split(/(?:\r\n?|\n)/g);
+ this.match = this.match.substr(0, this.match.length - 1);
+ this.matched = this.matched.substr(0, this.matched.length - 1);
+
+ if (lines.length - 1) this.yylineno -= lines.length - 1;
+ var r = this.yylloc.range;
+
+ this.yylloc = { first_line: this.yylloc.first_line,
+ last_line: this.yylineno + 1,
+ first_column: this.yylloc.first_column,
+ last_column: lines ? (lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length : this.yylloc.first_column - len
+ };
+
+ if (this.options.ranges) {
+ this.yylloc.range = [r[0], r[0] + this.yyleng - len];
+ }
+ return this;
+ },
+ more: function more() {
+ this._more = true;
+ return this;
+ },
+ less: function less(n) {
+ this.unput(this.match.slice(n));
+ },
+ pastInput: function pastInput() {
+ var past = this.matched.substr(0, this.matched.length - this.match.length);
+ return (past.length > 20 ? '...' : '') + past.substr(-20).replace(/\n/g, "");
+ },
+ upcomingInput: function upcomingInput() {
+ var next = this.match;
+ if (next.length < 20) {
+ next += this._input.substr(0, 20 - next.length);
+ }
+ return (next.substr(0, 20) + (next.length > 20 ? '...' : '')).replace(/\n/g, "");
+ },
+ showPosition: function showPosition() {
+ var pre = this.pastInput();
+ var c = new Array(pre.length + 1).join("-");
+ return pre + this.upcomingInput() + "\n" + c + "^";
+ },
+ next: function next() {
+ if (this.done) {
+ return this.EOF;
+ }
+ if (!this._input) this.done = true;
+
+ var token, match, tempMatch, index, col, lines;
+ if (!this._more) {
+ this.yytext = '';
+ this.match = '';
+ }
+ var rules = this._currentRules();
+ for (var i = 0; i < rules.length; i++) {
+ tempMatch = this._input.match(this.rules[rules[i]]);
+ if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
+ match = tempMatch;
+ index = i;
+ if (!this.options.flex) break;
+ }
+ }
+ if (match) {
+ lines = match[0].match(/(?:\r\n?|\n).*/g);
+ if (lines) this.yylineno += lines.length;
+ this.yylloc = { first_line: this.yylloc.last_line,
+ last_line: this.yylineno + 1,
+ first_column: this.yylloc.last_column,
+ last_column: lines ? lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length };
+ this.yytext += match[0];
+ this.match += match[0];
+ this.matches = match;
+ this.yyleng = this.yytext.length;
+ if (this.options.ranges) {
+ this.yylloc.range = [this.offset, this.offset += this.yyleng];
+ }
+ this._more = false;
+ this._input = this._input.slice(match[0].length);
+ this.matched += match[0];
+ token = this.performAction.call(this, this.yy, this, rules[index], this.conditionStack[this.conditionStack.length - 1]);
+ if (this.done && this._input) this.done = false;
+ if (token) return token;else return;
+ }
+ if (this._input === "") {
+ return this.EOF;
+ } else {
+ return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), { text: "", token: null, line: this.yylineno });
+ }
+ },
+ lex: function lex() {
+ var r = this.next();
+ if (typeof r !== 'undefined') {
+ return r;
+ } else {
+ return this.lex();
+ }
+ },
+ begin: function begin(condition) {
+ this.conditionStack.push(condition);
+ },
+ popState: function popState() {
+ return this.conditionStack.pop();
+ },
+ _currentRules: function _currentRules() {
+ return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules;
+ },
+ topState: function topState() {
+ return this.conditionStack[this.conditionStack.length - 2];
+ },
+ pushState: function begin(condition) {
+ this.begin(condition);
+ } };
+ lexer.options = {};
+ lexer.performAction = function anonymous(yy, yy_, $avoiding_name_collisions, YY_START
+ /**/) {
+
+ function strip(start, end) {
+ return yy_.yytext = yy_.yytext.substr(start, yy_.yyleng - end);
+ }
+
+ var YYSTATE = YY_START;
+ switch ($avoiding_name_collisions) {
+ case 0:
+ if (yy_.yytext.slice(-2) === "\\\\") {
+ strip(0, 1);
+ this.begin("mu");
+ } else if (yy_.yytext.slice(-1) === "\\") {
+ strip(0, 1);
+ this.begin("emu");
+ } else {
+ this.begin("mu");
+ }
+ if (yy_.yytext) return 15;
+
+ break;
+ case 1:
+ return 15;
+ break;
+ case 2:
+ this.popState();
+ return 15;
+
+ break;
+ case 3:
+ this.begin('raw');return 15;
+ break;
+ case 4:
+ this.popState();
+ // Should be using `this.topState()` below, but it currently
+ // returns the second top instead of the first top. Opened an
+ // issue about it at https://github.com/zaach/jison/issues/291
+ if (this.conditionStack[this.conditionStack.length - 1] === 'raw') {
+ return 15;
+ } else {
+ yy_.yytext = yy_.yytext.substr(5, yy_.yyleng - 9);
+ return 'END_RAW_BLOCK';
+ }
+
+ break;
+ case 5:
+ return 15;
+ break;
+ case 6:
+ this.popState();
+ return 14;
+
+ break;
+ case 7:
+ return 65;
+ break;
+ case 8:
+ return 68;
+ break;
+ case 9:
+ return 19;
+ break;
+ case 10:
+ this.popState();
+ this.begin('raw');
+ return 23;
+
+ break;
+ case 11:
+ return 55;
+ break;
+ case 12:
+ return 60;
+ break;
+ case 13:
+ return 29;
+ break;
+ case 14:
+ return 47;
+ break;
+ case 15:
+ this.popState();return 44;
+ break;
+ case 16:
+ this.popState();return 44;
+ break;
+ case 17:
+ return 34;
+ break;
+ case 18:
+ return 39;
+ break;
+ case 19:
+ return 51;
+ break;
+ case 20:
+ return 48;
+ break;
+ case 21:
+ this.unput(yy_.yytext);
+ this.popState();
+ this.begin('com');
+
+ break;
+ case 22:
+ this.popState();
+ return 14;
+
+ break;
+ case 23:
+ return 48;
+ break;
+ case 24:
+ return 73;
+ break;
+ case 25:
+ return 72;
+ break;
+ case 26:
+ return 72;
+ break;
+ case 27:
+ return 87;
+ break;
+ case 28:
+ // ignore whitespace
+ break;
+ case 29:
+ this.popState();return 54;
+ break;
+ case 30:
+ this.popState();return 33;
+ break;
+ case 31:
+ yy_.yytext = strip(1, 2).replace(/\\"/g, '"');return 80;
+ break;
+ case 32:
+ yy_.yytext = strip(1, 2).replace(/\\'/g, "'");return 80;
+ break;
+ case 33:
+ return 85;
+ break;
+ case 34:
+ return 82;
+ break;
+ case 35:
+ return 82;
+ break;
+ case 36:
+ return 83;
+ break;
+ case 37:
+ return 84;
+ break;
+ case 38:
+ return 81;
+ break;
+ case 39:
+ return 75;
+ break;
+ case 40:
+ return 77;
+ break;
+ case 41:
+ return 72;
+ break;
+ case 42:
+ yy_.yytext = yy_.yytext.replace(/\\([\\\]])/g, '$1');return 72;
+ break;
+ case 43:
+ return 'INVALID';
+ break;
+ case 44:
+ return 5;
+ break;
+ }
+ };
+ lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/, /^(?:[^\x00]+)/, /^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/, /^(?:\{\{\{\{(?=[^/]))/, /^(?:\{\{\{\{\/[^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=[=}\s\/.])\}\}\}\})/, /^(?:[^\x00]*?(?=(\{\{\{\{)))/, /^(?:[\s\S]*?--(~)?\}\})/, /^(?:\()/, /^(?:\))/, /^(?:\{\{\{\{)/, /^(?:\}\}\}\})/, /^(?:\{\{(~)?>)/, /^(?:\{\{(~)?#>)/, /^(?:\{\{(~)?#\*?)/, /^(?:\{\{(~)?\/)/, /^(?:\{\{(~)?\^\s*(~)?\}\})/, /^(?:\{\{(~)?\s*else\s*(~)?\}\})/, /^(?:\{\{(~)?\^)/, /^(?:\{\{(~)?\s*else\b)/, /^(?:\{\{(~)?\{)/, /^(?:\{\{(~)?&)/, /^(?:\{\{(~)?!--)/, /^(?:\{\{(~)?![\s\S]*?\}\})/, /^(?:\{\{(~)?\*?)/, /^(?:=)/, /^(?:\.\.)/, /^(?:\.(?=([=~}\s\/.)|])))/, /^(?:[\/.])/, /^(?:\s+)/, /^(?:\}(~)?\}\})/, /^(?:(~)?\}\})/, /^(?:"(\\["]|[^"])*")/, /^(?:'(\\[']|[^'])*')/, /^(?:@)/, /^(?:true(?=([~}\s)])))/, /^(?:false(?=([~}\s)])))/, /^(?:undefined(?=([~}\s)])))/, /^(?:null(?=([~}\s)])))/, /^(?:-?[0-9]+(?:\.[0-9]+)?(?=([~}\s)])))/, /^(?:as\s+\|)/, /^(?:\|)/, /^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)|]))))/, /^(?:\[(\\\]|[^\]])*\])/, /^(?:.)/, /^(?:$)/];
+ lexer.conditions = { "mu": { "rules": [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44], "inclusive": false }, "emu": { "rules": [2], "inclusive": false }, "com": { "rules": [6], "inclusive": false }, "raw": { "rules": [3, 4, 5], "inclusive": false }, "INITIAL": { "rules": [0, 1, 44], "inclusive": true } };
+ return lexer;
+ })();
+ parser.lexer = lexer;
+ function Parser() {
+ this.yy = {};
+ }Parser.prototype = parser;parser.Parser = Parser;
+ return new Parser();
+ })();exports.__esModule = true;
+ exports['default'] = handlebars;
+
+/***/ },
+/* 24 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _interopRequireDefault = __webpack_require__(1)['default'];
+
+ exports.__esModule = true;
+
+ var _visitor = __webpack_require__(25);
+
+ var _visitor2 = _interopRequireDefault(_visitor);
+
+ function WhitespaceControl() {
+ var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
+
+ this.options = options;
+ }
+ WhitespaceControl.prototype = new _visitor2['default']();
+
+ WhitespaceControl.prototype.Program = function (program) {
+ var doStandalone = !this.options.ignoreStandalone;
+
+ var isRoot = !this.isRootSeen;
+ this.isRootSeen = true;
+
+ var body = program.body;
+ for (var i = 0, l = body.length; i < l; i++) {
+ var current = body[i],
+ strip = this.accept(current);
+
+ if (!strip) {
+ continue;
+ }
+
+ var _isPrevWhitespace = isPrevWhitespace(body, i, isRoot),
+ _isNextWhitespace = isNextWhitespace(body, i, isRoot),
+ openStandalone = strip.openStandalone && _isPrevWhitespace,
+ closeStandalone = strip.closeStandalone && _isNextWhitespace,
+ inlineStandalone = strip.inlineStandalone && _isPrevWhitespace && _isNextWhitespace;
+
+ if (strip.close) {
+ omitRight(body, i, true);
+ }
+ if (strip.open) {
+ omitLeft(body, i, true);
+ }
+
+ if (doStandalone && inlineStandalone) {
+ omitRight(body, i);
+
+ if (omitLeft(body, i)) {
+ // If we are on a standalone node, save the indent info for partials
+ if (current.type === 'PartialStatement') {
+ // Pull out the whitespace from the final line
+ current.indent = /([ \t]+$)/.exec(body[i - 1].original)[1];
+ }
+ }
+ }
+ if (doStandalone && openStandalone) {
+ omitRight((current.program || current.inverse).body);
+
+ // Strip out the previous content node if it's whitespace only
+ omitLeft(body, i);
+ }
+ if (doStandalone && closeStandalone) {
+ // Always strip the next node
+ omitRight(body, i);
+
+ omitLeft((current.inverse || current.program).body);
+ }
+ }
+
+ return program;
+ };
+
+ WhitespaceControl.prototype.BlockStatement = WhitespaceControl.prototype.DecoratorBlock = WhitespaceControl.prototype.PartialBlockStatement = function (block) {
+ this.accept(block.program);
+ this.accept(block.inverse);
+
+ // Find the inverse program that is involed with whitespace stripping.
+ var program = block.program || block.inverse,
+ inverse = block.program && block.inverse,
+ firstInverse = inverse,
+ lastInverse = inverse;
+
+ if (inverse && inverse.chained) {
+ firstInverse = inverse.body[0].program;
+
+ // Walk the inverse chain to find the last inverse that is actually in the chain.
+ while (lastInverse.chained) {
+ lastInverse = lastInverse.body[lastInverse.body.length - 1].program;
+ }
+ }
+
+ var strip = {
+ open: block.openStrip.open,
+ close: block.closeStrip.close,
+
+ // Determine the standalone candiacy. Basically flag our content as being possibly standalone
+ // so our parent can determine if we actually are standalone
+ openStandalone: isNextWhitespace(program.body),
+ closeStandalone: isPrevWhitespace((firstInverse || program).body)
+ };
+
+ if (block.openStrip.close) {
+ omitRight(program.body, null, true);
+ }
+
+ if (inverse) {
+ var inverseStrip = block.inverseStrip;
+
+ if (inverseStrip.open) {
+ omitLeft(program.body, null, true);
+ }
+
+ if (inverseStrip.close) {
+ omitRight(firstInverse.body, null, true);
+ }
+ if (block.closeStrip.open) {
+ omitLeft(lastInverse.body, null, true);
+ }
+
+ // Find standalone else statments
+ if (!this.options.ignoreStandalone && isPrevWhitespace(program.body) && isNextWhitespace(firstInverse.body)) {
+ omitLeft(program.body);
+ omitRight(firstInverse.body);
+ }
+ } else if (block.closeStrip.open) {
+ omitLeft(program.body, null, true);
+ }
+
+ return strip;
+ };
+
+ WhitespaceControl.prototype.Decorator = WhitespaceControl.prototype.MustacheStatement = function (mustache) {
+ return mustache.strip;
+ };
+
+ WhitespaceControl.prototype.PartialStatement = WhitespaceControl.prototype.CommentStatement = function (node) {
+ /* istanbul ignore next */
+ var strip = node.strip || {};
+ return {
+ inlineStandalone: true,
+ open: strip.open,
+ close: strip.close
+ };
+ };
+
+ function isPrevWhitespace(body, i, isRoot) {
+ if (i === undefined) {
+ i = body.length;
+ }
+
+ // Nodes that end with newlines are considered whitespace (but are special
+ // cased for strip operations)
+ var prev = body[i - 1],
+ sibling = body[i - 2];
+ if (!prev) {
+ return isRoot;
+ }
+
+ if (prev.type === 'ContentStatement') {
+ return (sibling || !isRoot ? /\r?\n\s*?$/ : /(^|\r?\n)\s*?$/).test(prev.original);
+ }
+ }
+ function isNextWhitespace(body, i, isRoot) {
+ if (i === undefined) {
+ i = -1;
+ }
+
+ var next = body[i + 1],
+ sibling = body[i + 2];
+ if (!next) {
+ return isRoot;
+ }
+
+ if (next.type === 'ContentStatement') {
+ return (sibling || !isRoot ? /^\s*?\r?\n/ : /^\s*?(\r?\n|$)/).test(next.original);
+ }
+ }
+
+ // Marks the node to the right of the position as omitted.
+ // I.e. {{foo}}' ' will mark the ' ' node as omitted.
+ //
+ // If i is undefined, then the first child will be marked as such.
+ //
+ // If mulitple is truthy then all whitespace will be stripped out until non-whitespace
+ // content is met.
+ function omitRight(body, i, multiple) {
+ var current = body[i == null ? 0 : i + 1];
+ if (!current || current.type !== 'ContentStatement' || !multiple && current.rightStripped) {
+ return;
+ }
+
+ var original = current.value;
+ current.value = current.value.replace(multiple ? /^\s+/ : /^[ \t]*\r?\n?/, '');
+ current.rightStripped = current.value !== original;
+ }
+
+ // Marks the node to the left of the position as omitted.
+ // I.e. ' '{{foo}} will mark the ' ' node as omitted.
+ //
+ // If i is undefined then the last child will be marked as such.
+ //
+ // If mulitple is truthy then all whitespace will be stripped out until non-whitespace
+ // content is met.
+ function omitLeft(body, i, multiple) {
+ var current = body[i == null ? body.length - 1 : i - 1];
+ if (!current || current.type !== 'ContentStatement' || !multiple && current.leftStripped) {
+ return;
+ }
+
+ // We omit the last node if it's whitespace only and not preceeded by a non-content node.
+ var original = current.value;
+ current.value = current.value.replace(multiple ? /\s+$/ : /[ \t]+$/, '');
+ current.leftStripped = current.value !== original;
+ return current.leftStripped;
+ }
+
+ exports['default'] = WhitespaceControl;
+ module.exports = exports['default'];
+
+/***/ },
+/* 25 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _interopRequireDefault = __webpack_require__(1)['default'];
+
+ exports.__esModule = true;
+
+ var _exception = __webpack_require__(6);
+
+ var _exception2 = _interopRequireDefault(_exception);
+
+ function Visitor() {
+ this.parents = [];
+ }
+
+ Visitor.prototype = {
+ constructor: Visitor,
+ mutating: false,
+
+ // Visits a given value. If mutating, will replace the value if necessary.
+ acceptKey: function acceptKey(node, name) {
+ var value = this.accept(node[name]);
+ if (this.mutating) {
+ // Hacky sanity check: This may have a few false positives for type for the helper
+ // methods but will generally do the right thing without a lot of overhead.
+ if (value && !Visitor.prototype[value.type]) {
+ throw new _exception2['default']('Unexpected node type "' + value.type + '" found when accepting ' + name + ' on ' + node.type);
+ }
+ node[name] = value;
+ }
+ },
+
+ // Performs an accept operation with added sanity check to ensure
+ // required keys are not removed.
+ acceptRequired: function acceptRequired(node, name) {
+ this.acceptKey(node, name);
+
+ if (!node[name]) {
+ throw new _exception2['default'](node.type + ' requires ' + name);
+ }
+ },
+
+ // Traverses a given array. If mutating, empty respnses will be removed
+ // for child elements.
+ acceptArray: function acceptArray(array) {
+ for (var i = 0, l = array.length; i < l; i++) {
+ this.acceptKey(array, i);
+
+ if (!array[i]) {
+ array.splice(i, 1);
+ i--;
+ l--;
+ }
+ }
+ },
+
+ accept: function accept(object) {
+ if (!object) {
+ return;
+ }
+
+ /* istanbul ignore next: Sanity code */
+ if (!this[object.type]) {
+ throw new _exception2['default']('Unknown type: ' + object.type, object);
+ }
+
+ if (this.current) {
+ this.parents.unshift(this.current);
+ }
+ this.current = object;
+
+ var ret = this[object.type](object);
+
+ this.current = this.parents.shift();
+
+ if (!this.mutating || ret) {
+ return ret;
+ } else if (ret !== false) {
+ return object;
+ }
+ },
+
+ Program: function Program(program) {
+ this.acceptArray(program.body);
+ },
+
+ MustacheStatement: visitSubExpression,
+ Decorator: visitSubExpression,
+
+ BlockStatement: visitBlock,
+ DecoratorBlock: visitBlock,
+
+ PartialStatement: visitPartial,
+ PartialBlockStatement: function PartialBlockStatement(partial) {
+ visitPartial.call(this, partial);
+
+ this.acceptKey(partial, 'program');
+ },
+
+ ContentStatement: function ContentStatement() /* content */{},
+ CommentStatement: function CommentStatement() /* comment */{},
+
+ SubExpression: visitSubExpression,
+
+ PathExpression: function PathExpression() /* path */{},
+
+ StringLiteral: function StringLiteral() /* string */{},
+ NumberLiteral: function NumberLiteral() /* number */{},
+ BooleanLiteral: function BooleanLiteral() /* bool */{},
+ UndefinedLiteral: function UndefinedLiteral() /* literal */{},
+ NullLiteral: function NullLiteral() /* literal */{},
+
+ Hash: function Hash(hash) {
+ this.acceptArray(hash.pairs);
+ },
+ HashPair: function HashPair(pair) {
+ this.acceptRequired(pair, 'value');
+ }
+ };
+
+ function visitSubExpression(mustache) {
+ this.acceptRequired(mustache, 'path');
+ this.acceptArray(mustache.params);
+ this.acceptKey(mustache, 'hash');
+ }
+ function visitBlock(block) {
+ visitSubExpression.call(this, block);
+
+ this.acceptKey(block, 'program');
+ this.acceptKey(block, 'inverse');
+ }
+ function visitPartial(partial) {
+ this.acceptRequired(partial, 'name');
+ this.acceptArray(partial.params);
+ this.acceptKey(partial, 'hash');
+ }
+
+ exports['default'] = Visitor;
+ module.exports = exports['default'];
+
+/***/ },
+/* 26 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _interopRequireDefault = __webpack_require__(1)['default'];
+
+ exports.__esModule = true;
+ exports.SourceLocation = SourceLocation;
+ exports.id = id;
+ exports.stripFlags = stripFlags;
+ exports.stripComment = stripComment;
+ exports.preparePath = preparePath;
+ exports.prepareMustache = prepareMustache;
+ exports.prepareRawBlock = prepareRawBlock;
+ exports.prepareBlock = prepareBlock;
+ exports.prepareProgram = prepareProgram;
+ exports.preparePartialBlock = preparePartialBlock;
+
+ var _exception = __webpack_require__(6);
+
+ var _exception2 = _interopRequireDefault(_exception);
+
+ function validateClose(open, close) {
+ close = close.path ? close.path.original : close;
+
+ if (open.path.original !== close) {
+ var errorNode = { loc: open.path.loc };
+
+ throw new _exception2['default'](open.path.original + " doesn't match " + close, errorNode);
+ }
+ }
+
+ function SourceLocation(source, locInfo) {
+ this.source = source;
+ this.start = {
+ line: locInfo.first_line,
+ column: locInfo.first_column
+ };
+ this.end = {
+ line: locInfo.last_line,
+ column: locInfo.last_column
+ };
+ }
+
+ function id(token) {
+ if (/^\[.*\]$/.test(token)) {
+ return token.substr(1, token.length - 2);
+ } else {
+ return token;
+ }
+ }
+
+ function stripFlags(open, close) {
+ return {
+ open: open.charAt(2) === '~',
+ close: close.charAt(close.length - 3) === '~'
+ };
+ }
+
+ function stripComment(comment) {
+ return comment.replace(/^\{\{~?\!-?-?/, '').replace(/-?-?~?\}\}$/, '');
+ }
+
+ function preparePath(data, parts, loc) {
+ loc = this.locInfo(loc);
+
+ var original = data ? '@' : '',
+ dig = [],
+ depth = 0,
+ depthString = '';
+
+ for (var i = 0, l = parts.length; i < l; i++) {
+ var part = parts[i].part,
+
+ // If we have [] syntax then we do not treat path references as operators,
+ // i.e. foo.[this] resolves to approximately context.foo['this']
+ isLiteral = parts[i].original !== part;
+ original += (parts[i].separator || '') + part;
+
+ if (!isLiteral && (part === '..' || part === '.' || part === 'this')) {
+ if (dig.length > 0) {
+ throw new _exception2['default']('Invalid path: ' + original, { loc: loc });
+ } else if (part === '..') {
+ depth++;
+ depthString += '../';
+ }
+ } else {
+ dig.push(part);
+ }
+ }
+
+ return {
+ type: 'PathExpression',
+ data: data,
+ depth: depth,
+ parts: dig,
+ original: original,
+ loc: loc
+ };
+ }
+
+ function prepareMustache(path, params, hash, open, strip, locInfo) {
+ // Must use charAt to support IE pre-10
+ var escapeFlag = open.charAt(3) || open.charAt(2),
+ escaped = escapeFlag !== '{' && escapeFlag !== '&';
+
+ var decorator = /\*/.test(open);
+ return {
+ type: decorator ? 'Decorator' : 'MustacheStatement',
+ path: path,
+ params: params,
+ hash: hash,
+ escaped: escaped,
+ strip: strip,
+ loc: this.locInfo(locInfo)
+ };
+ }
+
+ function prepareRawBlock(openRawBlock, contents, close, locInfo) {
+ validateClose(openRawBlock, close);
+
+ locInfo = this.locInfo(locInfo);
+ var program = {
+ type: 'Program',
+ body: contents,
+ strip: {},
+ loc: locInfo
+ };
+
+ return {
+ type: 'BlockStatement',
+ path: openRawBlock.path,
+ params: openRawBlock.params,
+ hash: openRawBlock.hash,
+ program: program,
+ openStrip: {},
+ inverseStrip: {},
+ closeStrip: {},
+ loc: locInfo
+ };
+ }
+
+ function prepareBlock(openBlock, program, inverseAndProgram, close, inverted, locInfo) {
+ if (close && close.path) {
+ validateClose(openBlock, close);
+ }
+
+ var decorator = /\*/.test(openBlock.open);
+
+ program.blockParams = openBlock.blockParams;
+
+ var inverse = undefined,
+ inverseStrip = undefined;
+
+ if (inverseAndProgram) {
+ if (decorator) {
+ throw new _exception2['default']('Unexpected inverse block on decorator', inverseAndProgram);
+ }
+
+ if (inverseAndProgram.chain) {
+ inverseAndProgram.program.body[0].closeStrip = close.strip;
+ }
+
+ inverseStrip = inverseAndProgram.strip;
+ inverse = inverseAndProgram.program;
+ }
+
+ if (inverted) {
+ inverted = inverse;
+ inverse = program;
+ program = inverted;
+ }
+
+ return {
+ type: decorator ? 'DecoratorBlock' : 'BlockStatement',
+ path: openBlock.path,
+ params: openBlock.params,
+ hash: openBlock.hash,
+ program: program,
+ inverse: inverse,
+ openStrip: openBlock.strip,
+ inverseStrip: inverseStrip,
+ closeStrip: close && close.strip,
+ loc: this.locInfo(locInfo)
+ };
+ }
+
+ function prepareProgram(statements, loc) {
+ if (!loc && statements.length) {
+ var firstLoc = statements[0].loc,
+ lastLoc = statements[statements.length - 1].loc;
+
+ /* istanbul ignore else */
+ if (firstLoc && lastLoc) {
+ loc = {
+ source: firstLoc.source,
+ start: {
+ line: firstLoc.start.line,
+ column: firstLoc.start.column
+ },
+ end: {
+ line: lastLoc.end.line,
+ column: lastLoc.end.column
+ }
+ };
+ }
+ }
+
+ return {
+ type: 'Program',
+ body: statements,
+ strip: {},
+ loc: loc
+ };
+ }
+
+ function preparePartialBlock(open, program, close, locInfo) {
+ validateClose(open, close);
+
+ return {
+ type: 'PartialBlockStatement',
+ name: open.path,
+ params: open.params,
+ hash: open.hash,
+ program: program,
+ openStrip: open.strip,
+ closeStrip: close && close.strip,
+ loc: this.locInfo(locInfo)
+ };
+ }
+
+/***/ },
+/* 27 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /* eslint-disable new-cap */
+
+ 'use strict';
+
+ var _interopRequireDefault = __webpack_require__(1)['default'];
+
+ exports.__esModule = true;
+ exports.Compiler = Compiler;
+ exports.precompile = precompile;
+ exports.compile = compile;
+
+ var _exception = __webpack_require__(6);
+
+ var _exception2 = _interopRequireDefault(_exception);
+
+ var _utils = __webpack_require__(5);
+
+ var _ast = __webpack_require__(21);
+
+ var _ast2 = _interopRequireDefault(_ast);
+
+ var slice = [].slice;
+
+ function Compiler() {}
+
+ // the foundHelper register will disambiguate helper lookup from finding a
+ // function in a context. This is necessary for mustache compatibility, which
+ // requires that context functions in blocks are evaluated by blockHelperMissing,
+ // and then proceed as if the resulting value was provided to blockHelperMissing.
+
+ Compiler.prototype = {
+ compiler: Compiler,
+
+ equals: function equals(other) {
+ var len = this.opcodes.length;
+ if (other.opcodes.length !== len) {
+ return false;
+ }
+
+ for (var i = 0; i < len; i++) {
+ var opcode = this.opcodes[i],
+ otherOpcode = other.opcodes[i];
+ if (opcode.opcode !== otherOpcode.opcode || !argEquals(opcode.args, otherOpcode.args)) {
+ return false;
+ }
+ }
+
+ // We know that length is the same between the two arrays because they are directly tied
+ // to the opcode behavior above.
+ len = this.children.length;
+ for (var i = 0; i < len; i++) {
+ if (!this.children[i].equals(other.children[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ },
+
+ guid: 0,
+
+ compile: function compile(program, options) {
+ this.sourceNode = [];
+ this.opcodes = [];
+ this.children = [];
+ this.options = options;
+ this.stringParams = options.stringParams;
+ this.trackIds = options.trackIds;
+
+ options.blockParams = options.blockParams || [];
+
+ // These changes will propagate to the other compiler components
+ var knownHelpers = options.knownHelpers;
+ options.knownHelpers = {
+ 'helperMissing': true,
+ 'blockHelperMissing': true,
+ 'each': true,
+ 'if': true,
+ 'unless': true,
+ 'with': true,
+ 'log': true,
+ 'lookup': true
+ };
+ if (knownHelpers) {
+ for (var _name in knownHelpers) {
+ /* istanbul ignore else */
+ if (_name in knownHelpers) {
+ options.knownHelpers[_name] = knownHelpers[_name];
+ }
+ }
+ }
+
+ return this.accept(program);
+ },
+
+ compileProgram: function compileProgram(program) {
+ var childCompiler = new this.compiler(),
+ // eslint-disable-line new-cap
+ result = childCompiler.compile(program, this.options),
+ guid = this.guid++;
+
+ this.usePartial = this.usePartial || result.usePartial;
+
+ this.children[guid] = result;
+ this.useDepths = this.useDepths || result.useDepths;
+
+ return guid;
+ },
+
+ accept: function accept(node) {
+ /* istanbul ignore next: Sanity code */
+ if (!this[node.type]) {
+ throw new _exception2['default']('Unknown type: ' + node.type, node);
+ }
+
+ this.sourceNode.unshift(node);
+ var ret = this[node.type](node);
+ this.sourceNode.shift();
+ return ret;
+ },
+
+ Program: function Program(program) {
+ this.options.blockParams.unshift(program.blockParams);
+
+ var body = program.body,
+ bodyLength = body.length;
+ for (var i = 0; i < bodyLength; i++) {
+ this.accept(body[i]);
+ }
+
+ this.options.blockParams.shift();
+
+ this.isSimple = bodyLength === 1;
+ this.blockParams = program.blockParams ? program.blockParams.length : 0;
+
+ return this;
+ },
+
+ BlockStatement: function BlockStatement(block) {
+ transformLiteralToPath(block);
+
+ var program = block.program,
+ inverse = block.inverse;
+
+ program = program && this.compileProgram(program);
+ inverse = inverse && this.compileProgram(inverse);
+
+ var type = this.classifySexpr(block);
+
+ if (type === 'helper') {
+ this.helperSexpr(block, program, inverse);
+ } else if (type === 'simple') {
+ this.simpleSexpr(block);
+
+ // now that the simple mustache is resolved, we need to
+ // evaluate it by executing `blockHelperMissing`
+ this.opcode('pushProgram', program);
+ this.opcode('pushProgram', inverse);
+ this.opcode('emptyHash');
+ this.opcode('blockValue', block.path.original);
+ } else {
+ this.ambiguousSexpr(block, program, inverse);
+
+ // now that the simple mustache is resolved, we need to
+ // evaluate it by executing `blockHelperMissing`
+ this.opcode('pushProgram', program);
+ this.opcode('pushProgram', inverse);
+ this.opcode('emptyHash');
+ this.opcode('ambiguousBlockValue');
+ }
+
+ this.opcode('append');
+ },
+
+ DecoratorBlock: function DecoratorBlock(decorator) {
+ var program = decorator.program && this.compileProgram(decorator.program);
+ var params = this.setupFullMustacheParams(decorator, program, undefined),
+ path = decorator.path;
+
+ this.useDecorators = true;
+ this.opcode('registerDecorator', params.length, path.original);
+ },
+
+ PartialStatement: function PartialStatement(partial) {
+ this.usePartial = true;
+
+ var program = partial.program;
+ if (program) {
+ program = this.compileProgram(partial.program);
+ }
+
+ var params = partial.params;
+ if (params.length > 1) {
+ throw new _exception2['default']('Unsupported number of partial arguments: ' + params.length, partial);
+ } else if (!params.length) {
+ if (this.options.explicitPartialContext) {
+ this.opcode('pushLiteral', 'undefined');
+ } else {
+ params.push({ type: 'PathExpression', parts: [], depth: 0 });
+ }
+ }
+
+ var partialName = partial.name.original,
+ isDynamic = partial.name.type === 'SubExpression';
+ if (isDynamic) {
+ this.accept(partial.name);
+ }
+
+ this.setupFullMustacheParams(partial, program, undefined, true);
+
+ var indent = partial.indent || '';
+ if (this.options.preventIndent && indent) {
+ this.opcode('appendContent', indent);
+ indent = '';
+ }
+
+ this.opcode('invokePartial', isDynamic, partialName, indent);
+ this.opcode('append');
+ },
+ PartialBlockStatement: function PartialBlockStatement(partialBlock) {
+ this.PartialStatement(partialBlock);
+ },
+
+ MustacheStatement: function MustacheStatement(mustache) {
+ this.SubExpression(mustache);
+
+ if (mustache.escaped && !this.options.noEscape) {
+ this.opcode('appendEscaped');
+ } else {
+ this.opcode('append');
+ }
+ },
+ Decorator: function Decorator(decorator) {
+ this.DecoratorBlock(decorator);
+ },
+
+ ContentStatement: function ContentStatement(content) {
+ if (content.value) {
+ this.opcode('appendContent', content.value);
+ }
+ },
+
+ CommentStatement: function CommentStatement() {},
+
+ SubExpression: function SubExpression(sexpr) {
+ transformLiteralToPath(sexpr);
+ var type = this.classifySexpr(sexpr);
+
+ if (type === 'simple') {
+ this.simpleSexpr(sexpr);
+ } else if (type === 'helper') {
+ this.helperSexpr(sexpr);
+ } else {
+ this.ambiguousSexpr(sexpr);
+ }
+ },
+ ambiguousSexpr: function ambiguousSexpr(sexpr, program, inverse) {
+ var path = sexpr.path,
+ name = path.parts[0],
+ isBlock = program != null || inverse != null;
+
+ this.opcode('getContext', path.depth);
+
+ this.opcode('pushProgram', program);
+ this.opcode('pushProgram', inverse);
+
+ path.strict = true;
+ this.accept(path);
+
+ this.opcode('invokeAmbiguous', name, isBlock);
+ },
+
+ simpleSexpr: function simpleSexpr(sexpr) {
+ var path = sexpr.path;
+ path.strict = true;
+ this.accept(path);
+ this.opcode('resolvePossibleLambda');
+ },
+
+ helperSexpr: function helperSexpr(sexpr, program, inverse) {
+ var params = this.setupFullMustacheParams(sexpr, program, inverse),
+ path = sexpr.path,
+ name = path.parts[0];
+
+ if (this.options.knownHelpers[name]) {
+ this.opcode('invokeKnownHelper', params.length, name);
+ } else if (this.options.knownHelpersOnly) {
+ throw new _exception2['default']('You specified knownHelpersOnly, but used the unknown helper ' + name, sexpr);
+ } else {
+ path.strict = true;
+ path.falsy = true;
+
+ this.accept(path);
+ this.opcode('invokeHelper', params.length, path.original, _ast2['default'].helpers.simpleId(path));
+ }
+ },
+
+ PathExpression: function PathExpression(path) {
+ this.addDepth(path.depth);
+ this.opcode('getContext', path.depth);
+
+ var name = path.parts[0],
+ scoped = _ast2['default'].helpers.scopedId(path),
+ blockParamId = !path.depth && !scoped && this.blockParamIndex(name);
+
+ if (blockParamId) {
+ this.opcode('lookupBlockParam', blockParamId, path.parts);
+ } else if (!name) {
+ // Context reference, i.e. `{{foo .}}` or `{{foo ..}}`
+ this.opcode('pushContext');
+ } else if (path.data) {
+ this.options.data = true;
+ this.opcode('lookupData', path.depth, path.parts, path.strict);
+ } else {
+ this.opcode('lookupOnContext', path.parts, path.falsy, path.strict, scoped);
+ }
+ },
+
+ StringLiteral: function StringLiteral(string) {
+ this.opcode('pushString', string.value);
+ },
+
+ NumberLiteral: function NumberLiteral(number) {
+ this.opcode('pushLiteral', number.value);
+ },
+
+ BooleanLiteral: function BooleanLiteral(bool) {
+ this.opcode('pushLiteral', bool.value);
+ },
+
+ UndefinedLiteral: function UndefinedLiteral() {
+ this.opcode('pushLiteral', 'undefined');
+ },
+
+ NullLiteral: function NullLiteral() {
+ this.opcode('pushLiteral', 'null');
+ },
+
+ Hash: function Hash(hash) {
+ var pairs = hash.pairs,
+ i = 0,
+ l = pairs.length;
+
+ this.opcode('pushHash');
+
+ for (; i < l; i++) {
+ this.pushParam(pairs[i].value);
+ }
+ while (i--) {
+ this.opcode('assignToHash', pairs[i].key);
+ }
+ this.opcode('popHash');
+ },
+
+ // HELPERS
+ opcode: function opcode(name) {
+ this.opcodes.push({ opcode: name, args: slice.call(arguments, 1), loc: this.sourceNode[0].loc });
+ },
+
+ addDepth: function addDepth(depth) {
+ if (!depth) {
+ return;
+ }
+
+ this.useDepths = true;
+ },
+
+ classifySexpr: function classifySexpr(sexpr) {
+ var isSimple = _ast2['default'].helpers.simpleId(sexpr.path);
+
+ var isBlockParam = isSimple && !!this.blockParamIndex(sexpr.path.parts[0]);
+
+ // a mustache is an eligible helper if:
+ // * its id is simple (a single part, not `this` or `..`)
+ var isHelper = !isBlockParam && _ast2['default'].helpers.helperExpression(sexpr);
+
+ // if a mustache is an eligible helper but not a definite
+ // helper, it is ambiguous, and will be resolved in a later
+ // pass or at runtime.
+ var isEligible = !isBlockParam && (isHelper || isSimple);
+
+ // if ambiguous, we can possibly resolve the ambiguity now
+ // An eligible helper is one that does not have a complex path, i.e. `this.foo`, `../foo` etc.
+ if (isEligible && !isHelper) {
+ var _name2 = sexpr.path.parts[0],
+ options = this.options;
+
+ if (options.knownHelpers[_name2]) {
+ isHelper = true;
+ } else if (options.knownHelpersOnly) {
+ isEligible = false;
+ }
+ }
+
+ if (isHelper) {
+ return 'helper';
+ } else if (isEligible) {
+ return 'ambiguous';
+ } else {
+ return 'simple';
+ }
+ },
+
+ pushParams: function pushParams(params) {
+ for (var i = 0, l = params.length; i < l; i++) {
+ this.pushParam(params[i]);
+ }
+ },
+
+ pushParam: function pushParam(val) {
+ var value = val.value != null ? val.value : val.original || '';
+
+ if (this.stringParams) {
+ if (value.replace) {
+ value = value.replace(/^(\.?\.\/)*/g, '').replace(/\//g, '.');
+ }
+
+ if (val.depth) {
+ this.addDepth(val.depth);
+ }
+ this.opcode('getContext', val.depth || 0);
+ this.opcode('pushStringParam', value, val.type);
+
+ if (val.type === 'SubExpression') {
+ // SubExpressions get evaluated and passed in
+ // in string params mode.
+ this.accept(val);
+ }
+ } else {
+ if (this.trackIds) {
+ var blockParamIndex = undefined;
+ if (val.parts && !_ast2['default'].helpers.scopedId(val) && !val.depth) {
+ blockParamIndex = this.blockParamIndex(val.parts[0]);
+ }
+ if (blockParamIndex) {
+ var blockParamChild = val.parts.slice(1).join('.');
+ this.opcode('pushId', 'BlockParam', blockParamIndex, blockParamChild);
+ } else {
+ value = val.original || value;
+ if (value.replace) {
+ value = value.replace(/^this(?:\.|$)/, '').replace(/^\.\//, '').replace(/^\.$/, '');
+ }
+
+ this.opcode('pushId', val.type, value);
+ }
+ }
+ this.accept(val);
+ }
+ },
+
+ setupFullMustacheParams: function setupFullMustacheParams(sexpr, program, inverse, omitEmpty) {
+ var params = sexpr.params;
+ this.pushParams(params);
+
+ this.opcode('pushProgram', program);
+ this.opcode('pushProgram', inverse);
+
+ if (sexpr.hash) {
+ this.accept(sexpr.hash);
+ } else {
+ this.opcode('emptyHash', omitEmpty);
+ }
+
+ return params;
+ },
+
+ blockParamIndex: function blockParamIndex(name) {
+ for (var depth = 0, len = this.options.blockParams.length; depth < len; depth++) {
+ var blockParams = this.options.blockParams[depth],
+ param = blockParams && _utils.indexOf(blockParams, name);
+ if (blockParams && param >= 0) {
+ return [depth, param];
+ }
+ }
+ }
+ };
+
+ function precompile(input, options, env) {
+ if (input == null || typeof input !== 'string' && input.type !== 'Program') {
+ throw new _exception2['default']('You must pass a string or Handlebars AST to Handlebars.precompile. You passed ' + input);
+ }
+
+ options = options || {};
+ if (!('data' in options)) {
+ options.data = true;
+ }
+ if (options.compat) {
+ options.useDepths = true;
+ }
+
+ var ast = env.parse(input, options),
+ environment = new env.Compiler().compile(ast, options);
+ return new env.JavaScriptCompiler().compile(environment, options);
+ }
+
+ function compile(input, options, env) {
+ if (options === undefined) options = {};
+
+ if (input == null || typeof input !== 'string' && input.type !== 'Program') {
+ throw new _exception2['default']('You must pass a string or Handlebars AST to Handlebars.compile. You passed ' + input);
+ }
+
+ if (!('data' in options)) {
+ options.data = true;
+ }
+ if (options.compat) {
+ options.useDepths = true;
+ }
+
+ var compiled = undefined;
+
+ function compileInput() {
+ var ast = env.parse(input, options),
+ environment = new env.Compiler().compile(ast, options),
+ templateSpec = new env.JavaScriptCompiler().compile(environment, options, undefined, true);
+ return env.template(templateSpec);
+ }
+
+ // Template is only compiled on first use and cached after that point.
+ function ret(context, execOptions) {
+ if (!compiled) {
+ compiled = compileInput();
+ }
+ return compiled.call(this, context, execOptions);
+ }
+ ret._setup = function (setupOptions) {
+ if (!compiled) {
+ compiled = compileInput();
+ }
+ return compiled._setup(setupOptions);
+ };
+ ret._child = function (i, data, blockParams, depths) {
+ if (!compiled) {
+ compiled = compileInput();
+ }
+ return compiled._child(i, data, blockParams, depths);
+ };
+ return ret;
+ }
+
+ function argEquals(a, b) {
+ if (a === b) {
+ return true;
+ }
+
+ if (_utils.isArray(a) && _utils.isArray(b) && a.length === b.length) {
+ for (var i = 0; i < a.length; i++) {
+ if (!argEquals(a[i], b[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ function transformLiteralToPath(sexpr) {
+ if (!sexpr.path.parts) {
+ var literal = sexpr.path;
+ // Casting to string here to make false and 0 literal values play nicely with the rest
+ // of the system.
+ sexpr.path = {
+ type: 'PathExpression',
+ data: false,
+ depth: 0,
+ parts: [literal.original + ''],
+ original: literal.original + '',
+ loc: literal.loc
+ };
+ }
+ }
+
+/***/ },
+/* 28 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _interopRequireDefault = __webpack_require__(1)['default'];
+
+ exports.__esModule = true;
+
+ var _base = __webpack_require__(4);
+
+ var _exception = __webpack_require__(6);
+
+ var _exception2 = _interopRequireDefault(_exception);
+
+ var _utils = __webpack_require__(5);
+
+ var _codeGen = __webpack_require__(29);
+
+ var _codeGen2 = _interopRequireDefault(_codeGen);
+
+ function Literal(value) {
+ this.value = value;
+ }
+
+ function JavaScriptCompiler() {}
+
+ JavaScriptCompiler.prototype = {
+ // PUBLIC API: You can override these methods in a subclass to provide
+ // alternative compiled forms for name lookup and buffering semantics
+ nameLookup: function nameLookup(parent, name /* , type*/) {
+ if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
+ return [parent, '.', name];
+ } else {
+ return [parent, '[', JSON.stringify(name), ']'];
+ }
+ },
+ depthedLookup: function depthedLookup(name) {
+ return [this.aliasable('container.lookup'), '(depths, "', name, '")'];
+ },
+
+ compilerInfo: function compilerInfo() {
+ var revision = _base.COMPILER_REVISION,
+ versions = _base.REVISION_CHANGES[revision];
+ return [revision, versions];
+ },
+
+ appendToBuffer: function appendToBuffer(source, location, explicit) {
+ // Force a source as this simplifies the merge logic.
+ if (!_utils.isArray(source)) {
+ source = [source];
+ }
+ source = this.source.wrap(source, location);
+
+ if (this.environment.isSimple) {
+ return ['return ', source, ';'];
+ } else if (explicit) {
+ // This is a case where the buffer operation occurs as a child of another
+ // construct, generally braces. We have to explicitly output these buffer
+ // operations to ensure that the emitted code goes in the correct location.
+ return ['buffer += ', source, ';'];
+ } else {
+ source.appendToBuffer = true;
+ return source;
+ }
+ },
+
+ initializeBuffer: function initializeBuffer() {
+ return this.quotedString('');
+ },
+ // END PUBLIC API
+
+ compile: function compile(environment, options, context, asObject) {
+ this.environment = environment;
+ this.options = options;
+ this.stringParams = this.options.stringParams;
+ this.trackIds = this.options.trackIds;
+ this.precompile = !asObject;
+
+ this.name = this.environment.name;
+ this.isChild = !!context;
+ this.context = context || {
+ decorators: [],
+ programs: [],
+ environments: []
+ };
+
+ this.preamble();
+
+ this.stackSlot = 0;
+ this.stackVars = [];
+ this.aliases = {};
+ this.registers = { list: [] };
+ this.hashes = [];
+ this.compileStack = [];
+ this.inlineStack = [];
+ this.blockParams = [];
+
+ this.compileChildren(environment, options);
+
+ this.useDepths = this.useDepths || environment.useDepths || environment.useDecorators || this.options.compat;
+ this.useBlockParams = this.useBlockParams || environment.useBlockParams;
+
+ var opcodes = environment.opcodes,
+ opcode = undefined,
+ firstLoc = undefined,
+ i = undefined,
+ l = undefined;
+
+ for (i = 0, l = opcodes.length; i < l; i++) {
+ opcode = opcodes[i];
+
+ this.source.currentLocation = opcode.loc;
+ firstLoc = firstLoc || opcode.loc;
+ this[opcode.opcode].apply(this, opcode.args);
+ }
+
+ // Flush any trailing content that might be pending.
+ this.source.currentLocation = firstLoc;
+ this.pushSource('');
+
+ /* istanbul ignore next */
+ if (this.stackSlot || this.inlineStack.length || this.compileStack.length) {
+ throw new _exception2['default']('Compile completed with content left on stack');
+ }
+
+ if (!this.decorators.isEmpty()) {
+ this.useDecorators = true;
+
+ this.decorators.prepend('var decorators = container.decorators;\n');
+ this.decorators.push('return fn;');
+
+ if (asObject) {
+ this.decorators = Function.apply(this, ['fn', 'props', 'container', 'depth0', 'data', 'blockParams', 'depths', this.decorators.merge()]);
+ } else {
+ this.decorators.prepend('function(fn, props, container, depth0, data, blockParams, depths) {\n');
+ this.decorators.push('}\n');
+ this.decorators = this.decorators.merge();
+ }
+ } else {
+ this.decorators = undefined;
+ }
+
+ var fn = this.createFunctionContext(asObject);
+ if (!this.isChild) {
+ var ret = {
+ compiler: this.compilerInfo(),
+ main: fn
+ };
+
+ if (this.decorators) {
+ ret.main_d = this.decorators; // eslint-disable-line camelcase
+ ret.useDecorators = true;
+ }
+
+ var _context = this.context;
+ var programs = _context.programs;
+ var decorators = _context.decorators;
+
+ for (i = 0, l = programs.length; i < l; i++) {
+ if (programs[i]) {
+ ret[i] = programs[i];
+ if (decorators[i]) {
+ ret[i + '_d'] = decorators[i];
+ ret.useDecorators = true;
+ }
+ }
+ }
+
+ if (this.environment.usePartial) {
+ ret.usePartial = true;
+ }
+ if (this.options.data) {
+ ret.useData = true;
+ }
+ if (this.useDepths) {
+ ret.useDepths = true;
+ }
+ if (this.useBlockParams) {
+ ret.useBlockParams = true;
+ }
+ if (this.options.compat) {
+ ret.compat = true;
+ }
+
+ if (!asObject) {
+ ret.compiler = JSON.stringify(ret.compiler);
+
+ this.source.currentLocation = { start: { line: 1, column: 0 } };
+ ret = this.objectLiteral(ret);
+
+ if (options.srcName) {
+ ret = ret.toStringWithSourceMap({ file: options.destName });
+ ret.map = ret.map && ret.map.toString();
+ } else {
+ ret = ret.toString();
+ }
+ } else {
+ ret.compilerOptions = this.options;
+ }
+
+ return ret;
+ } else {
+ return fn;
+ }
+ },
+
+ preamble: function preamble() {
+ // track the last context pushed into place to allow skipping the
+ // getContext opcode when it would be a noop
+ this.lastContext = 0;
+ this.source = new _codeGen2['default'](this.options.srcName);
+ this.decorators = new _codeGen2['default'](this.options.srcName);
+ },
+
+ createFunctionContext: function createFunctionContext(asObject) {
+ var varDeclarations = '';
+
+ var locals = this.stackVars.concat(this.registers.list);
+ if (locals.length > 0) {
+ varDeclarations += ', ' + locals.join(', ');
+ }
+
+ // Generate minimizer alias mappings
+ //
+ // When using true SourceNodes, this will update all references to the given alias
+ // as the source nodes are reused in situ. For the non-source node compilation mode,
+ // aliases will not be used, but this case is already being run on the client and
+ // we aren't concern about minimizing the template size.
+ var aliasCount = 0;
+ for (var alias in this.aliases) {
+ // eslint-disable-line guard-for-in
+ var node = this.aliases[alias];
+
+ if (this.aliases.hasOwnProperty(alias) && node.children && node.referenceCount > 1) {
+ varDeclarations += ', alias' + ++aliasCount + '=' + alias;
+ node.children[0] = 'alias' + aliasCount;
+ }
+ }
+
+ var params = ['container', 'depth0', 'helpers', 'partials', 'data'];
+
+ if (this.useBlockParams || this.useDepths) {
+ params.push('blockParams');
+ }
+ if (this.useDepths) {
+ params.push('depths');
+ }
+
+ // Perform a second pass over the output to merge content when possible
+ var source = this.mergeSource(varDeclarations);
+
+ if (asObject) {
+ params.push(source);
+
+ return Function.apply(this, params);
+ } else {
+ return this.source.wrap(['function(', params.join(','), ') {\n ', source, '}']);
+ }
+ },
+ mergeSource: function mergeSource(varDeclarations) {
+ var isSimple = this.environment.isSimple,
+ appendOnly = !this.forceBuffer,
+ appendFirst = undefined,
+ sourceSeen = undefined,
+ bufferStart = undefined,
+ bufferEnd = undefined;
+ this.source.each(function (line) {
+ if (line.appendToBuffer) {
+ if (bufferStart) {
+ line.prepend(' + ');
+ } else {
+ bufferStart = line;
+ }
+ bufferEnd = line;
+ } else {
+ if (bufferStart) {
+ if (!sourceSeen) {
+ appendFirst = true;
+ } else {
+ bufferStart.prepend('buffer += ');
+ }
+ bufferEnd.add(';');
+ bufferStart = bufferEnd = undefined;
+ }
+
+ sourceSeen = true;
+ if (!isSimple) {
+ appendOnly = false;
+ }
+ }
+ });
+
+ if (appendOnly) {
+ if (bufferStart) {
+ bufferStart.prepend('return ');
+ bufferEnd.add(';');
+ } else if (!sourceSeen) {
+ this.source.push('return "";');
+ }
+ } else {
+ varDeclarations += ', buffer = ' + (appendFirst ? '' : this.initializeBuffer());
+
+ if (bufferStart) {
+ bufferStart.prepend('return buffer + ');
+ bufferEnd.add(';');
+ } else {
+ this.source.push('return buffer;');
+ }
+ }
+
+ if (varDeclarations) {
+ this.source.prepend('var ' + varDeclarations.substring(2) + (appendFirst ? '' : ';\n'));
+ }
+
+ return this.source.merge();
+ },
+
+ // [blockValue]
+ //
+ // On stack, before: hash, inverse, program, value
+ // On stack, after: return value of blockHelperMissing
+ //
+ // The purpose of this opcode is to take a block of the form
+ // `{{#this.foo}}...{{/this.foo}}`, resolve the value of `foo`, and
+ // replace it on the stack with the result of properly
+ // invoking blockHelperMissing.
+ blockValue: function blockValue(name) {
+ var blockHelperMissing = this.aliasable('helpers.blockHelperMissing'),
+ params = [this.contextName(0)];
+ this.setupHelperArgs(name, 0, params);
+
+ var blockName = this.popStack();
+ params.splice(1, 0, blockName);
+
+ this.push(this.source.functionCall(blockHelperMissing, 'call', params));
+ },
+
+ // [ambiguousBlockValue]
+ //
+ // On stack, before: hash, inverse, program, value
+ // Compiler value, before: lastHelper=value of last found helper, if any
+ // On stack, after, if no lastHelper: same as [blockValue]
+ // On stack, after, if lastHelper: value
+ ambiguousBlockValue: function ambiguousBlockValue() {
+ // We're being a bit cheeky and reusing the options value from the prior exec
+ var blockHelperMissing = this.aliasable('helpers.blockHelperMissing'),
+ params = [this.contextName(0)];
+ this.setupHelperArgs('', 0, params, true);
+
+ this.flushInline();
+
+ var current = this.topStack();
+ params.splice(1, 0, current);
+
+ this.pushSource(['if (!', this.lastHelper, ') { ', current, ' = ', this.source.functionCall(blockHelperMissing, 'call', params), '}']);
+ },
+
+ // [appendContent]
+ //
+ // On stack, before: ...
+ // On stack, after: ...
+ //
+ // Appends the string value of `content` to the current buffer
+ appendContent: function appendContent(content) {
+ if (this.pendingContent) {
+ content = this.pendingContent + content;
+ } else {
+ this.pendingLocation = this.source.currentLocation;
+ }
+
+ this.pendingContent = content;
+ },
+
+ // [append]
+ //
+ // On stack, before: value, ...
+ // On stack, after: ...
+ //
+ // Coerces `value` to a String and appends it to the current buffer.
+ //
+ // If `value` is truthy, or 0, it is coerced into a string and appended
+ // Otherwise, the empty string is appended
+ append: function append() {
+ if (this.isInline()) {
+ this.replaceStack(function (current) {
+ return [' != null ? ', current, ' : ""'];
+ });
+
+ this.pushSource(this.appendToBuffer(this.popStack()));
+ } else {
+ var local = this.popStack();
+ this.pushSource(['if (', local, ' != null) { ', this.appendToBuffer(local, undefined, true), ' }']);
+ if (this.environment.isSimple) {
+ this.pushSource(['else { ', this.appendToBuffer("''", undefined, true), ' }']);
+ }
+ }
+ },
+
+ // [appendEscaped]
+ //
+ // On stack, before: value, ...
+ // On stack, after: ...
+ //
+ // Escape `value` and append it to the buffer
+ appendEscaped: function appendEscaped() {
+ this.pushSource(this.appendToBuffer([this.aliasable('container.escapeExpression'), '(', this.popStack(), ')']));
+ },
+
+ // [getContext]
+ //
+ // On stack, before: ...
+ // On stack, after: ...
+ // Compiler value, after: lastContext=depth
+ //
+ // Set the value of the `lastContext` compiler value to the depth
+ getContext: function getContext(depth) {
+ this.lastContext = depth;
+ },
+
+ // [pushContext]
+ //
+ // On stack, before: ...
+ // On stack, after: currentContext, ...
+ //
+ // Pushes the value of the current context onto the stack.
+ pushContext: function pushContext() {
+ this.pushStackLiteral(this.contextName(this.lastContext));
+ },
+
+ // [lookupOnContext]
+ //
+ // On stack, before: ...
+ // On stack, after: currentContext[name], ...
+ //
+ // Looks up the value of `name` on the current context and pushes
+ // it onto the stack.
+ lookupOnContext: function lookupOnContext(parts, falsy, strict, scoped) {
+ var i = 0;
+
+ if (!scoped && this.options.compat && !this.lastContext) {
+ // The depthed query is expected to handle the undefined logic for the root level that
+ // is implemented below, so we evaluate that directly in compat mode
+ this.push(this.depthedLookup(parts[i++]));
+ } else {
+ this.pushContext();
+ }
+
+ this.resolvePath('context', parts, i, falsy, strict);
+ },
+
+ // [lookupBlockParam]
+ //
+ // On stack, before: ...
+ // On stack, after: blockParam[name], ...
+ //
+ // Looks up the value of `parts` on the given block param and pushes
+ // it onto the stack.
+ lookupBlockParam: function lookupBlockParam(blockParamId, parts) {
+ this.useBlockParams = true;
+
+ this.push(['blockParams[', blockParamId[0], '][', blockParamId[1], ']']);
+ this.resolvePath('context', parts, 1);
+ },
+
+ // [lookupData]
+ //
+ // On stack, before: ...
+ // On stack, after: data, ...
+ //
+ // Push the data lookup operator
+ lookupData: function lookupData(depth, parts, strict) {
+ if (!depth) {
+ this.pushStackLiteral('data');
+ } else {
+ this.pushStackLiteral('container.data(data, ' + depth + ')');
+ }
+
+ this.resolvePath('data', parts, 0, true, strict);
+ },
+
+ resolvePath: function resolvePath(type, parts, i, falsy, strict) {
+ // istanbul ignore next
+
+ var _this = this;
+
+ if (this.options.strict || this.options.assumeObjects) {
+ this.push(strictLookup(this.options.strict && strict, this, parts, type));
+ return;
+ }
+
+ var len = parts.length;
+ for (; i < len; i++) {
+ /* eslint-disable no-loop-func */
+ this.replaceStack(function (current) {
+ var lookup = _this.nameLookup(current, parts[i], type);
+ // We want to ensure that zero and false are handled properly if the context (falsy flag)
+ // needs to have the special handling for these values.
+ if (!falsy) {
+ return [' != null ? ', lookup, ' : ', current];
+ } else {
+ // Otherwise we can use generic falsy handling
+ return [' && ', lookup];
+ }
+ });
+ /* eslint-enable no-loop-func */
+ }
+ },
+
+ // [resolvePossibleLambda]
+ //
+ // On stack, before: value, ...
+ // On stack, after: resolved value, ...
+ //
+ // If the `value` is a lambda, replace it on the stack by
+ // the return value of the lambda
+ resolvePossibleLambda: function resolvePossibleLambda() {
+ this.push([this.aliasable('container.lambda'), '(', this.popStack(), ', ', this.contextName(0), ')']);
+ },
+
+ // [pushStringParam]
+ //
+ // On stack, before: ...
+ // On stack, after: string, currentContext, ...
+ //
+ // This opcode is designed for use in string mode, which
+ // provides the string value of a parameter along with its
+ // depth rather than resolving it immediately.
+ pushStringParam: function pushStringParam(string, type) {
+ this.pushContext();
+ this.pushString(type);
+
+ // If it's a subexpression, the string result
+ // will be pushed after this opcode.
+ if (type !== 'SubExpression') {
+ if (typeof string === 'string') {
+ this.pushString(string);
+ } else {
+ this.pushStackLiteral(string);
+ }
+ }
+ },
+
+ emptyHash: function emptyHash(omitEmpty) {
+ if (this.trackIds) {
+ this.push('{}'); // hashIds
+ }
+ if (this.stringParams) {
+ this.push('{}'); // hashContexts
+ this.push('{}'); // hashTypes
+ }
+ this.pushStackLiteral(omitEmpty ? 'undefined' : '{}');
+ },
+ pushHash: function pushHash() {
+ if (this.hash) {
+ this.hashes.push(this.hash);
+ }
+ this.hash = { values: [], types: [], contexts: [], ids: [] };
+ },
+ popHash: function popHash() {
+ var hash = this.hash;
+ this.hash = this.hashes.pop();
+
+ if (this.trackIds) {
+ this.push(this.objectLiteral(hash.ids));
+ }
+ if (this.stringParams) {
+ this.push(this.objectLiteral(hash.contexts));
+ this.push(this.objectLiteral(hash.types));
+ }
+
+ this.push(this.objectLiteral(hash.values));
+ },
+
+ // [pushString]
+ //
+ // On stack, before: ...
+ // On stack, after: quotedString(string), ...
+ //
+ // Push a quoted version of `string` onto the stack
+ pushString: function pushString(string) {
+ this.pushStackLiteral(this.quotedString(string));
+ },
+
+ // [pushLiteral]
+ //
+ // On stack, before: ...
+ // On stack, after: value, ...
+ //
+ // Pushes a value onto the stack. This operation prevents
+ // the compiler from creating a temporary variable to hold
+ // it.
+ pushLiteral: function pushLiteral(value) {
+ this.pushStackLiteral(value);
+ },
+
+ // [pushProgram]
+ //
+ // On stack, before: ...
+ // On stack, after: program(guid), ...
+ //
+ // Push a program expression onto the stack. This takes
+ // a compile-time guid and converts it into a runtime-accessible
+ // expression.
+ pushProgram: function pushProgram(guid) {
+ if (guid != null) {
+ this.pushStackLiteral(this.programExpression(guid));
+ } else {
+ this.pushStackLiteral(null);
+ }
+ },
+
+ // [registerDecorator]
+ //
+ // On stack, before: hash, program, params..., ...
+ // On stack, after: ...
+ //
+ // Pops off the decorator's parameters, invokes the decorator,
+ // and inserts the decorator into the decorators list.
+ registerDecorator: function registerDecorator(paramSize, name) {
+ var foundDecorator = this.nameLookup('decorators', name, 'decorator'),
+ options = this.setupHelperArgs(name, paramSize);
+
+ this.decorators.push(['fn = ', this.decorators.functionCall(foundDecorator, '', ['fn', 'props', 'container', options]), ' || fn;']);
+ },
+
+ // [invokeHelper]
+ //
+ // On stack, before: hash, inverse, program, params..., ...
+ // On stack, after: result of helper invocation
+ //
+ // Pops off the helper's parameters, invokes the helper,
+ // and pushes the helper's return value onto the stack.
+ //
+ // If the helper is not found, `helperMissing` is called.
+ invokeHelper: function invokeHelper(paramSize, name, isSimple) {
+ var nonHelper = this.popStack(),
+ helper = this.setupHelper(paramSize, name),
+ simple = isSimple ? [helper.name, ' || '] : '';
+
+ var lookup = ['('].concat(simple, nonHelper);
+ if (!this.options.strict) {
+ lookup.push(' || ', this.aliasable('helpers.helperMissing'));
+ }
+ lookup.push(')');
+
+ this.push(this.source.functionCall(lookup, 'call', helper.callParams));
+ },
+
+ // [invokeKnownHelper]
+ //
+ // On stack, before: hash, inverse, program, params..., ...
+ // On stack, after: result of helper invocation
+ //
+ // This operation is used when the helper is known to exist,
+ // so a `helperMissing` fallback is not required.
+ invokeKnownHelper: function invokeKnownHelper(paramSize, name) {
+ var helper = this.setupHelper(paramSize, name);
+ this.push(this.source.functionCall(helper.name, 'call', helper.callParams));
+ },
+
+ // [invokeAmbiguous]
+ //
+ // On stack, before: hash, inverse, program, params..., ...
+ // On stack, after: result of disambiguation
+ //
+ // This operation is used when an expression like `{{foo}}`
+ // is provided, but we don't know at compile-time whether it
+ // is a helper or a path.
+ //
+ // This operation emits more code than the other options,
+ // and can be avoided by passing the `knownHelpers` and
+ // `knownHelpersOnly` flags at compile-time.
+ invokeAmbiguous: function invokeAmbiguous(name, helperCall) {
+ this.useRegister('helper');
+
+ var nonHelper = this.popStack();
+
+ this.emptyHash();
+ var helper = this.setupHelper(0, name, helperCall);
+
+ var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper');
+
+ var lookup = ['(', '(helper = ', helperName, ' || ', nonHelper, ')'];
+ if (!this.options.strict) {
+ lookup[0] = '(helper = ';
+ lookup.push(' != null ? helper : ', this.aliasable('helpers.helperMissing'));
+ }
+
+ this.push(['(', lookup, helper.paramsInit ? ['),(', helper.paramsInit] : [], '),', '(typeof helper === ', this.aliasable('"function"'), ' ? ', this.source.functionCall('helper', 'call', helper.callParams), ' : helper))']);
+ },
+
+ // [invokePartial]
+ //
+ // On stack, before: context, ...
+ // On stack after: result of partial invocation
+ //
+ // This operation pops off a context, invokes a partial with that context,
+ // and pushes the result of the invocation back.
+ invokePartial: function invokePartial(isDynamic, name, indent) {
+ var params = [],
+ options = this.setupParams(name, 1, params);
+
+ if (isDynamic) {
+ name = this.popStack();
+ delete options.name;
+ }
+
+ if (indent) {
+ options.indent = JSON.stringify(indent);
+ }
+ options.helpers = 'helpers';
+ options.partials = 'partials';
+ options.decorators = 'container.decorators';
+
+ if (!isDynamic) {
+ params.unshift(this.nameLookup('partials', name, 'partial'));
+ } else {
+ params.unshift(name);
+ }
+
+ if (this.options.compat) {
+ options.depths = 'depths';
+ }
+ options = this.objectLiteral(options);
+ params.push(options);
+
+ this.push(this.source.functionCall('container.invokePartial', '', params));
+ },
+
+ // [assignToHash]
+ //
+ // On stack, before: value, ..., hash, ...
+ // On stack, after: ..., hash, ...
+ //
+ // Pops a value off the stack and assigns it to the current hash
+ assignToHash: function assignToHash(key) {
+ var value = this.popStack(),
+ context = undefined,
+ type = undefined,
+ id = undefined;
+
+ if (this.trackIds) {
+ id = this.popStack();
+ }
+ if (this.stringParams) {
+ type = this.popStack();
+ context = this.popStack();
+ }
+
+ var hash = this.hash;
+ if (context) {
+ hash.contexts[key] = context;
+ }
+ if (type) {
+ hash.types[key] = type;
+ }
+ if (id) {
+ hash.ids[key] = id;
+ }
+ hash.values[key] = value;
+ },
+
+ pushId: function pushId(type, name, child) {
+ if (type === 'BlockParam') {
+ this.pushStackLiteral('blockParams[' + name[0] + '].path[' + name[1] + ']' + (child ? ' + ' + JSON.stringify('.' + child) : ''));
+ } else if (type === 'PathExpression') {
+ this.pushString(name);
+ } else if (type === 'SubExpression') {
+ this.pushStackLiteral('true');
+ } else {
+ this.pushStackLiteral('null');
+ }
+ },
+
+ // HELPERS
+
+ compiler: JavaScriptCompiler,
+
+ compileChildren: function compileChildren(environment, options) {
+ var children = environment.children,
+ child = undefined,
+ compiler = undefined;
+
+ for (var i = 0, l = children.length; i < l; i++) {
+ child = children[i];
+ compiler = new this.compiler(); // eslint-disable-line new-cap
+
+ var index = this.matchExistingProgram(child);
+
+ if (index == null) {
+ this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children
+ index = this.context.programs.length;
+ child.index = index;
+ child.name = 'program' + index;
+ this.context.programs[index] = compiler.compile(child, options, this.context, !this.precompile);
+ this.context.decorators[index] = compiler.decorators;
+ this.context.environments[index] = child;
+
+ this.useDepths = this.useDepths || compiler.useDepths;
+ this.useBlockParams = this.useBlockParams || compiler.useBlockParams;
+ } else {
+ child.index = index;
+ child.name = 'program' + index;
+
+ this.useDepths = this.useDepths || child.useDepths;
+ this.useBlockParams = this.useBlockParams || child.useBlockParams;
+ }
+ }
+ },
+ matchExistingProgram: function matchExistingProgram(child) {
+ for (var i = 0, len = this.context.environments.length; i < len; i++) {
+ var environment = this.context.environments[i];
+ if (environment && environment.equals(child)) {
+ return i;
+ }
+ }
+ },
+
+ programExpression: function programExpression(guid) {
+ var child = this.environment.children[guid],
+ programParams = [child.index, 'data', child.blockParams];
+
+ if (this.useBlockParams || this.useDepths) {
+ programParams.push('blockParams');
+ }
+ if (this.useDepths) {
+ programParams.push('depths');
+ }
+
+ return 'container.program(' + programParams.join(', ') + ')';
+ },
+
+ useRegister: function useRegister(name) {
+ if (!this.registers[name]) {
+ this.registers[name] = true;
+ this.registers.list.push(name);
+ }
+ },
+
+ push: function push(expr) {
+ if (!(expr instanceof Literal)) {
+ expr = this.source.wrap(expr);
+ }
+
+ this.inlineStack.push(expr);
+ return expr;
+ },
+
+ pushStackLiteral: function pushStackLiteral(item) {
+ this.push(new Literal(item));
+ },
+
+ pushSource: function pushSource(source) {
+ if (this.pendingContent) {
+ this.source.push(this.appendToBuffer(this.source.quotedString(this.pendingContent), this.pendingLocation));
+ this.pendingContent = undefined;
+ }
+
+ if (source) {
+ this.source.push(source);
+ }
+ },
+
+ replaceStack: function replaceStack(callback) {
+ var prefix = ['('],
+ stack = undefined,
+ createdStack = undefined,
+ usedLiteral = undefined;
+
+ /* istanbul ignore next */
+ if (!this.isInline()) {
+ throw new _exception2['default']('replaceStack on non-inline');
+ }
+
+ // We want to merge the inline statement into the replacement statement via ','
+ var top = this.popStack(true);
+
+ if (top instanceof Literal) {
+ // Literals do not need to be inlined
+ stack = [top.value];
+ prefix = ['(', stack];
+ usedLiteral = true;
+ } else {
+ // Get or create the current stack name for use by the inline
+ createdStack = true;
+ var _name = this.incrStack();
+
+ prefix = ['((', this.push(_name), ' = ', top, ')'];
+ stack = this.topStack();
+ }
+
+ var item = callback.call(this, stack);
+
+ if (!usedLiteral) {
+ this.popStack();
+ }
+ if (createdStack) {
+ this.stackSlot--;
+ }
+ this.push(prefix.concat(item, ')'));
+ },
+
+ incrStack: function incrStack() {
+ this.stackSlot++;
+ if (this.stackSlot > this.stackVars.length) {
+ this.stackVars.push('stack' + this.stackSlot);
+ }
+ return this.topStackName();
+ },
+ topStackName: function topStackName() {
+ return 'stack' + this.stackSlot;
+ },
+ flushInline: function flushInline() {
+ var inlineStack = this.inlineStack;
+ this.inlineStack = [];
+ for (var i = 0, len = inlineStack.length; i < len; i++) {
+ var entry = inlineStack[i];
+ /* istanbul ignore if */
+ if (entry instanceof Literal) {
+ this.compileStack.push(entry);
+ } else {
+ var stack = this.incrStack();
+ this.pushSource([stack, ' = ', entry, ';']);
+ this.compileStack.push(stack);
+ }
+ }
+ },
+ isInline: function isInline() {
+ return this.inlineStack.length;
+ },
+
+ popStack: function popStack(wrapped) {
+ var inline = this.isInline(),
+ item = (inline ? this.inlineStack : this.compileStack).pop();
+
+ if (!wrapped && item instanceof Literal) {
+ return item.value;
+ } else {
+ if (!inline) {
+ /* istanbul ignore next */
+ if (!this.stackSlot) {
+ throw new _exception2['default']('Invalid stack pop');
+ }
+ this.stackSlot--;
+ }
+ return item;
+ }
+ },
+
+ topStack: function topStack() {
+ var stack = this.isInline() ? this.inlineStack : this.compileStack,
+ item = stack[stack.length - 1];
+
+ /* istanbul ignore if */
+ if (item instanceof Literal) {
+ return item.value;
+ } else {
+ return item;
+ }
+ },
+
+ contextName: function contextName(context) {
+ if (this.useDepths && context) {
+ return 'depths[' + context + ']';
+ } else {
+ return 'depth' + context;
+ }
+ },
+
+ quotedString: function quotedString(str) {
+ return this.source.quotedString(str);
+ },
+
+ objectLiteral: function objectLiteral(obj) {
+ return this.source.objectLiteral(obj);
+ },
+
+ aliasable: function aliasable(name) {
+ var ret = this.aliases[name];
+ if (ret) {
+ ret.referenceCount++;
+ return ret;
+ }
+
+ ret = this.aliases[name] = this.source.wrap(name);
+ ret.aliasable = true;
+ ret.referenceCount = 1;
+
+ return ret;
+ },
+
+ setupHelper: function setupHelper(paramSize, name, blockHelper) {
+ var params = [],
+ paramsInit = this.setupHelperArgs(name, paramSize, params, blockHelper);
+ var foundHelper = this.nameLookup('helpers', name, 'helper'),
+ callContext = this.aliasable(this.contextName(0) + ' != null ? ' + this.contextName(0) + ' : {}');
+
+ return {
+ params: params,
+ paramsInit: paramsInit,
+ name: foundHelper,
+ callParams: [callContext].concat(params)
+ };
+ },
+
+ setupParams: function setupParams(helper, paramSize, params) {
+ var options = {},
+ contexts = [],
+ types = [],
+ ids = [],
+ objectArgs = !params,
+ param = undefined;
+
+ if (objectArgs) {
+ params = [];
+ }
+
+ options.name = this.quotedString(helper);
+ options.hash = this.popStack();
+
+ if (this.trackIds) {
+ options.hashIds = this.popStack();
+ }
+ if (this.stringParams) {
+ options.hashTypes = this.popStack();
+ options.hashContexts = this.popStack();
+ }
+
+ var inverse = this.popStack(),
+ program = this.popStack();
+
+ // Avoid setting fn and inverse if neither are set. This allows
+ // helpers to do a check for `if (options.fn)`
+ if (program || inverse) {
+ options.fn = program || 'container.noop';
+ options.inverse = inverse || 'container.noop';
+ }
+
+ // The parameters go on to the stack in order (making sure that they are evaluated in order)
+ // so we need to pop them off the stack in reverse order
+ var i = paramSize;
+ while (i--) {
+ param = this.popStack();
+ params[i] = param;
+
+ if (this.trackIds) {
+ ids[i] = this.popStack();
+ }
+ if (this.stringParams) {
+ types[i] = this.popStack();
+ contexts[i] = this.popStack();
+ }
+ }
+
+ if (objectArgs) {
+ options.args = this.source.generateArray(params);
+ }
+
+ if (this.trackIds) {
+ options.ids = this.source.generateArray(ids);
+ }
+ if (this.stringParams) {
+ options.types = this.source.generateArray(types);
+ options.contexts = this.source.generateArray(contexts);
+ }
+
+ if (this.options.data) {
+ options.data = 'data';
+ }
+ if (this.useBlockParams) {
+ options.blockParams = 'blockParams';
+ }
+ return options;
+ },
+
+ setupHelperArgs: function setupHelperArgs(helper, paramSize, params, useRegister) {
+ var options = this.setupParams(helper, paramSize, params);
+ options = this.objectLiteral(options);
+ if (useRegister) {
+ this.useRegister('options');
+ params.push('options');
+ return ['options=', options];
+ } else if (params) {
+ params.push(options);
+ return '';
+ } else {
+ return options;
+ }
+ }
+ };
+
+ (function () {
+ var reservedWords = ('break else new var' + ' case finally return void' + ' catch for switch while' + ' continue function this with' + ' default if throw' + ' delete in try' + ' do instanceof typeof' + ' abstract enum int short' + ' boolean export interface static' + ' byte extends long super' + ' char final native synchronized' + ' class float package throws' + ' const goto private transient' + ' debugger implements protected volatile' + ' double import public let yield await' + ' null true false').split(' ');
+
+ var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
+
+ for (var i = 0, l = reservedWords.length; i < l; i++) {
+ compilerWords[reservedWords[i]] = true;
+ }
+ })();
+
+ JavaScriptCompiler.isValidJavaScriptVariableName = function (name) {
+ return !JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name);
+ };
+
+ function strictLookup(requireTerminal, compiler, parts, type) {
+ var stack = compiler.popStack(),
+ i = 0,
+ len = parts.length;
+ if (requireTerminal) {
+ len--;
+ }
+
+ for (; i < len; i++) {
+ stack = compiler.nameLookup(stack, parts[i], type);
+ }
+
+ if (requireTerminal) {
+ return [compiler.aliasable('container.strict'), '(', stack, ', ', compiler.quotedString(parts[i]), ')'];
+ } else {
+ return stack;
+ }
+ }
+
+ exports['default'] = JavaScriptCompiler;
+ module.exports = exports['default'];
+
+/***/ },
+/* 29 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /* global define */
+ 'use strict';
+
+ exports.__esModule = true;
+
+ var _utils = __webpack_require__(5);
+
+ var SourceNode = undefined;
+
+ try {
+ /* istanbul ignore next */
+ if (false) {
+ // We don't support this in AMD environments. For these environments, we asusme that
+ // they are running on the browser and thus have no need for the source-map library.
+ var SourceMap = require('source-map');
+ SourceNode = SourceMap.SourceNode;
+ }
+ } catch (err) {}
+ /* NOP */
+
+ /* istanbul ignore if: tested but not covered in istanbul due to dist build */
+ if (!SourceNode) {
+ SourceNode = function (line, column, srcFile, chunks) {
+ this.src = '';
+ if (chunks) {
+ this.add(chunks);
+ }
+ };
+ /* istanbul ignore next */
+ SourceNode.prototype = {
+ add: function add(chunks) {
+ if (_utils.isArray(chunks)) {
+ chunks = chunks.join('');
+ }
+ this.src += chunks;
+ },
+ prepend: function prepend(chunks) {
+ if (_utils.isArray(chunks)) {
+ chunks = chunks.join('');
+ }
+ this.src = chunks + this.src;
+ },
+ toStringWithSourceMap: function toStringWithSourceMap() {
+ return { code: this.toString() };
+ },
+ toString: function toString() {
+ return this.src;
+ }
+ };
+ }
+
+ function castChunk(chunk, codeGen, loc) {
+ if (_utils.isArray(chunk)) {
+ var ret = [];
+
+ for (var i = 0, len = chunk.length; i < len; i++) {
+ ret.push(codeGen.wrap(chunk[i], loc));
+ }
+ return ret;
+ } else if (typeof chunk === 'boolean' || typeof chunk === 'number') {
+ // Handle primitives that the SourceNode will throw up on
+ return chunk + '';
+ }
+ return chunk;
+ }
+
+ function CodeGen(srcFile) {
+ this.srcFile = srcFile;
+ this.source = [];
+ }
+
+ CodeGen.prototype = {
+ isEmpty: function isEmpty() {
+ return !this.source.length;
+ },
+ prepend: function prepend(source, loc) {
+ this.source.unshift(this.wrap(source, loc));
+ },
+ push: function push(source, loc) {
+ this.source.push(this.wrap(source, loc));
+ },
+
+ merge: function merge() {
+ var source = this.empty();
+ this.each(function (line) {
+ source.add([' ', line, '\n']);
+ });
+ return source;
+ },
+
+ each: function each(iter) {
+ for (var i = 0, len = this.source.length; i < len; i++) {
+ iter(this.source[i]);
+ }
+ },
+
+ empty: function empty() {
+ var loc = this.currentLocation || { start: {} };
+ return new SourceNode(loc.start.line, loc.start.column, this.srcFile);
+ },
+ wrap: function wrap(chunk) {
+ var loc = arguments.length <= 1 || arguments[1] === undefined ? this.currentLocation || { start: {} } : arguments[1];
+
+ if (chunk instanceof SourceNode) {
+ return chunk;
+ }
+
+ chunk = castChunk(chunk, this, loc);
+
+ return new SourceNode(loc.start.line, loc.start.column, this.srcFile, chunk);
+ },
+
+ functionCall: function functionCall(fn, type, params) {
+ params = this.generateList(params);
+ return this.wrap([fn, type ? '.' + type + '(' : '(', params, ')']);
+ },
+
+ quotedString: function quotedString(str) {
+ return '"' + (str + '').replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4
+ .replace(/\u2029/g, '\\u2029') + '"';
+ },
+
+ objectLiteral: function objectLiteral(obj) {
+ var pairs = [];
+
+ for (var key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ var value = castChunk(obj[key], this);
+ if (value !== 'undefined') {
+ pairs.push([this.quotedString(key), ':', value]);
+ }
+ }
+ }
+
+ var ret = this.generateList(pairs);
+ ret.prepend('{');
+ ret.add('}');
+ return ret;
+ },
+
+ generateList: function generateList(entries) {
+ var ret = this.empty();
+
+ for (var i = 0, len = entries.length; i < len; i++) {
+ if (i) {
+ ret.add(',');
+ }
+
+ ret.add(castChunk(entries[i], this));
+ }
+
+ return ret;
+ },
+
+ generateArray: function generateArray(entries) {
+ var ret = this.generateList(entries);
+ ret.prepend('[');
+ ret.add(']');
+
+ return ret;
+ }
+ };
+
+ exports['default'] = CodeGen;
+ module.exports = exports['default'];
+
+/***/ }
+/******/ ])
+});
+;
\ No newline at end of file