From d637ffe70cfb427bf06e25a9394b9f6f42f3235e Mon Sep 17 00:00:00 2001 From: Arthur ZHU Date: Mon, 24 Jan 2022 11:16:46 +0100 Subject: [PATCH 001/287] renomme tables application relations entreprises --- app/entreprises/models.py | 24 +-- ...ables_application_relations_entreprises.py | 165 ++++++++++++++++++ 2 files changed, 177 insertions(+), 12 deletions(-) create mode 100644 migrations/versions/ee3f2eab6f08_tables_application_relations_entreprises.py diff --git a/app/entreprises/models.py b/app/entreprises/models.py index e743df3d6..865d8ff2c 100644 --- a/app/entreprises/models.py +++ b/app/entreprises/models.py @@ -2,7 +2,7 @@ from app import db class Entreprise(db.Model): - __tablename__ = "entreprises" + __tablename__ = "are_entreprises" id = db.Column(db.Integer, primary_key=True) siret = db.Column(db.Text) nom = db.Column(db.Text) @@ -35,10 +35,10 @@ class Entreprise(db.Model): class EntrepriseContact(db.Model): - __tablename__ = "entreprise_contact" + __tablename__ = "are_entreprise_contact" id = db.Column(db.Integer, primary_key=True) entreprise_id = db.Column( - db.Integer, db.ForeignKey("entreprises.id", ondelete="cascade") + db.Integer, db.ForeignKey("are_entreprises.id", ondelete="cascade") ) nom = db.Column(db.Text) prenom = db.Column(db.Text) @@ -76,10 +76,10 @@ class EntrepriseContact(db.Model): class EntrepriseOffre(db.Model): - __tablename__ = "entreprise_offre" + __tablename__ = "are_entreprise_offre" id = db.Column(db.Integer, primary_key=True) entreprise_id = db.Column( - db.Integer, db.ForeignKey("entreprises.id", ondelete="cascade") + db.Integer, db.ForeignKey("are_entreprises.id", ondelete="cascade") ) date_ajout = db.Column(db.DateTime(timezone=True), server_default=db.func.now()) intitule = db.Column(db.Text) @@ -99,7 +99,7 @@ class EntrepriseOffre(db.Model): class EntrepriseLog(db.Model): - __tablename__ = "entreprise_log" + __tablename__ = "are_entreprise_log" id = db.Column(db.Integer, primary_key=True) date = db.Column(db.DateTime(timezone=True), server_default=db.func.now()) authenticated_user = db.Column(db.Text) @@ -108,9 +108,9 @@ class EntrepriseLog(db.Model): class EntrepriseEtudiant(db.Model): - __tablename__ = "entreprise_etudiant" + __tablename__ = "are_entreprise_etudiant" id = db.Column(db.Integer, primary_key=True) - entreprise_id = db.Column(db.Integer, db.ForeignKey("entreprises.id")) + entreprise_id = db.Column(db.Integer, db.ForeignKey("are_entreprises.id")) etudid = db.Column(db.Integer) type_offre = db.Column(db.Text) date_debut = db.Column(db.Date) @@ -120,18 +120,18 @@ class EntrepriseEtudiant(db.Model): class EntrepriseEnvoiOffre(db.Model): - __tablename__ = "entreprise_envoi_offre" + __tablename__ = "are_entreprise_envoi_offre" id = db.Column(db.Integer, primary_key=True) sender_id = db.Column(db.Integer, db.ForeignKey("user.id")) receiver_id = db.Column(db.Integer, db.ForeignKey("user.id")) - offre_id = db.Column(db.Integer, db.ForeignKey("entreprise_offre.id")) + offre_id = db.Column(db.Integer, db.ForeignKey("are_entreprise_offre.id")) date_envoi = db.Column(db.DateTime(timezone=True), server_default=db.func.now()) class EntrepriseEnvoiOffreEtudiant(db.Model): - __tablename__ = "entreprise_envoi_offre_etudiant" + __tablename__ = "are_entreprise_envoi_offre_etudiant" id = db.Column(db.Integer, primary_key=True) sender_id = db.Column(db.Integer, db.ForeignKey("user.id")) receiver_id = db.Column(db.Integer, db.ForeignKey("identite.id")) - offre_id = db.Column(db.Integer, db.ForeignKey("entreprise_offre.id")) + offre_id = db.Column(db.Integer, db.ForeignKey("are_entreprise_offre.id")) date_envoi = db.Column(db.DateTime(timezone=True), server_default=db.func.now()) diff --git a/migrations/versions/ee3f2eab6f08_tables_application_relations_entreprises.py b/migrations/versions/ee3f2eab6f08_tables_application_relations_entreprises.py new file mode 100644 index 000000000..08d5200f7 --- /dev/null +++ b/migrations/versions/ee3f2eab6f08_tables_application_relations_entreprises.py @@ -0,0 +1,165 @@ +"""tables application relations entreprises + +Revision ID: ee3f2eab6f08 +Revises: f40fbaf5831c +Create Date: 2022-01-24 10:44:09.706261 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = 'ee3f2eab6f08' +down_revision = 'f40fbaf5831c' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('are_entreprise_log', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('date', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), + sa.Column('authenticated_user', sa.Text(), nullable=True), + sa.Column('object', sa.Integer(), nullable=True), + sa.Column('text', sa.Text(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('are_entreprises', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('siret', sa.Text(), nullable=True), + sa.Column('nom', sa.Text(), nullable=True), + sa.Column('adresse', sa.Text(), nullable=True), + sa.Column('codepostal', sa.Text(), nullable=True), + sa.Column('ville', sa.Text(), nullable=True), + sa.Column('pays', sa.Text(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('are_entreprise_contact', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('entreprise_id', sa.Integer(), nullable=True), + sa.Column('nom', sa.Text(), nullable=True), + sa.Column('prenom', sa.Text(), nullable=True), + sa.Column('telephone', sa.Text(), nullable=True), + sa.Column('mail', sa.Text(), nullable=True), + sa.Column('poste', sa.Text(), nullable=True), + sa.Column('service', sa.Text(), nullable=True), + sa.ForeignKeyConstraint(['entreprise_id'], ['are_entreprises.id'], ondelete='cascade'), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('are_entreprise_etudiant', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('entreprise_id', sa.Integer(), nullable=True), + sa.Column('etudid', sa.Integer(), nullable=True), + sa.Column('type_offre', sa.Text(), nullable=True), + sa.Column('date_debut', sa.Date(), nullable=True), + sa.Column('date_fin', sa.Date(), nullable=True), + sa.Column('formation_text', sa.Text(), nullable=True), + sa.Column('formation_scodoc', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['entreprise_id'], ['are_entreprises.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('are_entreprise_offre', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('entreprise_id', sa.Integer(), nullable=True), + sa.Column('date_ajout', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), + sa.Column('intitule', sa.Text(), nullable=True), + sa.Column('description', sa.Text(), nullable=True), + sa.Column('type_offre', sa.Text(), nullable=True), + sa.Column('missions', sa.Text(), nullable=True), + sa.Column('duree', sa.Text(), nullable=True), + sa.ForeignKeyConstraint(['entreprise_id'], ['are_entreprises.id'], ondelete='cascade'), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('are_entreprise_envoi_offre', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('sender_id', sa.Integer(), nullable=True), + sa.Column('receiver_id', sa.Integer(), nullable=True), + sa.Column('offre_id', sa.Integer(), nullable=True), + sa.Column('date_envoi', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), + sa.ForeignKeyConstraint(['offre_id'], ['are_entreprise_offre.id'], ), + sa.ForeignKeyConstraint(['receiver_id'], ['user.id'], ), + sa.ForeignKeyConstraint(['sender_id'], ['user.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('are_entreprise_envoi_offre_etudiant', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('sender_id', sa.Integer(), nullable=True), + sa.Column('receiver_id', sa.Integer(), nullable=True), + sa.Column('offre_id', sa.Integer(), nullable=True), + sa.Column('date_envoi', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), + sa.ForeignKeyConstraint(['offre_id'], ['are_entreprise_offre.id'], ), + sa.ForeignKeyConstraint(['receiver_id'], ['identite.id'], ), + sa.ForeignKeyConstraint(['sender_id'], ['user.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.drop_table('entreprise_contact') + op.drop_table('entreprise_correspondant') + op.drop_index('ix_entreprises_dept_id', table_name='entreprises') + op.drop_table('entreprises') + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('entreprises', + sa.Column('id', sa.INTEGER(), server_default=sa.text("nextval('entreprises_id_seq'::regclass)"), autoincrement=True, nullable=False), + sa.Column('nom', sa.TEXT(), autoincrement=False, nullable=True), + sa.Column('adresse', sa.TEXT(), autoincrement=False, nullable=True), + sa.Column('ville', sa.TEXT(), autoincrement=False, nullable=True), + sa.Column('codepostal', sa.TEXT(), autoincrement=False, nullable=True), + sa.Column('pays', sa.TEXT(), autoincrement=False, nullable=True), + sa.Column('localisation', sa.TEXT(), autoincrement=False, nullable=True), + sa.Column('dept_id', sa.INTEGER(), autoincrement=False, nullable=True), + sa.Column('date_creation', postgresql.TIMESTAMP(timezone=True), server_default=sa.text('now()'), autoincrement=False, nullable=True), + sa.Column('secteur', sa.TEXT(), autoincrement=False, nullable=True), + sa.Column('privee', sa.TEXT(), autoincrement=False, nullable=True), + sa.Column('plus10salaries', sa.BOOLEAN(), autoincrement=False, nullable=True), + sa.Column('contact_origine', sa.TEXT(), autoincrement=False, nullable=True), + sa.Column('note', sa.TEXT(), autoincrement=False, nullable=True), + sa.Column('qualite_relation', sa.INTEGER(), autoincrement=False, nullable=True), + sa.ForeignKeyConstraint(['dept_id'], ['departement.id'], name='entreprises_dept_id_fkey'), + sa.PrimaryKeyConstraint('id', name='entreprises_pkey'), + postgresql_ignore_search_path=False + ) + op.create_index('ix_entreprises_dept_id', 'entreprises', ['dept_id'], unique=False) + op.create_table('entreprise_correspondant', + sa.Column('id', sa.INTEGER(), server_default=sa.text("nextval('entreprise_correspondant_id_seq'::regclass)"), autoincrement=True, nullable=False), + sa.Column('entreprise_id', sa.INTEGER(), autoincrement=False, nullable=True), + sa.Column('nom', sa.TEXT(), autoincrement=False, nullable=True), + sa.Column('prenom', sa.TEXT(), autoincrement=False, nullable=True), + sa.Column('civilite', sa.TEXT(), autoincrement=False, nullable=True), + sa.Column('fonction', sa.TEXT(), autoincrement=False, nullable=True), + sa.Column('phone1', sa.TEXT(), autoincrement=False, nullable=True), + sa.Column('phone2', sa.TEXT(), autoincrement=False, nullable=True), + sa.Column('mobile', sa.TEXT(), autoincrement=False, nullable=True), + sa.Column('mail1', sa.TEXT(), autoincrement=False, nullable=True), + sa.Column('mail2', sa.TEXT(), autoincrement=False, nullable=True), + sa.Column('fax', sa.TEXT(), autoincrement=False, nullable=True), + sa.Column('note', sa.TEXT(), autoincrement=False, nullable=True), + sa.ForeignKeyConstraint(['entreprise_id'], ['entreprises.id'], name='entreprise_correspondant_entreprise_id_fkey'), + sa.PrimaryKeyConstraint('id', name='entreprise_correspondant_pkey'), + postgresql_ignore_search_path=False + ) + op.create_table('entreprise_contact', + sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False), + sa.Column('entreprise_id', sa.INTEGER(), autoincrement=False, nullable=True), + sa.Column('entreprise_corresp_id', sa.INTEGER(), autoincrement=False, nullable=True), + sa.Column('etudid', sa.INTEGER(), autoincrement=False, nullable=True), + sa.Column('type_contact', sa.TEXT(), autoincrement=False, nullable=True), + sa.Column('date', postgresql.TIMESTAMP(timezone=True), autoincrement=False, nullable=True), + sa.Column('enseignant', sa.TEXT(), autoincrement=False, nullable=True), + sa.Column('description', sa.TEXT(), autoincrement=False, nullable=True), + sa.ForeignKeyConstraint(['entreprise_corresp_id'], ['entreprise_correspondant.id'], name='entreprise_contact_entreprise_corresp_id_fkey'), + sa.ForeignKeyConstraint(['entreprise_id'], ['entreprises.id'], name='entreprise_contact_entreprise_id_fkey'), + sa.PrimaryKeyConstraint('id', name='entreprise_contact_pkey') + ) + op.drop_table('are_entreprise_envoi_offre_etudiant') + op.drop_table('are_entreprise_envoi_offre') + op.drop_table('are_entreprise_offre') + op.drop_table('are_entreprise_etudiant') + op.drop_table('are_entreprise_contact') + op.drop_table('are_entreprises') + op.drop_table('are_entreprise_log') + # ### end Alembic commands ### From 6d1744dacd9a219acec2fc87a44604c224cc8022 Mon Sep 17 00:00:00 2001 From: Arthur ZHU Date: Mon, 24 Jan 2022 18:07:54 +0100 Subject: [PATCH 002/287] offres date expiration --- app/entreprises/forms.py | 6 + app/entreprises/models.py | 1 + app/entreprises/routes.py | 9 +- ...ables_application_relations_entreprises.py | 253 ++++++++++++++++++ ...ables_application_relations_entreprises.py | 165 ------------ 5 files changed, 265 insertions(+), 169 deletions(-) create mode 100644 migrations/versions/bd5e795fe77d_tables_application_relations_entreprises.py delete mode 100644 migrations/versions/ee3f2eab6f08_tables_application_relations_entreprises.py diff --git a/app/entreprises/forms.py b/app/entreprises/forms.py index 1f76732dc..9ea927813 100644 --- a/app/entreprises/forms.py +++ b/app/entreprises/forms.py @@ -138,6 +138,9 @@ class OffreCreationForm(FlaskForm): "Missions", validators=[DataRequired(message=CHAMP_REQUIS)] ) duree = StringField("Durée", validators=[DataRequired(message=CHAMP_REQUIS)]) + expiration_date = DateField( + "Date expiration", validators=[DataRequired(message=CHAMP_REQUIS)] + ) submit = SubmitField("Envoyer", render_kw={"style": "margin-bottom: 10px;"}) @@ -155,6 +158,9 @@ class OffreModificationForm(FlaskForm): "Missions", validators=[DataRequired(message=CHAMP_REQUIS)] ) duree = StringField("Durée", validators=[DataRequired(message=CHAMP_REQUIS)]) + expiration_date = DateField( + "Date expiration", validators=[DataRequired(message=CHAMP_REQUIS)] + ) submit = SubmitField("Modifier", render_kw={"style": "margin-bottom: 10px;"}) diff --git a/app/entreprises/models.py b/app/entreprises/models.py index 865d8ff2c..0585b4cc4 100644 --- a/app/entreprises/models.py +++ b/app/entreprises/models.py @@ -87,6 +87,7 @@ class EntrepriseOffre(db.Model): type_offre = db.Column(db.Text) missions = db.Column(db.Text) duree = db.Column(db.Text) + expiration_date = db.Column(db.Date) def to_dict(self): return { diff --git a/app/entreprises/routes.py b/app/entreprises/routes.py index f99fa8eef..7618d1644 100644 --- a/app/entreprises/routes.py +++ b/app/entreprises/routes.py @@ -1,6 +1,6 @@ import os from config import Config -from datetime import datetime, timedelta +from datetime import datetime, date import glob import shutil @@ -123,9 +123,7 @@ def fiche_entreprise(id): offres = entreprise.offres offres_with_files = [] for offre in offres: - if datetime.now() - offre.date_ajout.replace(tzinfo=None) >= timedelta( - days=90 - ): # pour une date d'expiration ? + if date.today() > offre.expiration_date: break files = [] path = os.path.join( @@ -350,6 +348,7 @@ def add_offre(id): type_offre=form.type_offre.data.strip(), missions=form.missions.data.strip(), duree=form.duree.data.strip(), + expiration_date=form.expiration_date.data, ) log = EntrepriseLog( authenticated_user=current_user.user_name, @@ -381,6 +380,7 @@ def edit_offre(id): offre.type_offre = form.type_offre.data.strip() offre.missions = form.missions.data.strip() offre.duree = form.duree.data.strip() + offre.expiration_date = form.expiration_date.data log = EntrepriseLog( authenticated_user=current_user.user_name, object=offre.entreprise_id, @@ -396,6 +396,7 @@ def edit_offre(id): form.type_offre.data = offre.type_offre form.missions.data = offre.missions form.duree.data = offre.duree + form.expiration_date.data = offre.expiration_date return render_template( "entreprises/form.html", title=("Modification offre"), form=form ) diff --git a/migrations/versions/bd5e795fe77d_tables_application_relations_entreprises.py b/migrations/versions/bd5e795fe77d_tables_application_relations_entreprises.py new file mode 100644 index 000000000..54ea8e09f --- /dev/null +++ b/migrations/versions/bd5e795fe77d_tables_application_relations_entreprises.py @@ -0,0 +1,253 @@ +"""tables application relations entreprises + +Revision ID: bd5e795fe77d +Revises: f40fbaf5831c +Create Date: 2022-01-24 17:43:29.261983 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = "bd5e795fe77d" +down_revision = "f40fbaf5831c" +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + "are_entreprise_log", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column( + "date", + sa.DateTime(timezone=True), + server_default=sa.text("now()"), + nullable=True, + ), + sa.Column("authenticated_user", sa.Text(), nullable=True), + sa.Column("object", sa.Integer(), nullable=True), + sa.Column("text", sa.Text(), nullable=True), + sa.PrimaryKeyConstraint("id"), + ) + op.create_table( + "are_entreprises", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("siret", sa.Text(), nullable=True), + sa.Column("nom", sa.Text(), nullable=True), + sa.Column("adresse", sa.Text(), nullable=True), + sa.Column("codepostal", sa.Text(), nullable=True), + sa.Column("ville", sa.Text(), nullable=True), + sa.Column("pays", sa.Text(), nullable=True), + sa.PrimaryKeyConstraint("id"), + ) + op.create_table( + "are_entreprise_contact", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("entreprise_id", sa.Integer(), nullable=True), + sa.Column("nom", sa.Text(), nullable=True), + sa.Column("prenom", sa.Text(), nullable=True), + sa.Column("telephone", sa.Text(), nullable=True), + sa.Column("mail", sa.Text(), nullable=True), + sa.Column("poste", sa.Text(), nullable=True), + sa.Column("service", sa.Text(), nullable=True), + sa.ForeignKeyConstraint( + ["entreprise_id"], ["are_entreprises.id"], ondelete="cascade" + ), + sa.PrimaryKeyConstraint("id"), + ) + op.create_table( + "are_entreprise_etudiant", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("entreprise_id", sa.Integer(), nullable=True), + sa.Column("etudid", sa.Integer(), nullable=True), + sa.Column("type_offre", sa.Text(), nullable=True), + sa.Column("date_debut", sa.Date(), nullable=True), + sa.Column("date_fin", sa.Date(), nullable=True), + sa.Column("formation_text", sa.Text(), nullable=True), + sa.Column("formation_scodoc", sa.Integer(), nullable=True), + sa.ForeignKeyConstraint( + ["entreprise_id"], + ["are_entreprises.id"], + ), + sa.PrimaryKeyConstraint("id"), + ) + op.create_table( + "are_entreprise_offre", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("entreprise_id", sa.Integer(), nullable=True), + sa.Column( + "date_ajout", + sa.DateTime(timezone=True), + server_default=sa.text("now()"), + nullable=True, + ), + sa.Column("intitule", sa.Text(), nullable=True), + sa.Column("description", sa.Text(), nullable=True), + sa.Column("type_offre", sa.Text(), nullable=True), + sa.Column("missions", sa.Text(), nullable=True), + sa.Column("duree", sa.Text(), nullable=True), + sa.Column("expiration_date", sa.Date(), nullable=True), + sa.ForeignKeyConstraint( + ["entreprise_id"], ["are_entreprises.id"], ondelete="cascade" + ), + sa.PrimaryKeyConstraint("id"), + ) + op.create_table( + "are_entreprise_envoi_offre", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("sender_id", sa.Integer(), nullable=True), + sa.Column("receiver_id", sa.Integer(), nullable=True), + sa.Column("offre_id", sa.Integer(), nullable=True), + sa.Column( + "date_envoi", + sa.DateTime(timezone=True), + server_default=sa.text("now()"), + nullable=True, + ), + sa.ForeignKeyConstraint( + ["offre_id"], + ["are_entreprise_offre.id"], + ), + sa.ForeignKeyConstraint( + ["receiver_id"], + ["user.id"], + ), + sa.ForeignKeyConstraint( + ["sender_id"], + ["user.id"], + ), + sa.PrimaryKeyConstraint("id"), + ) + op.create_table( + "are_entreprise_envoi_offre_etudiant", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("sender_id", sa.Integer(), nullable=True), + sa.Column("receiver_id", sa.Integer(), nullable=True), + sa.Column("offre_id", sa.Integer(), nullable=True), + sa.Column( + "date_envoi", + sa.DateTime(timezone=True), + server_default=sa.text("now()"), + nullable=True, + ), + sa.ForeignKeyConstraint( + ["offre_id"], + ["are_entreprise_offre.id"], + ), + sa.ForeignKeyConstraint( + ["receiver_id"], + ["identite.id"], + ), + sa.ForeignKeyConstraint( + ["sender_id"], + ["user.id"], + ), + sa.PrimaryKeyConstraint("id"), + ) + op.drop_table("entreprise_contact") + op.drop_table("entreprise_correspondant") + op.drop_index("ix_entreprises_dept_id", table_name="entreprises") + op.drop_table("entreprises") + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + "entreprises", + sa.Column( + "id", + sa.INTEGER(), + server_default=sa.text("nextval('entreprises_id_seq'::regclass)"), + autoincrement=True, + nullable=False, + ), + sa.Column("nom", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("adresse", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("ville", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("codepostal", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("pays", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("localisation", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("dept_id", sa.INTEGER(), autoincrement=False, nullable=True), + sa.Column( + "date_creation", + postgresql.TIMESTAMP(timezone=True), + server_default=sa.text("now()"), + autoincrement=False, + nullable=True, + ), + sa.Column("secteur", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("privee", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("plus10salaries", sa.BOOLEAN(), autoincrement=False, nullable=True), + sa.Column("contact_origine", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("note", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("qualite_relation", sa.INTEGER(), autoincrement=False, nullable=True), + sa.ForeignKeyConstraint( + ["dept_id"], ["departement.id"], name="entreprises_dept_id_fkey" + ), + sa.PrimaryKeyConstraint("id", name="entreprises_pkey"), + postgresql_ignore_search_path=False, + ) + op.create_index("ix_entreprises_dept_id", "entreprises", ["dept_id"], unique=False) + op.create_table( + "entreprise_contact", + sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False), + sa.Column("entreprise_id", sa.INTEGER(), autoincrement=False, nullable=True), + sa.Column( + "entreprise_corresp_id", sa.INTEGER(), autoincrement=False, nullable=True + ), + sa.Column("etudid", sa.INTEGER(), autoincrement=False, nullable=True), + sa.Column("type_contact", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column( + "date", + postgresql.TIMESTAMP(timezone=True), + autoincrement=False, + nullable=True, + ), + sa.Column("enseignant", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("description", sa.TEXT(), autoincrement=False, nullable=True), + sa.ForeignKeyConstraint( + ["entreprise_corresp_id"], + ["entreprise_correspondant.id"], + name="entreprise_contact_entreprise_corresp_id_fkey", + ), + sa.ForeignKeyConstraint( + ["entreprise_id"], + ["entreprises.id"], + name="entreprise_contact_entreprise_id_fkey", + ), + sa.PrimaryKeyConstraint("id", name="entreprise_contact_pkey"), + ) + op.create_table( + "entreprise_correspondant", + sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False), + sa.Column("entreprise_id", sa.INTEGER(), autoincrement=False, nullable=True), + sa.Column("nom", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("prenom", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("civilite", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("fonction", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("phone1", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("phone2", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("mobile", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("mail1", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("mail2", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("fax", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("note", sa.TEXT(), autoincrement=False, nullable=True), + sa.ForeignKeyConstraint( + ["entreprise_id"], + ["entreprises.id"], + name="entreprise_correspondant_entreprise_id_fkey", + ), + sa.PrimaryKeyConstraint("id", name="entreprise_correspondant_pkey"), + ) + op.drop_table("are_entreprise_envoi_offre_etudiant") + op.drop_table("are_entreprise_envoi_offre") + op.drop_table("are_entreprise_offre") + op.drop_table("are_entreprise_etudiant") + op.drop_table("are_entreprise_contact") + op.drop_table("are_entreprises") + op.drop_table("are_entreprise_log") + # ### end Alembic commands ### diff --git a/migrations/versions/ee3f2eab6f08_tables_application_relations_entreprises.py b/migrations/versions/ee3f2eab6f08_tables_application_relations_entreprises.py deleted file mode 100644 index 08d5200f7..000000000 --- a/migrations/versions/ee3f2eab6f08_tables_application_relations_entreprises.py +++ /dev/null @@ -1,165 +0,0 @@ -"""tables application relations entreprises - -Revision ID: ee3f2eab6f08 -Revises: f40fbaf5831c -Create Date: 2022-01-24 10:44:09.706261 - -""" -from alembic import op -import sqlalchemy as sa -from sqlalchemy.dialects import postgresql - -# revision identifiers, used by Alembic. -revision = 'ee3f2eab6f08' -down_revision = 'f40fbaf5831c' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('are_entreprise_log', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('date', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), - sa.Column('authenticated_user', sa.Text(), nullable=True), - sa.Column('object', sa.Integer(), nullable=True), - sa.Column('text', sa.Text(), nullable=True), - sa.PrimaryKeyConstraint('id') - ) - op.create_table('are_entreprises', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('siret', sa.Text(), nullable=True), - sa.Column('nom', sa.Text(), nullable=True), - sa.Column('adresse', sa.Text(), nullable=True), - sa.Column('codepostal', sa.Text(), nullable=True), - sa.Column('ville', sa.Text(), nullable=True), - sa.Column('pays', sa.Text(), nullable=True), - sa.PrimaryKeyConstraint('id') - ) - op.create_table('are_entreprise_contact', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('entreprise_id', sa.Integer(), nullable=True), - sa.Column('nom', sa.Text(), nullable=True), - sa.Column('prenom', sa.Text(), nullable=True), - sa.Column('telephone', sa.Text(), nullable=True), - sa.Column('mail', sa.Text(), nullable=True), - sa.Column('poste', sa.Text(), nullable=True), - sa.Column('service', sa.Text(), nullable=True), - sa.ForeignKeyConstraint(['entreprise_id'], ['are_entreprises.id'], ondelete='cascade'), - sa.PrimaryKeyConstraint('id') - ) - op.create_table('are_entreprise_etudiant', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('entreprise_id', sa.Integer(), nullable=True), - sa.Column('etudid', sa.Integer(), nullable=True), - sa.Column('type_offre', sa.Text(), nullable=True), - sa.Column('date_debut', sa.Date(), nullable=True), - sa.Column('date_fin', sa.Date(), nullable=True), - sa.Column('formation_text', sa.Text(), nullable=True), - sa.Column('formation_scodoc', sa.Integer(), nullable=True), - sa.ForeignKeyConstraint(['entreprise_id'], ['are_entreprises.id'], ), - sa.PrimaryKeyConstraint('id') - ) - op.create_table('are_entreprise_offre', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('entreprise_id', sa.Integer(), nullable=True), - sa.Column('date_ajout', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), - sa.Column('intitule', sa.Text(), nullable=True), - sa.Column('description', sa.Text(), nullable=True), - sa.Column('type_offre', sa.Text(), nullable=True), - sa.Column('missions', sa.Text(), nullable=True), - sa.Column('duree', sa.Text(), nullable=True), - sa.ForeignKeyConstraint(['entreprise_id'], ['are_entreprises.id'], ondelete='cascade'), - sa.PrimaryKeyConstraint('id') - ) - op.create_table('are_entreprise_envoi_offre', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('sender_id', sa.Integer(), nullable=True), - sa.Column('receiver_id', sa.Integer(), nullable=True), - sa.Column('offre_id', sa.Integer(), nullable=True), - sa.Column('date_envoi', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), - sa.ForeignKeyConstraint(['offre_id'], ['are_entreprise_offre.id'], ), - sa.ForeignKeyConstraint(['receiver_id'], ['user.id'], ), - sa.ForeignKeyConstraint(['sender_id'], ['user.id'], ), - sa.PrimaryKeyConstraint('id') - ) - op.create_table('are_entreprise_envoi_offre_etudiant', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('sender_id', sa.Integer(), nullable=True), - sa.Column('receiver_id', sa.Integer(), nullable=True), - sa.Column('offre_id', sa.Integer(), nullable=True), - sa.Column('date_envoi', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), - sa.ForeignKeyConstraint(['offre_id'], ['are_entreprise_offre.id'], ), - sa.ForeignKeyConstraint(['receiver_id'], ['identite.id'], ), - sa.ForeignKeyConstraint(['sender_id'], ['user.id'], ), - sa.PrimaryKeyConstraint('id') - ) - op.drop_table('entreprise_contact') - op.drop_table('entreprise_correspondant') - op.drop_index('ix_entreprises_dept_id', table_name='entreprises') - op.drop_table('entreprises') - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('entreprises', - sa.Column('id', sa.INTEGER(), server_default=sa.text("nextval('entreprises_id_seq'::regclass)"), autoincrement=True, nullable=False), - sa.Column('nom', sa.TEXT(), autoincrement=False, nullable=True), - sa.Column('adresse', sa.TEXT(), autoincrement=False, nullable=True), - sa.Column('ville', sa.TEXT(), autoincrement=False, nullable=True), - sa.Column('codepostal', sa.TEXT(), autoincrement=False, nullable=True), - sa.Column('pays', sa.TEXT(), autoincrement=False, nullable=True), - sa.Column('localisation', sa.TEXT(), autoincrement=False, nullable=True), - sa.Column('dept_id', sa.INTEGER(), autoincrement=False, nullable=True), - sa.Column('date_creation', postgresql.TIMESTAMP(timezone=True), server_default=sa.text('now()'), autoincrement=False, nullable=True), - sa.Column('secteur', sa.TEXT(), autoincrement=False, nullable=True), - sa.Column('privee', sa.TEXT(), autoincrement=False, nullable=True), - sa.Column('plus10salaries', sa.BOOLEAN(), autoincrement=False, nullable=True), - sa.Column('contact_origine', sa.TEXT(), autoincrement=False, nullable=True), - sa.Column('note', sa.TEXT(), autoincrement=False, nullable=True), - sa.Column('qualite_relation', sa.INTEGER(), autoincrement=False, nullable=True), - sa.ForeignKeyConstraint(['dept_id'], ['departement.id'], name='entreprises_dept_id_fkey'), - sa.PrimaryKeyConstraint('id', name='entreprises_pkey'), - postgresql_ignore_search_path=False - ) - op.create_index('ix_entreprises_dept_id', 'entreprises', ['dept_id'], unique=False) - op.create_table('entreprise_correspondant', - sa.Column('id', sa.INTEGER(), server_default=sa.text("nextval('entreprise_correspondant_id_seq'::regclass)"), autoincrement=True, nullable=False), - sa.Column('entreprise_id', sa.INTEGER(), autoincrement=False, nullable=True), - sa.Column('nom', sa.TEXT(), autoincrement=False, nullable=True), - sa.Column('prenom', sa.TEXT(), autoincrement=False, nullable=True), - sa.Column('civilite', sa.TEXT(), autoincrement=False, nullable=True), - sa.Column('fonction', sa.TEXT(), autoincrement=False, nullable=True), - sa.Column('phone1', sa.TEXT(), autoincrement=False, nullable=True), - sa.Column('phone2', sa.TEXT(), autoincrement=False, nullable=True), - sa.Column('mobile', sa.TEXT(), autoincrement=False, nullable=True), - sa.Column('mail1', sa.TEXT(), autoincrement=False, nullable=True), - sa.Column('mail2', sa.TEXT(), autoincrement=False, nullable=True), - sa.Column('fax', sa.TEXT(), autoincrement=False, nullable=True), - sa.Column('note', sa.TEXT(), autoincrement=False, nullable=True), - sa.ForeignKeyConstraint(['entreprise_id'], ['entreprises.id'], name='entreprise_correspondant_entreprise_id_fkey'), - sa.PrimaryKeyConstraint('id', name='entreprise_correspondant_pkey'), - postgresql_ignore_search_path=False - ) - op.create_table('entreprise_contact', - sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False), - sa.Column('entreprise_id', sa.INTEGER(), autoincrement=False, nullable=True), - sa.Column('entreprise_corresp_id', sa.INTEGER(), autoincrement=False, nullable=True), - sa.Column('etudid', sa.INTEGER(), autoincrement=False, nullable=True), - sa.Column('type_contact', sa.TEXT(), autoincrement=False, nullable=True), - sa.Column('date', postgresql.TIMESTAMP(timezone=True), autoincrement=False, nullable=True), - sa.Column('enseignant', sa.TEXT(), autoincrement=False, nullable=True), - sa.Column('description', sa.TEXT(), autoincrement=False, nullable=True), - sa.ForeignKeyConstraint(['entreprise_corresp_id'], ['entreprise_correspondant.id'], name='entreprise_contact_entreprise_corresp_id_fkey'), - sa.ForeignKeyConstraint(['entreprise_id'], ['entreprises.id'], name='entreprise_contact_entreprise_id_fkey'), - sa.PrimaryKeyConstraint('id', name='entreprise_contact_pkey') - ) - op.drop_table('are_entreprise_envoi_offre_etudiant') - op.drop_table('are_entreprise_envoi_offre') - op.drop_table('are_entreprise_offre') - op.drop_table('are_entreprise_etudiant') - op.drop_table('are_entreprise_contact') - op.drop_table('are_entreprises') - op.drop_table('are_entreprise_log') - # ### end Alembic commands ### From 0220607caa17505c6f60d96a122047bfc2715b28 Mon Sep 17 00:00:00 2001 From: Arthur ZHU Date: Mon, 24 Jan 2022 19:02:16 +0100 Subject: [PATCH 003/287] =?UTF-8?q?ajout=20page=20offres=20expir=C3=A9es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/entreprises/routes.py | 30 +++++++++++++++++++ .../entreprises/fiche_entreprise.html | 1 + .../entreprises/offres_expirees.html | 14 +++++++++ 3 files changed, 45 insertions(+) create mode 100644 app/templates/entreprises/offres_expirees.html diff --git a/app/entreprises/routes.py b/app/entreprises/routes.py index 7618d1644..51c693def 100644 --- a/app/entreprises/routes.py +++ b/app/entreprises/routes.py @@ -188,6 +188,36 @@ def offres(): ) +@bp.route("/fiche_entreprise//offres_expirees") +def offres_expirees(id): + entreprise = Entreprise.query.filter_by(id=id).first_or_404() + offres = entreprise.offres + offres_expirees_with_files = [] + for offre in offres: + if date.today() > offre.expiration_date: + files = [] + path = os.path.join( + Config.SCODOC_VAR_DIR, + "entreprises", + f"{offre.entreprise_id}", + f"{offre.id}", + ) + if os.path.exists(path): + for dir in glob.glob( + f"{path}/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]" + ): + for file in glob.glob(f"{dir}/*"): + file = [os.path.basename(dir), os.path.basename(file)] + files.append(file) + offres_expirees_with_files.append([offre, files]) + return render_template( + "entreprises/offres_expirees.html", + title=("Offres expirées"), + entreprise=entreprise, + offres_expirees=offres_expirees_with_files, + ) + + @bp.route("/add_entreprise", methods=["GET", "POST"]) def add_entreprise(): """ diff --git a/app/templates/entreprises/fiche_entreprise.html b/app/templates/entreprises/fiche_entreprise.html index 9bb20a8a8..8e03942d4 100644 --- a/app/templates/entreprises/fiche_entreprise.html +++ b/app/templates/entreprises/fiche_entreprise.html @@ -71,6 +71,7 @@ Ajouter contact Ajouter historique + Voir les offres expirées {% endblock %} \ No newline at end of file diff --git a/app/templates/entreprises/offres_expirees.html b/app/templates/entreprises/offres_expirees.html new file mode 100644 index 000000000..50c1b7d76 --- /dev/null +++ b/app/templates/entreprises/offres_expirees.html @@ -0,0 +1,14 @@ +{# -*- mode: jinja-html -*- #} +{% extends 'base.html' %} + +{% block app_content %} +
+

Offres expirées de {{ entreprise.nom }}

+{% if offres_expirees %} + {% for offre in offres_expirees%} + Offre {{loop.index}} (ajouté le {{offre[0].date_ajout.strftime('%d/%m/%Y') }}) + {% include 'entreprises/_offre.html' %} + {% endfor %} +{% endif %} +
+{% endblock %} \ No newline at end of file From 789d2a8c8803f94a2f5371ea76b3215fb2edf167 Mon Sep 17 00:00:00 2001 From: Arthur ZHU Date: Tue, 25 Jan 2022 19:42:17 +0100 Subject: [PATCH 004/287] validation entreprises --- app/entreprises/models.py | 1 + app/entreprises/routes.py | 19 +++++-- .../{offres.html => offres_recues.html} | 0 ...bles_application_relations_entreprises.py} | 53 ++++++++++--------- 4 files changed, 44 insertions(+), 29 deletions(-) rename app/templates/entreprises/{offres.html => offres_recues.html} (100%) rename migrations/versions/{bd5e795fe77d_tables_application_relations_entreprises.py => fa4d3f05e4f0_tables_application_relations_entreprises.py} (98%) diff --git a/app/entreprises/models.py b/app/entreprises/models.py index 0585b4cc4..b3389fa4a 100644 --- a/app/entreprises/models.py +++ b/app/entreprises/models.py @@ -10,6 +10,7 @@ class Entreprise(db.Model): codepostal = db.Column(db.Text) ville = db.Column(db.Text) pays = db.Column(db.Text) + visible = db.Column(db.Boolean, default=False) contacts = db.relationship( "EntrepriseContact", backref="entreprise", diff --git a/app/entreprises/routes.py b/app/entreprises/routes.py index 51c693def..c7be9643b 100644 --- a/app/entreprises/routes.py +++ b/app/entreprises/routes.py @@ -57,7 +57,7 @@ def index(): logs: liste des logs """ - entreprises = Entreprise.query.all() + entreprises = Entreprise.query.filter_by(visible=True).all() logs = EntrepriseLog.query.order_by(EntrepriseLog.date.desc()).limit(LOGS_LEN).all() return render_template( "entreprises/entreprises.html", @@ -67,6 +67,16 @@ def index(): ) +@bp.route("/validation", methods=["GET"]) +def validation_entreprise(): + entreprises = Entreprise.query.filter_by(visible=False).all() + return render_template( + "entreprises/entreprises.html", + title=("Entreprises"), + entreprises=entreprises, + ) + + @bp.route("/contacts", methods=["GET"]) def contacts(): """ @@ -84,6 +94,7 @@ def contacts(): contacts = ( db.session.query(EntrepriseContact, Entreprise) .join(Entreprise, EntrepriseContact.entreprise_id == Entreprise.id) + .filter_by(visible=True) .all() ) logs = EntrepriseLog.query.order_by(EntrepriseLog.date.desc()).limit(LOGS_LEN).all() @@ -165,7 +176,7 @@ def fiche_entreprise(id): ) -@bp.route("/offres", methods=["GET"]) +@bp.route("/offres_recues", methods=["GET"]) def offres(): """ Permet d'afficher la page où l'on recoit les offres @@ -184,7 +195,9 @@ def offres(): .all() ) return render_template( - "entreprises/offres.html", title=("Offres"), offres_recues=offres_recues + "entreprises/offres_recues.html", + title=("Offres reçues"), + offres_recues=offres_recues, ) diff --git a/app/templates/entreprises/offres.html b/app/templates/entreprises/offres_recues.html similarity index 100% rename from app/templates/entreprises/offres.html rename to app/templates/entreprises/offres_recues.html diff --git a/migrations/versions/bd5e795fe77d_tables_application_relations_entreprises.py b/migrations/versions/fa4d3f05e4f0_tables_application_relations_entreprises.py similarity index 98% rename from migrations/versions/bd5e795fe77d_tables_application_relations_entreprises.py rename to migrations/versions/fa4d3f05e4f0_tables_application_relations_entreprises.py index 54ea8e09f..b116c8e0f 100644 --- a/migrations/versions/bd5e795fe77d_tables_application_relations_entreprises.py +++ b/migrations/versions/fa4d3f05e4f0_tables_application_relations_entreprises.py @@ -1,8 +1,8 @@ """tables application relations entreprises -Revision ID: bd5e795fe77d +Revision ID: fa4d3f05e4f0 Revises: f40fbaf5831c -Create Date: 2022-01-24 17:43:29.261983 +Create Date: 2022-01-25 17:33:28.546610 """ from alembic import op @@ -10,7 +10,7 @@ import sqlalchemy as sa from sqlalchemy.dialects import postgresql # revision identifiers, used by Alembic. -revision = "bd5e795fe77d" +revision = "fa4d3f05e4f0" down_revision = "f40fbaf5831c" branch_labels = None depends_on = None @@ -41,6 +41,7 @@ def upgrade(): sa.Column("codepostal", sa.Text(), nullable=True), sa.Column("ville", sa.Text(), nullable=True), sa.Column("pays", sa.Text(), nullable=True), + sa.Column("visible", sa.Boolean(), nullable=True), sa.PrimaryKeyConstraint("id"), ) op.create_table( @@ -148,8 +149,8 @@ def upgrade(): sa.PrimaryKeyConstraint("id"), ) op.drop_table("entreprise_contact") - op.drop_table("entreprise_correspondant") op.drop_index("ix_entreprises_dept_id", table_name="entreprises") + op.drop_table("entreprise_correspondant") op.drop_table("entreprises") # ### end Alembic commands ### @@ -192,6 +193,28 @@ def downgrade(): postgresql_ignore_search_path=False, ) op.create_index("ix_entreprises_dept_id", "entreprises", ["dept_id"], unique=False) + op.create_table( + "entreprise_correspondant", + sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False), + sa.Column("entreprise_id", sa.INTEGER(), autoincrement=False, nullable=True), + sa.Column("nom", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("prenom", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("civilite", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("fonction", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("phone1", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("phone2", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("mobile", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("mail1", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("mail2", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("fax", sa.TEXT(), autoincrement=False, nullable=True), + sa.Column("note", sa.TEXT(), autoincrement=False, nullable=True), + sa.ForeignKeyConstraint( + ["entreprise_id"], + ["entreprises.id"], + name="entreprise_correspondant_entreprise_id_fkey", + ), + sa.PrimaryKeyConstraint("id", name="entreprise_correspondant_pkey"), + ) op.create_table( "entreprise_contact", sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False), @@ -221,28 +244,6 @@ def downgrade(): ), sa.PrimaryKeyConstraint("id", name="entreprise_contact_pkey"), ) - op.create_table( - "entreprise_correspondant", - sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False), - sa.Column("entreprise_id", sa.INTEGER(), autoincrement=False, nullable=True), - sa.Column("nom", sa.TEXT(), autoincrement=False, nullable=True), - sa.Column("prenom", sa.TEXT(), autoincrement=False, nullable=True), - sa.Column("civilite", sa.TEXT(), autoincrement=False, nullable=True), - sa.Column("fonction", sa.TEXT(), autoincrement=False, nullable=True), - sa.Column("phone1", sa.TEXT(), autoincrement=False, nullable=True), - sa.Column("phone2", sa.TEXT(), autoincrement=False, nullable=True), - sa.Column("mobile", sa.TEXT(), autoincrement=False, nullable=True), - sa.Column("mail1", sa.TEXT(), autoincrement=False, nullable=True), - sa.Column("mail2", sa.TEXT(), autoincrement=False, nullable=True), - sa.Column("fax", sa.TEXT(), autoincrement=False, nullable=True), - sa.Column("note", sa.TEXT(), autoincrement=False, nullable=True), - sa.ForeignKeyConstraint( - ["entreprise_id"], - ["entreprises.id"], - name="entreprise_correspondant_entreprise_id_fkey", - ), - sa.PrimaryKeyConstraint("id", name="entreprise_correspondant_pkey"), - ) op.drop_table("are_entreprise_envoi_offre_etudiant") op.drop_table("are_entreprise_envoi_offre") op.drop_table("are_entreprise_offre") From 17d954eea8f990ff8fbd20cc2a79c1ac35d54f32 Mon Sep 17 00:00:00 2001 From: Arthur ZHU Date: Wed, 26 Jan 2022 18:42:48 +0100 Subject: [PATCH 005/287] permissions pour les roles + fin validation entreprises --- app/entreprises/routes.py | 50 ++++++++++++++++++- app/scodoc/sco_permissions.py | 9 ++++ .../entreprises/entreprises_validation.html | 49 ++++++++++++++++++ .../entreprises/fiche_entreprise.html | 2 +- .../fiche_entreprise_validation.html | 45 +++++++++++++++++ .../entreprises/offres_expirees.html | 16 +++--- 6 files changed, 161 insertions(+), 10 deletions(-) create mode 100644 app/templates/entreprises/entreprises_validation.html create mode 100644 app/templates/entreprises/fiche_entreprise_validation.html diff --git a/app/entreprises/routes.py b/app/entreprises/routes.py index c7be9643b..8266d67a1 100644 --- a/app/entreprises/routes.py +++ b/app/entreprises/routes.py @@ -44,6 +44,7 @@ from werkzeug.utils import secure_filename @bp.route("/", methods=["GET"]) +@permission_required(Permission.RelationsEntreprisesView) def index(): """ Permet d'afficher une page avec la liste des entreprises et une liste des dernières opérations @@ -68,16 +69,18 @@ def index(): @bp.route("/validation", methods=["GET"]) +@permission_required(Permission.RelationsEntreprisesValidate) def validation_entreprise(): entreprises = Entreprise.query.filter_by(visible=False).all() return render_template( - "entreprises/entreprises.html", + "entreprises/entreprises_validation.html", title=("Entreprises"), entreprises=entreprises, ) @bp.route("/contacts", methods=["GET"]) +@permission_required(Permission.RelationsEntreprisesView) def contacts(): """ Permet d'afficher une page la liste des contacts et une liste des dernières opérations @@ -104,6 +107,7 @@ def contacts(): @bp.route("/fiche_entreprise/", methods=["GET"]) +@permission_required(Permission.RelationsEntreprisesView) def fiche_entreprise(id): """ Permet d'afficher la fiche entreprise d'une entreprise avec une liste des dernières opérations et @@ -130,7 +134,7 @@ def fiche_entreprise(id): historique: liste des étudiants ayant réaliser un stage ou une alternance dans l'entreprise """ - entreprise = Entreprise.query.filter_by(id=id).first_or_404() + entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404() offres = entreprise.offres offres_with_files = [] for offre in offres: @@ -176,7 +180,21 @@ def fiche_entreprise(id): ) +@bp.route("/fiche_entreprise_validation/", methods=["GET"]) +@permission_required(Permission.RelationsEntreprisesValidate) +def fiche_entreprise_validation(id): + entreprise = Entreprise.query.filter_by(id=id, visible=False).first_or_404() + contacts = entreprise.contacts + return render_template( + "entreprises/fiche_entreprise_validation.html", + title=("Fiche entreprise"), + entreprise=entreprise, + contacts=contacts, + ) + + @bp.route("/offres_recues", methods=["GET"]) +@permission_required(Permission.RelationsEntreprisesView) def offres(): """ Permet d'afficher la page où l'on recoit les offres @@ -202,6 +220,7 @@ def offres(): @bp.route("/fiche_entreprise//offres_expirees") +@permission_required(Permission.RelationsEntreprisesView) def offres_expirees(id): entreprise = Entreprise.query.filter_by(id=id).first_or_404() offres = entreprise.offres @@ -232,6 +251,7 @@ def offres_expirees(id): @bp.route("/add_entreprise", methods=["GET", "POST"]) +@permission_required(Permission.RelationsEntreprisesChange) def add_entreprise(): """ Permet d'ajouter une entreprise dans la base avec un formulaire @@ -276,6 +296,7 @@ def add_entreprise(): @bp.route("/edit_entreprise/", methods=["GET", "POST"]) +@permission_required(Permission.RelationsEntreprisesChange) def edit_entreprise(id): """ Permet de modifier une entreprise de la base avec un formulaire @@ -344,6 +365,7 @@ def edit_entreprise(id): @bp.route("/delete_entreprise/", methods=["GET", "POST"]) +@permission_required(Permission.RelationsEntreprisesChange) def delete_entreprise(id): """ Permet de supprimer une entreprise de la base avec un formulaire de confirmation @@ -372,7 +394,17 @@ def delete_entreprise(id): ) +@bp.route("/validate_entreprise/", methods=["GET", "POST"]) +@permission_required(Permission.RelationsEntreprisesValidate) +def validate_entreprise(id): + entreprise = Entreprise.query.filter_by(id=id).first_or_404() + entreprise.visible = True + db.session.commit() + return redirect(url_for("entreprises.fiche_entreprise", id=entreprise.id)) + + @bp.route("/add_offre/", methods=["GET", "POST"]) +@permission_required(Permission.RelationsEntreprisesChange) def add_offre(id): """ Permet d'ajouter une offre a une entreprise @@ -407,6 +439,7 @@ def add_offre(id): @bp.route("/edit_offre/", methods=["GET", "POST"]) +@permission_required(Permission.RelationsEntreprisesChange) def edit_offre(id): """ Permet de modifier une offre @@ -446,6 +479,7 @@ def edit_offre(id): @bp.route("/delete_offre/", methods=["GET", "POST"]) +@permission_required(Permission.RelationsEntreprisesChange) def delete_offre(id): """ Permet de supprimer une offre @@ -474,6 +508,7 @@ def delete_offre(id): @bp.route("/add_contact/", methods=["GET", "POST"]) +@permission_required(Permission.RelationsEntreprisesChange) def add_contact(id): """ Permet d'ajouter un contact a une entreprise @@ -508,6 +543,7 @@ def add_contact(id): @bp.route("/edit_contact/", methods=["GET", "POST"]) +@permission_required(Permission.RelationsEntreprisesChange) def edit_contact(id): """ Permet de modifier un contact @@ -549,6 +585,7 @@ def edit_contact(id): @bp.route("/delete_contact/", methods=["GET", "POST"]) +@permission_required(Permission.RelationsEntreprisesChange) def delete_contact(id): """ Permet de supprimer un contact @@ -586,6 +623,7 @@ def delete_contact(id): @bp.route("/add_historique/", methods=["GET", "POST"]) +@permission_required(Permission.RelationsEntreprisesChange) def add_historique(id): """ Permet d'ajouter un étudiant ayant réalisé un stage ou une alternance sur la fiche entreprise de l'entreprise @@ -630,6 +668,7 @@ def add_historique(id): @bp.route("/envoyer_offre/", methods=["GET", "POST"]) +@permission_required(Permission.RelationsEntreprisesSend) def envoyer_offre(id): """ Permet d'envoyer une offre à un utilisateur @@ -663,6 +702,7 @@ def envoyer_offre(id): @bp.route("/etudiants") +@permission_required(Permission.RelationsEntreprisesChange) def json_etudiants(): """ Permet de récuperer un JSON avec tous les étudiants @@ -696,6 +736,7 @@ def json_etudiants(): @bp.route("/responsables") +@permission_required(Permission.RelationsEntreprisesChange) def json_responsables(): """ Permet de récuperer un JSON avec tous les étudiants @@ -724,6 +765,7 @@ def json_responsables(): @bp.route("/export_entreprises") +@permission_required(Permission.RelationsEntreprisesExport) def export_entreprises(): """ Permet d'exporter la liste des entreprises sous format excel (.xlsx) @@ -763,6 +805,7 @@ def export_contacts(): @bp.route("/export_contacts_bis") +@permission_required(Permission.RelationsEntreprisesExport) def export_contacts_bis(): """ Permet d'exporter la liste des contacts avec leur entreprise sous format excel (.xlsx) @@ -798,6 +841,7 @@ def export_contacts_bis(): @bp.route( "/get_offre_file////" ) +@permission_required(Permission.RelationsEntreprisesView) def get_offre_file(entreprise_id, offre_id, filedir, filename): """ Permet de télécharger un fichier d'une offre @@ -838,6 +882,7 @@ def get_offre_file(entreprise_id, offre_id, filedir, filename): @bp.route("/add_offre_file/", methods=["GET", "POST"]) +@permission_required(Permission.RelationsEntreprisesChange) def add_offre_file(offre_id): """ Permet d'ajouter un fichier à une offre @@ -869,6 +914,7 @@ def add_offre_file(offre_id): @bp.route("/delete_offre_file//", methods=["GET", "POST"]) +@permission_required(Permission.RelationsEntreprisesChange) def delete_offre_file(offre_id, filedir): """ Permet de supprimer un fichier d'une offre diff --git a/app/scodoc/sco_permissions.py b/app/scodoc/sco_permissions.py index a1a06aba8..55981b033 100644 --- a/app/scodoc/sco_permissions.py +++ b/app/scodoc/sco_permissions.py @@ -37,6 +37,15 @@ _SCO_PERMISSIONS = ( (1 << 21, "ScoEditPVJury", "Éditer les PV de jury"), # ajouter maquettes Apogee (=> chef dept et secr): (1 << 22, "ScoEditApo", "Ajouter des maquettes Apogées"), + (1 << 23, "RelationsEntreprisesView", "Voir l'application relations entreprises"), + (1 << 24, "RelationsEntreprisesChange", "Modifier les entreprises"), + ( + 1 << 25, + "RelationsEntreprisesExport", + "Exporter les données de l'application relations entreprises", + ), + (1 << 25, "RelationsEntreprisesSend", "Envoyer des offres"), + (1 << 26, "RelationsEntreprisesValidate", "Valide les entreprises"), ) diff --git a/app/templates/entreprises/entreprises_validation.html b/app/templates/entreprises/entreprises_validation.html new file mode 100644 index 000000000..14a5b49da --- /dev/null +++ b/app/templates/entreprises/entreprises_validation.html @@ -0,0 +1,49 @@ +{# -*- mode: jinja-html -*- #} +{% extends 'base.html' %} + +{% block app_content %} + {% if logs %} +
+

Dernières opérations

+
    + {% for log in logs %} +
  • {{ log.date.strftime('%d %b %Hh%M') }}{{ log.text|safe }} par {{ log.authenticated_user|get_nomcomplet }}
  • + {% endfor %} +
+
+ {% endif %} +
+

Liste des entreprises à valider

+ {% if entreprises %} +
+ + + + + + + + + + + {% for entreprise in entreprises %} + + + + + + + + + + {% endfor %} +
SIRETNomAdresseCode postalVillePaysAction
{{ entreprise.siret }}{{ entreprise.nom }}{{ entreprise.adresse }}{{ entreprise.codepostal }}{{ entreprise.ville }}{{ entreprise.pays }} + Valider +
+ {% else %} +
Aucune entreprise à valider
+
+
+ {% endif %} +
+{% endblock %} \ No newline at end of file diff --git a/app/templates/entreprises/fiche_entreprise.html b/app/templates/entreprises/fiche_entreprise.html index 8e03942d4..a7cc09632 100644 --- a/app/templates/entreprises/fiche_entreprise.html +++ b/app/templates/entreprises/fiche_entreprise.html @@ -71,7 +71,7 @@ Ajouter contact Ajouter historique - Voir les offres expirées + Voir les offres expirées {% endblock %} \ No newline at end of file diff --git a/app/templates/entreprises/fiche_entreprise_validation.html b/app/templates/entreprises/fiche_entreprise_validation.html new file mode 100644 index 000000000..6daf2ce11 --- /dev/null +++ b/app/templates/entreprises/fiche_entreprise_validation.html @@ -0,0 +1,45 @@ +{# -*- mode: jinja-html -*- #} +{% extends 'base.html' %} + +{% block app_content %} +
+

Fiche entreprise - {{ entreprise.nom }} ({{ entreprise.siret }})

+ +
+

+ SIRET : {{ entreprise.siret }}
+ Nom : {{ entreprise.nom }}
+ Adresse : {{ entreprise.adresse }}
+ Code postal : {{ entreprise.codepostal }}
+ Ville : {{ entreprise.ville }}
+ Pays : {{ entreprise.pays }} +

+
+ + {% if contacts %} +
+ {% for contact in contacts %} + Contact {{loop.index}} +
+

+ Nom : {{ contact.nom }}
+ Prénom : {{ contact.prenom }}
+ Téléphone : {{ contact.telephone }}
+ Mail : {{ contact.mail }}
+ {% if contact.poste %} + Poste : {{ contact.poste }}
+ {% endif %} + {% if contact.service %} + Service : {{ contact.service }}
+ {% endif %} +

+
+ {% endfor %} +
+ {% endif %} + +
+ Valider +
+
+{% endblock %} \ No newline at end of file diff --git a/app/templates/entreprises/offres_expirees.html b/app/templates/entreprises/offres_expirees.html index 50c1b7d76..2b7b60f56 100644 --- a/app/templates/entreprises/offres_expirees.html +++ b/app/templates/entreprises/offres_expirees.html @@ -3,12 +3,14 @@ {% block app_content %}
-

Offres expirées de {{ entreprise.nom }}

-{% if offres_expirees %} - {% for offre in offres_expirees%} - Offre {{loop.index}} (ajouté le {{offre[0].date_ajout.strftime('%d/%m/%Y') }}) - {% include 'entreprises/_offre.html' %} - {% endfor %} -{% endif %} +

Offres expirées de {{ entreprise.nom }}

+ {% if offres_expirees %} + {% for offre in offres_expirees%} + Offre {{loop.index}} (ajouté le {{offre[0].date_ajout.strftime('%d/%m/%Y') }}) + {% include 'entreprises/_offre.html' %} + {% endfor %} + {% else %} +
Aucune offre expirées
+ {% endif %}
{% endblock %} \ No newline at end of file From 4578973f3f351b6d5a86ed5fe94ee82a0ae19135 Mon Sep 17 00:00:00 2001 From: Arthur ZHU Date: Wed, 26 Jan 2022 18:46:21 +0100 Subject: [PATCH 006/287] oubli --- app/entreprises/routes.py | 1 + 1 file changed, 1 insertion(+) diff --git a/app/entreprises/routes.py b/app/entreprises/routes.py index 8266d67a1..91383f348 100644 --- a/app/entreprises/routes.py +++ b/app/entreprises/routes.py @@ -787,6 +787,7 @@ def export_entreprises(): @bp.route("/export_contacts") +@permission_required(Permission.RelationsEntreprisesExport) def export_contacts(): """ Permet d'exporter la liste des contacts sous format excel (.xlsx) From a064d1aac8182c9a18e06af4730dcc5baa00ff0c Mon Sep 17 00:00:00 2001 From: Arthur ZHU Date: Thu, 27 Jan 2022 16:28:28 +0100 Subject: [PATCH 007/287] =?UTF-8?q?page=20=20diff=C3=A9rente=20selon=20les?= =?UTF-8?q?=20permissions=20de=20l'utilisateur?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/entreprises/routes.py | 26 +++++++++---------- app/scodoc/sco_permissions.py | 1 + app/templates/entreprises/_contact.html | 2 ++ app/templates/entreprises/_offre.html | 9 +++++++ app/templates/entreprises/contacts.html | 2 ++ app/templates/entreprises/entreprises.html | 12 +++++++-- .../entreprises/fiche_entreprise.html | 2 ++ 7 files changed, 39 insertions(+), 15 deletions(-) diff --git a/app/entreprises/routes.py b/app/entreprises/routes.py index 91383f348..651184920 100644 --- a/app/entreprises/routes.py +++ b/app/entreprises/routes.py @@ -74,7 +74,7 @@ def validation_entreprise(): entreprises = Entreprise.query.filter_by(visible=False).all() return render_template( "entreprises/entreprises_validation.html", - title=("Entreprises"), + title=("Validation entreprises"), entreprises=entreprises, ) @@ -187,7 +187,7 @@ def fiche_entreprise_validation(id): contacts = entreprise.contacts return render_template( "entreprises/fiche_entreprise_validation.html", - title=("Fiche entreprise"), + title=("Validation fiche entreprise"), entreprise=entreprise, contacts=contacts, ) @@ -195,7 +195,7 @@ def fiche_entreprise_validation(id): @bp.route("/offres_recues", methods=["GET"]) @permission_required(Permission.RelationsEntreprisesView) -def offres(): +def offres_recues(): """ Permet d'afficher la page où l'on recoit les offres @@ -222,7 +222,7 @@ def offres(): @bp.route("/fiche_entreprise//offres_expirees") @permission_required(Permission.RelationsEntreprisesView) def offres_expirees(id): - entreprise = Entreprise.query.filter_by(id=id).first_or_404() + entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404() offres = entreprise.offres offres_expirees_with_files = [] for offre in offres: @@ -305,7 +305,7 @@ def edit_entreprise(id): id: l'id de l'entreprise """ - entreprise = Entreprise.query.filter_by(id=id).first_or_404() + entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404() form = EntrepriseModificationForm() if form.validate_on_submit(): nom_entreprise = f"{form.nom.data.strip()}" @@ -374,7 +374,7 @@ def delete_entreprise(id): id: l'id de l'entreprise """ - entreprise = Entreprise.query.filter_by(id=id).first_or_404() + entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404() form = SuppressionConfirmationForm() if form.validate_on_submit(): db.session.delete(entreprise) @@ -397,7 +397,7 @@ def delete_entreprise(id): @bp.route("/validate_entreprise/", methods=["GET", "POST"]) @permission_required(Permission.RelationsEntreprisesValidate) def validate_entreprise(id): - entreprise = Entreprise.query.filter_by(id=id).first_or_404() + entreprise = Entreprise.query.filter_by(id=id, visible=False).first_or_404() entreprise.visible = True db.session.commit() return redirect(url_for("entreprises.fiche_entreprise", id=entreprise.id)) @@ -413,7 +413,7 @@ def add_offre(id): id: l'id de l'entreprise """ - entreprise = Entreprise.query.filter_by(id=id).first_or_404() + entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404() form = OffreCreationForm() if form.validate_on_submit(): offre = EntrepriseOffre( @@ -517,7 +517,7 @@ def add_contact(id): id: l'id de l'entreprise """ - entreprise = Entreprise.query.filter_by(id=id).first_or_404() + entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404() form = ContactCreationForm(hidden_entreprise_id=entreprise.id) if form.validate_on_submit(): contact = EntrepriseContact( @@ -632,7 +632,7 @@ def add_historique(id): id: l'id de l'entreprise """ - entreprise = Entreprise.query.filter_by(id=id).first_or_404() + entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404() form = HistoriqueCreationForm() if form.validate_on_submit(): etudiant_nomcomplet = form.etudiant.data.upper().strip() @@ -770,7 +770,7 @@ def export_entreprises(): """ Permet d'exporter la liste des entreprises sous format excel (.xlsx) """ - entreprises = Entreprise.query.all() + entreprises = Entreprise.query.filter_by(visible=True).all() if entreprises: keys = ["siret", "nom", "adresse", "ville", "codepostal", "pays"] titles = keys[:] @@ -792,7 +792,7 @@ def export_contacts(): """ Permet d'exporter la liste des contacts sous format excel (.xlsx) """ - contacts = EntrepriseContact.query.all() + contacts = EntrepriseContact.query.filter_by(visible=True).all() if contacts: keys = ["nom", "prenom", "telephone", "mail", "poste", "service"] titles = keys[:] @@ -811,7 +811,7 @@ def export_contacts_bis(): """ Permet d'exporter la liste des contacts avec leur entreprise sous format excel (.xlsx) """ - contacts = EntrepriseContact.query.all() + contacts = EntrepriseContact.query.filter_by(visible=True).all() if contacts: keys = [ "nom", diff --git a/app/scodoc/sco_permissions.py b/app/scodoc/sco_permissions.py index 55981b033..71cfede19 100644 --- a/app/scodoc/sco_permissions.py +++ b/app/scodoc/sco_permissions.py @@ -37,6 +37,7 @@ _SCO_PERMISSIONS = ( (1 << 21, "ScoEditPVJury", "Éditer les PV de jury"), # ajouter maquettes Apogee (=> chef dept et secr): (1 << 22, "ScoEditApo", "Ajouter des maquettes Apogées"), + # application relations entreprises (1 << 23, "RelationsEntreprisesView", "Voir l'application relations entreprises"), (1 << 24, "RelationsEntreprisesChange", "Modifier les entreprises"), ( diff --git a/app/templates/entreprises/_contact.html b/app/templates/entreprises/_contact.html index e7083a26f..29f7bd46f 100644 --- a/app/templates/entreprises/_contact.html +++ b/app/templates/entreprises/_contact.html @@ -13,8 +13,10 @@ {% endif %}

+ {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %} + {% endif %} \ No newline at end of file diff --git a/app/templates/entreprises/_offre.html b/app/templates/entreprises/_offre.html index ea69110e9..a893cf5b6 100644 --- a/app/templates/entreprises/_offre.html +++ b/app/templates/entreprises/_offre.html @@ -8,14 +8,23 @@ Durée : {{ offre[0].duree }}
{% for fichier in offre[1] %} {{ fichier[1] }} + {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %} supprimer
+ {% endif %} {% endfor %} + {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %} Ajoutez un fichier + {% endif %}

+ {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %} Modifier l'offre Supprimer l'offre + {% endif %} + {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesSend, None) %} Envoyer l'offre + {% endif %}
+ \ No newline at end of file diff --git a/app/templates/entreprises/contacts.html b/app/templates/entreprises/contacts.html index 22fb1be92..0d0df6797 100644 --- a/app/templates/entreprises/contacts.html +++ b/app/templates/entreprises/contacts.html @@ -42,11 +42,13 @@
Aucun contact présent dans la base
{% endif %} + {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesExport, None) %} + {% endif %} {% endblock %} \ No newline at end of file diff --git a/app/templates/entreprises/entreprises.html b/app/templates/entreprises/entreprises.html index fe790a8d6..4dd96a0e0 100644 --- a/app/templates/entreprises/entreprises.html +++ b/app/templates/entreprises/entreprises.html @@ -24,7 +24,9 @@ Code postal Ville Pays + {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %} Action + {% endif %} {% for entreprise in entreprises %} @@ -34,6 +36,7 @@ {{ entreprise.codepostal }} {{ entreprise.ville }} {{ entreprise.pays }} + {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %} + {% endif %} {% endfor %} @@ -54,9 +58,13 @@ {% endif %}
- Ajouter une entreprise + {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %} + Ajouter une entreprise + {% endif %} {% if entreprises %} - Exporter la liste des entreprises + {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesExport, None) %} + Exporter la liste des entreprises + {% endif %} {% endif %}
diff --git a/app/templates/entreprises/fiche_entreprise.html b/app/templates/entreprises/fiche_entreprise.html index a7cc09632..94bb21476 100644 --- a/app/templates/entreprises/fiche_entreprise.html +++ b/app/templates/entreprises/fiche_entreprise.html @@ -64,6 +64,7 @@ {% endif %} + {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %}
Modifier Supprimer @@ -73,5 +74,6 @@ historique Voir les offres expirées
+ {% endif %} {% endblock %} \ No newline at end of file From 2d9e428ebfac54d77dee7f3bd13b4abfbfdb47f6 Mon Sep 17 00:00:00 2001 From: Arthur ZHU Date: Mon, 31 Jan 2022 18:22:54 +0100 Subject: [PATCH 008/287] ajout pagination + nettoyage --- app/entreprises/__init__.py | 2 +- app/entreprises/routes.py | 159 ++++-------------- app/static/css/entreprises.css | 11 ++ app/templates/base.html | 4 + .../entreprises/ajout_entreprise.html | 3 +- .../entreprises/ajout_historique.html | 1 + app/templates/entreprises/contacts.html | 30 +++- app/templates/entreprises/entreprises.html | 32 +++- .../entreprises/entreprises_validation.html | 1 + .../entreprises/envoi_offre_form.html | 1 + .../entreprises/fiche_entreprise.html | 136 +++++++-------- app/templates/entreprises/logs.html | 37 ++++ .../entreprises/offres_expirees.html | 22 +-- app/templates/entreprises/offres_recues.html | 8 +- 14 files changed, 235 insertions(+), 212 deletions(-) create mode 100644 app/static/css/entreprises.css create mode 100644 app/templates/entreprises/logs.html diff --git a/app/entreprises/__init__.py b/app/entreprises/__init__.py index 44968ffb1..813fd73b6 100644 --- a/app/entreprises/__init__.py +++ b/app/entreprises/__init__.py @@ -7,7 +7,7 @@ from app.auth.models import User bp = Blueprint("entreprises", __name__) -LOGS_LEN = 10 +LOGS_LEN = 5 @bp.app_template_filter() diff --git a/app/entreprises/routes.py b/app/entreprises/routes.py index 651184920..a6f91813b 100644 --- a/app/entreprises/routes.py +++ b/app/entreprises/routes.py @@ -48,17 +48,11 @@ from werkzeug.utils import secure_filename def index(): """ Permet d'afficher une page avec la liste des entreprises et une liste des dernières opérations - - Retourne: template de la page (entreprises.html) - Arguments du template: - title: - titre de la page - entreprises: - liste des entreprises - logs: - liste des logs """ - entreprises = Entreprise.query.filter_by(visible=True).all() + page = request.args.get("page", 1, type=int) + entreprises = Entreprise.query.filter_by(visible=True).paginate( + page=page, per_page=10 + ) logs = EntrepriseLog.query.order_by(EntrepriseLog.date.desc()).limit(LOGS_LEN).all() return render_template( "entreprises/entreprises.html", @@ -68,9 +62,27 @@ def index(): ) +@bp.route("/logs", methods=["GET"]) +@permission_required(Permission.RelationsEntreprisesView) +def logs(): + """ + Permet d'afficher les logs (toutes les entreprises) + """ + page = request.args.get("page", 1, type=int) + logs = EntrepriseLog.query.order_by(EntrepriseLog.date.desc()).paginate( + page=page, per_page=20 + ) + if logs is None: + abort(404) + return render_template("entreprises/logs.html", title=("Logs"), logs=logs) + + @bp.route("/validation", methods=["GET"]) @permission_required(Permission.RelationsEntreprisesValidate) def validation_entreprise(): + """ + Permet d'afficher une page avec la liste des entreprises a valider + """ entreprises = Entreprise.query.filter_by(visible=False).all() return render_template( "entreprises/entreprises_validation.html", @@ -84,21 +96,13 @@ def validation_entreprise(): def contacts(): """ Permet d'afficher une page la liste des contacts et une liste des dernières opérations - - Retourne: template de la page (contacts.html) - Arguments du template: - title: - titre de la page - contacts: - liste des contacts - logs: - liste des logs """ + page = request.args.get("page", 1, type=int) contacts = ( db.session.query(EntrepriseContact, Entreprise) .join(Entreprise, EntrepriseContact.entreprise_id == Entreprise.id) .filter_by(visible=True) - .all() + .paginate(page=page, per_page=10) ) logs = EntrepriseLog.query.order_by(EntrepriseLog.date.desc()).limit(LOGS_LEN).all() return render_template( @@ -114,25 +118,6 @@ def fiche_entreprise(id): l'historique des étudiants ayant réaliser un stage ou une alternance dans cette entreprise. La fiche entreprise comporte les informations de l'entreprise, les contacts de l'entreprise et les offres de l'entreprise. - - Arguments: - id: - l'id de l'entreprise - - Retourne: template de la page (fiche_entreprise.html) - Arguments du template: - title: - titre de la page - entreprise: - un objet entreprise - contacts: - liste des contacts de l'entreprise - offres: - liste des offres de l'entreprise avec leurs fichiers - logs: - liste des logs - historique: - liste des étudiants ayant réaliser un stage ou une alternance dans l'entreprise """ entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404() offres = entreprise.offres @@ -183,6 +168,9 @@ def fiche_entreprise(id): @bp.route("/fiche_entreprise_validation/", methods=["GET"]) @permission_required(Permission.RelationsEntreprisesValidate) def fiche_entreprise_validation(id): + """ + Permet d'afficher la fiche entreprise d'une entreprise a valider + """ entreprise = Entreprise.query.filter_by(id=id, visible=False).first_or_404() contacts = entreprise.contacts return render_template( @@ -198,13 +186,6 @@ def fiche_entreprise_validation(id): def offres_recues(): """ Permet d'afficher la page où l'on recoit les offres - - Retourne: template de la page (offres.html) - Arguments du template: - title: - titre de la page - offres_recus: - liste des offres reçues """ offres_recues = ( db.session.query(EntrepriseEnvoiOffre, EntrepriseOffre) @@ -222,6 +203,9 @@ def offres_recues(): @bp.route("/fiche_entreprise//offres_expirees") @permission_required(Permission.RelationsEntreprisesView) def offres_expirees(id): + """ + Permet d'afficher la liste des offres expirés d'une entreprise + """ entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404() offres = entreprise.offres offres_expirees_with_files = [] @@ -290,7 +274,7 @@ def add_entreprise(): return redirect(url_for("entreprises.index")) return render_template( "entreprises/ajout_entreprise.html", - title=("Ajout entreprise + contact"), + title=("Ajout entreprise avec contact"), form=form, ) @@ -300,10 +284,6 @@ def add_entreprise(): def edit_entreprise(id): """ Permet de modifier une entreprise de la base avec un formulaire - - Arguments: - id: - l'id de l'entreprise """ entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404() form = EntrepriseModificationForm() @@ -369,10 +349,6 @@ def edit_entreprise(id): def delete_entreprise(id): """ Permet de supprimer une entreprise de la base avec un formulaire de confirmation - - Arguments: - id: - l'id de l'entreprise """ entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404() form = SuppressionConfirmationForm() @@ -397,6 +373,9 @@ def delete_entreprise(id): @bp.route("/validate_entreprise/", methods=["GET", "POST"]) @permission_required(Permission.RelationsEntreprisesValidate) def validate_entreprise(id): + """ + Permet de valider une entreprise + """ entreprise = Entreprise.query.filter_by(id=id, visible=False).first_or_404() entreprise.visible = True db.session.commit() @@ -408,10 +387,6 @@ def validate_entreprise(id): def add_offre(id): """ Permet d'ajouter une offre a une entreprise - - Arguments: - id: - l'id de l'entreprise """ entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404() form = OffreCreationForm() @@ -443,10 +418,6 @@ def add_offre(id): def edit_offre(id): """ Permet de modifier une offre - - Arguments: - id: - l'id de l'offre """ offre = EntrepriseOffre.query.filter_by(id=id).first_or_404() form = OffreModificationForm() @@ -483,10 +454,6 @@ def edit_offre(id): def delete_offre(id): """ Permet de supprimer une offre - - Arguments: - id: - l'id de l'offre """ offre = EntrepriseOffre.query.filter_by(id=id).first_or_404() entreprise_id = offre.entreprise.id @@ -512,10 +479,6 @@ def delete_offre(id): def add_contact(id): """ Permet d'ajouter un contact a une entreprise - - Arguments: - id: - l'id de l'entreprise """ entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404() form = ContactCreationForm(hidden_entreprise_id=entreprise.id) @@ -547,10 +510,6 @@ def add_contact(id): def edit_contact(id): """ Permet de modifier un contact - - Arguments: - id: - l'id du contact """ contact = EntrepriseContact.query.filter_by(id=id).first_or_404() form = ContactModificationForm() @@ -589,10 +548,6 @@ def edit_contact(id): def delete_contact(id): """ Permet de supprimer un contact - - Arguments: - id: - l'id du contact """ contact = EntrepriseContact.query.filter_by(id=id).first_or_404() entreprise_id = contact.entreprise.id @@ -627,10 +582,6 @@ def delete_contact(id): def add_historique(id): """ Permet d'ajouter un étudiant ayant réalisé un stage ou une alternance sur la fiche entreprise de l'entreprise - - Arguments: - id: - l'id de l'entreprise """ entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404() form = HistoriqueCreationForm() @@ -672,10 +623,6 @@ def add_historique(id): def envoyer_offre(id): """ Permet d'envoyer une offre à un utilisateur - - Arguments: - id: - l'id de l'offre """ offre = EntrepriseOffre.query.filter_by(id=id).first_or_404() form = EnvoiOffreForm() @@ -706,13 +653,6 @@ def envoyer_offre(id): def json_etudiants(): """ Permet de récuperer un JSON avec tous les étudiants - - Arguments: - term: - le terme utilisé pour le filtre de l'autosuggest - - Retourne: - le JSON de tous les étudiants (nom, prenom, formation actuelle?) correspondant au terme """ if request.args.get("term") == None: abort(400) @@ -740,13 +680,6 @@ def json_etudiants(): def json_responsables(): """ Permet de récuperer un JSON avec tous les étudiants - - Arguments: - term: - le terme utilisé pour le filtre de l'autosuggest - - Retourne: - le JSON de tous les utilisateurs (nom, prenom, login) correspondant au terme """ if request.args.get("term") == None: abort(400) @@ -792,7 +725,7 @@ def export_contacts(): """ Permet d'exporter la liste des contacts sous format excel (.xlsx) """ - contacts = EntrepriseContact.query.filter_by(visible=True).all() + contacts = EntrepriseContact.query.all() if contacts: keys = ["nom", "prenom", "telephone", "mail", "poste", "service"] titles = keys[:] @@ -811,7 +744,7 @@ def export_contacts_bis(): """ Permet d'exporter la liste des contacts avec leur entreprise sous format excel (.xlsx) """ - contacts = EntrepriseContact.query.filter_by(visible=True).all() + contacts = EntrepriseContact.query.all() if contacts: keys = [ "nom", @@ -846,16 +779,6 @@ def export_contacts_bis(): def get_offre_file(entreprise_id, offre_id, filedir, filename): """ Permet de télécharger un fichier d'une offre - - Arguments: - entreprise_id: - l'id de l'entreprise - offre_id: - l'id de l'offre - filedir: - le répertoire du fichier - filename: - le nom du fichier """ if os.path.isfile( os.path.join( @@ -887,10 +810,6 @@ def get_offre_file(entreprise_id, offre_id, filedir, filename): def add_offre_file(offre_id): """ Permet d'ajouter un fichier à une offre - - Arguments: - offre_id: - l'id de l'offre """ offre = EntrepriseOffre.query.filter_by(id=offre_id).first_or_404() form = AjoutFichierForm() @@ -919,12 +838,6 @@ def add_offre_file(offre_id): def delete_offre_file(offre_id, filedir): """ Permet de supprimer un fichier d'une offre - - Arguments: - offre_id: - l'id de l'offre - filedir: - le répertoire du fichier """ offre = EntrepriseOffre.query.filter_by(id=offre_id).first_or_404() form = SuppressionConfirmationForm() diff --git a/app/static/css/entreprises.css b/app/static/css/entreprises.css new file mode 100644 index 000000000..6dded2fa4 --- /dev/null +++ b/app/static/css/entreprises.css @@ -0,0 +1,11 @@ +.btn-inverse { + color: #ffffff; + text-shadow: 0 -1px 0 rgb(0 0 0 / 25%); + background-color: #363636; +} + +.btn-inverse:hover { + color: #ffffff; + background-color: #222222; + *background-color: #151515; +} \ No newline at end of file diff --git a/app/templates/base.html b/app/templates/base.html index adf70171b..176e4b993 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -4,6 +4,7 @@ {% block styles %} {{super()}} + {% endblock %} {% block title %} @@ -35,6 +36,9 @@ url_for('scolar.index_html', scodoc_dept=g.scodoc_dept) }}">Dept. {{ g.scodoc_dept }} {% endif %} + {% if not current_user.is_anonymous and current_user.has_permission(current_user.Permission.RelationsEntreprisesView, None) %} +
  • Entreprises
  • + {% endif %} ") H.append("") - H.append( - """

    Cette page décrit les inscriptions actuelles. - Vous pouvez changer (si vous en avez le droit) les inscrits dans chaque module en - cliquant sur la ligne du module.

    -

    Note: la déinscription d'un module ne perd pas les notes. Ainsi, si - l'étudiant est ensuite réinscrit au même module, il retrouvera ses notes.

    - """ - ) + H.append( + """

    Cette page décrit les inscriptions actuelles. + Vous pouvez changer (si vous en avez le droit) les inscrits dans chaque module en + cliquant sur la ligne du module.

    +

    Note: la déinscription d'un module ne perd pas les notes. Ainsi, si + l'étudiant est ensuite réinscrit au même module, il retrouvera ses notes.

    + """ + ) H.append(html_sco_header.sco_footer()) return "\n".join(H) diff --git a/app/scodoc/sco_prepajury.py b/app/scodoc/sco_prepajury.py index 1a6837379..12a1f2525 100644 --- a/app/scodoc/sco_prepajury.py +++ b/app/scodoc/sco_prepajury.py @@ -45,7 +45,6 @@ from app.scodoc import sco_codes_parcours import sco_version from app.scodoc import sco_etud from app.scodoc import sco_preferences -from app.scodoc.sco_excel import ScoExcelSheet def feuille_preparation_jury(formsemestre_id): From 3cafbf5988662d218fae0bbe03427acfc93e0f43 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sun, 13 Feb 2022 15:19:39 +0100 Subject: [PATCH 040/287] Fixes #293 : suppression utilisateur --- app/auth/models.py | 6 ++++-- scodoc.py | 30 ++++++++++++++++++++++++------ 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/app/auth/models.py b/app/auth/models.py index 32768df03..329bc3868 100644 --- a/app/auth/models.py +++ b/app/auth/models.py @@ -76,7 +76,9 @@ class User(UserMixin, db.Model): "Departement", foreign_keys=[Departement.acronym], primaryjoin=(dept == Departement.acronym), - lazy="dynamic", + lazy="select", + passive_deletes="all", + uselist=False, ) def __init__(self, **kwargs): @@ -236,7 +238,7 @@ class User(UserMixin, db.Model): def get_dept_id(self) -> int: "returns user's department id, or None" if self.dept: - return self._departement.first().id + return self._departement.id return None # Permissions management: diff --git a/scodoc.py b/scodoc.py index 28dfe7cfe..5b76ccb0e 100755 --- a/scodoc.py +++ b/scodoc.py @@ -14,6 +14,8 @@ import click import flask from flask.cli import with_appcontext from flask.templating import render_template +import psycopg2 +import sqlalchemy from app import create_app, cli, db from app import initialize_scodoc_database @@ -133,11 +135,11 @@ def user_create(username, role, dept, nom=None, prenom=None): # user-create "Create a new user" r = Role.get_named_role(role) if not r: - sys.stderr.write("user_create: role {r} does not exist\n".format(r=role)) + sys.stderr.write(f"user_create: role {role} does not exist\n") return 1 u = User.query.filter_by(user_name=username).first() if u: - sys.stderr.write("user_create: user {u} already exists\n".format(u=u)) + sys.stderr.write(f"user_create: user {u} already exists\n") return 2 if dept == "@all": dept = None @@ -145,11 +147,26 @@ def user_create(username, role, dept, nom=None, prenom=None): # user-create u.add_role(r, dept) db.session.add(u) db.session.commit() - click.echo( - "created user, login: {u.user_name}, with role {r} in dept. {dept}".format( - u=u, r=r, dept=dept + click.echo(f"created user, login: {u.user_name}, with role {r} in dept. {dept}") + + +@app.cli.command() +@click.argument("username") +def user_delete(username): # user-delete + "Try to delete this user. Fails if it's associated to some scodoc objects." + u = User.query.filter_by(user_name=username).first() + if not u: + sys.stderr.write(f"user_delete: user {username} not found\n") + return 2 + db.session.delete(u) + try: + db.session.commit() + except (sqlalchemy.exc.IntegrityError, psycopg2.errors.ForeignKeyViolation): + sys.stderr.write( + f"""\nuser_delete: ne peux pas supprimer l'utilisateur {username}\ncar il est associé à des objets dans ScoDoc (modules, notes, ...).\n""" ) - ) + return 1 + click.echo(f"deleted user, login: {username}") @app.cli.command() @@ -485,6 +502,7 @@ def recursive_help(cmd, parent=None): @app.cli.command() def dumphelp(): + """Génère la page d'aide complète pour la doc.""" recursive_help(app.cli) From 45c845d23bb92c1b3311a5b21feb63ba06b61fe8 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sun, 13 Feb 2022 15:50:16 +0100 Subject: [PATCH 041/287] was_capitalized / optim. -nt --- app/comp/res_common.py | 12 +++++- app/scodoc/sco_formsemestre_inscriptions.py | 17 ++++++--- app/scodoc/sco_moduleimpl_inscriptions.py | 8 +++- app/scodoc/sco_report.py | 42 ++++++++++----------- scodoc.py | 1 + 5 files changed, 52 insertions(+), 28 deletions(-) diff --git a/app/comp/res_common.py b/app/comp/res_common.py index 006cbe6b9..5b9ef625f 100644 --- a/app/comp/res_common.py +++ b/app/comp/res_common.py @@ -219,6 +219,7 @@ class ResultatsSemestre(ResultatsCache): if ue.type == UE_SPORT: return { "is_capitalized": False, + "was_capitalized": False, "is_external": False, "coef_ue": 0.0, "cur_moy_ue": 0.0, @@ -235,7 +236,10 @@ class ResultatsSemestre(ResultatsCache): self.validations = res_sem.load_formsemestre_validations(self.formsemestre) cur_moy_ue = self.etud_moy_ue[ue_id][etudid] moy_ue = cur_moy_ue - is_capitalized = False + is_capitalized = False # si l'UE prise en compte est une UE capitalisée + was_capitalized = ( + False # s'il y a precedemment une UE capitalisée (pas forcement meilleure) + ) if etudid in self.validations.ue_capitalisees.index: ue_cap = self._get_etud_ue_cap(etudid, ue) if ( @@ -243,6 +247,7 @@ class ResultatsSemestre(ResultatsCache): and not ue_cap.empty and not np.isnan(ue_cap["moy_ue"]) ): + was_capitalized = True if ue_cap["moy_ue"] > cur_moy_ue or np.isnan(cur_moy_ue): moy_ue = ue_cap["moy_ue"] is_capitalized = True @@ -251,6 +256,7 @@ class ResultatsSemestre(ResultatsCache): return { "is_capitalized": is_capitalized, + "was_capitalized": was_capitalized, "is_external": ue_cap["is_external"] if is_capitalized else ue.is_external, "coef_ue": coef_ue, "ects_pot": ue.ects or 0.0, @@ -425,6 +431,10 @@ class NotesTableCompat(ResultatsSemestre): ue_status_list.append(ue_status) return self.parcours.check_barre_ues(ue_status_list) + def etud_has_decision(self, etudid): + """True s'il y a une décision de jury pour cet étudiant""" + return self.get_etud_decision_ues(etudid) or self.get_etud_decision_sem(etudid) + def get_etud_decision_ues(self, etudid: int) -> dict: """Decisions du jury pour les UE de cet etudiant, ou None s'il n'y en pas eu. Ne tient pas compte des UE capitalisées. diff --git a/app/scodoc/sco_formsemestre_inscriptions.py b/app/scodoc/sco_formsemestre_inscriptions.py index 6ecfa32f2..3e398c837 100644 --- a/app/scodoc/sco_formsemestre_inscriptions.py +++ b/app/scodoc/sco_formsemestre_inscriptions.py @@ -32,14 +32,16 @@ import time import flask from flask import url_for, g, request +from app.comp import res_sem +from app.comp.res_common import NotesTableCompat +from app.models import FormSemestre import app.scodoc.sco_utils as scu from app import log from app.scodoc.scolog import logdb from app.scodoc.sco_exceptions import ScoException, ScoValueError -from app.scodoc.sco_permissions import Permission from app.scodoc.sco_codes_parcours import UE_STANDARD, UE_SPORT, UE_TYPE_NAME import app.scodoc.notesdb as ndb -from app.scodoc.TrivialFormulator import TrivialFormulator, TF +from app.scodoc.TrivialFormulator import TrivialFormulator from app.scodoc import sco_find_etud from app.scodoc import sco_formsemestre from app.scodoc import sco_moduleimpl @@ -186,7 +188,9 @@ def do_formsemestre_desinscription(etudid, formsemestre_id): raise ScoValueError("desinscription impossible: semestre verrouille") # -- Si decisions de jury, desinscription interdite - nt = sco_cache.NotesTableCache.get(formsemestre_id) + formsemestre = FormSemestre.query.get_or_404(formsemestre_id) + nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) + if nt.etud_has_decision(etudid): raise ScoValueError( "desinscription impossible: l'étudiant a une décision de jury (la supprimer avant si nécessaire)" @@ -475,7 +479,8 @@ def formsemestre_inscription_option(etudid, formsemestre_id): raise ScoValueError("Modification impossible: semestre verrouille") etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0] - nt = sco_cache.NotesTableCache.get(formsemestre_id) + formsemestre = FormSemestre.query.get_or_404(formsemestre_id) + nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) F = html_sco_header.sco_footer() H = [ @@ -785,7 +790,9 @@ def list_inscrits_ailleurs(formsemestre_id): Pour chacun, donne la liste des semestres. { etudid : [ liste de sems ] } """ - nt = sco_cache.NotesTableCache.get(formsemestre_id) # > get_etudids + formsemestre = FormSemestre.query.get_or_404(formsemestre_id) + nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) + etudids = nt.get_etudids() d = {} for etudid in etudids: diff --git a/app/scodoc/sco_moduleimpl_inscriptions.py b/app/scodoc/sco_moduleimpl_inscriptions.py index cbd9a3b0d..a0266219f 100644 --- a/app/scodoc/sco_moduleimpl_inscriptions.py +++ b/app/scodoc/sco_moduleimpl_inscriptions.py @@ -33,6 +33,10 @@ import flask from flask import url_for, g, request from flask_login import current_user +from app.comp import res_sem +from app.comp.res_common import NotesTableCompat +from app.models import FormSemestre + import app.scodoc.notesdb as ndb import app.scodoc.sco_utils as scu from app import log @@ -479,7 +483,9 @@ def get_etuds_with_capitalized_ue(formsemestre_id): returns { ue_id : [ { infos } ] } """ UECaps = scu.DictDefault(defaultvalue=[]) - nt = sco_cache.NotesTableCache.get(formsemestre_id) + formsemestre = FormSemestre.query.get_or_404(formsemestre_id) + nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) + inscrits = sco_formsemestre_inscriptions.do_formsemestre_inscription_list( args={"formsemestre_id": formsemestre_id} ) diff --git a/app/scodoc/sco_report.py b/app/scodoc/sco_report.py index 6c2582ef1..fff026471 100644 --- a/app/scodoc/sco_report.py +++ b/app/scodoc/sco_report.py @@ -39,14 +39,16 @@ from operator import itemgetter from flask import url_for, g, request import pydot +from app.comp import res_sem +from app.comp.res_common import NotesTableCompat +from app.models import FormSemestre + import app.scodoc.sco_utils as scu from app.models import FormationModalite from app.scodoc import notesdb as ndb from app.scodoc import html_sco_header from app.scodoc import sco_codes_parcours -from app.scodoc import sco_cache from app.scodoc import sco_etud -from app.scodoc import sco_excel from app.scodoc import sco_formsemestre from app.scodoc import sco_formsemestre_inscriptions from app.scodoc import sco_parcours_dut @@ -61,9 +63,9 @@ MAX_ETUD_IN_DESCR = 20 def formsemestre_etuds_stats(sem, only_primo=False): """Récupère liste d'etudiants avec etat et decision.""" - nt = sco_cache.NotesTableCache.get( - sem["formsemestre_id"] - ) # > get_table_moyennes_triees, identdict, get_etud_decision_sem, get_etud_etat, + formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"]) + nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) + T = nt.get_table_moyennes_triees() # Construit liste d'étudiants du semestre avec leur decision etuds = [] @@ -400,9 +402,8 @@ def table_suivi_cohorte( logt("table_suivi_cohorte: start") # 1-- Liste des semestres posterieurs dans lesquels ont été les etudiants de sem - nt = sco_cache.NotesTableCache.get( - formsemestre_id - ) # > get_etudids, get_etud_decision_sem + formsemestre = FormSemestre.query.get_or_404(formsemestre_id) + nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) etudids = nt.get_etudids() logt("A: orig etuds set") @@ -456,9 +457,8 @@ def table_suivi_cohorte( s["members"] = orig_set.intersection(inset) nb_dipl = 0 # combien de diplomes dans ce semestre ? if s["semestre_id"] == nt.parcours.NB_SEM: - nt = sco_cache.NotesTableCache.get( - s["formsemestre_id"] - ) # > get_etud_decision_sem + s_formsemestre = FormSemestre.query.get_or_404(s["formsemestre_id"]) + nt: NotesTableCompat = res_sem.load_formsemestre_results(s_formsemestre) for etudid in s["members"]: dec = nt.get_etud_decision_sem(etudid) if dec and code_semestre_validant(dec["code"]): @@ -905,9 +905,9 @@ def _descr_etud_set(etudids): def _count_dem_reo(formsemestre_id, etudids): "count nb of demissions and reorientation in this etud set" - nt = sco_cache.NotesTableCache.get( - formsemestre_id - ) # > get_etud_etat, get_etud_decision_sem + formsemestre = FormSemestre.query.get_or_404(formsemestre_id) + nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) + dems = set() reos = set() for etudid in etudids: @@ -971,9 +971,9 @@ def get_codeparcoursetud(etud, prefix="", separator=""): i = len(sems) - 1 while i >= 0: s = sems[i] # 'sems' est a l'envers, du plus recent au plus ancien - nt = sco_cache.NotesTableCache.get( - s["formsemestre_id"] - ) # > get_etud_etat, get_etud_decision_sem + s_formsemestre = FormSemestre.query.get_or_404(s["formsemestre_id"]) + nt: NotesTableCompat = res_sem.load_formsemestre_results(s_formsemestre) + p.append(_codesem(s, prefix=prefix)) # code decisions jury de chaque semestre: if nt.get_etud_etat(etud["etudid"]) == "D": @@ -1017,7 +1017,8 @@ def tsp_etud_list( """ # log('tsp_etud_list(%s, bac="%s")' % (formsemestre_id,bac)) sem = sco_formsemestre.get_formsemestre(formsemestre_id) - nt = sco_cache.NotesTableCache.get(formsemestre_id) # > get_etudids, + formsemestre = FormSemestre.query.get_or_404(formsemestre_id) + nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) etudids = nt.get_etudids() etuds = [] bacs = set() @@ -1260,9 +1261,8 @@ def graph_parcours( nxt = {} etudid = etud["etudid"] for s in etud["sems"]: # du plus recent au plus ancien - nt = sco_cache.NotesTableCache.get( - s["formsemestre_id"] - ) # > get_etud_decision_sem, get_etud_etat + s_formsemestre = FormSemestre.query.get_or_404(s["formsemestre_id"]) + nt: NotesTableCompat = res_sem.load_formsemestre_results(s_formsemestre) dec = nt.get_etud_decision_sem(etudid) if nxt: if ( diff --git a/scodoc.py b/scodoc.py index 5b76ccb0e..4dc5165f7 100755 --- a/scodoc.py +++ b/scodoc.py @@ -434,6 +434,7 @@ def localize_logo(logo: str = None, dept: str = None): # migrate-scodoc7-dept-l @click.argument("xlsfile", type=click.File("rb")) @click.argument("zipfile", type=click.File("rb")) def photos_import_files(formsemestre_id: int, xlsfile: str, zipfile: str): + """Import des photos d'étudiants à partir d'une liste excel et d'un zip avec les images.""" import app as mapp from app.scodoc import sco_trombino, sco_photos from app.scodoc import notesdb as ndb From e7a97919b4aa299ec9832d1c92dcf9e4c845d794 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sun, 13 Feb 2022 22:01:39 +0100 Subject: [PATCH 042/287] Fix: bac None --- app/scodoc/sco_bac.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/app/scodoc/sco_bac.py b/app/scodoc/sco_bac.py index ce00d96c7..6f316a10c 100644 --- a/app/scodoc/sco_bac.py +++ b/app/scodoc/sco_bac.py @@ -132,19 +132,29 @@ BACS_S = {t[0]: t[2:] for t in _BACS} class Baccalaureat: def __init__(self, bac, specialite=""): - self.bac = bac - self.specialite = specialite - self._abbrev, self._type = BACS_SSP.get((bac, specialite), (None, None)) + self.bac = bac or "" + self.specialite = specialite or "" + self._abbrev, self._type = BACS_SSP.get( + (self.bac, self.specialite), (None, None) + ) # Parfois, la specialite commence par la serie: essaye - if self._type is None and specialite and specialite.startswith(bac): - specialite = specialite[len(bac) :].strip(" -") - self._abbrev, self._type = BACS_SSP.get((bac, specialite), (None, None)) + if ( + self._type is None + and self.specialite + and self.specialite.startswith(self.bac) + ): + specialite = self.specialite[len(self.bac) :].strip(" -") + self._abbrev, self._type = BACS_SSP.get( + (self.bac, specialite), (None, None) + ) # Cherche la forme serie specialite if self._type is None and specialite: - self._abbrev, self._type = BACS_S.get(bac + " " + specialite, (None, None)) + self._abbrev, self._type = BACS_S.get( + self.bac + " " + specialite, (None, None) + ) # Cherche avec juste le bac, sans specialite if self._type is None: - self._abbrev, self._type = BACS_S.get(bac, (None, None)) + self._abbrev, self._type = BACS_S.get(self.bac, (None, None)) def abbrev(self): "abbreviation for this bac" From b28d22b3ed95aab5ce46efb17b2621fc6d8a7dfe Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sun, 13 Feb 2022 22:03:46 +0100 Subject: [PATCH 043/287] Modif css ue color var name --- app/views/scodoc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/scodoc.py b/app/views/scodoc.py index e5cdc7719..e65c4e666 100644 --- a/app/views/scodoc.py +++ b/app/views/scodoc.py @@ -374,7 +374,7 @@ def ue_colors_css(formation_id: int, semestre_idx: int): ":root{\n" + "\n".join( [ - f"--color-UE{semestre_idx}.{ue_idx+1}: {ue.color};" + f"--color-UE{semestre_idx}-{ue_idx+1}: {ue.color};" for ue_idx, ue in enumerate(ues) if ue.color ] From f3d2420117ddf212bc5520b0cef2dbfef4c51629 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sun, 13 Feb 2022 22:08:16 +0100 Subject: [PATCH 044/287] Fix: bug St Malo --- app/comp/moy_ue.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/comp/moy_ue.py b/app/comp/moy_ue.py index bb341baa0..b0a534e51 100644 --- a/app/comp/moy_ue.py +++ b/app/comp/moy_ue.py @@ -234,12 +234,12 @@ def compute_ue_moys_apc( modimpl_inscr_df: matrice d'inscription du semestre (etud x modimpl) modimpl_coefs_df: matrice coefficients (UE x modimpl), sans UEs bonus sport - Résultat: DataFrame columns UE (sans sport), rows etudid + Résultat: DataFrame columns UE (sans bonus), rows etudid """ nb_etuds, nb_modules, nb_ues_no_bonus = sem_cube.shape nb_ues_tot = len(ues) assert len(modimpls) == nb_modules - if nb_modules == 0 or nb_etuds == 0: + if nb_modules == 0 or nb_etuds == 0 or nb_ues_no_bonus == 0: return pd.DataFrame( index=modimpl_inscr_df.index, columns=modimpl_coefs_df.index ) From 129a39f7f0d0f67ffefa1c06482c3439c4db4e06 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sun, 13 Feb 2022 22:25:51 +0100 Subject: [PATCH 045/287] Fix: robustifie get_evals_in_mod --- app/comp/res_common.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/app/comp/res_common.py b/app/comp/res_common.py index 0adf82da5..09a06e796 100644 --- a/app/comp/res_common.py +++ b/app/comp/res_common.py @@ -9,6 +9,7 @@ from functools import cached_property import numpy as np import pandas as pd +from app import log from app.comp.aux_stats import StatsMoyenne from app.comp import moy_sem from app.comp.res_cache import ResultatsCache @@ -19,8 +20,7 @@ from app.models import FormSemestreUECoef from app.models.ues import UniteEns from app.scodoc import sco_utils as scu from app.scodoc.sco_cache import ResultatsSemestreCache -from app.scodoc.sco_codes_parcours import UE_SPORT, ATT, DEF -from app.scodoc.sco_exceptions import ScoValueError +from app.scodoc.sco_codes_parcours import UE_SPORT, DEF # Il faut bien distinguer # - ce qui est caché de façon persistente (via redis): @@ -554,25 +554,32 @@ class NotesTableCompat(ResultatsSemestre): Évaluation "complete" ssi toutes notes saisies ou en attente. """ modimpl = ModuleImpl.query.get(moduleimpl_id) + modimpl_results = self.modimpls_results.get(moduleimpl_id) + if not modimpl_results: + return [] # safeguard evals_results = [] for e in modimpl.evaluations: - if self.modimpls_results[moduleimpl_id].evaluations_completes_dict[e.id]: + if modimpl_results.evaluations_completes_dict.get(e.id, False): d = e.to_dict() - moduleimpl_results = self.modimpls_results[e.moduleimpl_id] d["heure_debut"] = e.heure_debut # datetime.time d["heure_fin"] = e.heure_fin d["jour"] = e.jour # datetime d["notes"] = { etud.id: { "etudid": etud.id, - "value": moduleimpl_results.evals_notes[e.id][etud.id], + "value": modimpl_results.evals_notes[e.id][etud.id], } for etud in self.etuds } d["etat"] = { - "evalattente": moduleimpl_results.evaluations_etat[e.id].nb_attente, + "evalattente": modimpl_results.evaluations_etat[e.id].nb_attente, } evals_results.append(d) + elif e.id not in modimpl_results.evaluations_completes_dict: + # ne devrait pas arriver ? XXX + log( + f"Warning: 220213 get_evals_in_mod {e.id} not in mod {moduleimpl_id} ?" + ) return evals_results def get_evaluations_etats(self): From 67fc12053ed2519d5cb3c7fa6001b9482ba5a21e Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sun, 13 Feb 2022 23:53:11 +0100 Subject: [PATCH 046/287] Elimination des derniers NotesTableCache --- app/comp/res_common.py | 6 ++--- app/models/formsemestre.py | 1 + app/pe/pe_jurype.py | 4 +-- app/scodoc/notes_table.py | 2 +- app/scodoc/sco_abs_views.py | 12 ++++++--- app/scodoc/sco_apogee_csv.py | 26 +++++++++++++----- app/scodoc/sco_bulletins.py | 6 +---- app/scodoc/sco_debouche.py | 11 +++++--- app/scodoc/sco_etape_apogee.py | 4 +-- app/scodoc/sco_evaluations.py | 10 ++++--- app/scodoc/sco_export_results.py | 6 ++++- app/scodoc/sco_formsemestre_exterieurs.py | 6 ++++- app/scodoc/sco_formsemestre_status.py | 7 +++-- app/scodoc/sco_liste_notes.py | 15 ++++++----- app/scodoc/sco_moduleimpl_status.py | 1 - app/scodoc/sco_parcours_dut.py | 9 ------- app/scodoc/sco_poursuite_dut.py | 6 ++++- app/scodoc/sco_pvjury.py | 3 --- app/scodoc/sco_saisie_notes.py | 11 ++++---- app/scodoc/sco_semset.py | 6 ++++- app/scodoc/sco_tag_module.py | 6 ++++- app/views/absences.py | 33 ++++++++++++----------- app/views/notes.py | 20 +++++++++----- tests/unit/test_caches.py | 8 ++++-- tests/unit/test_notes_modules.py | 15 ++++++++--- tests/unit/test_sco_basic.py | 8 ++++-- 26 files changed, 145 insertions(+), 97 deletions(-) diff --git a/app/comp/res_common.py b/app/comp/res_common.py index 09a06e796..948c0e95c 100644 --- a/app/comp/res_common.py +++ b/app/comp/res_common.py @@ -4,7 +4,7 @@ # See LICENSE ############################################################################## -from collections import defaultdict, Counter +from collections import Counter from functools import cached_property import numpy as np import pandas as pd @@ -367,7 +367,7 @@ class NotesTableCompat(ResultatsSemestre): sous forme de dict etud, classée dans l'ordre alphabétique de noms. """ - etuds = self.formsemestre.get_inscrits(include_demdef=True, sorted=True) + etuds = self.formsemestre.get_inscrits(include_demdef=True, order=True) return [e.to_dict_scodoc7() for e in etuds] @cached_property @@ -401,7 +401,7 @@ class NotesTableCompat(ResultatsSemestre): d = modimpl.to_dict() # compat ScoDoc < 9.2: ajoute matières d["mat"] = modimpl.module.matiere.to_dict() - modimpls_dict.append(d) + modimpls_dict.append(d) return modimpls_dict def compute_rangs(self): diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py index c2850c2dc..245142484 100644 --- a/app/models/formsemestre.py +++ b/app/models/formsemestre.py @@ -121,6 +121,7 @@ class FormSemestre(db.Model): d.pop("_sa_instance_state", None) # ScoDoc7 output_formators: (backward compat) d["formsemestre_id"] = self.id + d["titre_num"] = self.titre_num() if self.date_debut: d["date_debut"] = self.date_debut.strftime("%d/%m/%Y") d["date_debut_iso"] = self.date_debut.isoformat() diff --git a/app/pe/pe_jurype.py b/app/pe/pe_jurype.py index d29d040ff..2720ad435 100644 --- a/app/pe/pe_jurype.py +++ b/app/pe/pe_jurype.py @@ -322,12 +322,10 @@ class JuryPE(object): etudiants = [] for sem in semsListe: # pour chacun des semestres de la liste - # nt = self.get_notes_d_un_semestre( sem['formsemestre_id'] ) nt = self.get_cache_notes_d_un_semestre(sem["formsemestre_id"]) - # sco_cache.NotesTableCache.get( sem['formsemestre_id']) etudiantsDuSemestre = ( nt.get_etudids() - ) # nt.identdict.keys() # identification des etudiants du semestre + ) # identification des etudiants du semestre if pe_tools.PE_DEBUG: pe_tools.pe_print( diff --git a/app/scodoc/notes_table.py b/app/scodoc/notes_table.py index 7fc03ce89..b1ac97b85 100644 --- a/app/scodoc/notes_table.py +++ b/app/scodoc/notes_table.py @@ -171,7 +171,7 @@ class NotesTable: def __init__(self, formsemestre_id): # log(f"NotesTable( formsemestre_id={formsemestre_id} )") - # raise NotImplementedError() # XXX + raise NotImplementedError() # XXX if not formsemestre_id: raise ValueError("invalid formsemestre_id (%s)" % formsemestre_id) self.formsemestre_id = formsemestre_id diff --git a/app/scodoc/sco_abs_views.py b/app/scodoc/sco_abs_views.py index 2f108c243..d92ee8559 100644 --- a/app/scodoc/sco_abs_views.py +++ b/app/scodoc/sco_abs_views.py @@ -33,7 +33,9 @@ import datetime from flask import url_for, g, request, abort from app import log -from app.models import Identite +from app.comp import res_sem +from app.comp.res_common import NotesTableCompat +from app.models import Identite, FormSemestre import app.scodoc.sco_utils as scu from app.scodoc import notesdb as ndb from app.scodoc.scolog import logdb @@ -118,7 +120,8 @@ def doSignaleAbsence( if moduleimpl_id and moduleimpl_id != "NULL": mod = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0] formsemestre_id = mod["formsemestre_id"] - nt = sco_cache.NotesTableCache.get(formsemestre_id) + formsemestre = FormSemestre.query.get_or_404(formsemestre_id) + nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) ues = nt.get_ues_stat_dict() for ue in ues: modimpls = nt.get_modimpls_dict(ue_id=ue["ue_id"]) @@ -179,11 +182,12 @@ def SignaleAbsenceEtud(): # etudid implied menu_module = "" else: formsemestre_id = etud["cursem"]["formsemestre_id"] + formsemestre = FormSemestre.query.get_or_404(formsemestre_id) + nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) + ues = nt.get_ues_stat_dict() require_module = sco_preferences.get_preference( "abs_require_module", formsemestre_id ) - nt = sco_cache.NotesTableCache.get(formsemestre_id) - ues = nt.get_ues_stat_dict() if require_module: menu_module = """ + + +{% endblock %} + {% block app_content %} {% include 'entreprises/nav.html' %} @@ -19,63 +26,77 @@ {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesExport, None) %}
    Importer des contacts {% endif %} - {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesExport, None) and contacts.items %} + {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesExport, None) and contacts %} Exporter la liste des contacts {% endif %}

    Liste des contacts

    - {% if contacts.items %} -
    - +
    + - - - - - - - + + + + + + + - {% for contact in contacts.items %} - - - - - - - - + + + {% for contact in contacts %} + + + + + + + + - {% endfor %} -
    NomPrenomTelephoneMailPosteServiceEntrepriseNomPrenomTelephoneMailPosteServiceEntreprise
    {{ contact[0].nom }}{{ contact[0].prenom }}{{ contact[0].telephone }}{{ contact[0].mail }}{{ contact[0].poste}}{{ contact[0].service}}{{ contact[1].nom }}
    {{ contact[0].nom }}{{ contact[0].prenom }}{{ contact[0].telephone }}{{ contact[0].mail }}{{ contact[0].poste}}{{ contact[0].service}}{{ contact[1].nom }}
    -
    - -
    - - « - - {% for page_num in contacts.iter_pages(left_edge=1, right_edge=1, left_current=1, right_current=2) %} - {% if page_num %} - {% if contacts.page == page_num %} - {{ page_num }} - {% else %} - {{ page_num }} - {% endif %} - {% else %} - ... - {% endif %} {% endfor %} - - » - -
    -

    - Page {{ contacts.page }} sur {{ contacts.pages }} -

    - {% else %} -
    Aucun contact présent dans la base
    - {% endif %} + + + + Nom + Prenom + Telephone + Mail + Poste + Service + Entreprise + + +
    + + {% endblock %} \ No newline at end of file diff --git a/app/templates/entreprises/entreprises.html b/app/templates/entreprises/entreprises.html index 3219c78dd..8e2768c66 100644 --- a/app/templates/entreprises/entreprises.html +++ b/app/templates/entreprises/entreprises.html @@ -1,6 +1,13 @@ {# -*- mode: jinja-html -*- #} {% extends 'base.html' %} +{% block styles %} +{{super()}} + + + +{% endblock %} + {% block app_content %} {% include 'entreprises/nav.html' %} @@ -22,80 +29,93 @@ {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesExport, None) %} Importer des entreprises {% endif %} - {% if entreprises %} - {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesExport, None) and entreprises.items%} - Exporter la liste des entreprises - {% endif %} + {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesExport, None) and entreprises %} + Exporter la liste des entreprises {% endif %}

    Liste des entreprises

    - {% if entreprises.items %} -
    - +
    + - - - - - - + + + + + + {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %} - + {% endif %} - {% for entreprise in entreprises.items %} - - - - - - - + + + {% for entreprise in entreprises %} + + + + + + + {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %} - {% endif %} {% endfor %} -
    SIRETNomAdresseCode postalVillePaysSIRETNomAdresseCode postalVillePaysActionAction
    {{ entreprise.siret }}{{ entreprise.nom }}{{ entreprise.adresse }}{{ entreprise.codepostal }}{{ entreprise.ville }}{{ entreprise.pays }}
    {{ entreprise.siret }}{{ entreprise.nom }}{{ entreprise.adresse }}{{ entreprise.codepostal }}{{ entreprise.ville }}{{ entreprise.pays }} + - +
    -
    - -
    - - « - - {% for page_num in entreprises.iter_pages(left_edge=1, right_edge=1, left_current=1, right_current=2) %} - {% if page_num %} - {% if entreprises.page == page_num %} - {{ page_num }} - {% else %} - {{ page_num }} + + + + SIRET + Nom + Adresse + Code postal + Ville + Pays + {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %} + Action {% endif %} - {% else %} - ... - {% endif %} - {% endfor %} - - » - -
    - -

    - Page {{ entreprises.page }} sur {{ entreprises.pages }} -

    - {% else %} -
    Aucune entreprise présent dans la base
    - {% endif %} + + +
    + + {% endblock %} \ No newline at end of file diff --git a/app/templates/entreprises/entreprises_validation.html b/app/templates/entreprises/entreprises_validation.html index 90c787a54..a7fbf0c94 100644 --- a/app/templates/entreprises/entreprises_validation.html +++ b/app/templates/entreprises/entreprises_validation.html @@ -1,6 +1,13 @@ {# -*- mode: jinja-html -*- #} {% extends 'base.html' %} +{% block styles %} +{{super()}} + + + +{% endblock %} + {% block app_content %} {% include 'entreprises/nav.html' %} @@ -17,35 +24,72 @@

    Liste des entreprises à valider

    - {% if entreprises %} -
    - +
    + - - - - - - - + + + + + + + - {% for entreprise in entreprises %} - - - - - - - - + + + {% for entreprise in entreprises %} + + + + + + + + + + {% endfor %} + + + + + + + + + + - {% endfor %} -
    SIRETNomAdresseCode postalVillePaysActionSIRETNomAdresseCode postalVillePaysAction
    {{ entreprise.siret }}{{ entreprise.nom }}{{ entreprise.adresse }}{{ entreprise.codepostal }}{{ entreprise.ville }}{{ entreprise.pays }} - Voir -
    {{ entreprise.siret }}{{ entreprise.nom }}{{ entreprise.adresse }}{{ entreprise.codepostal }}{{ entreprise.ville }}{{ entreprise.pays }} + Voir +
    SIRETNomAdresseCode postalVillePaysAction
    -
    - {% else %} -
    Aucune entreprise à valider
    - {% endif %} + +
    + + {% endblock %} \ No newline at end of file From 98e7f7a7105bbadf78cd4313b2969beb3b2f3337 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Thu, 17 Feb 2022 22:40:11 +0100 Subject: [PATCH 073/287] Corrige affichage numero version sur templates Jinja --- app/templates/sidebar.html | 2 +- app/views/__init__.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/templates/sidebar.html b/app/templates/sidebar.html index c5b06a6f3..5ed8ee883 100644 --- a/app/templates/sidebar.html +++ b/app/templates/sidebar.html @@ -4,7 +4,7 @@ From cca72dfed27089f9308cf3d6ce13df994110a4cc Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sat, 19 Feb 2022 00:28:24 +0100 Subject: [PATCH 093/287] Bonus IUT Amiens --- app/comp/bonus_spo.py | 15 +++++++++++++++ sco_version.py | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/app/comp/bonus_spo.py b/app/comp/bonus_spo.py index ed4bf5db3..65f6c03b9 100644 --- a/app/comp/bonus_spo.py +++ b/app/comp/bonus_spo.py @@ -295,6 +295,21 @@ class BonusDirect(BonusSportAdditif): proportion_point = 1.0 +class BonusAmiens(BonusSportAdditif): + """Bonus IUT Amiens pour les modules optionnels (sport, culture, ...). + + Toute note non nulle, peu importe sa valeur, entraine un bonus de 0,1 point + sur toutes les moyennes d'UE. + """ + + name = "bonus_amiens" + displayed_name = "IUT d'Amiens" + seuil_moy_gen = 0.0 # tous les points sont comptés + proportion_point = 1e10 + bonus_max = 0.1 + classic_use_bonus_ues = True # s'applique aux UEs en DUT et LP + + # Finalement ils n'en veulent pas. # class BonusAnnecy(BonusSport): # """Calcul bonus modules optionnels (sport), règle IUT d'Annecy. diff --git a/sco_version.py b/sco_version.py index 04070622d..96ef7d1da 100644 --- a/sco_version.py +++ b/sco_version.py @@ -1,7 +1,7 @@ # -*- mode: python -*- # -*- coding: utf-8 -*- -SCOVERSION = "9.1.59" +SCOVERSION = "9.1.60" SCONAME = "ScoDoc" From 63784e341ad1d33f1bdb7060b88e25e0b3ad4d9e Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sat, 19 Feb 2022 01:00:40 +0100 Subject: [PATCH 094/287] Correction pour Amiens, Roanne --- app/comp/bonus_spo.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/app/comp/bonus_spo.py b/app/comp/bonus_spo.py index 65f6c03b9..0a95621e8 100644 --- a/app/comp/bonus_spo.py +++ b/app/comp/bonus_spo.py @@ -205,7 +205,8 @@ class BonusSportAdditif(BonusSport): """calcul du bonus sem_modimpl_moys_inscrits: les notes de sport En APC: ndarray (nb_etuds, nb_mod_sport, nb_ues_non_bonus) - modimpl_coefs_etuds_no_nan: + En classic: ndarray (nb_etuds, nb_mod_sport) + modimpl_coefs_etuds_no_nan: même shape, les coefs. """ if 0 in sem_modimpl_moys_inscrits.shape: # pas d'étudiants ou pas d'UE ou pas de module... @@ -228,12 +229,22 @@ class BonusSportAdditif(BonusSport): bonus_moy_arr = np.clip(bonus_moy_arr, 0.0, 20.0, out=bonus_moy_arr) # en APC, bonus_moy_arr est (nb_etuds, nb_ues_non_bonus) - if self.formsemestre.formation.is_apc() or self.classic_use_bonus_ues: + if self.formsemestre.formation.is_apc(): # Bonus sur les UE et None sur moyenne générale ues_idx = [ue.id for ue in self.formsemestre.query_ues(with_sport=False)] self.bonus_ues = pd.DataFrame( bonus_moy_arr, index=self.etuds_idx, columns=ues_idx, dtype=float ) + elif self.classic_use_bonus_ues: + # Formations classiques apppliquant le bonus sur les UEs + # ici bonus_moy_arr = ndarray 1d nb_etuds + ues_idx = [ue.id for ue in self.formsemestre.query_ues(with_sport=False)] + self.bonus_ues = pd.DataFrame( + np.stack([bonus_moy_arr] * len(ues_idx)).T, + index=self.etuds_idx, + columns=ues_idx, + dtype=float, + ) else: # Bonus sur la moyenne générale seulement self.bonus_moy_gen = pd.Series( @@ -693,7 +704,7 @@ class BonusRoanne(BonusSportAdditif): displayed_name = "IUT de Roanne" seuil_moy_gen = 0.0 bonus_max = 0.6 # plafonnement à 0.6 points - apply_bonus_mg_to_ues = True # sur les UE, même en DUT et LP + classic_use_bonus_ues = True # sur les UE, même en DUT et LP class BonusStDenis(BonusSportAdditif): @@ -792,7 +803,7 @@ class BonusIUTV(BonusSportAdditif): name = "bonus_iutv" displayed_name = "IUT de Villetaneuse" - pass # oui, c'ets le bonus par défaut + pass # oui, c'est le bonus par défaut def get_bonus_class_dict(start=BonusSport, d=None): From 44123c022eac799449173f8d92734bcebb75f8c1 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sat, 19 Feb 2022 16:16:52 +0100 Subject: [PATCH 095/287] =?UTF-8?q?Am=C3=A9liore=20=C3=A9dition=20programm?= =?UTF-8?q?es=20classiques?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/scodoc/sco_edit_ue.py | 34 +++++++++++++++++------ app/scodoc/sco_formsemestre_validation.py | 16 +++++++---- app/static/css/scodoc.css | 4 +++ sco_version.py | 2 +- 4 files changed, 41 insertions(+), 15 deletions(-) diff --git a/app/scodoc/sco_edit_ue.py b/app/scodoc/sco_edit_ue.py index 17cdc8c07..061bf43c6 100644 --- a/app/scodoc/sco_edit_ue.py +++ b/app/scodoc/sco_edit_ue.py @@ -601,7 +601,12 @@ def ue_table(formation_id=None, semestre_idx=1, msg=""): # was ue_list _add_ue_semestre_id(ues_externes, is_apc) ues.sort(key=lambda u: (u["semestre_id"], u["numero"])) ues_externes.sort(key=lambda u: (u["semestre_id"], u["numero"])) - has_duplicate_ue_codes = len(set([ue["ue_code"] for ue in ues])) != len(ues) + # Codes dupliqués (pour aider l'utilisateur) + seen = set() + duplicated_codes = { + ue["ue_code"] for ue in ues if ue["ue_code"] in seen or seen.add(ue["ue_code"]) + } + ues_with_duplicated_code = [ue for ue in ues if ue["ue_code"] in duplicated_codes] has_perm_change = current_user.has_permission(Permission.ScoChangeFormation) # editable = (not locked) and has_perm_change @@ -664,11 +669,17 @@ du programme" (menu "Semestre") si vous avez un semestre en cours); if msg: H.append('

    ' + msg + "

    ") - if has_duplicate_ue_codes: + if ues_with_duplicated_code: H.append( - """
    Attention: plusieurs UE de cette - formation ont le même code. Il faut corriger cela ci-dessous, - sinon les calculs d'ECTS seront erronés !
    """ + f"""
    Attention: plusieurs UE de cette + formation ont le même code : { + ', '.join([ + '' + ue["acronyme"] + " (code " + ue["ue_code"] + ")" + for ue in ues_with_duplicated_code ]) + }. + Il faut corriger cela, sinon les capitalisations et ECTS seront + erronés !
    """ ) # Description de la formation @@ -930,8 +941,8 @@ def _ue_table_ues( if cur_ue_semestre_id != ue["semestre_id"]: cur_ue_semestre_id = ue["semestre_id"] - if iue > 0: - H.append("") + # if iue > 0: + # H.append("") if ue["semestre_id"] == sco_codes_parcours.UE_SEM_DEFAULT: lab = "Pas d'indication de semestre:" else: @@ -953,7 +964,6 @@ def _ue_table_ues( ) else: H.append(arrow_none) - iue += 1 ue["acro_titre"] = str(ue["acronyme"]) if ue["titre"] != ue["acronyme"]: ue["acro_titre"] += " " + str(ue["titre"]) @@ -1001,6 +1011,14 @@ def _ue_table_ues( delete_disabled_icon, ) ) + if (iue >= len(ues) - 1) or ue["semestre_id"] != ues[iue + 1]["semestre_id"]: + H.append( + f"""""" + ) + iue += 1 + return "\n".join(H) diff --git a/app/scodoc/sco_formsemestre_validation.py b/app/scodoc/sco_formsemestre_validation.py index f755bb118..987dc962f 100644 --- a/app/scodoc/sco_formsemestre_validation.py +++ b/app/scodoc/sco_formsemestre_validation.py @@ -1250,7 +1250,7 @@ def check_formation_ues(formation_id): for ue in ues: # formsemestres utilisant cette ue ? sems = ndb.SimpleDictFetch( - """SELECT DISTINCT sem.id AS formsemestre_id, sem.* + """SELECT DISTINCT sem.id AS formsemestre_id, sem.* FROM notes_formsemestre sem, notes_modules mod, notes_moduleimpl mi WHERE sem.formation_id = %(formation_id)s AND mod.id = mi.module_id @@ -1269,11 +1269,11 @@ def check_formation_ues(formation_id): return "", {} # Genere message HTML: H = [ - """
    Attention: les UE suivantes de cette formation + """
    Attention: les UE suivantes de cette formation sont utilisées dans des - semestres de rangs différents (eg S1 et S3).
    Cela peut engendrer des problèmes pour - la capitalisation des UE. Il serait préférable d'essayer de rectifier cette situation: - soit modifier le programme de la formation (définir des UE dans chaque semestre), + semestres de rangs différents (eg S1 et S3).
    Cela peut engendrer des problèmes pour + la capitalisation des UE. Il serait préférable d'essayer de rectifier cette situation: + soit modifier le programme de la formation (définir des UE dans chaque semestre), soit veiller à saisir le bon indice de semestre dans le menu lors de la validation d'une UE extérieure.
      @@ -1286,7 +1286,11 @@ def check_formation_ues(formation_id): for x in ue_multiples[ue["ue_id"]] ] slist = ", ".join( - ["%(titreannee)s (semestre %(semestre_id)s)" % s for s in sems] + [ + """%(titreannee)s (semestre %(semestre_id)s)""" + % s + for s in sems + ] ) H.append("
    • %s : %s
    • " % (ue["acronyme"], slist)) H.append("
    ") diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css index e88930857..ecd8b0ab0 100644 --- a/app/static/css/scodoc.css +++ b/app/static/css/scodoc.css @@ -1707,6 +1707,9 @@ ul.notes_ue_list { li.notes_ue_list { margin-top: 9px; list-style-type: none; + border: 1px solid maroon; + border-radius: 10px; + padding-bottom: 5px; } span.ue_type_1 { color: green; @@ -1749,6 +1752,7 @@ ul.notes_matiere_list { background-color: rgb(220,220,220); font-weight: normal; font-style: italic; + border-top: 1px solid maroon; } ul.notes_module_list { diff --git a/sco_version.py b/sco_version.py index 96ef7d1da..9e02cffd1 100644 --- a/sco_version.py +++ b/sco_version.py @@ -1,7 +1,7 @@ # -*- mode: python -*- # -*- coding: utf-8 -*- -SCOVERSION = "9.1.60" +SCOVERSION = "9.1.61" SCONAME = "ScoDoc" From aa3a2fb3e0efc875139108d4ee60a0f1cf669390 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sun, 20 Feb 2022 15:10:15 +0100 Subject: [PATCH 096/287] Cosmetic: edition prog. classiques --- app/scodoc/sco_edit_module.py | 7 +++++-- app/scodoc/sco_edit_ue.py | 10 ++++++---- app/static/css/scodoc.css | 23 ++++++++++++++++++++++- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/app/scodoc/sco_edit_module.py b/app/scodoc/sco_edit_module.py index 2bedc0c11..9c8aa07df 100644 --- a/app/scodoc/sco_edit_module.py +++ b/app/scodoc/sco_edit_module.py @@ -512,8 +512,8 @@ def module_edit(module_id=None): ] else: mat_names = ["%s / %s" % (mat.ue.acronyme, mat.titre or "") for mat in matieres] - ue_mat_ids = ["%s!%s" % (mat.ue.id, mat.id) for mat in matieres] + ue_mat_ids = ["%s!%s" % (mat.ue.id, mat.id) for mat in matieres] module["ue_matiere_id"] = "%s!%s" % (module["ue_id"], module["matiere_id"]) semestres_indices = list(range(1, parcours.NB_SEM + 1)) @@ -741,8 +741,11 @@ def module_edit(module_id=None): else: # l'UE de rattachement peut changer tf[2]["ue_id"], tf[2]["matiere_id"] = tf[2]["ue_matiere_id"].split("!") + x, y = tf[2]["ue_matiere_id"].split("!") + tf[2]["ue_id"] = int(x) + tf[2]["matiere_id"] = int(y) old_ue_id = a_module.ue.id - new_ue_id = int(tf[2]["ue_id"]) + new_ue_id = tf[2]["ue_id"] if (old_ue_id != new_ue_id) and in_use: new_ue = UniteEns.query.get_or_404(new_ue_id) if new_ue.semestre_idx != a_module.ue.semestre_idx: diff --git a/app/scodoc/sco_edit_ue.py b/app/scodoc/sco_edit_ue.py index 061bf43c6..408109122 100644 --- a/app/scodoc/sco_edit_ue.py +++ b/app/scodoc/sco_edit_ue.py @@ -941,13 +941,13 @@ def _ue_table_ues( if cur_ue_semestre_id != ue["semestre_id"]: cur_ue_semestre_id = ue["semestre_id"] - # if iue > 0: - # H.append("") if ue["semestre_id"] == sco_codes_parcours.UE_SEM_DEFAULT: lab = "Pas d'indication de semestre:" else: lab = "Semestre %s:" % ue["semestre_id"] - H.append('
    %s
    ' % lab) + H.append( + '
    %s
    ' % lab + ) H.append('
      ') H.append('
    • ') if iue != 0 and editable: @@ -1015,7 +1015,9 @@ def _ue_table_ues( H.append( f"""
    """ + }">Ajouter une UE dans le semestre {ue['semestre_id'] or ''} +
    + """ ) iue += 1 diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css index ecd8b0ab0..9079cfa7d 100644 --- a/app/static/css/scodoc.css +++ b/app/static/css/scodoc.css @@ -1699,7 +1699,7 @@ ul.notes_ue_list { margin-top: 4px; margin-right: 1em; margin-left: 1em; - padding-top: 1em; + /* padding-top: 1em; */ padding-bottom: 1em; font-weight: bold; } @@ -1761,6 +1761,27 @@ ul.notes_module_list { font-style: normal; } +div.ue_list_div { + border: 3px solid rgb(35, 0, 160); + padding-left: 5px; + padding-top: 5px; + margin-bottom: 5px; + margin-right: 5px; +} + +div.ue_list_tit_sem { + font-size: 120%; + font-weight: bold; + color: orangered; + display: list-item; /* This has to be "list-item" */ + list-style-type: disc; /* See https://developer.mozilla.org/en-US/docs/Web/CSS/list-style-type */ + list-style-position: inside; +} + +input.sco_tag_checkbox { + margin-bottom: 10px; +} + .notes_ue_list a.stdlink { color: #001084; text-decoration: underline; From ba974df04f138743168b732f2f254852b6985ac6 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 21 Feb 2022 15:10:10 +0100 Subject: [PATCH 097/287] =?UTF-8?q?Fix:=20mise=20=C3=A0=20jour=20bonus=20s?= =?UTF-8?q?ur=20oy.=20gen.=20apr=C3=A8s=20capitalisation=20UEs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/comp/res_common.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/app/comp/res_common.py b/app/comp/res_common.py index b019c9770..14042364a 100644 --- a/app/comp/res_common.py +++ b/app/comp/res_common.py @@ -165,7 +165,6 @@ class ResultatsSemestre(ResultatsCache): """ # Supposant qu'il y a peu d'UE capitalisées, # on va soustraire la moyenne d'UE et ajouter celle de l'UE capitalisée. - # return # XXX XXX XXX if not self.validations: self.validations = res_sem.load_formsemestre_validations(self.formsemestre) ue_capitalisees = self.validations.ue_capitalisees @@ -184,7 +183,9 @@ class ResultatsSemestre(ResultatsCache): sum_coefs_ue = 0.0 for ue in self.formsemestre.query_ues(): ue_cap = self.get_etud_ue_status(etudid, ue.id) - if ue_cap and ue_cap["is_capitalized"]: + if ue_cap is None: + continue + if ue_cap["is_capitalized"]: recompute_mg = True coef = ue_cap["coef_ue"] if not np.isnan(ue_cap["moy"]): @@ -195,6 +196,12 @@ class ResultatsSemestre(ResultatsCache): # On doit prendre en compte une ou plusieurs UE capitalisées # et donc recalculer la moyenne générale self.etud_moy_gen[etudid] = sum_notes_ue / sum_coefs_ue + # Ajoute le bonus sport + if self.bonus is not None and self.bonus[etudid]: + self.etud_moy_gen[etudid] += self.bonus[etudid] + self.etud_moy_gen[etudid] = max( + 0.0, min(self.etud_moy_gen[etudid], 20.0) + ) def _get_etud_ue_cap(self, etudid, ue): """""" From 0801919b80d6e24c81f8dab3b94489c74c53f5bc Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 21 Feb 2022 17:36:50 +0100 Subject: [PATCH 098/287] =?UTF-8?q?Calcul=20moyennes=20mati=C3=A8res=20(fo?= =?UTF-8?q?rmations=20classiques).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/comp/moy_mat.py | 52 +++++++++++++++++++++++++++++++++++++++++ app/comp/moy_ue.py | 1 - app/comp/res_classic.py | 17 +++++++++++++- app/comp/res_common.py | 8 +++++-- 4 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 app/comp/moy_mat.py diff --git a/app/comp/moy_mat.py b/app/comp/moy_mat.py new file mode 100644 index 000000000..e5ba903c2 --- /dev/null +++ b/app/comp/moy_mat.py @@ -0,0 +1,52 @@ +############################################################################## +# ScoDoc +# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved. +# See LICENSE +############################################################################## + +"""Calcul des moyennes de matières +""" + +# C'est un recalcul (optionnel) effectué _après_ le calcul standard. + +import numpy as np +import pandas as pd +from app.comp import moy_ue +from app.models.formsemestre import FormSemestre + +from app.scodoc.sco_codes_parcours import UE_SPORT +from app.scodoc.sco_utils import ModuleType + + +def compute_mat_moys_classic( + formsemestre: FormSemestre, + sem_matrix: np.array, + ues: list, + modimpl_inscr_df: pd.DataFrame, + modimpl_coefs: np.array, +) -> dict: + """Calcul des moyennes par matières. + Result: dict, { matiere_id : Series, index etudid } + """ + modimpls_std = [ + m + for m in formsemestre.modimpls_sorted + if (m.module.module_type == ModuleType.STANDARD) + and (m.module.ue.type != UE_SPORT) + ] + matiere_ids = {m.module.matiere.id for m in modimpls_std} + matiere_moy = {} # { matiere_id : moy pd.Series, index etudid } + for matiere_id in matiere_ids: + modimpl_mask = np.array( + [m.module.matiere.id == matiere_id for m in formsemestre.modimpls_sorted] + ) + etud_moy_gen, _, _ = moy_ue.compute_ue_moys_classic( + formsemestre, + sem_matrix=sem_matrix, + ues=ues, + modimpl_inscr_df=modimpl_inscr_df, + modimpl_coefs=modimpl_coefs, + modimpl_mask=modimpl_mask, + ) + matiere_moy[matiere_id] = etud_moy_gen + return matiere_moy diff --git a/app/comp/moy_ue.py b/app/comp/moy_ue.py index 8b98d2ef4..563fb3b1d 100644 --- a/app/comp/moy_ue.py +++ b/app/comp/moy_ue.py @@ -27,7 +27,6 @@ """Fonctions de calcul des moyennes d'UE (classiques ou BUT) """ -from re import X import numpy as np import pandas as pd diff --git a/app/comp/res_classic.py b/app/comp/res_classic.py index 1dfcfb4da..ecc1e5004 100644 --- a/app/comp/res_classic.py +++ b/app/comp/res_classic.py @@ -15,7 +15,7 @@ from flask import g, url_for from app import db from app import log -from app.comp import moy_mod, moy_ue, inscr_mod +from app.comp import moy_mat, moy_mod, moy_ue, inscr_mod from app.comp.res_common import NotesTableCompat from app.comp.bonus_spo import BonusSport from app.models import ScoDocSiteConfig @@ -24,6 +24,7 @@ from app.models.formsemestre import FormSemestre from app.models.ues import UniteEns from app.scodoc.sco_codes_parcours import UE_SPORT from app.scodoc.sco_exceptions import ScoValueError +from app.scodoc import sco_preferences from app.scodoc.sco_utils import ModuleType @@ -133,6 +134,10 @@ class ResultatsSemestreClassic(NotesTableCompat): # --- Classements: self.compute_rangs() + # --- En option, moyennes par matières + if sco_preferences.get_preference("bul_show_matieres", self.formsemestre.id): + self.compute_moyennes_matieres() + def get_etud_mod_moy(self, moduleimpl_id: int, etudid: int) -> float: """La moyenne de l'étudiant dans le moduleimpl Result: valeur float (peut être NaN) ou chaîne "NI" (non inscrit ou DEM) @@ -158,6 +163,16 @@ class ResultatsSemestreClassic(NotesTableCompat): ), } + def compute_moyennes_matieres(self): + """Calcul les moyennes par matière. Doit être appelée au besoin, en fin de compute.""" + self.moyennes_matieres = moy_mat.compute_mat_moys_classic( + self.formsemestre, + self.sem_matrix, + self.ues, + self.modimpl_inscr_df, + self.modimpl_coefs, + ) + def compute_etud_ue_coef(self, etudid: int, ue: UniteEns) -> float: """Détermine le coefficient de l'UE pour cet étudiant. N'est utilisé que pour l'injection des UE capitalisées dans la diff --git a/app/comp/res_common.py b/app/comp/res_common.py index 14042364a..5f652ec5c 100644 --- a/app/comp/res_common.py +++ b/app/comp/res_common.py @@ -39,6 +39,7 @@ class ResultatsSemestre(ResultatsCache): "modimpl_inscr_df", "modimpls_results", "etud_coef_ue_df", + "moyennes_matieres", ) def __init__(self, formsemestre: FormSemestre): @@ -57,6 +58,8 @@ class ResultatsSemestre(ResultatsCache): self.etud_coef_ue_df = None """coefs d'UE effectifs pour chaque étudiant (pour form. classiques)""" self.validations = None + self.moyennes_matieres = {} + """Moyennes de matières, si calculées. { matiere_id : Series, index etudid }""" def compute(self): "Charge les notes et inscriptions et calcule toutes les moyennes" @@ -517,8 +520,9 @@ class NotesTableCompat(ResultatsSemestre): def get_etud_mat_moy(self, matiere_id, etudid): """moyenne d'un étudiant dans une matière (ou NA si pas de notes)""" - # non supporté en 9.2 - return "na" + if not self.moyennes_matieres: + return "nd" + return self.moyennes_matieres[matiere_id][etudid] def get_etud_mod_moy(self, moduleimpl_id: int, etudid: int) -> float: """La moyenne de l'étudiant dans le moduleimpl From d314d47dc5044f351a53f378792dc7cfb8ccf037 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 21 Feb 2022 18:51:45 +0100 Subject: [PATCH 099/287] traitement erreur sur formsemestre_description --- app/scodoc/sco_formsemestre_status.py | 7 ++++--- sco_version.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/scodoc/sco_formsemestre_status.py b/app/scodoc/sco_formsemestre_status.py index d8be56f27..2c8465150 100644 --- a/app/scodoc/sco_formsemestre_status.py +++ b/app/scodoc/sco_formsemestre_status.py @@ -595,11 +595,12 @@ def formsemestre_description_table(formsemestre_id, with_evals=False): """Description du semestre sous forme de table exportable Liste des modules et de leurs coefficients """ - sem = sco_formsemestre.get_formsemestre(formsemestre_id) formsemestre = FormSemestre.query.get_or_404(formsemestre_id) nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) use_ue_coefs = sco_preferences.get_preference("use_ue_coefs", formsemestre_id) - F = sco_formations.formation_list(args={"formation_id": sem["formation_id"]})[0] + F = sco_formations.formation_list(args={"formation_id": formsemestre.formation_id})[ + 0 + ] parcours = sco_codes_parcours.get_parcours_from_code(F["type_parcours"]) Mlist = sco_moduleimpl.moduleimpl_withmodule_list( formsemestre_id=formsemestre_id, sort_by_ue=True @@ -709,7 +710,7 @@ def formsemestre_description_table(formsemestre_id, with_evals=False): titles["coefficient"] = "Coef. éval." titles["evalcomplete_str"] = "Complète" titles["publish_incomplete_str"] = "Toujours Utilisée" - title = "%s %s" % (parcours.SESSION_NAME.capitalize(), sem["titremois"]) + title = "%s %s" % (parcours.SESSION_NAME.capitalize(), formsemestre.titre_mois()) return GenTable( columns_ids=columns_ids, diff --git a/sco_version.py b/sco_version.py index 9e02cffd1..4ac94b210 100644 --- a/sco_version.py +++ b/sco_version.py @@ -1,7 +1,7 @@ # -*- mode: python -*- # -*- coding: utf-8 -*- -SCOVERSION = "9.1.61" +SCOVERSION = "9.1.62" SCONAME = "ScoDoc" From 663daa564b02c2f6e809717776e43e4b035ceb95 Mon Sep 17 00:00:00 2001 From: Arthur ZHU Date: Mon, 21 Feb 2022 20:22:27 +0100 Subject: [PATCH 100/287] not found module gestion entreprises --- app/__init__.py | 3 +- app/entreprises/routes.py | 83 ++++++++++++++++++++++++++++----------- app/scodoc/sco_excel.py | 46 ++++++++++++++++++++++ 3 files changed, 108 insertions(+), 24 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 76f9471bb..cedb4564b 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -190,6 +190,7 @@ def create_app(config_class=DevConfig): app.register_error_handler(ScoGenError, handle_sco_value_error) app.register_error_handler(ScoValueError, handle_sco_value_error) + app.register_error_handler(404, handle_sco_value_error) app.register_error_handler(AccessDenied, handle_access_denied) app.register_error_handler(500, internal_server_error) @@ -201,7 +202,7 @@ def create_app(config_class=DevConfig): app.register_blueprint(auth_bp, url_prefix="/auth") from app.entreprises import bp as entreprises_bp - + app.register_blueprint(entreprises_bp, url_prefix="/ScoDoc/entreprises") from app.views import scodoc_bp diff --git a/app/entreprises/routes.py b/app/entreprises/routes.py index 43cef4a31..eaef9275c 100644 --- a/app/entreprises/routes.py +++ b/app/entreprises/routes.py @@ -123,7 +123,9 @@ def fiche_entreprise(id): La fiche entreprise comporte les informations de l'entreprise, les contacts de l'entreprise et les offres de l'entreprise. """ - entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404() + entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404( + description=f"fiche entreprise {id} inconnu" + ) offres_with_files = [] depts = are.get_depts() for offre in entreprise.offres: @@ -163,7 +165,9 @@ def logs_entreprise(id): Permet d'afficher les logs (toutes les entreprises) """ page = request.args.get("page", 1, type=int) - entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404() + entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404( + description=f"logs fiche entreprise {id} inconnu" + ) logs = ( EntrepriseLog.query.order_by(EntrepriseLog.date.desc()) .filter_by(object=id) @@ -183,7 +187,9 @@ def fiche_entreprise_validation(id): """ Permet d'afficher la fiche entreprise d'une entreprise a valider """ - entreprise = Entreprise.query.filter_by(id=id, visible=False).first_or_404() + entreprise = Entreprise.query.filter_by(id=id, visible=False).first_or_404( + description=f"fiche entreprise (validation) {id} inconnu" + ) contacts = entreprise.contacts return render_template( "entreprises/fiche_entreprise_validation.html", @@ -235,7 +241,9 @@ def offres_expirees(id): """ Permet d'afficher la liste des offres expirés d'une entreprise """ - entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404() + entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404( + description=f"fiche entreprise {id} inconnu" + ) offres_expirees_with_files = [] depts = are.get_depts() for offre in entreprise.offres: @@ -309,7 +317,9 @@ def edit_entreprise(id): """ Permet de modifier une entreprise de la base avec un formulaire """ - entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404() + entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404( + description=f"entreprise {id} inconnu" + ) form = EntrepriseModificationForm() if form.validate_on_submit(): nom_entreprise = f"{form.nom.data.strip()}" @@ -376,7 +386,9 @@ def delete_entreprise(id): """ Permet de supprimer une entreprise de la base avec un formulaire de confirmation """ - entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404() + entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404( + description=f"entreprise {id} inconnu" + ) form = SuppressionConfirmationForm() if form.validate_on_submit(): db.session.delete(entreprise) @@ -411,7 +423,9 @@ def validate_entreprise(id): Permet de valider une entreprise """ form = ValidationConfirmationForm() - entreprise = Entreprise.query.filter_by(id=id, visible=False).first_or_404() + entreprise = Entreprise.query.filter_by(id=id, visible=False).first_or_404( + description=f"entreprise (validation) {id} inconnu" + ) if form.validate_on_submit(): entreprise.visible = True nom_entreprise = f"{entreprise.nom}" @@ -436,7 +450,9 @@ def delete_validation_entreprise(id): """ Permet de supprimer une entreprise en attente de validation avec une formulaire de validation """ - entreprise = Entreprise.query.filter_by(id=id, visible=False).first_or_404() + entreprise = Entreprise.query.filter_by(id=id, visible=False).first_or_404( + description=f"entreprise (validation) {id} inconnu" + ) form = SuppressionConfirmationForm() if form.validate_on_submit(): db.session.delete(entreprise) @@ -456,7 +472,9 @@ def add_offre(id): """ Permet d'ajouter une offre a une entreprise """ - entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404() + entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404( + description=f"entreprise {id} inconnu" + ) form = OffreCreationForm() if form.validate_on_submit(): offre = EntrepriseOffre( @@ -499,7 +517,9 @@ def edit_offre(id): """ Permet de modifier une offre """ - offre = EntrepriseOffre.query.filter_by(id=id).first_or_404() + offre = EntrepriseOffre.query.filter_by(id=id).first_or_404( + description=f"offre {id} inconnu" + ) offre_depts = EntrepriseOffreDepartement.query.filter_by(offre_id=offre.id).all() form = OffreModificationForm() offre_depts_list = [(offre_dept.dept_id) for offre_dept in offre_depts] @@ -554,7 +574,9 @@ def delete_offre(id): """ Permet de supprimer une offre """ - offre = EntrepriseOffre.query.filter_by(id=id).first_or_404() + offre = EntrepriseOffre.query.filter_by(id=id).first_or_404( + description=f"offre {id} inconnu" + ) entreprise_id = offre.entreprise.id form = SuppressionConfirmationForm() if form.validate_on_submit(): @@ -588,7 +610,7 @@ def delete_offre(id): def delete_offre_recue(id): offre_recue = EntrepriseEnvoiOffre.query.filter_by( id=id, receiver_id=current_user.id - ).first_or_404() + ).first_or_404(description=f"offre recu {id} inconnu") db.session.delete(offre_recue) db.session.commit() return redirect(url_for("entreprises.offres_recues")) @@ -600,7 +622,9 @@ def add_contact(id): """ Permet d'ajouter un contact a une entreprise """ - entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404() + entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404( + description=f"entreprise {id} inconnu" + ) form = ContactCreationForm(hidden_entreprise_id=entreprise.id) if form.validate_on_submit(): contact = EntrepriseContact( @@ -635,7 +659,9 @@ def edit_contact(id): """ Permet de modifier un contact """ - contact = EntrepriseContact.query.filter_by(id=id).first_or_404() + contact = EntrepriseContact.query.filter_by(id=id).first_or_404( + description=f"contact {id} inconnu" + ) form = ContactModificationForm( hidden_entreprise_id=contact.entreprise_id, hidden_contact_id=contact.id, @@ -678,7 +704,9 @@ def delete_contact(id): """ Permet de supprimer un contact """ - contact = EntrepriseContact.query.filter_by(id=id).first_or_404() + contact = EntrepriseContact.query.filter_by(id=id).first_or_404( + description=f"contact {id} inconnu" + ) form = SuppressionConfirmationForm() if form.validate_on_submit(): contact_count = EntrepriseContact.query.filter_by( @@ -717,7 +745,9 @@ def add_historique(id): """ Permet d'ajouter un étudiant ayant réalisé un stage ou une alternance sur la fiche entreprise de l'entreprise """ - entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404() + entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404( + description=f"entreprise {id} inconnu" + ) form = HistoriqueCreationForm() if form.validate_on_submit(): etudiant_nomcomplet = form.etudiant.data.upper().strip() @@ -760,7 +790,9 @@ def envoyer_offre(id): """ Permet d'envoyer une offre à un utilisateur """ - offre = EntrepriseOffre.query.filter_by(id=id).first_or_404() + offre = EntrepriseOffre.query.filter_by(id=id).first_or_404( + description=f"offre {id} inconnu" + ) form = EnvoiOffreForm() if form.validate_on_submit(): responsable_data = form.responsable.data.upper().strip() @@ -794,7 +826,7 @@ def json_etudiants(): """ Permet de récuperer un JSON avec tous les étudiants """ - if request.args.get("term") == None: + if request.args.get("term") is None: abort(400) term = request.args.get("term").strip() etudiants = Identite.query.filter(Identite.nom.ilike(f"%{term}%")).all() @@ -820,7 +852,7 @@ def json_responsables(): """ Permet de récuperer un JSON avec tous les étudiants """ - if request.args.get("term") == None: + if request.args.get("term") is None: abort(400) term = request.args.get("term").strip() responsables = User.query.filter( @@ -873,8 +905,9 @@ def get_import_entreprises_file_sample(): "pays", ] titles = keys[:] + # lines = [["" for x in range(6)] for y in range(100)] title = "ImportEntreprises" - xlsx = sco_excel.excel_simple_table(titles=titles, sheet_name="Entreprises") + xlsx = sco_excel.excel_simple_table_test(titles=titles, sheet_name="Entreprises") filename = title return scu.send_file(xlsx, filename, scu.XLSX_SUFFIX, scu.XLSX_MIMETYPE) @@ -1126,7 +1159,7 @@ def get_offre_file(entreprise_id, offre_id, filedir, filename): as_attachment=True, ) else: - abort(404) + abort(404, description=f"fichier {filename} inconnu") @bp.route("/add_offre_file/", methods=["GET", "POST"]) @@ -1135,7 +1168,9 @@ def add_offre_file(offre_id): """ Permet d'ajouter un fichier à une offre """ - offre = EntrepriseOffre.query.filter_by(id=offre_id).first_or_404() + offre = EntrepriseOffre.query.filter_by(id=offre_id).first_or_404( + description=f"offre {offre_id} inconnu" + ) form = AjoutFichierForm() if form.validate_on_submit(): date = f"{datetime.now().strftime('%Y-%m-%d-%H-%M-%S')}" @@ -1165,7 +1200,9 @@ def delete_offre_file(offre_id, filedir): """ Permet de supprimer un fichier d'une offre """ - offre = EntrepriseOffre.query.filter_by(id=offre_id).first_or_404() + offre = EntrepriseOffre.query.filter_by(id=offre_id).first_or_404( + description=f"offre {offre_id} inconnu" + ) form = SuppressionConfirmationForm() if form.validate_on_submit(): path = os.path.join( diff --git a/app/scodoc/sco_excel.py b/app/scodoc/sco_excel.py index 978247800..cdeb40875 100644 --- a/app/scodoc/sco_excel.py +++ b/app/scodoc/sco_excel.py @@ -428,6 +428,52 @@ def excel_simple_table( return ws.generate() +def excel_simple_table_test( + titles=None, lines=None, sheet_name=b"feuille", titles_styles=None, comments=None +): + """Export simple type 'CSV': 1ere ligne en gras, le reste tel quel""" + ws = ScoExcelSheet(sheet_name) + + if titles is None: + titles = [] + if lines is None: + lines = [[]] + if titles_styles is None: + style = excel_make_style(bold=True) + titles_styles = [style] * len(titles) + if comments is None: + comments = [None] * len(titles) + # ligne de titres + ws.append_row( + [ + ws.make_cell(it, style, comment) + for (it, style, comment) in zip(titles, titles_styles, comments) + ] + ) + default_style = excel_make_style() + text_style = excel_make_style(number_format=FORMAT_GENERAL) + int_style = excel_make_style() + float_style = excel_make_style(number_format=FORMAT_NUMBER_00) + for line in lines: + cells = [] + for it in line: + cell_style = default_style + if type(it) == float: + cell_style = float_style + elif type(it) == int: + cell_style = int_style + else: + cell_style = text_style + cells.append(ws.make_cell(it, cell_style)) + ws.append_row(cells) + + # sheet = ws.wb.active + # for cell in sheet["A2":"A100"]: + # cell.number_format = FORMAT_GENERAL + + return ws.generate() + + def excel_feuille_saisie(e, titreannee, description, lines): """Genere feuille excel pour saisie des notes. E: evaluation (dict) From 0e42df55c927bde01949984d4c20a741db03e834 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 22 Feb 2022 18:44:53 +0100 Subject: [PATCH 101/287] =?UTF-8?q?Option=20pour=20afficher=20coef.=20UE?= =?UTF-8?q?=20s=C3=A9par=C3=A9e=20de=20celle=20pour=20les=20coefs=20module?= =?UTF-8?q?s=20(et=20=C3=A9vals).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/scodoc/sco_bulletins_standard.py | 10 ++++++---- app/scodoc/sco_preferences.py | 12 +++++++++++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/app/scodoc/sco_bulletins_standard.py b/app/scodoc/sco_bulletins_standard.py index 60c6f2a00..25111f7e6 100644 --- a/app/scodoc/sco_bulletins_standard.py +++ b/app/scodoc/sco_bulletins_standard.py @@ -284,7 +284,7 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator): ) with_col_moypromo = prefs["bul_show_moypromo"] with_col_rang = prefs["bul_show_rangs"] - with_col_coef = prefs["bul_show_coef"] + with_col_coef = prefs["bul_show_coef"] or prefs["bul_show_ue_coef"] with_col_ects = prefs["bul_show_ects"] colkeys = ["titre", "module"] # noms des colonnes à afficher @@ -409,7 +409,7 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator): # Chaque UE: for ue in I["ues"]: ue_type = None - coef_ue = ue["coef_ue_txt"] + coef_ue = ue["coef_ue_txt"] if prefs["bul_show_ue_coef"] else "" ue_descr = ue["ue_descr_txt"] rowstyle = "" plusminus = minuslink # @@ -592,7 +592,7 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator): "_titre_colspan": 2, "rang": mod["mod_rang_txt"], # vide si pas option rang "note": mod["mod_moy_txt"], - "coef": mod["mod_coef_txt"], + "coef": mod["mod_coef_txt"] if prefs["bul_show_coef"] else "", "abs": mod.get( "mod_abs_txt", "" ), # absent si pas option show abs module @@ -656,7 +656,9 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator): eval_style = "" t = { "module": ' ' + e["name"], - "coef": "" + e["coef_txt"] + "", + "coef": ("" + e["coef_txt"] + "") + if prefs["bul_show_coef"] + else "", "_hidden": hidden, "_module_target": e["target_html"], # '_module_help' : , diff --git a/app/scodoc/sco_preferences.py b/app/scodoc/sco_preferences.py index b639d5ee4..aab148e70 100644 --- a/app/scodoc/sco_preferences.py +++ b/app/scodoc/sco_preferences.py @@ -1296,11 +1296,21 @@ class BasePreferences(object): "labels": ["non", "oui"], }, ), + ( + "bul_show_ue_coef", + { + "initvalue": 1, + "title": "Afficher coefficient des UE sur les bulletins", + "input_type": "boolcheckbox", + "category": "bul", + "labels": ["non", "oui"], + }, + ), ( "bul_show_coef", { "initvalue": 1, - "title": "Afficher coefficient des ue/modules sur les bulletins", + "title": "Afficher coefficient des modules sur les bulletins", "input_type": "boolcheckbox", "category": "bul", "labels": ["non", "oui"], From 276d7977a79e9167df9a66d1b8d6f7bfa3f0460c Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 22 Feb 2022 18:45:43 +0100 Subject: [PATCH 102/287] Ajout UE bonus aux parcours ILEPS --- app/scodoc/sco_codes_parcours.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scodoc/sco_codes_parcours.py b/app/scodoc/sco_codes_parcours.py index 59372b8d6..f6ca2ff29 100644 --- a/app/scodoc/sco_codes_parcours.py +++ b/app/scodoc/sco_codes_parcours.py @@ -587,7 +587,7 @@ class ParcoursILEPS(TypeParcours): # SESSION_ABBRV = 'A' # A1, A2, ... COMPENSATION_UE = False UNUSED_CODES = set((ADC, ATT, ATB, ATJ)) - ALLOWED_UE_TYPES = [UE_STANDARD, UE_OPTIONNELLE] + ALLOWED_UE_TYPES = [UE_STANDARD, UE_OPTIONNELLE, UE_SPORT] # Barre moy gen. pour validation semestre: BARRE_MOY = 10.0 # Barre pour UE ILEPS: 8/20 pour UE standards ("fondamentales") From e7b980bff7d3be0a9021091509a65c7bcba905e6 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 22 Feb 2022 18:46:47 +0100 Subject: [PATCH 103/287] =?UTF-8?q?Fix:=20acc=C3=A8s=20moyennes=5Fmatieres?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/comp/res_common.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/comp/res_common.py b/app/comp/res_common.py index 5f652ec5c..92b0ee5ff 100644 --- a/app/comp/res_common.py +++ b/app/comp/res_common.py @@ -518,11 +518,11 @@ class NotesTableCompat(ResultatsSemestre): return "" return ins.etat - def get_etud_mat_moy(self, matiere_id, etudid): + def get_etud_mat_moy(self, matiere_id: int, etudid: int) -> str: """moyenne d'un étudiant dans une matière (ou NA si pas de notes)""" if not self.moyennes_matieres: return "nd" - return self.moyennes_matieres[matiere_id][etudid] + return self.moyennes_matieres[matiere_id].get(etudid, "-") def get_etud_mod_moy(self, moduleimpl_id: int, etudid: int) -> float: """La moyenne de l'étudiant dans le moduleimpl From 875c12d703ea2e888d0cc09591caeed3ff15754b Mon Sep 17 00:00:00 2001 From: Jean-Marie PLACE Date: Tue, 22 Feb 2022 19:25:49 +0100 Subject: [PATCH 104/287] soften error when logo not found --- app/scodoc/sco_logos.py | 2 +- app/views/scodoc.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/scodoc/sco_logos.py b/app/scodoc/sco_logos.py index c489510b5..46e0c066a 100644 --- a/app/scodoc/sco_logos.py +++ b/app/scodoc/sco_logos.py @@ -276,7 +276,7 @@ class Logo: if self.mm is None: return f'' else: - return f'' + return f'' def last_modified(self): path = Path(self.filepath) diff --git a/app/views/scodoc.py b/app/views/scodoc.py index 809d8e463..d1c842dd4 100644 --- a/app/views/scodoc.py +++ b/app/views/scodoc.py @@ -304,8 +304,9 @@ def _return_logo(name="header", dept_id="", small=False, strict: bool = True): # stockée dans /opt/scodoc-data/config/logos donc servie manuellement ici # from app.scodoc.sco_photos import _http_jpeg_file - logo = sco_logos.find_logo(name, dept_id, strict).select() + logo = sco_logos.find_logo(name, dept_id, strict) if logo is not None: + logo.select() suffix = logo.suffix if small: with PILImage.open(logo.filepath) as im: From 722ec09eb58380d3593f060b3a0316da684497cc Mon Sep 17 00:00:00 2001 From: Arthur ZHU Date: Tue, 22 Feb 2022 21:52:32 +0100 Subject: [PATCH 105/287] preferences, modif export --- app/entreprises/app_relations_entreprises.py | 4 +- app/entreprises/forms.py | 10 ++ app/entreprises/models.py | 12 ++- app/entreprises/routes.py | 91 ++++++++++++++----- app/scodoc/sco_excel.py | 46 ---------- .../entreprises/import_contacts.html | 2 +- .../entreprises/import_entreprises.html | 2 +- app/templates/entreprises/nav.html | 1 + app/templates/entreprises/preferences.html | 15 +++ ...e2915_tables_module_gestion_relations_.py} | 51 +++++++---- 10 files changed, 141 insertions(+), 93 deletions(-) create mode 100644 app/templates/entreprises/preferences.html rename migrations/versions/{593451ab68b3_tables_module_gestion_relations_.py => 717a8dfe2915_tables_module_gestion_relations_.py} (91%) diff --git a/app/entreprises/app_relations_entreprises.py b/app/entreprises/app_relations_entreprises.py index 6f060616d..a08b0417f 100644 --- a/app/entreprises/app_relations_entreprises.py +++ b/app/entreprises/app_relations_entreprises.py @@ -117,13 +117,13 @@ def verif_contact_data(contact_data): return False # entreprise_id existant - entreprise = Entreprise.query.filter_by(id=contact_data[6]).first() + entreprise = Entreprise.query.filter_by(siret=contact_data[6]).first() if entreprise is None: return False # contact possède le meme nom et prénom dans la meme entreprise contact = EntrepriseContact.query.filter_by( - nom=contact_data[0], prenom=contact_data[1], entreprise_id=contact_data[6] + nom=contact_data[0], prenom=contact_data[1], entreprise_id=entreprise.id ).first() if contact is not None: return False diff --git a/app/entreprises/forms.py b/app/entreprises/forms.py index ca74da261..4f2cfd849 100644 --- a/app/entreprises/forms.py +++ b/app/entreprises/forms.py @@ -39,6 +39,7 @@ from wtforms import ( HiddenField, SelectMultipleField, DateField, + BooleanField, ) from wtforms.validators import ValidationError, DataRequired, Email, Optional from wtforms.widgets import ListWidget, CheckboxInput @@ -356,3 +357,12 @@ class ImportForm(FlaskForm): ], ) submit = SubmitField("Importer", render_kw=SUBMIT_MARGE) + + +class PreferencesForm(FlaskForm): + mail_entreprise = StringField( + "Mail notifications", + validators=[Optional(), Email(message="Adresse e-mail invalide")], + ) + check_siret = BooleanField("Vérification SIRET") + submit = SubmitField("Valider", render_kw=SUBMIT_MARGE) diff --git a/app/entreprises/models.py b/app/entreprises/models.py index 9a99f4bc8..ce0acc984 100644 --- a/app/entreprises/models.py +++ b/app/entreprises/models.py @@ -27,7 +27,7 @@ class Entreprise(db.Model): def to_dict(self): return { "siret": self.siret, - "nom": self.nom, + "nom_entreprise": self.nom, "adresse": self.adresse, "code_postal": self.codepostal, "ville": self.ville, @@ -49,6 +49,7 @@ class EntrepriseContact(db.Model): service = db.Column(db.Text) def to_dict(self): + entreprise = Entreprise.query.filter_by(id=self.entreprise_id).first() return { "nom": self.nom, "prenom": self.prenom, @@ -56,7 +57,7 @@ class EntrepriseContact(db.Model): "mail": self.mail, "poste": self.poste, "service": self.service, - "entreprise_id": self.entreprise_id, + "entreprise_siret": entreprise.siret, } @@ -138,3 +139,10 @@ class EntrepriseOffreDepartement(db.Model): db.Integer, db.ForeignKey("are_entreprise_offre.id", ondelete="cascade") ) dept_id = db.Column(db.Integer, db.ForeignKey("departement.id", ondelete="cascade")) + + +class EntreprisePreferences(db.Model): + __tablename__ = "are_preferences" + id = db.Column(db.Integer, primary_key=True) + name = db.Column(db.Text) + value = db.Column(db.Text) diff --git a/app/entreprises/routes.py b/app/entreprises/routes.py index eaef9275c..c3bfcfecd 100644 --- a/app/entreprises/routes.py +++ b/app/entreprises/routes.py @@ -24,6 +24,7 @@ from app.entreprises.forms import ( AjoutFichierForm, ValidationConfirmationForm, ImportForm, + PreferencesForm, ) from app.entreprises import bp from app.entreprises.models import ( @@ -34,6 +35,7 @@ from app.entreprises.models import ( EntrepriseEtudiant, EntrepriseEnvoiOffre, EntrepriseOffreDepartement, + EntreprisePreferences, ) from app.entreprises import app_relations_entreprises as are from app.models import Identite @@ -124,7 +126,7 @@ def fiche_entreprise(id): les offres de l'entreprise. """ entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404( - description=f"fiche entreprise {id} inconnu" + description=f"fiche entreprise {id} inconnue" ) offres_with_files = [] depts = are.get_depts() @@ -188,7 +190,7 @@ def fiche_entreprise_validation(id): Permet d'afficher la fiche entreprise d'une entreprise a valider """ entreprise = Entreprise.query.filter_by(id=id, visible=False).first_or_404( - description=f"fiche entreprise (validation) {id} inconnu" + description=f"fiche entreprise (validation) {id} inconnue" ) contacts = entreprise.contacts return render_template( @@ -242,7 +244,7 @@ def offres_expirees(id): Permet d'afficher la liste des offres expirés d'une entreprise """ entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404( - description=f"fiche entreprise {id} inconnu" + description=f"fiche entreprise {id} inconnue" ) offres_expirees_with_files = [] depts = are.get_depts() @@ -318,7 +320,7 @@ def edit_entreprise(id): Permet de modifier une entreprise de la base avec un formulaire """ entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404( - description=f"entreprise {id} inconnu" + description=f"entreprise {id} inconnue" ) form = EntrepriseModificationForm() if form.validate_on_submit(): @@ -387,7 +389,7 @@ def delete_entreprise(id): Permet de supprimer une entreprise de la base avec un formulaire de confirmation """ entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404( - description=f"entreprise {id} inconnu" + description=f"entreprise {id} inconnue" ) form = SuppressionConfirmationForm() if form.validate_on_submit(): @@ -424,7 +426,7 @@ def validate_entreprise(id): """ form = ValidationConfirmationForm() entreprise = Entreprise.query.filter_by(id=id, visible=False).first_or_404( - description=f"entreprise (validation) {id} inconnu" + description=f"entreprise (validation) {id} inconnue" ) if form.validate_on_submit(): entreprise.visible = True @@ -451,7 +453,7 @@ def delete_validation_entreprise(id): Permet de supprimer une entreprise en attente de validation avec une formulaire de validation """ entreprise = Entreprise.query.filter_by(id=id, visible=False).first_or_404( - description=f"entreprise (validation) {id} inconnu" + description=f"entreprise (validation) {id} inconnue" ) form = SuppressionConfirmationForm() if form.validate_on_submit(): @@ -473,7 +475,7 @@ def add_offre(id): Permet d'ajouter une offre a une entreprise """ entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404( - description=f"entreprise {id} inconnu" + description=f"entreprise {id} inconnue" ) form = OffreCreationForm() if form.validate_on_submit(): @@ -518,7 +520,7 @@ def edit_offre(id): Permet de modifier une offre """ offre = EntrepriseOffre.query.filter_by(id=id).first_or_404( - description=f"offre {id} inconnu" + description=f"offre {id} inconnue" ) offre_depts = EntrepriseOffreDepartement.query.filter_by(offre_id=offre.id).all() form = OffreModificationForm() @@ -575,7 +577,7 @@ def delete_offre(id): Permet de supprimer une offre """ offre = EntrepriseOffre.query.filter_by(id=id).first_or_404( - description=f"offre {id} inconnu" + description=f"offre {id} inconnue" ) entreprise_id = offre.entreprise.id form = SuppressionConfirmationForm() @@ -610,7 +612,7 @@ def delete_offre(id): def delete_offre_recue(id): offre_recue = EntrepriseEnvoiOffre.query.filter_by( id=id, receiver_id=current_user.id - ).first_or_404(description=f"offre recu {id} inconnu") + ).first_or_404(description=f"offre recu {id} inconnue") db.session.delete(offre_recue) db.session.commit() return redirect(url_for("entreprises.offres_recues")) @@ -623,7 +625,7 @@ def add_contact(id): Permet d'ajouter un contact a une entreprise """ entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404( - description=f"entreprise {id} inconnu" + description=f"entreprise {id} inconnue" ) form = ContactCreationForm(hidden_entreprise_id=entreprise.id) if form.validate_on_submit(): @@ -746,7 +748,7 @@ def add_historique(id): Permet d'ajouter un étudiant ayant réalisé un stage ou une alternance sur la fiche entreprise de l'entreprise """ entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404( - description=f"entreprise {id} inconnu" + description=f"entreprise {id} inconnue" ) form = HistoriqueCreationForm() if form.validate_on_submit(): @@ -791,7 +793,7 @@ def envoyer_offre(id): Permet d'envoyer une offre à un utilisateur """ offre = EntrepriseOffre.query.filter_by(id=id).first_or_404( - description=f"offre {id} inconnu" + description=f"offre {id} inconnue" ) form = EnvoiOffreForm() if form.validate_on_submit(): @@ -876,7 +878,7 @@ def export_entreprises(): """ entreprises = Entreprise.query.filter_by(visible=True).all() if entreprises: - keys = ["siret", "nom", "adresse", "ville", "code_postal", "pays"] + keys = ["siret", "nom_entreprise", "adresse", "ville", "code_postal", "pays"] titles = keys[:] L = [ [entreprise.to_dict().get(k, "") for k in keys] @@ -901,13 +903,12 @@ def get_import_entreprises_file_sample(): "nom_entreprise", "adresse", "ville", - "codepostal", + "code_postal", "pays", ] titles = keys[:] - # lines = [["" for x in range(6)] for y in range(100)] title = "ImportEntreprises" - xlsx = sco_excel.excel_simple_table_test(titles=titles, sheet_name="Entreprises") + xlsx = sco_excel.excel_simple_table(titles=titles, sheet_name="Entreprises") filename = title return scu.send_file(xlsx, filename, scu.XLSX_SUFFIX, scu.XLSX_MIMETYPE) @@ -930,7 +931,7 @@ def import_entreprises(): entreprises_import = [] siret_list = [] ligne = 0 - titles = ["siret", "nom", "adresse", "ville", "code_postal", "pays"] + titles = ["siret", "nom_entreprise", "adresse", "ville", "code_postal", "pays"] if data[1][0] != titles: flash("Veuillez utilisez la feuille excel à remplir") return render_template( @@ -1010,7 +1011,7 @@ def export_contacts(): "mail", "poste", "service", - "entreprise_id", + "entreprise_siret", ] titles = keys[:] L = [[contact.to_dict().get(k, "") for k in keys] for contact in contacts] @@ -1035,7 +1036,7 @@ def get_import_contacts_file_sample(): "mail", "poste", "service", - "entreprise_id", + "entreprise_siret", ] titles = keys[:] title = "ImportContacts" @@ -1069,7 +1070,7 @@ def import_contacts(): "mail", "poste", "service", - "entreprise_id", + "entreprise_siret", ] if data[1][0] != titles: flash("Veuillez utilisez la feuille excel à remplir") @@ -1169,7 +1170,7 @@ def add_offre_file(offre_id): Permet d'ajouter un fichier à une offre """ offre = EntrepriseOffre.query.filter_by(id=offre_id).first_or_404( - description=f"offre {offre_id} inconnu" + description=f"offre {offre_id} inconnue" ) form = AjoutFichierForm() if form.validate_on_submit(): @@ -1201,7 +1202,7 @@ def delete_offre_file(offre_id, filedir): Permet de supprimer un fichier d'une offre """ offre = EntrepriseOffre.query.filter_by(id=offre_id).first_or_404( - description=f"offre {offre_id} inconnu" + description=f"offre {offre_id} inconnue" ) form = SuppressionConfirmationForm() if form.validate_on_submit(): @@ -1223,3 +1224,45 @@ def delete_offre_file(offre_id, filedir): title="Suppression fichier d'une offre", form=form, ) + + +@bp.route("/preferences", methods=["GET", "POST"]) +@permission_required(Permission.RelationsEntreprisesValidate) +def preferences(): + form = PreferencesForm() + if form.validate_on_submit(): + exists = EntreprisePreferences.query.filter_by(name="check_siret").first() + if not exists: + prefs = EntreprisePreferences( + name="check_siret", value=int(form.check_siret.data) + ) + db.session.add(prefs) + else: + exists.value = int(form.check_siret.data) + db.session.commit() + exists = EntreprisePreferences.query.filter_by( + name="mail_notifications_entreprise" + ).first() + if not exists and form.mail_entreprise.data: + prefs = EntreprisePreferences( + name="mail_notifications_entreprise", + value=form.mail_entreprise.data.strip(), + ) + db.session.add(prefs) + else: + exists.value = form.mail_entreprise.data + db.session.commit() + db.session.commit() + return redirect(url_for("entreprises.index")) + elif request.method == "GET": + mail = EntreprisePreferences.query.filter_by( + name="mail_notifications_entreprise" + ).first() + check_siret = EntreprisePreferences.query.filter_by(name="check_siret").first() + form.mail_entreprise.data = mail.value + form.check_siret.data = int(check_siret.value) + return render_template( + "entreprises/preferences.html", + title="Préférences", + form=form, + ) diff --git a/app/scodoc/sco_excel.py b/app/scodoc/sco_excel.py index cdeb40875..978247800 100644 --- a/app/scodoc/sco_excel.py +++ b/app/scodoc/sco_excel.py @@ -428,52 +428,6 @@ def excel_simple_table( return ws.generate() -def excel_simple_table_test( - titles=None, lines=None, sheet_name=b"feuille", titles_styles=None, comments=None -): - """Export simple type 'CSV': 1ere ligne en gras, le reste tel quel""" - ws = ScoExcelSheet(sheet_name) - - if titles is None: - titles = [] - if lines is None: - lines = [[]] - if titles_styles is None: - style = excel_make_style(bold=True) - titles_styles = [style] * len(titles) - if comments is None: - comments = [None] * len(titles) - # ligne de titres - ws.append_row( - [ - ws.make_cell(it, style, comment) - for (it, style, comment) in zip(titles, titles_styles, comments) - ] - ) - default_style = excel_make_style() - text_style = excel_make_style(number_format=FORMAT_GENERAL) - int_style = excel_make_style() - float_style = excel_make_style(number_format=FORMAT_NUMBER_00) - for line in lines: - cells = [] - for it in line: - cell_style = default_style - if type(it) == float: - cell_style = float_style - elif type(it) == int: - cell_style = int_style - else: - cell_style = text_style - cells.append(ws.make_cell(it, cell_style)) - ws.append_row(cells) - - # sheet = ws.wb.active - # for cell in sheet["A2":"A100"]: - # cell.number_format = FORMAT_GENERAL - - return ws.generate() - - def excel_feuille_saisie(e, titreannee, description, lines): """Genere feuille excel pour saisie des notes. E: evaluation (dict) diff --git a/app/templates/entreprises/import_contacts.html b/app/templates/entreprises/import_contacts.html index a18122930..204a5e970 100644 --- a/app/templates/entreprises/import_contacts.html +++ b/app/templates/entreprises/import_contacts.html @@ -28,7 +28,7 @@ mailtextmail du contact postetextposte du contact servicetextservice dans lequel travaille le contact - entreprise_idintegerl'id de l'entreprise + entreprise_siretintegerSIRET de l'entreprise {% endif %} diff --git a/app/templates/entreprises/import_entreprises.html b/app/templates/entreprises/import_entreprises.html index 21aeb6a06..2539aeb68 100644 --- a/app/templates/entreprises/import_entreprises.html +++ b/app/templates/entreprises/import_entreprises.html @@ -23,7 +23,7 @@ - + diff --git a/app/templates/entreprises/nav.html b/app/templates/entreprises/nav.html index f4673bfc3..e24211653 100644 --- a/app/templates/entreprises/nav.html +++ b/app/templates/entreprises/nav.html @@ -6,6 +6,7 @@
  • Offres reçues
  • {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesValidate, None) %}
  • Entreprises à valider
  • +
  • Préférences
  • {% endif %} \ No newline at end of file diff --git a/app/templates/entreprises/preferences.html b/app/templates/entreprises/preferences.html new file mode 100644 index 000000000..625143728 --- /dev/null +++ b/app/templates/entreprises/preferences.html @@ -0,0 +1,15 @@ +{# -*- mode: jinja-html -*- #} +{% extends 'base.html' %} +{% import 'bootstrap/wtf.html' as wtf %} + +{% block app_content %} + {% include 'entreprises/nav.html' %} + +

    Préférences module gestion entreprises

    +
    +
    +
    + {{ wtf.quick_form(form, novalidate=True) }} +
    +
    +{% endblock %} \ No newline at end of file diff --git a/migrations/versions/593451ab68b3_tables_module_gestion_relations_.py b/migrations/versions/717a8dfe2915_tables_module_gestion_relations_.py similarity index 91% rename from migrations/versions/593451ab68b3_tables_module_gestion_relations_.py rename to migrations/versions/717a8dfe2915_tables_module_gestion_relations_.py index e72dff94b..eb32d4c1d 100644 --- a/migrations/versions/593451ab68b3_tables_module_gestion_relations_.py +++ b/migrations/versions/717a8dfe2915_tables_module_gestion_relations_.py @@ -1,8 +1,8 @@ """tables module gestion relations entreprises -Revision ID: 593451ab68b3 -Revises: c95d5a3bf0de -Create Date: 2022-02-04 17:06:02.519231 +Revision ID: 717a8dfe2915 +Revises: b9aadc10227f +Create Date: 2022-02-22 20:18:57.171246 """ from alembic import op @@ -10,8 +10,8 @@ import sqlalchemy as sa from sqlalchemy.dialects import postgresql # revision identifiers, used by Alembic. -revision = "593451ab68b3" -down_revision = "c95d5a3bf0de" +revision = "717a8dfe2915" +down_revision = "b9aadc10227f" branch_labels = None depends_on = None @@ -44,6 +44,13 @@ def upgrade(): sa.Column("visible", sa.Boolean(), nullable=True), sa.PrimaryKeyConstraint("id"), ) + op.create_table( + "are_preferences", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("name", sa.Text(), nullable=True), + sa.Column("value", sa.Text(), nullable=True), + sa.PrimaryKeyConstraint("id"), + ) op.create_table( "are_entreprise_contact", sa.Column("id", sa.Integer(), nullable=False), @@ -148,14 +155,31 @@ def upgrade(): op.drop_table("entreprise_correspondant") op.drop_index("ix_entreprises_dept_id", table_name="entreprises") op.drop_table("entreprises") + op.drop_index("ix_apc_competence_id_orebut", table_name="apc_competence") + op.create_index( + op.f("ix_apc_competence_id_orebut"), + "apc_competence", + ["id_orebut"], + unique=False, + ) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### + op.drop_index(op.f("ix_apc_competence_id_orebut"), table_name="apc_competence") + op.create_index( + "ix_apc_competence_id_orebut", "apc_competence", ["id_orebut"], unique=False + ) op.create_table( "entreprises", - sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False), + sa.Column( + "id", + sa.INTEGER(), + server_default=sa.text("nextval('entreprises_id_seq'::regclass)"), + autoincrement=True, + nullable=False, + ), sa.Column("nom", sa.TEXT(), autoincrement=False, nullable=True), sa.Column("adresse", sa.TEXT(), autoincrement=False, nullable=True), sa.Column("ville", sa.TEXT(), autoincrement=False, nullable=True), @@ -180,18 +204,12 @@ def downgrade(): ["dept_id"], ["departement.id"], name="entreprises_dept_id_fkey" ), sa.PrimaryKeyConstraint("id", name="entreprises_pkey"), + postgresql_ignore_search_path=False, ) + op.create_index("ix_entreprises_dept_id", "entreprises", ["dept_id"], unique=False) op.create_table( "entreprise_correspondant", - sa.Column( - "id", - sa.INTEGER(), - server_default=sa.text( - "nextval('entreprise_correspondant_id_seq'::regclass)" - ), - autoincrement=True, - nullable=False, - ), + sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False), sa.Column("entreprise_id", sa.INTEGER(), autoincrement=False, nullable=True), sa.Column("nom", sa.TEXT(), autoincrement=False, nullable=True), sa.Column("prenom", sa.TEXT(), autoincrement=False, nullable=True), @@ -210,7 +228,6 @@ def downgrade(): name="entreprise_correspondant_entreprise_id_fkey", ), sa.PrimaryKeyConstraint("id", name="entreprise_correspondant_pkey"), - postgresql_ignore_search_path=False, ) op.create_table( "entreprise_contact", @@ -241,13 +258,13 @@ def downgrade(): ), sa.PrimaryKeyConstraint("id", name="entreprise_contact_pkey"), ) - op.create_index("ix_entreprises_dept_id", "entreprises", ["dept_id"], unique=False) op.drop_table("are_entreprise_offre_departement") op.drop_table("are_entreprise_envoi_offre_etudiant") op.drop_table("are_entreprise_envoi_offre") op.drop_table("are_entreprise_offre") op.drop_table("are_entreprise_etudiant") op.drop_table("are_entreprise_contact") + op.drop_table("are_preferences") op.drop_table("are_entreprises") op.drop_table("are_entreprise_log") # ### end Alembic commands ### From e9ad417f1f5abcc9eec5390959b2df005cc84dc9 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Wed, 23 Feb 2022 09:42:41 +0100 Subject: [PATCH 106/287] check matieres --- app/comp/res_common.py | 6 +++++- sco_version.py | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/comp/res_common.py b/app/comp/res_common.py index 92b0ee5ff..f13201262 100644 --- a/app/comp/res_common.py +++ b/app/comp/res_common.py @@ -522,7 +522,11 @@ class NotesTableCompat(ResultatsSemestre): """moyenne d'un étudiant dans une matière (ou NA si pas de notes)""" if not self.moyennes_matieres: return "nd" - return self.moyennes_matieres[matiere_id].get(etudid, "-") + return ( + self.moyennes_matieres[matiere_id].get(etudid, "-") + if matiere_id in self.moyennes_matieres + else "-" + ) def get_etud_mod_moy(self, moduleimpl_id: int, etudid: int) -> float: """La moyenne de l'étudiant dans le moduleimpl diff --git a/sco_version.py b/sco_version.py index 4ac94b210..5c1b87f2e 100644 --- a/sco_version.py +++ b/sco_version.py @@ -1,7 +1,7 @@ # -*- mode: python -*- # -*- coding: utf-8 -*- -SCOVERSION = "9.1.62" +SCOVERSION = "9.1.63" SCONAME = "ScoDoc" From c86d780585bedf58a10a9ddbcba49320a8f37e92 Mon Sep 17 00:00:00 2001 From: Arthur ZHU Date: Wed, 23 Feb 2022 19:12:26 +0100 Subject: [PATCH 107/287] =?UTF-8?q?page=20preferences=20fonctionnelle=20(m?= =?UTF-8?q?ail=20a=20v=C3=A9rifier)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/entreprises/app_relations_entreprises.py | 34 +++++++++++++++ app/entreprises/forms.py | 37 ++++++++-------- app/entreprises/models.py | 44 ++++++++++++++++++++ app/entreprises/routes.py | 36 ++++------------ 4 files changed, 105 insertions(+), 46 deletions(-) diff --git a/app/entreprises/app_relations_entreprises.py b/app/entreprises/app_relations_entreprises.py index a08b0417f..421f08824 100644 --- a/app/entreprises/app_relations_entreprises.py +++ b/app/entreprises/app_relations_entreprises.py @@ -37,8 +37,11 @@ from app.entreprises.models import ( EntrepriseContact, EntrepriseOffre, EntrepriseOffreDepartement, + EntreprisePreferences, ) +from app import email +from app.scodoc import sco_preferences from app.models import Departement from app.scodoc.sco_permissions import Permission @@ -101,6 +104,37 @@ def get_offre_files_and_depts(offre: EntrepriseOffre, depts: list): return None +def send_email_notifications_entreprise( + subject, entreprise: Entreprise, contact: EntrepriseContact +): + txt = [ + "Une entreprise est en attente de validation", + "Entreprise:", + f"\tnom: {entreprise.nom}", + f"\tsiret: {entreprise.siret}", + f"\tadresse: {entreprise.adresse}", + f"\tcode postal: {entreprise.codepostal}", + f"\tville: {entreprise.ville}", + f"\tpays: {entreprise.pays}", + "", + "Contact:", + f"nom: {contact.nom}", + f"prenom: {contact.prenom}", + f"telephone: {contact.telephone}", + f"mail: {contact.mail}", + f"poste: {contact.poste}", + f"service: {contact.service}", + ] + txt = "\n".join(txt) + email.send_email( + subject, + sco_preferences.get_preference("email_from_addr"), + [EntreprisePreferences.get_email_notifications], + txt, + ) + return txt + + def verif_contact_data(contact_data): """ Verifie les données d'une ligne Excel (contact) diff --git a/app/entreprises/forms.py b/app/entreprises/forms.py index 4f2cfd849..5b1b175f8 100644 --- a/app/entreprises/forms.py +++ b/app/entreprises/forms.py @@ -44,7 +44,7 @@ from wtforms import ( from wtforms.validators import ValidationError, DataRequired, Email, Optional from wtforms.widgets import ListWidget, CheckboxInput -from app.entreprises.models import Entreprise, EntrepriseContact +from app.entreprises.models import Entreprise, EntrepriseContact, EntreprisePreferences from app.models import Identite, Departement from app.auth.models import User @@ -100,23 +100,24 @@ class EntrepriseCreationForm(FlaskForm): return validate def validate_siret(self, siret): - siret = siret.data.strip() - if re.match("^\d{14}$", siret) is None: - raise ValidationError("Format incorrect") - try: - req = requests.get( - f"https://entreprise.data.gouv.fr/api/sirene/v1/siret/{siret}" - ) - except requests.ConnectionError: - print("no internet") - if req.status_code != 200: - raise ValidationError("SIRET inexistant") - entreprise = Entreprise.query.filter_by(siret=siret).first() - if entreprise is not None: - lien = f'ici' - raise ValidationError( - Markup(f"Entreprise déjà présent, lien vers la fiche : {lien}") - ) + if EntreprisePreferences.get_check_siret(): + siret = siret.data.strip() + if re.match("^\d{14}$", siret) is None: + raise ValidationError("Format incorrect") + try: + req = requests.get( + f"https://entreprise.data.gouv.fr/api/sirene/v1/siret/{siret}" + ) + except requests.ConnectionError: + print("no internet") + if req.status_code != 200: + raise ValidationError("SIRET inexistant") + entreprise = Entreprise.query.filter_by(siret=siret).first() + if entreprise is not None: + lien = f'ici' + raise ValidationError( + Markup(f"Entreprise déjà présent, lien vers la fiche : {lien}") + ) class EntrepriseModificationForm(FlaskForm): diff --git a/app/entreprises/models.py b/app/entreprises/models.py index ce0acc984..923b2445f 100644 --- a/app/entreprises/models.py +++ b/app/entreprises/models.py @@ -146,3 +146,47 @@ class EntreprisePreferences(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.Text) value = db.Column(db.Text) + + @classmethod + def get_email_notifications(cls): + mail = EntreprisePreferences.query.filter_by( + name="mail_notifications_entreprise" + ).first() + if mail is None: + return "" + else: + return mail.value + + @classmethod + def set_email_notifications(cls, mail: str): + if mail != cls.get_email_notifications(): + m = EntreprisePreferences.query.filter_by( + name="mail_notifications_entreprise" + ).first() + if m is None: + prefs = EntreprisePreferences( + name="mail_notifications_entreprise", + value=mail, + ) + db.session.add(prefs) + else: + m.value = mail + db.session.commit() + + @classmethod + def get_check_siret(cls): + check_siret = EntreprisePreferences.query.filter_by(name="check_siret").first() + if check_siret is None: + return 1 + else: + return int(check_siret.value) + + @classmethod + def set_check_siret(cls, check_siret: int): + cs = EntreprisePreferences.query.filter_by(name="check_siret").first() + if cs is None: + prefs = EntreprisePreferences(name="check_siret", value=check_siret) + db.session.add(prefs) + else: + cs.value = check_siret + db.session.commit() diff --git a/app/entreprises/routes.py b/app/entreprises/routes.py index c3bfcfecd..301813341 100644 --- a/app/entreprises/routes.py +++ b/app/entreprises/routes.py @@ -304,6 +304,10 @@ def add_entreprise(): else: entreprise.visible = False db.session.commit() + if EntreprisePreferences.get_email_notifications(): + are.send_email_notifications_entreprise( + "entreprise en attente de validation", entreprise, contact + ) flash("L'entreprise a été ajouté à la liste pour la validation.") return redirect(url_for("entreprises.index")) return render_template( @@ -1231,36 +1235,12 @@ def delete_offre_file(offre_id, filedir): def preferences(): form = PreferencesForm() if form.validate_on_submit(): - exists = EntreprisePreferences.query.filter_by(name="check_siret").first() - if not exists: - prefs = EntreprisePreferences( - name="check_siret", value=int(form.check_siret.data) - ) - db.session.add(prefs) - else: - exists.value = int(form.check_siret.data) - db.session.commit() - exists = EntreprisePreferences.query.filter_by( - name="mail_notifications_entreprise" - ).first() - if not exists and form.mail_entreprise.data: - prefs = EntreprisePreferences( - name="mail_notifications_entreprise", - value=form.mail_entreprise.data.strip(), - ) - db.session.add(prefs) - else: - exists.value = form.mail_entreprise.data - db.session.commit() - db.session.commit() + EntreprisePreferences.set_email_notifications(form.mail_entreprise.data.strip()) + EntreprisePreferences.set_check_siret(int(form.check_siret.data)) return redirect(url_for("entreprises.index")) elif request.method == "GET": - mail = EntreprisePreferences.query.filter_by( - name="mail_notifications_entreprise" - ).first() - check_siret = EntreprisePreferences.query.filter_by(name="check_siret").first() - form.mail_entreprise.data = mail.value - form.check_siret.data = int(check_siret.value) + form.mail_entreprise.data = EntreprisePreferences.get_email_notifications() + form.check_siret.data = int(EntreprisePreferences.get_check_siret()) return render_template( "entreprises/preferences.html", title="Préférences", From 2cac0031f6c4aa03cf8bbf03d5989b509dc819d8 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Wed, 23 Feb 2022 20:15:28 +0100 Subject: [PATCH 108/287] Erreur si la reponse portail n'a pas le mail --- app/scodoc/sco_synchro_etuds.py | 38 ++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/app/scodoc/sco_synchro_etuds.py b/app/scodoc/sco_synchro_etuds.py index bbcf4a083..db775438c 100644 --- a/app/scodoc/sco_synchro_etuds.py +++ b/app/scodoc/sco_synchro_etuds.py @@ -854,23 +854,27 @@ def formsemestre_import_etud_admission( apo_emailperso = etud.get("mailperso", "") if info["emailperso"] and not apo_emailperso: apo_emailperso = info["emailperso"] - if ( - import_email - and info["email"] != etud["mail"] - or info["emailperso"] != apo_emailperso - ): - sco_etud.adresse_edit( - cnx, - args={ - "etudid": etudid, - "adresse_id": info["adresse_id"], - "email": etud["mail"], - "emailperso": apo_emailperso, - }, - ) - # notifie seulement les changements d'adresse mail institutionnelle - if info["email"] != etud["mail"]: - changed_mails.append((info, etud["mail"])) + if import_email: + if not "mail" in etud: + raise ScoValueError( + "la réponse portail n'a pas le champs requis 'mail'" + ) + if ( + info["email"] != etud["mail"] + or info["emailperso"] != apo_emailperso + ): + sco_etud.adresse_edit( + cnx, + args={ + "etudid": etudid, + "adresse_id": info["adresse_id"], + "email": etud["mail"], + "emailperso": apo_emailperso, + }, + ) + # notifie seulement les changements d'adresse mail institutionnelle + if info["email"] != etud["mail"]: + changed_mails.append((info, etud["mail"])) else: unknowns.append(code_nip) sco_cache.invalidate_formsemestre(formsemestre_id=sem["formsemestre_id"]) From 6a07bb85a0e3b93350b1eebcd5a649a7fae74bc7 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Wed, 23 Feb 2022 20:21:13 +0100 Subject: [PATCH 109/287] Message erreur si bul_intro_mail invalide --- app/scodoc/sco_bulletins.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/app/scodoc/sco_bulletins.py b/app/scodoc/sco_bulletins.py index de7f28c9d..ca6748de7 100644 --- a/app/scodoc/sco_bulletins.py +++ b/app/scodoc/sco_bulletins.py @@ -1013,11 +1013,16 @@ def mail_bulletin(formsemestre_id, I, pdfdata, filename, recipient_addr): intro_mail = sco_preferences.get_preference("bul_intro_mail", formsemestre_id) if intro_mail: - hea = intro_mail % { - "nomprenom": etud["nomprenom"], - "dept": dept, - "webmaster": webmaster, - } + try: + hea = intro_mail % { + "nomprenom": etud["nomprenom"], + "dept": dept, + "webmaster": webmaster, + } + except KeyError as e: + raise ScoValueError( + "format 'Message d'accompagnement' (bul_intro_mail) invalide, revoir les réglages dans les préférences" + ) else: hea = "" From 5e77ca53a5d2879b92fbb1609fe9d01c207c9c9d Mon Sep 17 00:00:00 2001 From: Arthur ZHU Date: Fri, 25 Feb 2022 09:45:14 +0100 Subject: [PATCH 110/287] corrections --- app/entreprises/app_relations_entreprises.py | 33 ++++++++++--------- app/entreprises/forms.py | 8 +++-- app/templates/entreprises/contacts.html | 2 +- app/templates/entreprises/entreprises.html | 2 +- .../entreprises/entreprises_validation.html | 2 +- .../form_modification_entreprise.html | 2 +- app/templates/entreprises/offres_recues.html | 2 +- 7 files changed, 28 insertions(+), 23 deletions(-) diff --git a/app/entreprises/app_relations_entreprises.py b/app/entreprises/app_relations_entreprises.py index 421f08824..af06f6e18 100644 --- a/app/entreprises/app_relations_entreprises.py +++ b/app/entreprises/app_relations_entreprises.py @@ -172,21 +172,22 @@ def verif_entreprise_data(entreprise_data): """ Verifie les données d'une ligne Excel (entreprise) """ - for data in entreprise_data: # champs obligatoires + for data in entreprise_data[1:]: # champs obligatoires if data == "": return False - siret = entreprise_data[0].strip() # vérification sur le siret - if re.match("^\d{14}$", siret) is None: - return False - try: - req = requests.get( - f"https://entreprise.data.gouv.fr/api/sirene/v1/siret/{siret}" - ) - except requests.ConnectionError: - print("no internet") - if req.status_code != 200: - return False - entreprise = Entreprise.query.filter_by(siret=siret).first() - if entreprise is not None: - return False - return True + if EntreprisePreferences.get_check_siret(): + siret = entreprise_data[0].strip() # vérification sur le siret + if re.match("^\d{14}$", siret) is None: + return False + try: + req = requests.get( + f"https://entreprise.data.gouv.fr/api/sirene/v1/siret/{siret}" + ) + except requests.ConnectionError: + print("no internet") + if req.status_code != 200: + return False + entreprise = Entreprise.query.filter_by(siret=siret).first() + if entreprise is not None: + return False + return True diff --git a/app/entreprises/forms.py b/app/entreprises/forms.py index 5b1b175f8..e5e334c34 100644 --- a/app/entreprises/forms.py +++ b/app/entreprises/forms.py @@ -145,7 +145,9 @@ class OffreCreationForm(FlaskForm): choices=[("Stage"), ("Alternance")], validators=[DataRequired(message=CHAMP_REQUIS)], ) - missions = _build_string_field("Missions") + missions = TextAreaField( + "Missions", validators=[DataRequired(message=CHAMP_REQUIS)] + ) duree = _build_string_field("Durée") depts = MultiCheckboxField("Départements", validators=[Optional()], coerce=int) expiration_date = DateField( @@ -171,7 +173,9 @@ class OffreModificationForm(FlaskForm): choices=[("Stage"), ("Alternance")], validators=[DataRequired(message=CHAMP_REQUIS)], ) - missions = _build_string_field("Missions") + missions = TextAreaField( + "Missions", validators=[DataRequired(message=CHAMP_REQUIS)] + ) duree = _build_string_field("Durée") depts = MultiCheckboxField("Départements", validators=[Optional()], coerce=int) expiration_date = DateField( diff --git a/app/templates/entreprises/contacts.html b/app/templates/entreprises/contacts.html index 7830f83a2..0437c2bc4 100644 --- a/app/templates/entreprises/contacts.html +++ b/app/templates/entreprises/contacts.html @@ -31,7 +31,7 @@ {% endif %} -
    +

    Liste des contacts

    AttributTypeDescription
    sirettextsiret de l'entreprise
    nomtextnom de l'entreprise
    nom_entreprisetextnom de l'entreprise
    adressetextadresse de l'entreprise
    villetextville de l'entreprise
    code_postaltextcode postal de l'entreprise
    diff --git a/app/templates/entreprises/entreprises.html b/app/templates/entreprises/entreprises.html index 8e2768c66..b48668e09 100644 --- a/app/templates/entreprises/entreprises.html +++ b/app/templates/entreprises/entreprises.html @@ -34,7 +34,7 @@ {% endif %} -
    +

    Liste des entreprises

    diff --git a/app/templates/entreprises/entreprises_validation.html b/app/templates/entreprises/entreprises_validation.html index a7fbf0c94..d37e2494d 100644 --- a/app/templates/entreprises/entreprises_validation.html +++ b/app/templates/entreprises/entreprises_validation.html @@ -22,7 +22,7 @@ {% endif %} -
    +

    Liste des entreprises à valider

    diff --git a/app/templates/entreprises/form_modification_entreprise.html b/app/templates/entreprises/form_modification_entreprise.html index c77cc12f8..47ce42e65 100644 --- a/app/templates/entreprises/form_modification_entreprise.html +++ b/app/templates/entreprises/form_modification_entreprise.html @@ -15,7 +15,7 @@
    - Informations de l'API Sirene + Informations de la base SIRENE
    diff --git a/app/templates/entreprises/offres_recues.html b/app/templates/entreprises/offres_recues.html index 2d3c9698e..a8814739f 100644 --- a/app/templates/entreprises/offres_recues.html +++ b/app/templates/entreprises/offres_recues.html @@ -23,7 +23,7 @@ {% endfor %}
    - supprimer + supprimer
    {% endfor %} From 117764d3da9f1206fdf2f70cfed2ee36db94af94 Mon Sep 17 00:00:00 2001 From: Arthur ZHU Date: Fri, 25 Feb 2022 09:47:42 +0100 Subject: [PATCH 111/287] corrections --- app/entreprises/app_relations_entreprises.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/entreprises/app_relations_entreprises.py b/app/entreprises/app_relations_entreprises.py index af06f6e18..1a7480058 100644 --- a/app/entreprises/app_relations_entreprises.py +++ b/app/entreprises/app_relations_entreprises.py @@ -172,9 +172,14 @@ def verif_entreprise_data(entreprise_data): """ Verifie les données d'une ligne Excel (entreprise) """ - for data in entreprise_data[1:]: # champs obligatoires - if data == "": - return False + if EntreprisePreferences.get_check_siret(): + for data in entreprise_data: # champs obligatoires + if data == "": + return False + else: + for data in entreprise_data[1:]: # champs obligatoires + if data == "": + return False if EntreprisePreferences.get_check_siret(): siret = entreprise_data[0].strip() # vérification sur le siret if re.match("^\d{14}$", siret) is None: From 9bc5f27b165395b7f7a32e977dbe0700d694c089 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Fri, 25 Feb 2022 10:30:57 +0100 Subject: [PATCH 112/287] moduleimpl_withmodule_list (api ScoDoc 7 compat): fix --- app/views/notes.py | 2 +- sco_version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/notes.py b/app/views/notes.py index 7be106444..cd211ca05 100644 --- a/app/views/notes.py +++ b/app/views/notes.py @@ -2686,7 +2686,7 @@ def moduleimpl_list( @permission_required(Permission.ScoView) @scodoc7func def moduleimpl_withmodule_list( - moduleimpl_id=None, formsemestre_id=None, module_id=None + moduleimpl_id=None, formsemestre_id=None, module_id=None, format="json" ): """API ScoDoc 7""" data = sco_moduleimpl.moduleimpl_withmodule_list( diff --git a/sco_version.py b/sco_version.py index 5c1b87f2e..1bdc8323b 100644 --- a/sco_version.py +++ b/sco_version.py @@ -1,7 +1,7 @@ # -*- mode: python -*- # -*- coding: utf-8 -*- -SCOVERSION = "9.1.63" +SCOVERSION = "9.1.64" SCONAME = "ScoDoc" From 46eb1185d61e064ebc16da07674fbd93eaee9aa3 Mon Sep 17 00:00:00 2001 From: Arthur ZHU Date: Fri, 25 Feb 2022 10:40:51 +0100 Subject: [PATCH 113/287] fix --- app/entreprises/app_relations_entreprises.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/entreprises/app_relations_entreprises.py b/app/entreprises/app_relations_entreprises.py index 1a7480058..68ff99865 100644 --- a/app/entreprises/app_relations_entreprises.py +++ b/app/entreprises/app_relations_entreprises.py @@ -195,4 +195,4 @@ def verif_entreprise_data(entreprise_data): entreprise = Entreprise.query.filter_by(siret=siret).first() if entreprise is not None: return False - return True + return True From aa609aa0cf44a800ae6ad5aa93bf8c47652947df Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sat, 26 Feb 2022 10:09:14 +0100 Subject: [PATCH 114/287] =?UTF-8?q?Am=C3=A9liore=20form.=20logos=20(valida?= =?UTF-8?q?tion=20des=20noms)=20+=20messages=20flash?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/forms/main/config_logos.py | 34 +++++++++++++++++++--------------- app/scodoc/sco_utils.py | 12 +++++++++++- app/templates/base.html | 10 ++++------ app/templates/sco_page.html | 10 ++++------ 4 files changed, 38 insertions(+), 28 deletions(-) diff --git a/app/forms/main/config_logos.py b/app/forms/main/config_logos.py index 2be78713d..c89983271 100644 --- a/app/forms/main/config_logos.py +++ b/app/forms/main/config_logos.py @@ -30,17 +30,15 @@ Formulaires configuration logos Contrib @jmp, dec 21 """ -import re from flask import flash, url_for, redirect, render_template from flask_wtf import FlaskForm from flask_wtf.file import FileField, FileAllowed -from wtforms import SelectField, SubmitField, FormField, validators, FieldList +from wtforms import SubmitField, FormField, validators, FieldList +from wtforms import ValidationError from wtforms.fields.simple import StringField, HiddenField -from app import AccessDenied from app.models import Departement -from app.models import ScoDocSiteConfig from app.scodoc import sco_logos, html_sco_header from app.scodoc import sco_utils as scu from app.scodoc.sco_config_actions import ( @@ -49,10 +47,11 @@ from app.scodoc.sco_config_actions import ( LogoInsert, ) -from flask_login import current_user +from app.scodoc import sco_utils as scu from app.scodoc.sco_logos import find_logo + JAVASCRIPTS = html_sco_header.BOOTSTRAP_MULTISELECT_JS + [] CSSSTYLES = html_sco_header.BOOTSTRAP_MULTISELECT_CSS @@ -111,6 +110,15 @@ def dept_key_to_id(dept_key): return dept_key +def logo_name_validator(message=None): + def validate_logo_name(form, field): + name = field.data if field.data else "" + if not scu.is_valid_filename(name): + raise ValidationError(message) + + return validate_logo_name + + class AddLogoForm(FlaskForm): """Formulaire permettant l'ajout d'un logo (dans un département)""" @@ -118,11 +126,7 @@ class AddLogoForm(FlaskForm): name = StringField( label="Nom", validators=[ - validators.regexp( - r"^[a-zA-Z0-9-_]*$", - re.IGNORECASE, - "Ne doit comporter que lettres, chiffres, _ ou -", - ), + logo_name_validator("Nom de logo invalide (alphanumérique, _)"), validators.Length( max=20, message="Un nom ne doit pas dépasser 20 caractères" ), @@ -373,11 +377,11 @@ def config_logos(): if action: action.execute() flash(action.message) - return redirect( - url_for( - "scodoc.configure_logos", - ) - ) + return redirect(url_for("scodoc.configure_logos")) + else: + if not form.validate(): + scu.flash_errors(form) + return render_template( "config_logos.html", scodoc_dept=None, diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py index 1cc6e89c0..b3d99ac3e 100644 --- a/app/scodoc/sco_utils.py +++ b/app/scodoc/sco_utils.py @@ -50,7 +50,7 @@ import pydot import requests from flask import g, request -from flask import url_for, make_response, jsonify +from flask import flash, url_for, make_response, jsonify from config import Config from app import log @@ -616,6 +616,16 @@ def bul_filename(sem, etud, format): return filename +def flash_errors(form): + """Flashes form errors (version sommaire)""" + for field, errors in form.errors.items(): + flash( + "Erreur: voir le champs %s" % (getattr(form, field).label.text,), + "warning", + ) + # see https://getbootstrap.com/docs/4.0/components/alerts/ + + def sendCSVFile(data, filename): # DEPRECATED utiliser send_file """publication fichier CSV.""" return send_file(data, filename=filename, mime=CSV_MIMETYPE, attached=True) diff --git a/app/templates/base.html b/app/templates/base.html index adf70171b..c4083a53c 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -57,12 +57,10 @@ {% block content %}
    - {% with messages = get_flashed_messages() %} - {% if messages %} - {% for message in messages %} - - {% endfor %} - {% endif %} + {% with messages = get_flashed_messages(with_categories=true) %} + {% for category, message in messages %} + + {% endfor %} {% endwith %} {# application content needs to be provided in the app_content block #} diff --git a/app/templates/sco_page.html b/app/templates/sco_page.html index d3fbdcf87..e1aa9e3c5 100644 --- a/app/templates/sco_page.html +++ b/app/templates/sco_page.html @@ -23,12 +23,10 @@
    - {% with messages = get_flashed_messages() %} - {% if messages %} - {% for message in messages %} - - {% endfor %} - {% endif %} + {% with messages = get_flashed_messages(with_categories=true) %} + {% for category, message in messages %} + + {% endfor %} {% endwith %}
    {% if sco.sem %} From 9b27503d019ce6a85ce6af748d7a82e300ec5437 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sat, 26 Feb 2022 10:15:00 +0100 Subject: [PATCH 115/287] Fix: gestion logos --- app/scodoc/sco_logos.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/scodoc/sco_logos.py b/app/scodoc/sco_logos.py index 46e0c066a..02272ce87 100644 --- a/app/scodoc/sco_logos.py +++ b/app/scodoc/sco_logos.py @@ -151,6 +151,8 @@ class Logo: Le format est renseigné au moment de la lecture (select) ou de la création (create) de l'objet """ self.logoname = secure_filename(logoname) + if not self.logoname: + self.logoname = "*** *** nom de logo invalide *** à changer ! *** ***" self.scodoc_dept_id = dept_id self.prefix = prefix or "" if self.scodoc_dept_id: From dbab59039c7c2a8abe1e625027c8e7c622809d94 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sat, 26 Feb 2022 11:00:08 +0100 Subject: [PATCH 116/287] Fix: recherche images fond de page (logos) --- app/scodoc/sco_pdf.py | 8 ++++++-- app/scodoc/sco_pvpdf.py | 6 ++++++ sco_version.py | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/app/scodoc/sco_pdf.py b/app/scodoc/sco_pdf.py index 0e0996800..3949f50a9 100755 --- a/app/scodoc/sco_pdf.py +++ b/app/scodoc/sco_pdf.py @@ -220,12 +220,16 @@ class ScolarsPageTemplate(PageTemplate): PageTemplate.__init__(self, "ScolarsPageTemplate", [content]) self.logo = None logo = find_logo( - logoname="bul_pdf_background", dept_id=g.scodoc_dept_id, prefix=None + logoname="bul_pdf_background", dept_id=g.scodoc_dept_id + ) or find_logo( + logoname="bul_pdf_background", dept_id=g.scodoc_dept_id, prefix="" ) if logo is None: # Also try to use PV background logo = find_logo( - logoname="letter_background", dept_id=g.scodoc_dept_id, prefix=None + logoname="letter_background", dept_id=g.scodoc_dept_id + ) or find_logo( + logoname="letter_background", dept_id=g.scodoc_dept_id, prefix="" ) if logo is not None: self.background_image_filename = logo.filepath diff --git a/app/scodoc/sco_pvpdf.py b/app/scodoc/sco_pvpdf.py index 1fb98e3d3..2e8cdaf66 100644 --- a/app/scodoc/sco_pvpdf.py +++ b/app/scodoc/sco_pvpdf.py @@ -206,12 +206,18 @@ class CourrierIndividuelTemplate(PageTemplate): background = find_logo( logoname="pvjury_background", dept_id=g.scodoc_dept_id, + ) or find_logo( + logoname="pvjury_background", + dept_id=g.scodoc_dept_id, prefix="", ) else: background = find_logo( logoname="letter_background", dept_id=g.scodoc_dept_id, + ) or find_logo( + logoname="letter_background", + dept_id=g.scodoc_dept_id, prefix="", ) if not self.background_image_filename and background is not None: diff --git a/sco_version.py b/sco_version.py index 1bdc8323b..7eaec052d 100644 --- a/sco_version.py +++ b/sco_version.py @@ -1,7 +1,7 @@ # -*- mode: python -*- # -*- coding: utf-8 -*- -SCOVERSION = "9.1.64" +SCOVERSION = "9.1.65" SCONAME = "ScoDoc" From c1c9f22a319c5b3dfe0b0e0d4de5a3dcce1c4926 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sat, 26 Feb 2022 20:11:22 +0100 Subject: [PATCH 117/287] exception -handling --- app/scodoc/sco_find_etud.py | 6 +++++- sco_version.py | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/scodoc/sco_find_etud.py b/app/scodoc/sco_find_etud.py index 157cb6e59..4bc039baa 100644 --- a/app/scodoc/sco_find_etud.py +++ b/app/scodoc/sco_find_etud.py @@ -39,6 +39,7 @@ from app.scodoc.gen_tables import GenTable from app.scodoc import html_sco_header from app.scodoc import sco_etud from app.scodoc import sco_groups +from app.scodoc.sco_exceptions import ScoException from app.scodoc.sco_permissions import Permission from app.scodoc import sco_preferences @@ -221,7 +222,10 @@ def search_etuds_infos(expnom=None, code_nip=None): cnx = ndb.GetDBConnexion() if expnom and not may_be_nip: expnom = expnom.upper() # les noms dans la BD sont en uppercase - etuds = sco_etud.etudident_list(cnx, args={"nom": expnom}, test="~") + try: + etuds = sco_etud.etudident_list(cnx, args={"nom": expnom}, test="~") + except ScoException: + etuds = [] else: code_nip = code_nip or expnom if code_nip: diff --git a/sco_version.py b/sco_version.py index 7eaec052d..b47a266d7 100644 --- a/sco_version.py +++ b/sco_version.py @@ -1,7 +1,7 @@ # -*- mode: python -*- # -*- coding: utf-8 -*- -SCOVERSION = "9.1.65" +SCOVERSION = "9.1.66" SCONAME = "ScoDoc" From c0494d8d71af1aa062d387ed0fe28319b60ace6a Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sat, 26 Feb 2022 20:22:18 +0100 Subject: [PATCH 118/287] exception handling (export Apo) --- app/scodoc/sco_apogee_csv.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/scodoc/sco_apogee_csv.py b/app/scodoc/sco_apogee_csv.py index e7710a910..b1482ec5b 100644 --- a/app/scodoc/sco_apogee_csv.py +++ b/app/scodoc/sco_apogee_csv.py @@ -98,7 +98,7 @@ from chardet import detect as chardet_detect from app import log from app.comp import res_sem from app.comp.res_common import NotesTableCompat -from app.models import FormSemestre +from app.models import FormSemestre, Identite from app.models.config import ScoDocSiteConfig import app.scodoc.sco_utils as scu from app.scodoc.sco_exceptions import ScoValueError, ScoFormatError @@ -111,7 +111,6 @@ from app.scodoc.sco_codes_parcours import ( NAR, RAT, ) -from app.scodoc import sco_cache from app.scodoc import sco_formsemestre from app.scodoc import sco_parcours_dut from app.scodoc import sco_etud @@ -454,6 +453,12 @@ class ApoEtud(dict): def comp_elt_semestre(self, nt, decision, etudid): """Calcul résultat apo semestre""" + if decision is None: + etud = Identite.query.get(etudid) + nomprenom = etud.nomprenom if etud else "(inconnu)" + raise ScoValueError( + f"decision absente pour l'étudiant {nomprenom} ({etudid})" + ) # resultat du semestre decision_apo = ScoDocSiteConfig.get_code_apo(decision["code"]) note = nt.get_etud_moy_gen(etudid) From 40f823ee7c5f4cd453d44a7ecc363ca9eeb4325d Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sat, 26 Feb 2022 20:35:34 +0100 Subject: [PATCH 119/287] Fix: edition module --- app/scodoc/sco_edit_module.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/scodoc/sco_edit_module.py b/app/scodoc/sco_edit_module.py index 2bedc0c11..9ea4e2fe7 100644 --- a/app/scodoc/sco_edit_module.py +++ b/app/scodoc/sco_edit_module.py @@ -551,7 +551,11 @@ def module_edit(module_id=None): # ne propose pas SAE et Ressources, sauf si déjà de ce type... module_types = ( set(scu.ModuleType) - {scu.ModuleType.RESSOURCE, scu.ModuleType.SAE} - ) | {a_module.module_type or scu.ModuleType.STANDARD} + ) | { + scu.ModuleType(a_module.module_type) + if a_module.module_type + else scu.ModuleType.STANDARD + } descr = [ ( From 1dfccb67371ea0e0730acbb99603c934275e2b6c Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sun, 27 Feb 2022 09:45:15 +0100 Subject: [PATCH 120/287] Modif bonus Roanne --- app/comp/bonus_spo.py | 1 + 1 file changed, 1 insertion(+) diff --git a/app/comp/bonus_spo.py b/app/comp/bonus_spo.py index 0a95621e8..18c57beb0 100644 --- a/app/comp/bonus_spo.py +++ b/app/comp/bonus_spo.py @@ -705,6 +705,7 @@ class BonusRoanne(BonusSportAdditif): seuil_moy_gen = 0.0 bonus_max = 0.6 # plafonnement à 0.6 points classic_use_bonus_ues = True # sur les UE, même en DUT et LP + proportion_point = 1 class BonusStDenis(BonusSportAdditif): From 091d34dd8811db144a0343932e88f52dfc54604d Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sun, 27 Feb 2022 10:19:25 +0100 Subject: [PATCH 121/287] =?UTF-8?q?Am=C3=A9liore=20creation=20UE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/scodoc/sco_edit_ue.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/app/scodoc/sco_edit_ue.py b/app/scodoc/sco_edit_ue.py index 061bf43c6..7124d3c30 100644 --- a/app/scodoc/sco_edit_ue.py +++ b/app/scodoc/sco_edit_ue.py @@ -29,7 +29,7 @@ """ import flask -from flask import url_for, render_template +from flask import flash, render_template, url_for from flask import g, request from flask_login import current_user @@ -107,8 +107,6 @@ def ue_list(*args, **kw): def do_ue_create(args): "create an ue" - from app.scodoc import sco_formations - cnx = ndb.GetDBConnexion() # check duplicates ues = ue_list({"formation_id": args["formation_id"], "acronyme": args["acronyme"]}) @@ -117,6 +115,14 @@ def do_ue_create(args): f"""Acronyme d'UE "{args['acronyme']}" déjà utilisé ! (chaque UE doit avoir un acronyme unique dans la formation)""" ) + if not "ue_code" in args: + # évite les conflits de code + while True: + cursor = db.session.execute("select notes_newid_ucod();") + code = cursor.fetchone()[0] + if UniteEns.query.filter_by(ue_code=code).count() == 0: + break + args["ue_code"] = code # create ue_id = _ueEditor.create(cnx, args) @@ -128,6 +134,8 @@ def do_ue_create(args): formation = Formation.query.get(args["formation_id"]) formation.invalidate_module_coefs() # news + ue = UniteEns.query.get(ue_id) + flash(f"UE créée (code {ue.ue_code})") formation = Formation.query.get(args["formation_id"]) sco_news.add( typ=sco_news.NEWS_FORM, From 6b8410e43b4ddecc712c4fbbe39a622e17340e89 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sun, 27 Feb 2022 17:49:39 +0100 Subject: [PATCH 122/287] cosmetic: edit prog. --- app/scodoc/sco_edit_ue.py | 3 ++- app/static/css/scodoc.css | 10 +++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/scodoc/sco_edit_ue.py b/app/scodoc/sco_edit_ue.py index 7124d3c30..8f9488557 100644 --- a/app/scodoc/sco_edit_ue.py +++ b/app/scodoc/sco_edit_ue.py @@ -754,6 +754,7 @@ du programme" (menu "Semestre") si vous avez un semestre en cours); ) ) else: + H.append('
    ') H.append( _ue_table_ues( parcours, @@ -783,7 +784,7 @@ du programme" (menu "Semestre") si vous avez un semestre en cours); """ ) - + H.append("
    ") H.append("
    ") # formation_ue_list if ues_externes: diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css index ecd8b0ab0..b74eba0e3 100644 --- a/app/static/css/scodoc.css +++ b/app/static/css/scodoc.css @@ -1703,8 +1703,11 @@ ul.notes_ue_list { padding-bottom: 1em; font-weight: bold; } +.formation_classic_infos ul.notes_ue_list { + padding-top: 0px; +} -li.notes_ue_list { +.formation_classic_infos li.notes_ue_list { margin-top: 9px; list-style-type: none; border: 1px solid maroon; @@ -1761,6 +1764,11 @@ ul.notes_module_list { font-style: normal; } +div.ue_list_tit_sem { + font-size: 120%; + font-weight: bold; +} + .notes_ue_list a.stdlink { color: #001084; text-decoration: underline; From 29b5d54d222df3cc334a4bca4c2a3023916e8d3d Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sun, 27 Feb 2022 20:12:20 +0100 Subject: [PATCH 123/287] =?UTF-8?q?Prise=20en=20compte=20UE=20capitalis?= =?UTF-8?q?=C3=A9es=20lorsque=20non=20inscrit=20dans=20le=20sem.=20courant?= =?UTF-8?q?.=20Affichage=20sur=20bulletins=20classiques.=20Capitalisation?= =?UTF-8?q?=20en=20BUT=20avec=20ECTS.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/comp/res_common.py | 61 +++++++++++++++++----- app/models/moduleimpls.py | 31 +++++++++-- app/scodoc/sco_bulletins.py | 8 +-- app/scodoc/sco_codes_parcours.py | 2 +- app/scodoc/sco_formsemestre_status.py | 2 +- app/scodoc/sco_formsemestre_validation.py | 10 ++-- app/scodoc/sco_parcours_dut.py | 4 +- app/static/css/scodoc.css | 6 +-- app/static/icons/scologo_img.png | Bin 12724 -> 37970 bytes app/views/notes.py | 25 +++++---- 10 files changed, 108 insertions(+), 41 deletions(-) diff --git a/app/comp/res_common.py b/app/comp/res_common.py index f13201262..7fa75c1b7 100644 --- a/app/comp/res_common.py +++ b/app/comp/res_common.py @@ -9,18 +9,22 @@ from functools import cached_property import numpy as np import pandas as pd +from flask import g, url_for + from app import log from app.comp.aux_stats import StatsMoyenne from app.comp import moy_sem from app.comp.res_cache import ResultatsCache from app.comp import res_sem from app.comp.moy_mod import ModuleImplResults -from app.models import FormSemestre, Identite, ModuleImpl -from app.models import FormSemestreUECoef +from app.models import FormSemestre, FormSemestreUECoef +from app.models import Identite +from app.models import ModuleImpl, ModuleImplInscription from app.models.ues import UniteEns from app.scodoc import sco_utils as scu from app.scodoc.sco_cache import ResultatsSemestreCache from app.scodoc.sco_codes_parcours import UE_SPORT, DEF +from app.scodoc.sco_exceptions import ScoValueError # Il faut bien distinguer # - ce qui est caché de façon persistente (via redis): @@ -206,12 +210,18 @@ class ResultatsSemestre(ResultatsCache): 0.0, min(self.etud_moy_gen[etudid], 20.0) ) - def _get_etud_ue_cap(self, etudid, ue): - """""" + def _get_etud_ue_cap(self, etudid: int, ue: UniteEns) -> dict: + """Donne les informations sur la capitalisation de l'UE ue pour cet étudiant. + Résultat: + Si pas capitalisée: None + Si capitalisée: un dict, avec les colonnes de validation. + """ capitalisations = self.validations.ue_capitalisees.loc[etudid] if isinstance(capitalisations, pd.DataFrame): ue_cap = capitalisations[capitalisations["ue_code"] == ue.ue_code] - if isinstance(ue_cap, pd.DataFrame) and not ue_cap.empty: + if ue_cap.empty: + return None + if isinstance(ue_cap, pd.DataFrame): # si plusieurs fois capitalisée, prend le max cap_idx = ue_cap["moy_ue"].values.argmax() ue_cap = ue_cap.iloc[cap_idx] @@ -219,8 +229,9 @@ class ResultatsSemestre(ResultatsCache): if capitalisations["ue_code"] == ue.ue_code: ue_cap = capitalisations else: - ue_cap = None - return ue_cap + return None + # converti la Series en dict, afin que les np.int64 reviennent en int + return ue_cap.to_dict() def get_etud_ue_status(self, etudid: int, ue_id: int) -> dict: """L'état de l'UE pour cet étudiant. @@ -253,17 +264,41 @@ class ResultatsSemestre(ResultatsCache): ) if etudid in self.validations.ue_capitalisees.index: ue_cap = self._get_etud_ue_cap(etudid, ue) - if ( - ue_cap is not None - and not ue_cap.empty - and not np.isnan(ue_cap["moy_ue"]) - ): + if ue_cap and not np.isnan(ue_cap["moy_ue"]): was_capitalized = True if ue_cap["moy_ue"] > cur_moy_ue or np.isnan(cur_moy_ue): moy_ue = ue_cap["moy_ue"] is_capitalized = True - coef_ue = self.etud_coef_ue_df[ue_id][etudid] + # Coef l'UE dans le semestre courant: + if self.is_apc: + # utilise les ECTS comme coef. + coef_ue = ue.ects + else: + # formations classiques + coef_ue = self.etud_coef_ue_df[ue_id][etudid] + if (not coef_ue) and is_capitalized: # étudiant non inscrit dans l'UE courante + if self.is_apc: + # Coefs de l'UE capitalisée en formation APC: donné par ses ECTS + ue_capitalized = UniteEns.query.get(ue_cap["ue_id"]) + coef_ue = ue_capitalized.ects + if coef_ue is None: + orig_sem = FormSemestre.query.get(ue_cap["formsemestre_id"]) + raise ScoValueError( + f"""L'UE capitalisée {ue_capitalized.acronyme} + du semestre {orig_sem.titre_annee()} + n'a pas d'indication d'ECTS. + Corrigez ou faite corriger le programme + via cette page. + """ + ) + else: + # Coefs de l'UE capitalisée en formation classique: + # va chercher le coef dans le semestre d'origine + coef_ue = ModuleImplInscription.sum_coefs_modimpl_ue( + ue_cap["formsemestre_id"], etudid, ue_cap["ue_id"] + ) return { "is_capitalized": is_capitalized, diff --git a/app/models/moduleimpls.py b/app/models/moduleimpls.py index 700dec26e..0aa74ef4b 100644 --- a/app/models/moduleimpls.py +++ b/app/models/moduleimpls.py @@ -2,6 +2,7 @@ """ScoDoc models: moduleimpls """ import pandas as pd +import flask_sqlalchemy from app import db from app.comp import df_cache @@ -129,14 +130,36 @@ class ModuleImplInscription(db.Model): ) @classmethod - def nb_inscriptions_dans_ue( + def etud_modimpls_in_ue( cls, formsemestre_id: int, etudid: int, ue_id: int - ) -> int: - """Nombre de moduleimpls de l'UE auxquels l'étudiant est inscrit""" + ) -> flask_sqlalchemy.BaseQuery: + """moduleimpls de l'UE auxquels l'étudiant est inscrit""" return ModuleImplInscription.query.filter( ModuleImplInscription.etudid == etudid, ModuleImplInscription.moduleimpl_id == ModuleImpl.id, ModuleImpl.formsemestre_id == formsemestre_id, ModuleImpl.module_id == Module.id, Module.ue_id == ue_id, - ).count() + ) + + @classmethod + def nb_inscriptions_dans_ue( + cls, formsemestre_id: int, etudid: int, ue_id: int + ) -> int: + """Nombre de moduleimpls de l'UE auxquels l'étudiant est inscrit""" + return cls.etud_modimpls_in_ue(formsemestre_id, etudid, ue_id).count() + + @classmethod + def sum_coefs_modimpl_ue( + cls, formsemestre_id: int, etudid: int, ue_id: int + ) -> float: + """Somme des coefficients des modules auxquels l'étudiant est inscrit + dans l'UE du semestre indiqué. + N'utilise que les coefficients, donc inadapté aux formations APC. + """ + return sum( + [ + inscr.modimpl.module.coefficient + for inscr in cls.etud_modimpls_in_ue(formsemestre_id, etudid, ue_id) + ] + ) diff --git a/app/scodoc/sco_bulletins.py b/app/scodoc/sco_bulletins.py index ca6748de7..a5d84cf4f 100644 --- a/app/scodoc/sco_bulletins.py +++ b/app/scodoc/sco_bulletins.py @@ -291,15 +291,17 @@ def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"): I["matieres_modules"] = {} I["matieres_modules_capitalized"] = {} for ue in ues: + u = ue.copy() + ue_status = nt.get_etud_ue_status(etudid, ue["ue_id"]) if ( ModuleImplInscription.nb_inscriptions_dans_ue( formsemestre_id, etudid, ue["ue_id"] ) == 0 - ): + ) and not ue_status["is_capitalized"]: + # saute les UE où l'on est pas inscrit et n'avons pas de capitalisation continue - u = ue.copy() - ue_status = nt.get_etud_ue_status(etudid, ue["ue_id"]) + u["ue_status"] = ue_status # { 'moy', 'coef_ue', ...} if ue["type"] != sco_codes_parcours.UE_SPORT: u["cur_moy_ue_txt"] = scu.fmt_note(ue_status["cur_moy_ue"]) diff --git a/app/scodoc/sco_codes_parcours.py b/app/scodoc/sco_codes_parcours.py index f6ca2ff29..bcd6522b1 100644 --- a/app/scodoc/sco_codes_parcours.py +++ b/app/scodoc/sco_codes_parcours.py @@ -282,7 +282,7 @@ class TypeParcours(object): return [ ue_status for ue_status in ues_status - if ue_status["coef_ue"] > 0 + if ue_status["coef_ue"] and isinstance(ue_status["moy"], float) and ue_status["moy"] < self.get_barre_ue(ue_status["ue"]["type"]) ] diff --git a/app/scodoc/sco_formsemestre_status.py b/app/scodoc/sco_formsemestre_status.py index 2c8465150..4bfa7b725 100644 --- a/app/scodoc/sco_formsemestre_status.py +++ b/app/scodoc/sco_formsemestre_status.py @@ -1078,7 +1078,7 @@ def formsemestre_status(formsemestre_id=None): "

    ", ] - if use_ue_coefs: + if use_ue_coefs and not formsemestre.formation.is_apc(): H.append( """

    utilise les coefficients d'UE pour calculer la moyenne générale.

    diff --git a/app/scodoc/sco_formsemestre_validation.py b/app/scodoc/sco_formsemestre_validation.py index 987dc962f..c83e1cc4d 100644 --- a/app/scodoc/sco_formsemestre_validation.py +++ b/app/scodoc/sco_formsemestre_validation.py @@ -585,15 +585,17 @@ def formsemestre_recap_parcours_table( else: H.append('
    ') H.append('' % ass) # abs - # acronymes UEs auxquelles l'étudiant est inscrit: - # XXX il est probable que l'on doive ici ajouter les - # XXX UE capitalisées + # acronymes UEs auxquelles l'étudiant est inscrit (ou capitalisé) ues = nt.get_ues_stat_dict(filter_sport=True) cnx = ndb.GetDBConnexion() + etud_ue_status = { + ue["ue_id"]: nt.get_etud_ue_status(etudid, ue["ue_id"]) for ue in ues + } ues = [ ue for ue in ues if etud_est_inscrit_ue(cnx, etudid, sem["formsemestre_id"], ue["ue_id"]) + or etud_ue_status[ue["ue_id"]]["is_capitalized"] ] for ue in ues: @@ -644,7 +646,7 @@ def formsemestre_recap_parcours_table( code = decisions_ue[ue["ue_id"]]["code"] else: code = "" - ue_status = nt.get_etud_ue_status(etudid, ue["ue_id"]) + ue_status = etud_ue_status[ue["ue_id"]] moy_ue = ue_status["moy"] if ue_status else "" explanation_ue = [] # list of strings if code == ADM: diff --git a/app/scodoc/sco_parcours_dut.py b/app/scodoc/sco_parcours_dut.py index d6e244e79..fbf190c52 100644 --- a/app/scodoc/sco_parcours_dut.py +++ b/app/scodoc/sco_parcours_dut.py @@ -139,9 +139,7 @@ class SituationEtudParcoursGeneric(object): # pour le DUT, le dernier est toujours S4. # Ici: terminal si semestre == NB_SEM ou bien semestre_id==-1 # (licences et autres formations en 1 seule session)) - self.semestre_non_terminal = ( - self.sem["semestre_id"] != self.parcours.NB_SEM - ) # True | False + self.semestre_non_terminal = self.sem["semestre_id"] != self.parcours.NB_SEM if self.sem["semestre_id"] == NO_SEMESTRE_ID: self.semestre_non_terminal = False # Liste des semestres du parcours de cet étudiant: diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css index b74eba0e3..bd99c80c6 100644 --- a/app/static/css/scodoc.css +++ b/app/static/css/scodoc.css @@ -287,15 +287,15 @@ div.logo-insidebar { width: 75px; /* la marge fait 130px */ } div.logo-logo { + margin-left: -5px; text-align: center ; } div.logo-logo img { box-sizing: content-box; - margin-top: -10px; - width: 128px; + margin-top: 10px; /* -10px */ + width: 135px; /* 128px */ padding-right: 5px; - margin-left: -75px; } div.sidebar-bottom { margin-top: 10px; diff --git a/app/static/icons/scologo_img.png b/app/static/icons/scologo_img.png index fb0467ae6dc06f2db5371963a391dcb5da83171b..5c710a76ae816308cd3b5ab46a840cea74ee3d6a 100644 GIT binary patch delta 37804 zcmV)gK%~F4W74Pse~C~|M-2)Z3IG5A4M|8uQUCw|fB*mhs|W@F006F4ls*6e0byxF zLr`l&M?-IHZ*o&`VPj=PX>)LFVR=w9001bFV_;xXNh~PHVPRlk$jvJ$3UYT+h=`0* zV1LNK4urf6Vhjq2$;AbZ0RcWhB@8ec6@0tKzzCu*>w?TWeR+Snlmtf!W^Rdb09b@8O6>Z#G3CjFxc+@|NsAP zgqYWU28NA5om@K+Vj30<41(MY3@3ILBo-xtg_wbuDJ_kG;nQ*k2Hr>p2H^`pJ<-K! z#ztUyMjj^y2G)E3|9@6vU|^rj!0>m%|Np-i{r~@W6){lr9R`L2c>on5W$rb{(fa@Z z0Cdus2l?&^Kt7pb+hR!g$H$VLKeY>3%%Z6{y|%V5Y#GP%zr^CWjHGPz9V zW=H}|5=i>-ZE@B7|eUDegK-rxJR#KSz3*xrDEAa1p1w5C_=gZx9pKotvrDuG6Jg0lEED+g zxm@lipKZ^cJzo9(_pd$w((A5#UuG+?d-rZX(*22lF#omN%jNF#NkR0t z#~ypk&$kzS{(Tpp`>$Q=|Fqv}v6kiIF$Dj(Sr!FI@8%94z5grMCl=y2&rHp1C@ZgA zD6g!VDvm@R3l|pb^?0^V>O<%?yLRnL>*ua#pRF#fu3pR*6=fg$-uK#@o0?L21qHJW zm6g%b*47y*joIyg+5gk6!Hez`E#w>VK0T@6&&DePdbve`%;GyLo(a%4(`B ztgtX*qhnK+&Sb2qBJ)31Zo2M;7oL3l?djC)r;_pbs?mwrSXWQC=jtt+ zs>1~lOQq6_o?Is3$!30U`>nU%%jG>-4BsWCc_TjS8~vVt%Sr)c?r&ea*4uf<9mz+& z_4QkPxy+|eo$uZp4w;pg7H5teJ)PaLW2+|^%C}TvF*iIs{}wuRWFojiTPj-BeZm2LI5c6Em(5=m2_un?cOmgZ(Fsi^;*hP7M%LIRN6xTFNK zBKD>?nPQE9JMOq6^F|BkwSNCMTmclU?fulJd^_*C=cj|Y{O^3_FXq~t>->*BbucqA zHkfN^Zt+Lw;}(e&T2*X{D#+E>FX_@7JvS}+VDY4GAt1Lf1?0kPPTw?7j!gl8L zaqAwOv_L56Idl9uzu)Jvp6>IOO6P21e8ftMi|xRnL$>dUC+x`=oILH9Z`tDc@JBx8 z9~~P{mX1yY8|!NC|K=C|^w)cP``@2SC2py!EV9YI^SQ1Ue)Roozz-gO zJQ&!zb!+P1i}3Y1URMj?qV$V9{^^JAyQOcS|IYrtf$JNpOIOy{RapkpJv=g%J9hHC zXL5YNmrZ9Zlg(hZ3$3xS$yTQ+%_>=bDyFO`~H*H3Fip=K=*x2}gxOMmRl3QeL+f{3AVx-^Bb`52BT)*A>(8G^d zIKL39QJvYesWa!zW&Pz9m6lB9usZ4QcmsvM+q_|0*G0GR@5UOuZWiF)yYCL{+PypV z;O9OU@>GYvG#{P2Yj$edqS3gWUsy;_Oig<#%FBKE`T2IsTdyNxU*vBKcD}2B*UHPw zZE|YDjvYOUInG%v!rpq#4m;UBXruE_8B(?A%s9fz+6dW!P@i4z_=s)Ua<%z=J}WLR zvBO7R;2N`b%gr}gd0DYdO^(}qY~CV;bKd#+x!inoHnW(@c~-4%_XSXvKq#D>n2u!@ z7UJHbaNfJ43-dP(oIdoChSght?$gfs>A+F{zFZ%#ivrwt-|fCT?)YNrzOR0@KAxL< zC_kNCH#sw%_67X8o}LT7Y&Pw`<)*iqkDVKvow54bYAYkMZ>Z1NnpN#KGq=F*t+1Jy zDTKCYeFMXG`a-WAKhtZYgTvM{KV~ais;#o7-r81duv9We;FbmXJ7e2_w_lBrBQ`%D zvm?(Rwx)&#+t}G*r%s)0@O@ zd8(qUxF9t@@lU6odHBxm>Gb=^8WwZ71kYve5?)gUkiTEM*8F$eu{-(s|MrJFr^dQ} zFgZ1u7tYU5HrH1K=VoVr?a;H&*e~66mz9;4nm3oR3QT+k&vb#EzpxOqbSh=#6}8S; zm7){@zu!WkJOu0`#cQ#h*Q~XiKVlwVo<-*u?8Nzgn;h-8zV6d(O25s{%v-j$$_fgK zEnHA!XU?9p#l(WOw6@qV3Q$r~Zi~bVS8ds5>pIusDm+|g)*g6&;6ZC?X~*@HgEiC# z;?q;vp7HL?nspoATUd}gbmXb0-i+|aF88?LHBo>|Q0v7!TB(&~(u?<$6cyzC<9!b& z-uAXz@(S}q&L^+EYKPU-NWfXEs;M!r*K6PW=6&|mqu;f>aJkKl57^qPuCsOPH&|PH zJ859Vu*;TQOq!Q}5FRdzhu;^p^123ZVOheP zSWF~KN{Tyu{?v(qlLtT4uy*VBl_hvQmnUZMsw#j4Us-v7(z9#V9WJ$d_~HBO$^%8= zSSGn{|GtN|7qi=%+c)J^mK0ckowk_tSY2JU^Xr2H1J+bmX}!I@mLM*8_b>mt6%qOS zeO`MGD=|A0vr%?zmY}dGT)=KFkZHDfJZ96=vnWo$!a<*HT-jjFHRblm!i>#MPule4 zgvA#YQ7{jG08pbG0@AV#e`nNrv>ppwA#ssfc7U03$`}lH# z|H5bfWMf@j)u+#eEEJG+&~65q zfA`z)-w7KWoyQHBP0!3&QBkp-IoD%-J>3YffgPD|dBLEq?c87`xQ*1}BEetE78cXI zHcJ4QLrGGWkcA)s)Cbhh(bxhp#I)sMd6J2Qtz5Cfy)H~zDFx{1>f+i#Yi?|?=E zOY}ZtGt<-N4~6mT5q9_#xqgWi78O}>X$1p3V#o59>buZhWxofXCBz=5n(HuSfwd3g1DeU;g}Oc6+_qdqP~%%Z`rD zOr+a8*7%ga_xBH2X>p;ax3Aw;tY|aREz-4V>s-CUrD-Fl`fc^f6?Xc>5gYEy#|$5| zJ>Po3Dr?)VsI-Vct&(6ciMh@*;x)^Edi-{hUAkgryA=WrcXgd-XBSvYTZZ>3wc7f6 zu>3)LV&7xL0U;D1Zi`?C8B$1GxCMfKJ4%4r*tSwTnR_tXwq-LZXE*mcXqz^4;v(iz zwn_5`^Kds2EKJH_#OXBFW+85;Pn|R%WnV!!Kb_4a{o}o(-#+)?xy>tgtz5)^6$Xia zTn}pT*7kJ;`+1 zzW>7?+JFAT-8MckZMWY1W?SF6l9VfG+qZ4B);c15Z_du0J8MrJIAM+L8*G-8(Cg1P z?c%YqA>2U`IeaO?TqNi-J9T=03E5L{7|P4H1i@j>(oUewjg7Wu^%_vav=x_?TTyux ze+yt;uma&C^B0ubiIZnhq@%Wf|9+bzOF9}~8aztB-GK7J`lQu z9VgdUnb-w-K5&E>LE+?o2-ltm0W84(r`g$E0{?8oRokqtq0NCx%K!7jg?6T^2ce&{ z-o63L%gf{LL%`4{aZ{%edXBiD*lO!)u|SJ9jPRudMZn7+`RK>&!~fwo$s*DysXvh7 z4N6NQzqaqY|MInc-`(>cBsi_la#sS3-_QThhXM%6e(BHttZZ<9u=iUNljC^{iKK_L z%v;J%d*}xblS3oagiLRW2)faV5VQp%RzMZclS^8KB6yI#3=5dR9PdAHfW7M>C9H$y z^%i@_EjMG{3#_fF(yIC0$rGor6dP(}F`b*#M?CkVGNpo)U=U?g9{uM7v0nlv!-o1N&v)i_I?cu@_VAT_zPSCnoERLB!XSFpI zEXoj(G^QC;?eK}y);~0hpndGnfZM?nnE1@fwAECWlE+WG>fPv6+-mBH(laqTe(bot z0Mxs>z1|KUIAj~i%NMB@&6CQlU)^Fw?95nfC1v8Moj-pL2$?JbvWLeXvRHh<9((v7 zt^A&U|4BVy6YgNae)!OX_P)D5O1kN>lJYWJyK0L?@&mS}vy;FvOk|m~k&$7nMj`ls z-_nRHNQyYk^^anGw9_lN*BOANGiT1)Tq@7vy_5F%<4;;Me_NmqkaDSEGr#w;!0mQ^IDtuK@mYOg_P4+5R(s*`A6RKo zfgOI{oQd`kvd8iBb6^BnK%6LMofS{zbXOq}ubbI;p6)k5L=*Is*__4Jc} zzmvmnA-^XJwAE|YI7nHzLp~NrxqUhju+hmmn+G@Aw7Juw#2h1oQG&)&tFEfVrxRk5 zjjUU<0*qn~lyTm^@poUayFT_wXKBuzJ#YS1AdcxpA2CZN63)A(YyXdL#A5ElZGsjq zKVr!%Qh;!N!6MQl2QMepTCjB+)|(%H`1Zp2^A;&fu=@%25NJtpfn`!LYig{sjq6w2 zs`h5LV0olh^Q2{UwGChaQ5!;03UU;K>g%k!y2gI%?hn|0cJRq#M_eJO2Nxp~uE1*o zaz|fJA0^>9J3Ik66tD`ILhIJ8BX%gZty`|btk+qXd&?lS%~+7ShGwhbD-oN2#saia zD)2i*P)Z=!SV}xNzF@m{UT0;I5Eg9O8e3LbCpg2z2o*=jD4{@r*r6R4BaT9;^$u@m zr|X_FHZeJk3+e-AuA;DIU>^hE6{R0wZ|>W>_fyLu6WAA_Otrkmq zZEn$HiDZU~+$scBZ2diF@ce0ib}J?xlrE50xMYG!=U5=jZJ6|K4C2NF0at_Vyl%7Y z`_cDM4zsJTy}`=LD{SYEZKQK6><14$V$VMPI1zXmHGvgY3JRz)uZJ{|5+1wS2fmQB zV<%47h7IcwPS_T3KWXws06SZ`YPFSB*13RgW@60Rus*uixx5e=Ny>_U@;z46vC6jR z6~H%$q0n=-YRzhb%t9L*=(6$QUJHXc@KzL&hOr10R$o`oJ(dwelv6$Iw;Y*DO?{)0 z{_^^$=lKKs!7}{U$~f-ZnDgZcOmvoA z8VmuT%#PXI!mO3#0wPv_P>nn5flv8BRaIF%U{YRQ(8fqjbG)xWqlLwsr>=R80TPuX_(B9fFGW~xkDogW zxEo@}XFl_p)F1!B@6^xD%zizwnDIo4OFi?kIZu=YYs2i0jEsV|1+5+76i@(4q&zk{ zJYaR;?4-;tLQf=rQdUgVolb$vcdT}G{zrfGeSEgpR;^xbEtG`|NFA$47fZ{lZE_|~ zDu+uU%~Oqk(^Xrk+BF06lv$YKP+l;^Ydz%qC?0MnsFE@N7C@x3@MlX#9gz#P8Z zECzEZjL;)kA(2pIJ;sK5+0CV(jb4N~WQlkb*N_MN3j|z$Rb!P@5EbWC5f2D)T(@Zx zzpJ4BkhLQODM~pP$xz0z5XBU-xChVT!d!l0KK_l*fAPx`%P}SVxh#OHeV|;a&wu{Q zb(8%k@5d~9{ehrZe7=(>j#!{+4u@BHH!l=ou}3TmUeMQjfo$Re z>J@^28&Cjqr-S%n1v{{WfNd55f*+(n;;*H{&^qN4~Ou>c-;bDEyyC0X(2t>_fAW@xiYr6Y**= z`b8rR6y%yyjlK-5orM(oS65wW<3P5BrFG^DhS~W;F3_7{Hww_HsA&LupSO{rZUVVt zI03abG&E%WP`y-huP7^G;p5JYY`%Jj31$s)og&B}O8?^Qz%UlTgHSvOS_K*@gCQn= z?LrvF{7pMHg9`|grIcavXIxMy!l2)u$8#ZjPK;u85Ljsq|I+XMC=wY3X5Oe#2)-7J zC>RJ@e2zE-kFkfZ{EmW$@@(% z|FpOgd|y_NpUDF3-o4Yed-vY-AN=lrC;!XB+~nJ%6hDA;Lxl*Tue-}q+pn{hmNq-r z-RDefC8UcA%x`z!814Z7yO0J$pJdnh?ZojTRPmC~ysB&rAs;*XoDKF>vcn6l6wF_O zo0*x#fBNA5jZ&`N&+F#^TiWOaXmv=S%y))*fOftQp&@C$`}hj7yP=I^J!Ia0(ko##tep$2gzHbj%E?e|^X0()5mX2c zUeC}t2;HRhcb^4@Enxv;)^p)3ubHte+jbDZ)e;=`IscqN88T!B0fMeZubx75!GtijL27zbc~1buNp?OIv`w zdlkTB`?}8DR1_&9J1R_n%}tL3_ZRRH1?}=j?CRm8$MCf|YiVk8rW8v~07m`~Tc;G5 zxUpp=nEdnP)7|DRsJH&!E^6^jR=M#i8yp;aiTZK~BgL){6VWRomy+Zt)JU0%ORHTF$FER-Kp;L8CN@2e;A?SD zSP6D@9_ga2L>2{15=bs4Qz&4F*OT`X#Hpew^f7?&Jp?X5zV6GLBcSAS>NPFRE#`YO z*#s8j9E6us6qLrN=j`i$_s@3M`|h&hyvTc4$IqL6YT4|5X`qDrqL00o{^|*BALxgv z8;5H*MY)x-=s1mk6^}pi4GJZ_*0FYz9Y1oAMGI3kBfVosE61K^7j&-au;$uwJAdYs z6_nPxx_|%Bgk3m$oYZcVf{)*|Y>C-ZNdd+eECAt4*~D}d;m@$>5I)&yitfcC((Y3g zQ6*wo0l5LWg)G09I?DG4C=$v4D>#J1=gfSJsD5H>n6wms)q?yP%E!_G^yI-0$ivqc zmQ?fe5_?$jfZU2qzg$5E<%xkH0`Q;=vo2G?=DhQR6a1!O9bEVDWqLD z#Daw)We8}0vmH6`n6<9iYAe?5;MqA!sy?hiA^f^p$R88d0P(XPI+eKorDZFeP#%Be zA?w1dPtQcHhIk=DDmMXiJWFuc(9q;^^DN*J(nqigy7aR&7U4+&2*gyo2U|mUN&`v# zsM#ZXS0PNGC|O*C8bkaZ#Q>yoSfh%ndK8KH!3B+f9;^jv9qF2`1964eqrkZlbr_36 z7KRTXS5ZW;m(GY%#^1?HRez9j#duF4jUoO$Gp#hY*tT7_10_q7-p<;GKm1`2F-MBj zIFOg;UBdz$X=`iK#^X-k_{Yzz0QlByB^@~jpM4Tx))C34iRf$W>Kkrm7f-W0X5CI3 zAvczPr1J68LfTYlnPLYtkQr>8006eg;3e;v)~ouqk}wux5x_E;YGv_LM1`E8Y}=+3kao2iD~{yZKmYSTc}hwvrG&1pFdB_68#wqS6=3I1I%f9* z;>?aG%Gd=PHeUnU>BUDPSWI4J!)k&o%r;Jc4xc~F@1~)06&BXG;7#@O1m4X0B+ijH*|o9goJ|vuh1u0~khrKmgYYw%loO-^Xt{xW zVfg%BUyA0J2%jP67TEVLh*a*cKo!ryb94>4g9Hjf!pN6-fv~Uu4hN7JNdeUsR$2z> z1N=ZcJ-Hais)%M5aGZt3g(#nODGN}4RuCl4kRs^X%q=1SZl|#%MyAu@6y@;qhggeJ zujUg3!;ul*)plN-bEKc&=*LScfbG3_i`mrkG-ckUMoTqkgxDSO_gefQ%AkeF59e8e zUD~aFK9r@luErWj-^L(lE+$tZl&rmJ*PCo~sGt0~+&bD@fN=p{`0^r^7`=LbDzhf= ztuwHO7oFc ze2F}w-5dgNQZ^wAqTfm23ivXZbPuitm&a8pZY5|s;dl82ieWGY85{+E9?ZU8>jFY4 z2rfnzsG8=M3CN@e_CE)!7?>D;jB4l3H~CVT+|g|}-u#qS)3b~QPskU&=;K6Xr88Gl z(jHN79)V8)6Pul$7$SWmXXZmI=*nkt^;N>|kpPE*b4C8R_UbJxUa>Qg{k`3QIfZup zjvHCbJcLb_z|NuDhHDTzkXgtQ2mQYI!mNlK?+&H+9MOp!i+i|Yg@1n`nD zq=>Rm;`ilYCFDYss;Q1o6R1n&lKeailBhUArW*}n_v1%MCA|RwOiRdOidaK&flU4! zR!w|E`FrLGkTnn-Vimk}4fz6OCA=yRcOZ=;agu z>V96b7<7`+YCCuC^#9|3zkGLO^@`U0Wu+DG$A5a}X2x^z=%go7QUm9XTpfWZ#}+DA zK!A9Ply9D940QlOk8&wrnnnKhKm8p|oORaLwvwHf0Sz2*O&MpPh{`1lN;$6y1^OpFi{)LC(PtsQ#i5mLp~5Ih>l>!D$-?X(k} zSKFSi{kg5%dW$1glo0_|vty(juEPgkNih|HEUl4tsZ6tWxW2?66yg^q1MvrdTq(}X z&CT!~v|i8gvTJ$%9I=E5pCRr|mS7yR27dm|f6v&+V6L>hoLWhc!q0@Yv$N!T zg}>J~w%hQ3K);O+oVWJ1+t_JQ>*;|S#;)0a;3))lqrK-n@3rmMY^MjXn>EASC$b=P z_~Q^31fQLyy5<5lfFA8cA#&QyDTo~^@9LjkOmHSc>_JMFR8WT*SA{N$iI-bi#HGl% ziCQKhm4OOMp@xS?Z2kImuD?Lfk$`7NLlsEoQ_#wPsIGt#@CIC)_<;9Qs3C<>JfW(f zVjlN9JrA;r0z|nG#SLVFye?#ubU~>l{km(fwi|Z*HRbGjyoeucnTHf$89nq_{>{fF z;s4erKDv(f$zwEU5^RTxDvAEyOPZl?pdw!W^8=O!I~UtL*7 zLXf1AM->x+3P4hz7b&jf=MX&z%p!vHseS-|0Ysv?3FK1AS@$+HIEY&Vy@Vn*On^HV zop*&IbsI-#r_xk0{bQ4J-)dQZ%`YyuPU07}0G*xVQ~}NMecp9q_p&${%qdYHiv#aY z0v!S!)buUY&M%xf3az^e9~rRTbI%hLVWwHI1cDu-r%%CIZ~p_t1ztLTD-jfeV*!PK z<2SV_oh)Q$qZI5;p>Qho%4{o0)IwJm)}b1T%tiX}!8M4x*6;#$rXqjw@~FYNVvfo! zWz;C-|EJ&&3?ifn2%j;KyrH2%+|gRAEH5G3pjgCCui?F^aw5E0URUExyxvPiCw;d0 zd0=9!ivrysR?kOlljiX?=MU_&cfI!x)}=yvz3d(@ zssNYnHkC=X3vIy#5D7=ErG2eK$Yuac1k+Yj*Au)I+a%!5(I=m>8{hIaTeE4Wi<+k< zhVku~W^8vx7(4iSfTGS)G)-{Dq6s8XK}8B7U%Z6B6QE%MlxC^+o+hxGq9#y(Qc}jP zWGzxon>TohhDs^06SG*)Phs}G&=gd|&#^-lr)d`l7lh+uv=OMfdk!6X9wk`g5Xb(0 zz^gPC4I-#m#0orBRdg@lo-{jX5(O4sp$tWhtSLUr7_e^v*-UF|yNe67HWW$hfp7h@ zwYIg}YGR%>o$H7@Xh};XAs^^}ar?4TgcnzUz3z_jf6+P>S@ManBjDvqwbJZL1xo>< z@aZuYke#aDy|wE)9CN3puGyk6cI6Y50GZ{qrg zu@WV?fjAj}C}K(@j~+eZa(lUh0)&)K;VR$)$mdJ(wEKeugAuYAxe>L7tGqihGKkf{ z3ZN+BGN?mHvC1N>;i8fX+x6C4+`YziKeIEQ(xO5us;DViT21HSF8=t&e|u2{xP$?) z%}OYDSZSqt7zD*qU^stOu|v5Qndee*-;p&%C7z07Vp)`%nqlM@lG{p`L>> zW)mzD6wdHIQ^Y$$_hJB5Y8=gy28y9vgn3t~T2@4VrEGOYO95B4HQ6vjDVR;1L7{mI z|2Mw*FZb{JHJU}gx_7U1e_1?UQ~?mayUEXf;qSVS9em=$n8y+}EI?q&BZf~YV2^?( z`O5UDJuToXJ1B|UiPXf_s|_7_HfBK_Wyx(`0^zyryzJoZ@bQ=j@2cey+s zFX{rgMXjfgR`B%QzjW)V#l&PI%A8djco57y6o&gwTBP7j^>K0KRVY%bw1_V}@Z8gM z#N6T{^1;4dM!5Fd+6|lBVms`eg;r68RcC>v5Tba=J?d@w;%@?b^tUuVo3cLfg+{=C zfX1O1f@#GN(nDmGYI1RzefFuR0jip9!}?BG$b-}>NK4)O z@nRTSNfb-aZru5CVir1!rlt!navQKVGmBW5u&v*)g`l<4flGdbtP-`Rm3dIe1N#rT z%tyiFGZcf~bmP@o2(I2#*1!ACkA5_NdhfmWGDCH4)n*JfbuI7)Pz8=!W2ImH}!vveUQY_aL@~7u5 z`DF49u6a=fT%eXuaHknS0(u1VDsB*TtN>0fKLO)o1(>RhXtvPtqsKG(P|X^f zR(ywDzn~cbe3xD?tH(hGM<4vBQOx|X^78(H{#*fQmu3LW!nA2%z8_h%6)@C+ zgBILw5u;Z@Vj)3N37}1XDfR#6rh114F0BCh1B#=3To0Llrxdsn<^2l86l?-JyZAw^ zUozPm8z+=44)~*TZ3vL4oL!kf=nj=5;-BOmBtWK;LOJh&oI2xZV`3F|bgZN%FpPU( zqL@qJMDQdX;+o;>cD$5dO(Cj(G^#9|&%G+GbRa1% zj1x_AD0hHUOy-IUD*vlK-_D&owMUlS<0Tbw2Z8X6hoz82~1Ib6(wc`q*4S0i(^FKQv_w&a^*zl zQZxW9Tfc4{W8UhWwW@`yC<~NC5#;~nzVr|mLHLHyN)@Dn2sy!L()92pyn)$6xCqXv zAoX0sC|M?$ldX6tWGP7e7m8D%~BBPXYQ}&2`YAAssg{4o?rKpH_&o> z(sdP67NL?}*H>1gAw)PA!&>^O^B~S@PpSh@zElP(n8d;4L@5h5A6; z9)9ovz@nIKqMJ6!&eB7ISI{SyBJ;0YTqalaumEYEltfXt^6Wy$rJ5z6p1X3|#wsex zoF%A*X)G(D*U!(*yIfv^RqUW3R6GIY?1G{7voQP-gf=+=5XJMvFqT`^?pKf}%jD%} z1)2JPyZ$YApcw;tjC6i~{g2AMF;5o^}0)$E~(xgpQ^MTsvv z-+%GG+{U={^S}B1Yy?P*M_xhrw8#$#%j*gwM95Ky7fOe;5W|CgJj-i4cD>b}CheMK z;>K<7d>4^-kNv~f|CYe$FfM{JFu;j|CJ9-8xcd?gz(4u76he#}P3#C@CDeK)Qiseu z18Go#h}+#I#SDC6wof5}r${0KkC;{H7|7Gi2p0QT>>??GBbBh56E4qquFSG z8?U-r;E->}yLLEjm$EO{$IoN|c3uo%@*?4*tOE+4rWeDTD=HF)p2{1$w-9=kBLAZ= zynt^G+FRcKE{Y~&EKtPm`jw9`_;IxzJaUp9*uz>ZRs4hnNa*@;+?PjHz#3`74DS*hGI%ZC3r`|&fphgnc zQ^=ht<`8ZnrIa!#7Fo(X^!fx@LCh(LV?7afNSGQoKRnb=_CXK~c~t`~6Ew_78D=IY zGCf`0WDC*1;qq}s|9oGz7C=zkOFs7Q-K!7aJ9Omi%!ZEUZNveqAYu|Ur@VrHRW*%6 z<j%Q*v8+z0x{m2MXx4 zi$y`3VG5Y6maK>5qzpr5zknToE@G*aP|&Uex@crk;Kyyj9awPHL0KNkNSOYhcn%tM z7$$T{pzw6zSjR|vH*G_R>0Y@a9;lZ5P^b}$E)3=+;^UoOkFV= z#;{_|dfR&4n;FCeGkCBcUL4#!7BYaqbVQ5j*K!v!&B_4uT?>j4a3GU^z#X|6kvkM$ zDAN$GAnxDH93>o-#Wj5rp-b^pPL}D7P;Ds#jFH7DCT@@$QFDrJTGd9?9#qs(dzr@8 z;`zD$QYB9(kI5<#+!6x_jl?D30u*3o@c%lSKs68Do6=CZ1O=%LWD^xAMG3WzNTd{M zLe3A%DO=yz`u}Ln_U_()tqr!U72xM}PEwfcoo~BlKdo8Y7GYNe;7zlxO!-nHsOIuk zFw|)^J6*ZGht!axT!2o)^ynWuKLnIJ$Lt+W{Ur61kY#e!gRkKzHrAYzZWoZlZ z&do(H^v!HqvvsQ{g(C4W_~SBu{LB_Wp8+f2o?lp8^p|{U{hvTNn~{lCAg19+2M!#z z&wc5ecK`kVz<|ep$L-;VzDp^VL5>hH1O_R^;&slj@S2<4YA7askAbyoYpK>|P%;R7sDBk6^s;L@F zP*1Rixx{>rPcRCOaw>_G>mdlSV0tW>W)5&*Cp%s~0zfuyA=O->AWjM*p~)Aga2X2d zL`oSQ9e0C&B;-G2##E45gqtXfE0>{GE^R%<3pzuPLq42hD4o*|UcdsV1k8?gLR62R z-b;!gKnTpkxdJI!IaW>HGO@t#QA*(!OT-mw78oC;i&9?ICv+#86L`5iel7+0=@0e5 zV+Y?y&)csorm|<5u;odn7IO*+8J3Jd*g|~8SS;;-Adw_A{Ar4ABGJbqrI=F6$%J%H zL6k)(E>Jcgj6nfj5mi2wnWtb3PmE7GRBx25VwT-6nwRPaQV@nTv+yEk@?N~FtdW4A zu!28!t7uzFS+%o8EK$xb;mZZ6*b@aE6mlq+qxV0DxBjlvjxwbMzvKcW9PLOkbC*WCEp-R! z?>bOQL=62byuZ7<2SVnA>m8JNS8lGhEp_mJDBVkfAgZ3Az)zjUf@noZ5r0rK3^klm z4526_);yF=6;9F1l#B?{mFZX_hUU5KLY7LUX>}Z_*Ff$>?!`?O5rXKHhv<^e!y{Jq z!V9t2LwK*od%PS4(EH{(qET61m@$i;;`q`1nwg(p@Nh`8^N&?<^XfRfNx8c4dhr8) zipr|3fQVfW5i|9B*T~7r%d9$~vDnJhW0-U8N+EL+u45!qe@J7VRSVDr5BYF4i^^n6 zITZY^wUz^e8=m z3D7)0yDV3X8xSE zb`kCw;rQKXmLLkEK+5f8hYq5DTkK$GVpu?pXO)1-&JhTM8n|W<%9#{Ku4joD0;>me zui#9Q7Eq)2mf#edsaPZB=^q}W7BI&3RRIKyA}ev&1J}}Gi0hXiBN5|BaB|;3uN^&p z%mxOB92daF3|vpHPFBEKFu5tr)*@_Z<`efgneW;2ve(wV{&o7#5*+t`GT%%^qP=!V zSpC_67YfzXbgr7C-qk{-T06Ue2z!YoJUP~9#Rx+SuClO7$O3ShR;4XF z-cpz_tXwvn>*Nudr*SV5Di^RcK_Ie}RN0M6B^79@$4~%J$XN^367qb-<{@JcEUbc% zidVy9jF|_E@a77C;>+WIy!QfMI+R+iYEVH1s0s)bqX=MfX&^`8w7_jpYgiD( z&;^eu1gBx3e8Hn`IV&qK>F>*2-Ph-3uSfwd6^V$#yTsUm#Nk;w#1Y@AdOdtssD3z>&EJr*|xtNH4a=H%`F<{dZqbMA`e-jfZ z#wbG8Oacy@hIJ&cNtAF0ALHATvIx^l@bfCp3y>l*@z1@tVgQ*d@fYLix62 zUXcP+R_=8{PI4iCc5)tnT@)$sQzy@Lb$5BH7#mYpU*}S_!eWL*wRdvIAaI=Q5vG5z z=ggF~wy&_6DCrnewktWqM=YWwMU|z@UgmwN2}Qd)OwV1Mo$dh(5X`H5T__;wr={7k zI!RP9gVMy(GEzvqNFq&825n6=FP$qqFg$^Ba5k{mM3`-VH|T-hhPl|qBjShw;#j8` z!p`tLjD^w8kHUJI94~e*B|=Gh%a-+kLZFsVzR*ZAf~AyEiU1&Wu?6ha5zuRWl~<$y zG>*Ew=Yc1VAN_?L>yKbMH&Qr}MfQ#1XJY^^j1sV>*46Ad54m{-{*@zJLGGGYuD8~f zHV6AYdw`*TOT93cf4BIS^_Y5sunE}3&ZUqv0Ud6bq3U{X4#$syI$6q;IB z+RDy<&9-LUW@}%$4k}rLd!5+C6<94bgt%r>ToNcTbn%R>UCD9wO#AAf*`tDv;*jDF zvIxx*R{ZBWk}oPKzHQm3em|{1ugC)ELiZjzl>Q>$D=Mn~ad4pTkEx-T&CSON;feP# z)6>lO7Z@aSdFJTTR$bqMFqh!g3KYfzSfi1DtgAcP?fFB8$hE-~5Ofmjp+g!}I@SPy zK!3mVEfGVMUlTbLAiz;qh9zA`TjI_rFnjoX>k<`OcGTLp?QQx za41Mw0pINOIM0zHF;#?WrW99vKt=dv#T*MqPiISGEp>=e-it}+#2;b$3nTPHrg2A7 zJRAT`f3oTi5Jf&mQGiOI{&N{TUa1A(16yu4sNkRc^*5(EO!O`3_l;% zu7shTQp)HUap=#VKJ4;saqiVapvqc9T@@`}6|NIVLmmY4D&H3PqBl|SC!&Z1uA+^0 zwk)+QfUJT@8fwf`Bk3YDi5&)maFnj85T*V=f4L4kk%Z(FN!Kc3$Cop~yp-Kv$dJdz zrdG}{sm))%isn!o$g-X&o5lqw}Vx>y%sgN=$BjO9z0Ed}^6J zfBNV?+xPfh0yu&$_yqt<^Z_az48k57bTflRH=pHbITeTm!^;1v^eiBW1jD7BB8!TG zCS_o#sS60*gfJ9GV391#>W*dv55)_sFbS_;6FeH58Z8AX$=Sws_0?N!-Kr*A-HJkx z>Qyrcv#F`gO$u396z-*vhqD5}JmiMZeZ>nxzu^l}is?(x-9024B}d$)P{ zp8nRu&wi>PShST|c^?%*9COYKf7YH7aZ-&WjGVVVP891x@T?v?s@x55l2GMBgyFl? z4?jIHIEb2%n?ovzk$O2GhICOtlW1HS3O`~N$we%66j6sn0d!<7Bn_Sur;^8*c>KD~ z9@gogjrH{$5x*fw0_Y>70J4#u+dDgh_doI6$%e|3b(Bnh9b~YN z{F&f9kdu%#N~N^C#zqD%xRW?qA&ibsjN4IW>G$<^v(xD7hgZ1B z@pEz?A=iCOeV#%O8o=(yf4}o-)T*w*je?m40c*ao#?Fo~A*>wEpg+IFU1yRqv)8A? zq7WH<2nryT<14_FE!Q)j`fQz3ux97x(q`Haz_JOCO-+K7Dzv57)tB4H0gHUpsf72f+E=JBtYh8Vn z3*544O120?%@;}`kHaiZEG!LU5bJhufc`&*G00D=uU`|zmGYHfo|VIkS)?+tYW#{5 zbQG;l{&J^~01D|qN{xN5s%>&aj}fMRjY9|1u`oLGPkn^5SS7KFn#u+Q0#j*%F z931G!dQ7_+MdAZ!e~hhK#^>QZYLY0yFStVpSU}_D@|MQIT?WF}Ey`xSCJ%ZFgi=LVsx8}AE3lJ=>-_U7!jAu)7 z#Ef=%5lkbEkDF!`T@gblLhSzG!G7DgK_`S3;f*z_4ZNPRfAKUYgpUjkFv*-YG5)Qg z4L)y^8(-(=3_~%BR8*Q^j-Lix$KniqK$!99xC=Iwb@X&!kPwMI#&9cS3%IS3kzP(0 zZ{)ognoUgs&2VMz$tl{%>u>`+)1S+D}jnPfiiCU+=pd+xdC zoXOv~=_*e7IA!haZT9T5&*5g$s%sFBgc%uEO@k@teEbYF)Aj}o*%mFTU zG_YXMlY@rlNyZYfNIED0!t9=Va`K7G{qb5Wz@^XcBI9H>c_01y|7mn=$X6d~CAg|4 zGhpl*MHw|=OpW*3P~T}%#&a(4Qp%@uc?h`?0C7R4ln&h?tDsYtlgj~)4zqJX4Iymk z1TO`Ke`-NzLps)ws9(`JI)wWNsO@tC2^ONKyUU@B=P&eN#>cF(G~d-M#3E{GX|*)~ zQiJ_{DA3ZuQW5(7R>N}E;gth@7wnNAJ`CE3$}z1%&8X89lG1PrLO{jT4dP8(wi8uc zJ`Yy+wSO>b#&sBfbI*4NH?C=4g^At3sQDBfe?C6-@(=cPGUA2?hCQNVK#%$_^_ zz7jAQf3CK%-OU>!CgACqUcjM3SUt5&<0>bBQ(7qAUp7t05FyK`X7nLM9qzDs(?;92 zWs_Yv7ji?K#z)6+BXcf2)3LN7qsp)Ae-Nsv`83#n2mOT{7fUlqm_v{A0`w9zF!+I- zzmU7U*6N$yBt^|>j_}M} zyhoq;(4lDs*Ovtz@Orrb&Bx2^1Twz&Uw(A%{qMZt%idh#W6ToBumSz0m~_<#f3zEe zfG)AFX-qH&M*#RV0L>;a-y(CW`W9xghpL79pM8ch@{l_;x`O`yy1F_C&8lHjRPRwv zE>S12(76O;k#%cVIaW{-h*{IgU;uIy9LLELL&WA%9CFb`M=$dYa0NPRQ1QdeH1jP>M~CO)GS5u4HR6w@nzcD=^9 z=%g~z4lIo35UA-R=3b|H2VxP6=a-T)a1Uxt_ZQ>yxvx#@R@s03{8y-C9*5^B7n3*;-Nfh+E`W23r#N_e zun%TYu{9CUwYRskg9``@%iZZ@N&K}Ye1rjPR5dK5fmATB`V$gR!V2@ft_3X2=z3K$ zOKMwTdBOclfFJ@QNdZ(#*sy+;t>3tj`-GfI5Ia9N?a?7ok>c_Je<$+2%U|%9?(lV0 zfX>cN(!xDf81RlawXBGNwHFNcUC0%H1rV88y!#yHStowv+YD346!;aF(?A`n()cA7!a zMU{|U%X0a7K_AmXQqP}0d&Dj5#di8ji@cn_zpe@ZSnSrKsMr&oi3Q?`XuN=?jvVub zJY^O292LWCfZ3C-&rrO7!Mv)~7ZVJMs5wtlsRlSyRaG*7e<0;+DNE!rJ1wgoj?uty+=_7`%7P5rOOONDiIBwX+Lh4pFelr6=q5>`4VuL*@BbM%+-okSzX47 z-XMwWb{*&}Au`p7>#5C~^8$g6LwRZ(f0?J~1W#ceLMl_n(Knt#D;X~!xkuTU9zr~# z-LDpP$1%jJ%rb;B3u?Kz81;Hk3P#wU=9RX08669&`+2FyYf%pV-`3cCif5aRkK? zx#QT8BXlecqXg;<0(|27@z@L!JW%U0v>dAW(c*fAsHYES_c|p->QxvDl)C!yj~w-i|a|(gqBy$g?Tskmoe=$z8DI5mD z&}jn8^B1~!oj<1;!r`LQv1BgjxPYwbWfK5O0bcVUkYn7WOtY(n&mnLTB zC;%;ZtIEqfY8}@ul~V8xAu{BFA4JQlt*xg5sDqv<3t@uYiC$WWTyoy+6`%n?XcmX!qx3z^zMAm#FWe~K?2Z`?6$WDT4N zMhS{B*={rpSwe(HQq}fD?AGC-J`|*p!q2?R=QWDX174tOb`uwP%sp3`1WW2^j0qUz1_QaCoc-!!_OBt*xsdI@$Cd?DCY-L zTXNCH#izb;-(Cv^5OF5AcWIuGK3V3jU$}bXgivFETK8I6f7C zM?01c<^nsFUK<*KVu@2V$G?yYUZvoe`C)SRNs2xF;^DBHf5{XOUWUNnM~^&8?S6$b z+2g>&jGweB4vNz8cA5{UlgV{#&84}(v+6S--Au%0sS>K;LkBS7l8z zKS$Z&eyoFzY>C=642&#>Mm7z1&*vp-SEm+4&N-f^f1p#-#wx2D2{d~tGwby5p!N3j z060~+10(0DB#saF^IFl$u~5_vqP!N?p-?}^S_(r&E5vOm6JYR!XL52fH##!nWfc8e zBLV+g;S6T}==Xl}DA#zFW8)vK(qs;01o8M%Z?ICcIK`Vve0eq#11O^G+S)-x9%5J15K4h2O9znXV7-0AwwU!} zmMfeUsjRJINHvqdN4gz%Ppx4u96f`=Da%lhe;Eg9%*W@WI5eZmulIKMqP984+}D6Z z)Y*hUr+I)qlvH%{A{0;ff=rYeR5MCPftfK0Dq(vdj^+qBGb$PZaB1ZDX7~<#*{{}+ zl_=|QlTK)Z``Q=&qW2Ge_gDY+eIMENC!L*lB=5fa?!Xtn_{BGbN%TsBK>2xpPft&d ze}E@@Xm~jLftznGSlik72LPoXTSzd>EtjQv*B@duYj$#K#toRxXIPUYFE^kuEZUWq zW(BC}LtjGcunp`k`UDvMsN-lC5t^978qzE!V$1~BSegY80GIbe^q83(w3Tr6R)XIT z3=Poev2=cs$fGI=4-WN%;t5!yQ-~^|f2xirPMmU0C1NRakCc@eB@g{uZQ*(- zArSI;OSs0aW6$^8_1;@=d+O7l`OLuX-M0rjI(B$}@Auj`uJ+);ZWyq0VCx!$#Zsk1dJY}58==AUC5s121r>7fQIL2 z{P5(Gu!-t@}DVE%hjfZe?H2~G%!EA zJ0oE$wYentyKlQK+}6?f-nN#8FXqxYdIIw{V`B42=^)``;8SpEA}TG0Ouai{6n`or zhMF&Ql&kW2DFAlWnO5yGJro;=+owNeVGfrNje9}&<{eQ}W*bmOu>yF!0y6lW8cS*FY=N0BJRwYJ7|`0R@%#1smch8Q}(b)GbEoU(ki6>=6P^rM0?OeKrwX z$!a_dxAL$td^Dq^Q6L{}^zVDmJKnb9`fXR$zj@aU;m7tp)w_4^f3B=zD&hkVil9Y$ zO&B=(Nmj z0F$bnFD7wqT>}{bf3z=Lh3Md#NG@9W*|R4pDpgPHfNCH`Wo4fdDUoR53_3>WGmu7`9Pw1s&BR}rAZ=7-vg;Fbe+qx|;0pfAAks0ts08zp{sur_R|m*In&)yt<8)9#-Kh1Rd+tFmVuuM#uR?K__?( zp^7pSKq>0kGiP0FK&KO~W@$dMT-7uCHP=8p9>NH&f2Dr_;wtZ{!z~0%=^kYjWckE? z*2$+iey3Oj*WlsQlic9wScVf(GOVG-(^s+1x9`}#ZS9@!{>8l?|E>Qvk0NM^ge~}A zO^fiqC;%5%79QdalKfHRHIv-czVAbIedgg)d5uOP|&?nQpJ{rI;Me? zI*TATA)h`yIbtJFyH1`TcIOVLS8$-`0)UV>e*yFwbalZISVwROQwgrYBEZq`*o5`= z4?65X>>~9EPR?lBDcAxoK~qyCe#Hy2c-jP7WIg0g6!$P6L0iEKO6kJ|d6~16!G&c3 z#n#Ww&wlilH}7n{Y3G|_Kia#m2idsAks`2BjejpK+R`O|?*INo0c7(3>aYGvfnEAT ze;@i#2_(rU(8dTsOag&;xlukF=3Cobp)S*wq^(ObLy#ARr@QgfrY$R=6U6ju4Rn<7 zHI-8eq2NzxpMGW|xrbCoi?Os*u!zzz1S(&uir&&(KIZ&lN>LxKslAr9x@xH7WD21? zCXb} z&xtc#SR76y#eD0GA{CNa+uE(Kr<-h{+?{(QR~8@z)EN8Wu_=zk>2Xz2haY_@BB_u!oQak@_UC4y=*0L3UD`be!l+5Bk5my_q$u#+gkn@ zrt4=Aay=$j(-eawW*$w^)IcU~3PFOJA$RRK)gLq*4%Z^4`9YH?N|d6|npLY^E4gcHC(d~R>oPW}%B5T!g(w|X!Tr)Bf8c^v#Sy|B z^f}zwNUW9O44Hp^CBNx19&Ltv0^Px(5!aBypSXVwo%Uw2dTGT&tY0Gt@_VCG;~##@ z4L4N08zf+d&xC8>!5%CtPkJacW()N@q33-x8HVKYbu*Qg5ur4-YSv8 zA_%ctoPd?HYqp*SE-g*wf0FQ(#>p2irEe0LpGEQOSb2g1eQKF(`El(ices;&kB}um zeRv^(mjWY6UICf}sW16g(Y1B*hnPJ&tWg1?uBV(_uTQY!#pqp#g37VG1@kJ6lv32U zZm_(xPdtS+$llBO zgdhCi2f-0syx`vNf2IE8J9G#D=K~+8g6#NxXi?4d*CptAqgJ0`V=f6x0gXCr+-~QJ zvH}vmzWCS0?~0u9{|JgFxLu%KuAoheEPB_HuoduP0-XVo@Npw3j%M!2jfju$W&rWt zQi3A${>Z(EFjmH&vj)v#O&3=i?zF$P^Ph@Tv2G|f2|;g)f9WOdJpV!HbWyR z&(+z$;`C{R-MaPbx#xV>GMt6DT%1zpwJJ%Et=?klmR7 z$!VCxSU6QCmEMMM1KQE!49HRiQ751jQ%_KpQC~t9?v@Z!6hk0 z)|zQ$6kx`Hf30yJUN(c5vl+4srAnh5c^qDG6RzPsZ@uX)hkx^v|FKWP*FjZZ`N~&* zrc=s&x4-M1_cKoI^Z4Wja#V(1d4ensx29VCl4;kj^K#S5?Jo&O$|2z`DS`a=MQk4n z5yBKoNhDC|kj%GCUOpdI`MTVMcCP{^T~i-k2S(_ze{@}4n}CkjI3>brOf%$3r++A$ z(0wVJKrh|(_45*_#I#aUJH;9~@c+S{6Fd*77Sk#M$20||sflsx>N@XSkw7N7h8QG| z^WB3sOTWKj1-U47ElU~2N>WTSJUoN~X&^-uf#m=Hb=_I7rB`~;@l$80>C`;9?6QsR zw$trSf6|F)q6h>MYLJLpAc3NQ5TGbhka7Vx+;ib?0TRkZBM3@B2~w^=iaG*uLx3m= zA?>(_bi3`gtI9QxrzZZtXVq?mAiKPM&e{8Y*Spp;PwQE;!Ibf*1kKhp1QLe<hh7jy?^+3|IW|7{tG|<3*Y=}U;XN*j;Q~7YT;{1h5_uK^1q!Q z`{KL*CQeJb9}W-Cv+A2bREL6*rk{|&Xc>vncV4)2u9>SBB7DvR7^DqSl~`#N?{LYe ze>?GrTa81iuoDnY9|W$YY5)QNeCAEJ+MP3>nNMF4o4z&`muf130Ol337#}e8`LTWc zPJ0F#eohhZ>UJRRme2nnbr83Oz>f zk$UE~0$^)R2u=ku2B8|LOGuXQ@FHDEtm`$X;9B}_8gWL94Vmd#Fw(a{k?lNZ&q(WmK*RT7T36h7Khf*%?bB7@tpXeuY|-9P6+rqE`&yR(lF=RcpAr`?;->hg;wL z_V=g210pWBw~rjU(bn`ge=nckdgUkI9HKo@kVzGBIB#!3NG{Oic>+^f+2TlqS!sCO z{)34}Xkv|7%;jX8OFwB})PMUdZ@Jl15iDO|I;7 zkesq@PO6(k^;~wsbTbJ?%HSW}y0v%mn7fOZuG@INZ3+bta8d2gxBZWjn5&@T*XhM$O^~u2Grmc??kLTts)M8g1fsK4;8j z_&N21x=6YY2O%y}e<8Y^m+OgM$Ju{Ys21|x|K@ko`RC?+?X$e82<76rwuN0R_E5I6 zc6TAW^|t1Y#E77(5N=Y$_vR%!Sy-gw(~ORj&Yx3Bu3(ArK-;rf7!G+#8=8~@WuAJe&bpl z+pizKbm`TDnBef$&#wL3Z+zn$@4Wl&yLaAu@4fBb|Cc%_z!SiuXa_!By3l!i0sb&c zK7^SZ0QgDVn<%9D8BXHl0zPr4i7MTq`vLJtsacXiNZ0tvv{5u9%#rVL+79ctkv%&& zErdgE&nG?XfA;a{-F}~@4h*c+h6p1&gJDNaEqj2$3h^X_#*k52fAd_t5a%M6?(ZIe z!c|{-_qDAzUnv*x?Dp1;tKY81|5n{cG=Z#eHTTmIxYUYrboGYp6htf%Nh)rL%sRyU z&sV;VJ5>%tA}-}}9;wBwZRqB9w{SFA8Q0$!Y>2rre~g1j?OhN)CiW*98u$Ahy@c?>fs7m4$4uy^!vZ_-`{I!eG>i;<@%u4_L(?B z{@c+mU;L3jv-Ra4eJj5i;N;tDrJCV(re+I%Ka#5>SR#Zfk+MjM6;A>b$mlzqD&nP& z?gVope;hz}fD=*d?MNAwH(3u!s_qY2lV1IkeuSfw2;o z5e?){aEiUqc;i_FO~eJ+U6{)j_javQNvcciFvyZUM>_~An!R-4DR)#+Rn%6Arx^m(3)=mFpu4yDa3m*fAKE2AcZWpfUrAYwR*-=8E)&;vW8C0 zfR9H9o6)lfZ5yzDDx3>)aPs658C{3tN`1| zW9>#xtW!Hw7u~uf*33)?cfAqV*`!B449T2h5J@eXr9so@8bX&Bhr+=J&A`$aaf9l{; z4VcdC?`^$&{>0WBue9OfLJO>&s)ANAdZ%R*HC}P`wd(xo)4b^&zhS8)1(PqI` zd!ho4{q7ar6S8G=28Kbn=1ctEYOLedHfPij%9+1DKNOeqRQ9r6c2ZUT#`W`VEmRmO zlxO=wMbO#QhkE`(#;xzQSI!OKe^$J|`6tcPD~NSCBaqQ~j{zA$Ws?_9c9KXZ>QSAOMJ zec$+Xb$xG$VCScQ`Y*iq`YV@mc`gp%)YM-oV`h-C{$tC-iLo;!M)oSQbSn3`{Ac^` zAC_)4S@wcds>TdN_Y`16o!mT90f$+%>>yrRIx8ygdsaW)&CnWeU;tndt1Jv*Xv7Gq zIGGsNau(-u6$PC7qcN7~f8WW2X;#f6gK_MMMKtcGBj0|t3}8e|2P^D68uFh!XT!wF zNhkLR;G|S02!xo2;Nn)^3#lgLJcm<-Iox+xjg3x0?rmcS0upK6e_Yu^EKI(Dc7(qcp+OW8W-w>bqQ{eM&qvv1fLo{0#?z@+2pXHuHT!|pYXwz+9!l!vP-IMfUGq@KrJ=gjbozB>;e+OthgY>dK*Aed|SkxXI z8M6^(NS1Ko4N#XG93id^tbP9Q;9#d?@DAD(^QFK3GhaRZ8^8IR|DnE0d%Fy_XGNCe zs~_H}b7qsG=O9nPMx@vTJWw!(cwHMakA{@}mkLt!_kPCIgNi0t%FC*?d!{{qO#*dF z(caB40%*Tae~=`=hU%@|xXw->gtpB&?}(P60{`p3?OePC`BX`ggf4dmAYj!vB>IWc zQy~b6VYKlCx@*MixK(lCOQ$l@E=J%18u858!U1?VJp}pOd;u3?5Dx>*$)duu4@+$~ zk@;+-6R8v8G?m>JSRnxaEKX9 z7uUC*Myc>-RNn^ao<%j7(=@A04cL<~_E6X2c!aUnh8e{xi1cCc1MVXi{8*(1M}rTd z?Eb@7uU>i5A>RMwU;Xkg|M5Tg#b5mA1^IR+TzTYBsn&DnE4Nm}!3V`@k`*l9#gV~y z5PUS?f8c7sLj5P|#sAt%C%3-)>D_c^=~tU9y4T`Z=UhM4Iomr`+g9proNgYfeqKUG zb&U*Jg0;`%;IRo-K}Z)30UVj&RAN6c?KL*U8mK<>jmr~w;fD4(ZtreSdPpI517g3Bi^^~>u#`=3D<(Yl&;H%N{MX;> zf3(l~@RiSoOrrKy0Sbnh#hMsF4A}r~k`7xi!2w2-Br1v1Q+3PyazT}^|IYgZd<7qy z1)R-oJctV)_niGy0-`fvC>IqQDU{o&iUu$NY%hb7+So)StD+nOv;6c>xp1kh;7-V^ zL@6#>gdhjt{$zeWeT13uDj~GEiz-Tge-fW@yWYcRB6=K!lc*iu4)J#PKDn3W-i{<`EKx&JtESw&f6wH7 zI3>NB#$Fk@hf)dg&7&%{Kl{x#=Ay?43Ghte8A9Xj1*7n;0M_ zGuQM$;uG-R{@m+Z-|t|?Z+(oy`0m{Y7k!VYcn_W-rmdKA{Jsby@C|SQ^znY2(*hnR za@|LNVF9%W3^IEFxtgRBE|~dbe z-|0}r8`iU870oUEtbj9~>+^JU2I6+bpx}UtJkKGP5Dy;yBepB%dm#;^zk_L!!B0Ce zU5tg7B`$ERXNf%Cx&CoPkcIvzmDGJ0g6tdB)|wf#5IhKN?T@po5XjgGe|=B9^YfQ& zRi~}i)e$|xr|ERPlhda@^7^eIU>#Loef8BzU1I3E{`u|OH)4}kaIOkgz^7js zQn-Og61e*2eYy{v<6ceRfrPnW=-nvp(Erpm#qWt1B>7bf8H#Uht3|Z|I zgjo1)e-z5>K|Pxh#t0O7f6I>!Xph^0<50>jouJe~eFNKF7UK50=0V6lTKKjDB(h^z z=3F`iya;c33L`~QA$A)ffF?iBm}iB^9x`)V>npxqamQ}mKps9yU*~E)j(F5N5~<*I zbaE%fD1s4UtXygWWyC!R0(NQ=Kdi-_pwP3evkP{?D9EHYqaE6* zv6frvGsP7M4sqz$W4;Iu;E&h%(VVAnG;Sd^7=1$#;M)AD3*vkefWplX%cz@3T+d^N zNQzN|I*NqnVG<$$2TDTm-RXT}N!%cCzPR%WF2w2J;mF#{f0yfa65+|JDoB0a*$B=e zfT%;o-$+LYqFT+5Or#2^+2r?PcPo8Q@~~eRr(AE| z5NV`l;TwPa!AOF)-~N2hyH#7AD~EQ^oZ!+$WxbyiaKQy0Y~X@OYeFH2mEIqVQb~vW z=DC)xMhF3oe+4W>sh{7m8aOBia}d~H-}3*kMWa>TU^xt@OUKe1rSGFB>K&b^*l)L_l0Z#j?i;q z_lr*YO#EP6KWhoG%FG^jkcB9zWD|puJ>c0~TPnyie@AzBJ+Y5fZuI%J;wWEu_X{<) zu19g)$8bA#wwAL!MKBGNBZPO}{@m90zW4o-N!PdDdFONOrM$egU7y=Ec%n;? z15$^}e~G0gKm`EMIv)==E-FPJQ@zslxMxNCq3MIeiswYO3ZLIJ38aTT5C&0?pnjuwJGsENZI*vz-?vtz}` zS1z5=wURZ~Vod-$!JE;x5m(%*Qb#nApU)_ze|s6Fbg^@Ys3K<)Ph>KRN_(VM)9+-!O|nw@n#P3`59MPv)%+-}ljV4cKj))90=x*y!qDKg^RCleN-aD zSlC3+ks3grN_PXQvh9~I#?hw~Osw8ONAtghGBtdr&so-pbM#ne$A+E+C@`+pP1ke>`RZ+yd zq0c+tAoW9+V-|ra5|qUanOCboiZ-*zPmjJ;oI=7J4ymV#o2d5#H-}x{XJ{hSV7cJd zjWF2@(ueq(C+S8#v1!bE!=$4=`b=tAXxPRT#7@PsM;xZ1|Ka-|w6m!-f7u7oZlt`n zH@3EA_?*e>a0Qdl$U#)l;2!S12*B?|>6%o34DzW0028DD7(k%Y0ByNe+_&y+!je8n zN!d1$eYnpu$P>eYKL9PfDU7SEdPVy>RATr7p?UZKvGaeN0fa+58$p^|BLUfP$3ke= zH>U}`ma)Svno%qwVPvW1e^~(|d5TBreLIAteu;T*;!L<_u*Qj9Z?=u78)^4IqN?xH z9i@dkYd9o?qdDnJGpd*CSo-PJ&$2`8Xi7~4SE1XB7djUyJ7|o*5TyXsyq=}IL-9xz zu=PUx!)PyX0#Boo`<`ksNz#C1MwA1ms811zO|1GTB8V@4`Oj7ne|2*_lj}9NI9f(@ z>Hwt_>v)}LZ87bsyI)Cl`vB{VrPEf?sIj6K5&<3Z!$i+nHbUP7AYwI(7>4^B_j#yA z@Mno(FNu^ZS31}sLgUKOvxuDNx2dk4sXxG8 zyMydWkj*nDfSTjje=Ch?UMzi)v6*Av;VzQPKE{pI^AqtR9!8Z)pa-2%I4Y!j#18Bb zhBW&V?xyp{GeS(HU{cCH1B4B6LBv?aId+XFKtXcIB^6aU=p0o=0|Mi{=--Z z`fA1`A2o|;c`Idm8!yO#MfXz+DzDip?(o@OUek$eDxQoYf0ei1e53U^y04ScN?BK6 zlQo@4e)OP{sGjn)bNN);=#_6FfUs9Co6ZDC#z{}@0lkRb`tSo71Bmz@?&^EsCKd;1 z{bf=-gj%Hx1>VRymZ;Hi*+c>Je&1WzEN~XJkhd1oa{?}cAvRp&y{SEs&kb+a!cn#e=M(y++!w#^l$!F8I0B~EJFtPP@*%)`9v_lwo z6Th~vlS&Ul?&Zs`j>^y7s4FPl#vkKXIM`Pp~eAwZva!l6XZ7;574D@N|;^yX_l zMCRRM0k59DxOFZIe{$j7fBRNJji@vMT+Tonm!qA?nLh4$jK78-)q!BV5FJ3<;X}ea z&23}Ie@=2JVn8t5JM;26%x&jOkG&A^a4o`wV3J_3ZRETHfc5!?XjBA^IxFcl60otU zIb~ThcIxVG>fm~z4cBK;7oSG`K@c8elKJ_YCpl5)_-VfDeOV` z?zh@X9x`5vAP_Ir*YI&{$KAxu)Ry&{lNSkNe=a-L6H=)F#GpgkLCnjp;4(gHZE^4r z4R~AMiRR3Uqwbxc%0*3D7IZ0Af8+X$S{B7^XFfhjhO{QDRz z@cGXV@t&$-1#VRV_25rPKXy&xxcjxke-{@1?spCk<5?qV$gK$w)-(}23 z@L^&KabxbrU;75wUhYLFINw@4o7hL-)~(A5ms(^LtVIQPH9(X$JhYP~-9yJE3@IMA zR}b7}Tp47E#7!e?Jct0M@j-|>)I;X?h(u&7$-WGtuAx7V9yt?2YRsGkem`Owe{M`y zqw>4=u8pfi-+HUj*N^XEZCdTxaZuD7Z@$%p6PbMM5JE%>iQYWul+b{L01kSN0EaV% zof~xa+~E*;znDnkw5ZuuCxH;_MA#v5>V9s-J1fLy)`yL8yOTtJ@ArPM(?c%Lj^Mg{ z&2e=P)0?7i@+QKnTwexrXC6cde?GgLF*yrAymK& ztW*+{C@QN&_#j^0;)Jk6s_WTDr0w>0E@=!U3_b2{h~PztG*Tl<#l-+f^<}%U9l~d0 zfH`xH&G%_N6VDVXj?k9he<>Ay7vSF4;2plzJfml3-%hT>^(xe+1DoL5v1< zp9O7axy%0pE~D+}5j$d*E>cOP!Ujd6-j%c74+ytM&k=9C9oL1+@5C_=qNGPr@ztx> zI>7mr8b7MMT~bHZOK{{~NPDT6z@^UoBe4((;M}c7!7=gX&N|jC%KYejAyQJzJDLrV zk7m!HY~pu6?7)dcq(%^ee@B&8N2Cu1k(X;p?~p5QAc?q2zw-Ty6+CY5;n5>2iuk

    qQ*FxTY|$9W5n6>vR*7veN4YM1?>1nYFE*Q+lGs}=(hSyUTvNFGAj^T!zK z{^A>L<7%8%z-X~^cCUz?XHq+32sIZ4oa_`SW1^ocM-1X1I{DLb5I7b`eDd)Riu@fN z9mr@?ohB^+RzC$%wQ+}17bVP_EFVvAua zgw^wfuEAmN*r{6Gd}kz_+J35ov3Bar#c6o;X@Miivio`@a`Ql_&pJ+bx!)@m;t_}* zN00t*9O{%&$z~xPg}$Zv@5C4g9|Oo2EaKrAt$qZPZRA3re-H$)pH=F>URO;bBY`oN@xhw7)3p>Pn z1`0(GI3IIH_OWa%ExJk5XXiL=fqE*KZHiRqv3IV1yv5N@bgZY@<5 z%MF~RrbEXtq4>+Qr!R~>aLLg1jI}Xkg{Vn$DhrICq<^M`uHk7@Z!ix*A)5pP%N}C9 zh|%Ugz=9~GOFtQG{hhH08F9bKmSb(QYXM>i>;y>l1M>6)cCY8HFP23<1km;34Qn4D zU$}H@O&LyIc>Tp3(PxDc%}tQyPHN%C^{b^d*H$kzhtk7a&nhU%_L$6AkI^^aWQnCW zN`o%rC4bSJwSKm)-ueVcjXqFH6_MP@P!o3vs(%0g5SB?qK~$sQDhaDbiIYx!mReaZ zBPkbwR2|LOLlCD*@$Tn_se3rr5%)wsf`derI3%h{>CbM6zNPM3qxFLA={%nEqn_0A z$>ee4G^kotSzt`c$~Gb<5P^= zh+v9JA#IE)tm6SM^fqza+EG9s`voj;Zi9s=MhRUq#z{j@cvr1Q0i>tT1ZcRAiSs6E zBJ%lq_v)5mV+rm;fm4V%qpw{&GoQYT%tmCb>e>C~n2{LK$OUNkD&|f!LI7e=!gV2! zMt^I%N1ZPAq;jh(?ehJ>55C(R94h_Nh(iZIt*{Coy6shQ9>|CU-pCsfq14IbL@njm z69QHG59$+W!-w^l0Z> z6%Acp0o6h0dynE6qEnQ^Z3Mqv!H`7&nOlrAk8^Q1h4PTL+z@)%=N>qO(Be=ZE=2^y zmCxzKhZ%z7>j!uV4gf<~t~pjT>tq!-cC~ODpFit>-idwhBnp)_tzwZ0#Pp4tIe!Ev zh;%oj=IoPLeOjs*}W$(<_RSF5%~@i9K=Yx4;xH0i+J4U zmuflVEM)Fm-94tBKxh_Y@%LXkpMUzw_L5PwPK*H+3_|-fJCuCX9f<;=B*&V|65|LM z><7howMpS_sbT5~0lANno&lEn5&&D$dKY&{W1>XJG|&W4xFY?&Q~>TpkwNao!(7j( zKp;}0d}4@xX!B#a?kVwqNbk^5yXEgPD`#=#DivY6>wZDp~8Z zy}SNJaT6C*;KXhk$r;A!ja;)c*$mpr->K@BdQjA9y^u%z+WvhgpzfckFg0MGXwqD_ zv*$XMG!AVefo+UiU4P0LwX?~!YoE3w=}ZL3*j!uX>Q@v&$&^m2JBh}g3K@eR z1cwlCFdJiqi^D_T<9c%fzj`|+5eiUM2B$pTF0PRvNtJOi!*BZpwsrv#bwDmxZg!yH z=5+cZfPU|xLc8}mT=Dd|+O{HuD9ycos{MyxNt2a4>btU9IGnhG+<$xdz&K(zH%`|s z$sU#{i7`~&I5?XxOnq^-D*>{uZzIaFCFV(=+3$BE zL_}<-s>wf9NH**bf^1I3wRa*2T;T{gDhXf_cFXT?oEG4F;d+2qbiv>>XND9tsq6~@ zQ!9+uQEd_Yy|!iDzkhd-)xEcMBS{3gfJHTO_ozMyWG^WDvWa9QOV5>292YyuNNRdE zIAb`l=LTzbu_QHa=RMh!%I!fa$~u*CpvwFBtk(cFwMgH?LU; zDG;ERdxqm%TJM7q;i#w2dhw}6)kfC{@%BAcV1mzk;QWkoAb*!=RLg(oK>?b$>t03| z#2TqvqE=Sx3T2kO%Cf&501IGr?{#_g4ur5@5w|`l(Ly~5TDcd(>?wOwwq$=FUb6~4rOa^v{8TbkosiC}?q#_ZgOumAd&S)OEP;UxB5GZM~wpK5>v#+_>(1yt6ugonl0YQD468N2o-8@!+fHoy-Q9f}CK5kc@G* z)&RQv82MiM2ma((_s%Emt(F%W|N{7eq7?J z01?W|0NSnqRK}5wakfcax^$^izFwa`{zYA#>BwQnk%8wo+Odg*6`&QfQj?ga3?#(139@+<;9-07u?QD^s2_kSUz zLm@-uFxe#1IT6V|Ka%<|9w6^zxa^h!7j(iT_aZE=B$o`M5Yu zLcoFe6}LxhPYT{7>1LeILJR|IMd@ne-guE*QXxOSxe$Y_eYOA%&LxsN7yxvg014za z-F}83>nIW?>ZN%@^c!abSf9I~4;C?yWUkFKaPUO`_S#~V+?vlUoJXP)*?)Kk5s7n! zRR?2^+u0${cE#YiY%x%FRq}*` zxm%1N7W0WyC~p~##2BeUYzw^-+0j7&C}Gp*t|OX=>v3Zmj5t;C1Bk?*h5C*tLj;gG zT$wZ&;u*jy884|4RX{-9?*&)E2HF>X&Vx)~`TJhJWBe*K)-kmR1Ib zPm4728jjQJ-A6Y+%&OOK7?)EK;OIQU+PKl$(*<p__`tD8wv&-8!P}FB|fR_+C(8r+L6fZ5Tw3Kqy}KST_NmPhRXzy zBqtgd)eoTJez^kQ0oEd_JdAYg<{1cq#@kRTD}16>5zPulEdvgM__yK@3_6xILrL3| z33T)sBace){TN35C0%{%!HuNWstF)v5X_knYmKMc+kY?f7uE&|_5{$KV(OY>@FD<` z{$3}b8G8l1?iNHsFzg{x5S+kJOkpHoh+ybRCar{8FwcJ%#JZOnuuX5b!q)qRjg`rX zXGje%Mko^7T80T~jNsX0pvDN?ckrbe98;qp#+=-b7!#ODI-%oS@(key>bcKm!$?ph z`iVmp@PCWAeUt$h5QMU9Jn%bW8ByCn{)Q}6zP-)us4Au?o}xuB(Xt<^m;NRZn3%?! zM$Hk17cLciGWk_kh)5d0f73`IqLY@MTtbUQkY1*SqdLB37Gu6R9e~&zvw34AMZuZ^ zATn}@rL1|Pa&-)a__aHo7XOR-9gnT=WtAbZQw}r1EstPJuZ_X^fs>Y|jBF zFe7oS5kk46b^*bO&kiPMQTv;S7Lg#hKvN?R63w}r0HoPI%sy&$Ak0I7=uTTtRB432&SZAkPWuy1{%m;K_| zIKcDf^Uezz!>`X7fs+>Q*{tVf`0;gXRTD5EQmr8=Gls08dk{&a1bY#3NRBuZqPYKQ zw!!q%iI|qOO4UT%$NJv&wpJYtU^((*iGPzY^7jl*Ouz$?oKbLUzM^}xj-jg5YEt7+ z2Ug+0O&8I*Fi6}jLVBy*!P!#F(|{^N_s%U*PAUzuU&Qj8$J5lxNY>T}u45zdK>BWy zYW)=E<_<0!NqW8sC7~xC0wxin;Gg61PL=T5Rc+(Taf`a3vrMgFUUV_Pc#tI3YJU>x zC&-rm1#OhKL}SsgyXlqg^l)y77vi9o5D`&k;>IH#yb+O~00>Et&i3H5kIQ8Y+&hmW zGFjHy7L5UjSrr~Lf15AcVs$E`GMA(Z#UbHELx=9CSI6F=hN8{OoPU^RUoq66-Nt3fx;M`&0FP_qL64Ic*k_9 zf_$f7u(pq3as?!|hYgFFP_rL^F&MnMXAs`HMkg<%Lsk+az!2cug%mgU;eSfIXdm_v zE)HT@FS<+!wnxQvMOH^AY>7BW2XSj} z;q%N*C|%T&PcEW)L}3c9?`JB+uPv-&W*}LFu1Q7Q&8zPf<+5F7&tZfh3YfeaqU7iE zf=C9|{{*=rJ}qkww>ehS4}!r1ks???jZTsx^(x91fwv{0lj00z^N)Z?E-CE)4SuM6 UE1#;N&Hw-a07*qoM6N<$g11NsxBvhE delta 12391 zcmV-tFqqHMr~fP?@5`Tzg`fam}Kbua(`>RI+y?e7jT@q zQ9J+u0EA^&NoGw=04e|g00;mD0TKWM00001009610U7`Wldu6nEd!td00RI300962 z005u@00aO4009610ED0e00aO4009610Am0E005`R^R%-P0(=2~FEvR-K~#7F?VSm* z9oJdszti1!zi)p}wybAK-fekPunh?bi4t$w9q`C77>a}{k{V`UpoU5UGhn%DYQi?5 zYA9fanyCV&punC~5(r705L-#SB#vdWS+ZlvmgJ}H?aO_4>*dVv>wC{r>sqoUS>EJ# zq<-gg_vzE!=ll16x1H~tYwo$n`jV!5W$V_hR*QFc|J-$#SfgcQ(&Jh@on&pNnUlTN zyu|yR?0r`2J--LcJr+RRd+dp=Tg7HUp=VErNG||{6lcfY^_aaBfTwfMV_I3=IprQO z4_F%F(H7U>vW1TV9@H-WJ;J+aX3bElc`G zWczke;+ai%b@KF+JxSJo95AG9Y4apkK3?9baqM41d){%{Jhs;A-Wllu^VnlHr!AFA zDWTFv8=J%~!5w5f_<&QS5`{l1N~mzcFZKjPQ^LFC$}V@uQ@pvIZhqWjtK6cem(K96 zr|qR+*hE2pH&SV*n5msRy}m7CcI*&uOuy=_BKO{VZ~9el+t&GF6#&_-bM-NQvxIl$ zY~EXT``U<>-R2ry?%gJzmvnnmev>IFL9XkF6!2ii#At4p<*sh_oGZI)T%EL$?jJp-dc~@4k?oZ; zQ1+AqxYUR?+KudN+#=geFRgr(L+qp>xPnUx2Hj+%@PDI}_lh@J7H?^<_>%+TtpOZ6_)0Il zaEFIQl7hnN7_`w#Jl%K6m0hmKU43^fyYI@q*Jt-rZs88B=BM8Ss-y+_xf| zXgLMLIE4u|ms33Ai)qJVTanmtw)Vwh(M2tPB1M+26T3yNlTLEP?e2EkWyc-wCA6#O zuGf86c6s(#Z&~*>C99T5rz1}1uebe}t9GyKJqHqw96Drt0N@{jh=4-Nr8)5`vq!wX zf_PI!@sxAyRy_le;Fv9pHN*v+Zjv59?`;xNC5yWz%c@E*whx`3V_02GiEyA zSnK8B8U?rpsz=H>_L8&p5?Ncz9_!uDo^v2@c}nOPxL(`RslOh73Z=z# zlr4yk2OB%A!0#JTWY?lFx)!FU#GIo$Go2&8ijeN6pvVCV2actsS${Dn{^FGQDL4Q` z;gEQT4jsx8REd>M*?mXIZ0@er+?Dlww(Qz)*SYr7dg`-q2UhbF_kgD(nJFl!bLrAj zs!yos*aaXI6v`#Su`W2^5HZ|;LYs4d(0tj0Q@}X_@><}f067*;^XLDCxHBGfAj+6L+ z`4l06g>C_S8cUt8IIeO9mwKkNU!#q{UqY1hSwx7y zEjk1m9t0^k2LMVi&*lw(OKo0caFnabNy+T&tPCqio}U~z+!@_Z@7v9_e7x&i{odSN ztDHhXk@Qx0qwgQ>a2>hq^oAZY+u5dYSXJQ?SP}+h(o|*<1BGcX@JHF7hf@r~DVDs! zfxa#K>FO1AQ{|(B;Z#-WtfEUS`-m46F`n1g+1d>W+8&NjwpLSu9C^Fp2lXWhkTgC_ zBdZVSvt_}cW!v0CJfcW8y=AW=m9$L-hv2c2`q5i7IOaDSUZq@0@4bwu zDkzsINm3$L(N*aq*RLCd3=FJ%<=JP|vis7rxt5Q&=>r^pubw-u=T`L!Iw9N1+Bs?J zYT_MGZ0&^Cttgqr349OZW*ktUFM56#6!`!pbD-Ze>lh%)CF+P6B5P(F;-$dow(Ymr zM`1NhF)ixh$WrPfHUy3%iGqWBrGRkYP#r`Sk^cUECEW3z`FO-miQK)dmXB9QPiN1? zZ}f4H<8`io_L13U35219i^6DdjK)LgctxJ_)I{o#>VP8kLCkq0!$T`vLPdo!l~jDR z;07MtAZ#^#Peq3wm4Z?=y|)94wJjSZg*dUzB#4V~T$E%)fl))>t<-F#T1^!|bP*-s z37&g}xQ@trjVn_;ZduQ3a`oQOdPQnwbo%4y-_(A8po8wF&Vk7409FC_o zsvD>?s;fi>2I4pCD3BcXO1{@t?jT;s@hD95?7dTN(r&dal(9iBpXw4pB5^xtM%8>V zDj-gZT~Sh2=x72Q&ZbHCkN(MmAj>7P$2)C*bgt>Gqeqofyx~BReyvCQ5o(}RX7_a( z7h)qF?@<4Q4uT1;O^t<6PiBlKb7&0K4v}Wqkn*;Vjowa)Ta*&zrnQ9*5#b87))o~# z0K~U(n6t42He&PhIKA_^FqS+Xf_&XdF==_Fc3q0gk>nQ_Bsbq|1WiwTlv6HGxs5)5 zZ||11I`E3XtvYqH$F=OP({i?s9)Cl6Huc4iNzVgBr_-D+Av<>Lp!2SiRG%Q`QY{Z1 z%u>;y96~qM73vU8IRYjpoFX+feIEdXVdr?nxwzgAyh7eX*s(&V!Pa((<|I{n)jYpP^9pq=R6=#fT5~nFhwk+}S(=X%rNgmb&>ZK%txhH3HGm zf+GNo6bNAuM>)TpggM{j00?yw@f8?}A0#2e@qhu*pH>Ra)1IrL>{|;+!>R`20DzM#5PKS z0rQTr1){Qtvgzj{2I1fqk}x0_=M@xi3%CZD5Zi2u;1zXX&^K{kd@mS!>vZ0_D>B$Q zt3i<^u6yxbQ1sTx?x!BiXK+Pt#Wz9HbGoT=nC2Ro>k)J}Ffd?hH5^Y}@xhlKV1W8< z6ihfofapMffI~EY!+bL|1un+35ttSn11_QMxn!xUtcRmPq0vcz3^p;G{aUgO&6 zD41PP6d*ExXfXaX`DjO%@Kl5-hd^}TVN|dLaPkxsVY`JXT2M}rtHoh{X4&)~nK$d| zp&2``-##@q;Lpv};=#!Uvp#`$tf|=j<-D!8!XQ^`#|2{b!fK9@4-bvJ z5mEs(=oU#KFBXePhf?srx8N3dGdfB0^s7g-SVW6|de1Bz%~q=`+`!e8?@i<&)K=@x*4st z%|NweC&wyw%D3pLsi_*GaOM(KI?K8Aix&mPLR|{WP061}R3E@-=(EB&><z4fyD*|Ij0ijGZ3mCO@= z0)o0JFrY+$X{e$jVE8jtGyw+6X5Me&z$)UE+%qj}pO{E)YeeRfk+Oa8%JaOhA6$_2 zd#CLORScceXSc5%NS;`12GyD6WFx-M8lc!yLI+V`pj<}vw&d_`w%7Ef#7{x7e^&Y? zmt}agB#T#_Cx>|^C9Zk+85w(SUd~^CHz51oc9A@*$KV!ThFfqbO%5QAQ>db;<=18E zCFU_N@dBXey)L`&%9{6X3V`h929$hsi5%vkS{`^a(=XEKxQBW)W5fz>@fd|O_vl`K z%Vf>Gmk_+Ei-wcW1Q2-7r1?-Yv=;rIx*8W+uDT<{yT=jNUOTvJEtll_k zA&!a!0mmChf*Iu&$|)vir1Io+d?8*|xoWLEH9nMz3;XRoa?X!tWOLq==?`p@M{$Wa zi5d-9Zz&-%U3CYS94H*8c-?}+5zoEY^YRQRvURg%y(YWgTh@KIWx?Re4ipLo)%gHK z+s`xLsd64rcc3{w4H%!YG-tR(cjdT@1Bti!meBD94 zCHaCM#nx6nqT zoKIQ5?Jszf*2K|LL&ipb`s~50#*^m&TrgJ7H@~xA*6*K}x8VJ(UA9)f3CGw!xgdS_ zJt^;QMsm?WA^w*;uJ<3&_vo6@$+r(kxi2r#rm-}7RNqUvhbpVDJ5Hg*IqB2`ir#Cp z`^PKmG2OJodbbroa4t1NwT|irSy0rY5T8ZPTU?e>t&IWUNqhHyw72QNqP+v(WpSip zzf{S~F<-~PhKE@v+U~oye>hJB^>W?atUB4K{aKs&z6sO&Yjn5wVVZocA$!RxI>z& zw(sLFz*j{*qOJJc((53qIM>x8II8h7L zmqsY(^E?;e)7Z0ly?p-ib7b-#9+O)M?Yo^Io@XyzBmd{7%TumXIE=!%{b|`y@ucyA zYh_>eJsc?7uNRM|66Um0hFfIYc(JmccUu-14iE|o-E{vLP_)r240?s?6i9H7NE!nR z&+VCv&s_?C{eg&4@!7h$9#FiQ8_bk)_7UPIa`VgPU5t;f?JwFL=M2a{&ezP~eABzh zGdQuBSx6{ou9Q!n@IgpD_RcSQ$w8EW01bgiJ+A~niYT;ec-Wfc@t^*}PXyo6=YDol@((>DSKth5{M>baY51v!>t67`z~~4aeI1OFW(mkM zpL*&7Ly4;?+g`SuJ*UUr=0M>9;c^9qo=Z2B&D6cE;~spvDJY1{Nfl0biajtZL;I%X z!lkARG}_6AC^5?J3(O|`E+XPE-p=cm+x8k&I7ch-=fcF!&((vQ5J?3_(WjZG-mju0 z4;bKo3KuijJ_u`K-f}XZSnoW>)GK+PAz0rsIB)JF_Tr(rWw{DKY^DBi-ZOvkvA4@- zc-{n1l)k!0-okS>Kl~PXm}6?P7-pp@C|ZCbYn|xn*Hr2y+G#&rSByA9YdgJdXZKw_ z&6Vg1gp@0gI}VXOmU0Vx6rST0)H7Z2q1W4g8Zno<4#pQwF8Y@&x0Cgpz7*4Rl&ONx z`JR0$j_tZeXs%~Qh$))ZgM{Tg(Xgd!o2}Lcl+Z~D^8GZlSPJYD%y?hlO3W32Vm2^# zAMbXqHQsvmbxLE7>_KDWF9V42zz^OJr@AnSlE1y}TJKLcjLPE9De3$AF1Z!mrS&U+ zKP6w{`4S!E>vD?MG$^t};<;a1>JcN3=&sT1y|U*VAT)Pn2L=a{G{*vAw3H8D>oMmP ze+9G@)IdC(AOIvK&&DSzRbbD}@K>8kt$pr}0XL~^?^Ui;3?^8c8DrdEeOyWQ|wzMOA1rDeozHG)oWp6u-7nu!o2~$AMV;tp3Q5uh+M&y_tbZs0qBj%}^ z#1ux14R;rE!8{>aZ;leF5dOC-=i9|%p>QQL%m#{ioFm3N*b1Z1*BUK5P$~Wd;TxAX z+x9zas^*Vwyi$HRM{x1iewh4!GT|W2+pd$p8t+fRpzolAXR1@Y=0K4p5YKpKQwA8? z37WF^)3P3S$J~BObdEa^^yVr)I(3);hWAQM)3goc7|i=f@0CMI{N90R{OOtC-Ahe- zBbLHijgMeFZn^HCI2yYYG&O7(Cm{mjH$%a!M@j&vw5HEY`0>cs4-7gD>Z21`CQ`udoby7g^#gZ2d!{-KcFn>4&m$Zqb(Vz#N zC8jrF23Yj?0ol0wNOET*HXnq*{e1;9$wZNvS~DJ6Zboa6_0Yy1%$fEqTw@p=wak!5 zt=W$H>mlo><>kqLN+Ce6Fc-AjQJ5rgGoK3z`5Yr~eC0YVElRw@%`jd-v@li8?+asf zW}46T6{Guxi^0^hbIC^$GqX2eDu0GKYsZ+y$lBow3M}2%1}L<1U-1Mm9C1^^W*)%p zJ7Bo|6XmX+VZ=1mB?xd?c_#pq+7zsD;g9r5$jD~#(Y?uktqTqFQ5w90#aCzfqNm%T zEicxiG4u_M>S4{aXr84F$`TZ+0H=nIP@Jhrf8cw2`YTKmux10gNWh!`feV--qhI7P zkiyuIWt>(#PD0$LmyctQp%eQ+Ip_UzxgZl$HTfk^k|RHLzV|;Dc&;l(Wa*r9Qcz%y zzWSh8>AVboQC^W^M!#_2aQD?`QUK_tX@%&N9WY!SsS~sd=?pWtQv05HIv(g?H3Il? zg9(2ckWXTf5*RmwPy^E5zB9UPV$u6|$o>zNbJkRg<^UhKx73VBmm4uYDpN-aEEau2 zGlO8DOwa{W0fHk7VSr9B-B-c+VZHu#l;k6P=72$eaD_`gU^2A&iFw zNxV3;=DV1o|AcO_6A$XobIG$;tdqZ)Uy#BLKQ4zhrb?y`n7z87(2jjo(+Pm#2(Ec{ z(`U`@r!fk97p2I^XMWI^_C@D)VjVR2W}3Ar%1qi>1|6^uU5~ZEoa_xxR%Xmos zm)|PS@NNXyq_6m@DVpi+^$}j}bR1x037_SE7W$~!bLsw%CZx1yQ3f<1cYReBH*ZWM zoh)MvxduxKT(Bn9>gC~QW#G`fjP(UlyX9&*@b}+|u0FWne}XUhgXLTjmUCu~i3pWu zD=M^@7}Ab?;Dk&GY?aVFKZlnK&L98>xzA%UYY4)7dQ1(55^k#;-Ymom)@>?6Vn9KE z7^s3W1;rx3xR28Pw0(sRI7|3evmt|9A~{ui9rFB3OjE{8w+xU5?W<=o*yYvTQz3kSD9DPw!) z;>{SL<#Pw*UoYDz(_h(<{6f8LKG|1)F>9E5zJxyD*Zc^^B}%2>ViGbqqJyU&oomxWhG6T3**LUw_kua_EuWa>HCbc?WEI`n;<5mBn^6 zJhc@3Hc?dX#s83?E4COU!-WyaLesRD8a68UMB}k&0U_czE>RB=7mST4D3A}Vq|~;! z)DuBhuw@k?JUu59tP>VzLj&P|^QSsw!Cu)bjW>Xg!PWe=jIBt=Bepl9970hV&VX1!oS-EDpk!EAO|2aJiwD>d?C2QbzN{}D&ZGwp|EbYCLd!wVjSB2BU61)3+yiu zaI+cWE3Z$Afl@1um)j=BRAtq@Bn1T?OPyw*a}1d{gkV4{Fp#Dq1oyU;O2Jqi{{TGc zioOuvB0~@zDoRWasWaJV%MZw5ILX5>m_cCk_yr68-`{Zuy67u^C_Y|SfN&H)4ltBs zxU}+4`xlr)%F4Ur<7sGH`=5Ux8~4o0`-rKy0d7&p<4DlGT)-HIM&f*7?T|c*s`w6E z-M<1WZxVI2iwWo#mGW{eA^_vo5Xv9h0Di!9LtO_PG~x|M*uyMzbql0}S`>f-6@cl< z(gu>s77!h_l^t0llxO;vkKZDH&pEDnWps*_ z&U3x_ddj=NP%yY5^DHogA!q-wNvUAg6$yfE-h5fQo`3sqAC~KnH02`G_NLop6^YW$FH6XIx0ytEJIAEl`%f5D=`S!C?A)J0JZb>y4v={IEiToap zhkvm>{$MSC@_&O*`eIl*16Q`j7dpUK{R|CkA1q5h3g^%A6<@K~ux*`D)}Ob1)J3bX z2~qqOE0n~IpeO`RqhG*8N4HR_LqjFJ0z)fmT{x4)A%ZlKc`OZvf zkL?8GF;8NlV64hte*6~mMZL$%ZF!tEfPlbhqSJbRfuYA$$@IRsOGfuk$whF6VU{;L z@}bM*yNBu$+`lLJFe2bT@bwQP8uk>JOGbQy-wtIb$DXL8z;G|HN}ce3bz>y5I^OR}(Z>F_J1g3J}`0STgC_N*n|fxGDh!brJ;y z93o(UIcanYv#%A|g&=4C@V9O>-`Ixbwe4k$x;pCsk)nb>0HarwK!$Ygg#UNnmhsu9 zY({xIpRk7g7o8&yP0dT?$a3=QSOOp63l0WKW{+AJNcRv$b0CFqC~x1Fb?D6 zn^;l6)7kHmnyR<*MKX)KT=l4QjaP=(seS`#o=L=wiu9`M|3^F z)Pqm{#!cqP%LR(F9uV|#npFN$I36&}Up*oh&o|`#5aD`gw1=ewz5yXOLgbH?isnr) zfF|P)(})V&jBTC4sl!NuJiyq9mM~0zyGl=JtM`DCN_DW20swjwzNc0Q-b+LYSa6`w z2UAd>Cunu$7HLE29?bwa@W&z;ppT%NWNw)sCrHd+moJdt`}Ipq>*dfX-Y|gB&ezlh zhW^%=&xB-eVq$_m7?+*=7U|Oq!jXL4o(OQ;*{3{;Da7sl7%B7+yg3Bc6Fa&TAADWo|`iWc3|KMWarLCSh%Oh=0n|vcC2abDpNOfw7 zA0PDEjFq!MRVW*XfVmYr;4+wh_#Oyy5DH$8E^s696GY0{dVf(zG#N5)SVp$hs!+d^ z(vj79A(YyY`qk@lzG`l2Qc$QK!8ivCc4ComP8Cp1dK@J(6(LwV9D$pFFqBQ2LV0C0 zj8WGJP~>K6W*T$%S3mh~^Z9%3vA#O5(nij}pEoohvi)}teLl5a#xN~^FQ!w@!LTeK zHr7Fl8=&_PR_0!4L1LC|e7Y=MW`7KpumQ^>#$naw zYxeMLdVIP3t{8lVC7u-nSd!|GPB{bMO7EZ+h&r@rFI70ZcmQvzJ#;}q?z5triV|Gx z9A*tZ+!lxq9Un=+VE)Lw{bn4S+kfZ1W@;;(;@&gBDOLfIlBoNC2jW2!QisQHd%zY; zEk;Ovc{>NMhgusT4C|M%FcKrARMlmSu3+?YXn>`Qbc9o_0?gEu#%h+T@u1>>aJ$qL z)v^MEdg^yb@0KnC4t$hhaBt45qS+B6Iv%2R)rkeaP*G!1Lrj0kkLxV=dw5>{Z~I&F z;ceSgO1*T)m3sDnR+H-iC+z9iZFh^=MqC1?9@XtrU$k%X{p5Xo);|R>E`o65kah|Z zFkwg5;N4sgAd0L%k>JTB>}#h01OmOmf*t%qB^(h zlob?=o)L^e1P-WB;H2|LG#tam{y^D_Mk?kPXWn9Va?$U9->nz&P;952QcRxq)o1&K z3Jf}VTgEf^-~Pp3%Hr$q<~x2LpX{}CAc6fd32UkIWskttNBfErR1hlakm8u?hAAGD zRH|2WM21bdfN}#>K$UZV8nr-Fl%z?|sfQEi6r-moB^)K%d!=4E@5O}eF`>k-vrNH< z5gngROphfFqVaRg5K?E<0 zWichaRLI#NAHe4ppr)7s#6MAI7q_>!R&I! z6*#S&Lph3?tJGyY9=UX6dO_wE7NyM6yk)h4t7Tg)SHfyJ&(8yx&+Xi8?)=M-DYsJa zb-=5CZJlgd1;okrR8KwS7;=}$wyrq&^gXr|4GQ{2!VEF<9=`A~E?IiD3^dE7=l{9`-xlq|H#1BJNarq z4W;>cTNx*&!b~sQS%NP3r3h-WAto#_8U)U$Nn$KHi$!uHL!{(k{GIL$*>*~fFPa|3k4mc)lPo6d%`X( z%)@YusS>;~fL+^<8B=8uZ;i-+QQ+M2YzwoeZK{D^=>IFY)JHncuA=D0t&UYdyc9~G z;$h+xg+0yj~3%xZe~IL=0DwReyQ`^FU}=a0dXcMe41_OS9|47u};VM z^!@fq#zlS}*8kIZu-0QdB>YGWKRCw%oqYU<=bGN`=O)d}%q&0tl9ztw77Pvc$r_g1 z9b&~)ejp+Y9#2n7v*k@B6Lynw<(nC$>)X$g6{YTPNz7SKzo>CHgbk zN~pWAG*AtmVD~@&!Tt7c7_#^`wYI$tN7E&`HWmRmtxBbsTX*gnok3`3XXc5}iB$o` z8o?#Xui0sso^Eg(sj;FCrfh^tF@*HEns#?Saj)toFPvVq!V6!%diG5AKn56)ROG+k zS3f^8rT0N&UD#xQGZJB>j*^L&GC6p7(#$U``6ELEtdu)|9|GqTe58O5f#^uX@4!vC z+!B`3GJo>PTg~sQuY{DgeWK@H1;mMZ=2bkdz{r}b+dgXtOBH!LfcPMkCO4Px6H+oa zvzRO_E!)0I$@JmI)}?ke3X6KFuM6E{31^pvUHtD)++u!zZxs-)B2mx8t<}qz9WPN= z^qzrmGX~}d-~xB>lh#)-%pr>lbt0+!Fo#@Wumm3`(?vi7qon-UsrfQeVjr@mlW7BT*rAm@LS1!`_!VJo8b>|vZ#x~^3jK;)4P-)TqffB(Dh zE$$K8!0q*ag5pA7bX8=$>f}C!2Y{&Cx-@gv!moYN7RCd48-A(LuodZVbr8TC%pf`H z=$VH;d9ztKSumW!ldM*Kt@VI%4PriD)JoKPr}FHlRQXgIUakAe^neolUPf8RncQV6_KUdtkLH2UdGvwFg#vV6_KUdtkK(-k3e` Z{{d1ufCu*9Zr}g_002ovPDHLkV1jOzoFxDN diff --git a/app/views/notes.py b/app/views/notes.py index cd211ca05..a8c387e4b 100644 --- a/app/views/notes.py +++ b/app/views/notes.py @@ -35,7 +35,7 @@ from operator import itemgetter from xml.etree import ElementTree import flask -from flask import flash, jsonify, render_template, url_for +from flask import abort, flash, jsonify, render_template, url_for from flask import current_app, g, request from flask_login import current_user from werkzeug.utils import redirect @@ -68,10 +68,14 @@ from app.scodoc import sco_utils as scu from app.scodoc import notesdb as ndb from app import log, send_scodoc_alarm -from app.scodoc import scolog from app.scodoc.scolog import logdb -from app.scodoc.sco_exceptions import AccessDenied, ScoValueError, ScoInvalidIdType +from app.scodoc.sco_exceptions import ( + AccessDenied, + ScoException, + ScoValueError, + ScoInvalidIdType, +) from app.scodoc import html_sco_header from app.pe import pe_view from app.scodoc import sco_abs @@ -2672,12 +2676,15 @@ def check_integrity_all(): def moduleimpl_list( moduleimpl_id=None, formsemestre_id=None, module_id=None, format="json" ): - data = sco_moduleimpl.moduleimpl_list( - moduleimpl_id=moduleimpl_id, - formsemestre_id=formsemestre_id, - module_id=module_id, - ) - return scu.sendResult(data, format=format) + try: + data = sco_moduleimpl.moduleimpl_list( + moduleimpl_id=moduleimpl_id, + formsemestre_id=formsemestre_id, + module_id=module_id, + ) + return scu.sendResult(data, format=format) + except ScoException: + abort(404) @bp.route("/do_moduleimpl_withmodule_list") # ancien nom From 00fa91e598b12833dbd2669c16c7c3783be44b69 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sun, 27 Feb 2022 20:32:38 +0100 Subject: [PATCH 124/287] Calcul moyenne gen. BUT avec ECTS --- app/comp/moy_sem.py | 31 ++++++++++++++++++++++++++++++- app/comp/res_but.py | 13 +++++++++---- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/app/comp/moy_sem.py b/app/comp/moy_sem.py index 5caa3d393..6a44dbc00 100644 --- a/app/comp/moy_sem.py +++ b/app/comp/moy_sem.py @@ -30,8 +30,11 @@ import numpy as np import pandas as pd +from flask import g, url_for +from app.scodoc.sco_exceptions import ScoValueError -def compute_sem_moys_apc( + +def compute_sem_moys_apc_using_coefs( etud_moy_ue_df: pd.DataFrame, modimpl_coefs_df: pd.DataFrame ) -> pd.Series: """Calcule les moyennes générales indicatives de tous les étudiants @@ -48,6 +51,32 @@ def compute_sem_moys_apc( return moy_gen +def compute_sem_moys_apc_using_ects( + etud_moy_ue_df: pd.DataFrame, ects: list, formation_id=None +) -> pd.Series: + """Calcule les moyennes générales indicatives de tous les étudiants + = moyenne des moyennes d'UE, pondérée par leurs ECTS. + + etud_moy_ue_df: DataFrame, colonnes ue_id, lignes etudid + ects: liste de floats ou None, 1 par UE + + Result: panda Series, index etudid, valeur float (moyenne générale) + """ + try: + moy_gen = (etud_moy_ue_df * ects).sum(axis=1) / sum(ects) + except TypeError: + if None in ects: + raise ScoValueError( + f"""Calcul impossible: ECTS des UE manquants ! + voir la page du programme. + """ + ) + else: + raise + return moy_gen + + def comp_ranks_series(notes: pd.Series) -> (pd.Series, pd.Series): """Calcul rangs à partir d'une séries ("vecteur") de notes (index etudid, valeur numérique) en tenant compte des ex-aequos. diff --git a/app/comp/res_but.py b/app/comp/res_but.py index 1d01f4f42..f4cdda8ab 100644 --- a/app/comp/res_but.py +++ b/app/comp/res_but.py @@ -14,7 +14,7 @@ from app import log from app.comp import moy_ue, moy_sem, inscr_mod from app.comp.res_common import NotesTableCompat from app.comp.bonus_spo import BonusSport -from app.models import ScoDocSiteConfig +from app.models import ScoDocSiteConfig, formsemestre from app.models.ues import UniteEns from app.scodoc.sco_codes_parcours import UE_SPORT @@ -73,7 +73,7 @@ class ResultatsSemestreBUT(NotesTableCompat): ) # Les coefficients d'UE ne sont pas utilisés en APC self.etud_coef_ue_df = pd.DataFrame( - 1.0, index=self.etud_moy_ue.index, columns=self.etud_moy_ue.columns + 0.0, index=self.etud_moy_ue.index, columns=self.etud_moy_ue.columns ) # --- Modules de MALUS sur les UEs @@ -103,8 +103,13 @@ class ResultatsSemestreBUT(NotesTableCompat): # Moyenne générale indicative: # (note: le bonus sport a déjà été appliqué aux moyennes d'UE, et impacte # donc la moyenne indicative) - self.etud_moy_gen = moy_sem.compute_sem_moys_apc( - self.etud_moy_ue, self.modimpl_coefs_df + # self.etud_moy_gen = moy_sem.compute_sem_moys_apc_using_coefs( + # self.etud_moy_ue, self.modimpl_coefs_df + # ) + self.etud_moy_gen = moy_sem.compute_sem_moys_apc_using_ects( + self.etud_moy_ue, + [ue.ects for ue in self.ues], + formation_id=self.formsemestre.formation_id, ) # --- UE capitalisées self.apply_capitalisation() From 68680e89d32de6f414220beb5ddd4b4c22c5cc0c Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 28 Feb 2022 09:22:17 +0100 Subject: [PATCH 125/287] Exception si erreur connexion vers assistance --- app/scodoc/sco_dump_db.py | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/app/scodoc/sco_dump_db.py b/app/scodoc/sco_dump_db.py index b11f63ca8..f9521b292 100644 --- a/app/scodoc/sco_dump_db.py +++ b/app/scodoc/sco_dump_db.py @@ -186,18 +186,28 @@ def _send_db(ano_db_name): log("uploading anonymized dump...") files = {"file": (ano_db_name + ".dump", dump)} - r = requests.post( - scu.SCO_DUMP_UP_URL, - files=files, - data={ - "dept_name": sco_preferences.get_preference("DeptName"), - "serial": _get_scodoc_serial(), - "sco_user": str(current_user), - "sent_by": sco_users.user_info(str(current_user))["nomcomplet"], - "sco_version": sco_version.SCOVERSION, - "sco_fullversion": scu.get_scodoc_version(), - }, - ) + try: + r = requests.post( + scu.SCO_DUMP_UP_URL, + files=files, + data={ + "dept_name": sco_preferences.get_preference("DeptName"), + "serial": _get_scodoc_serial(), + "sco_user": str(current_user), + "sent_by": sco_users.user_info(str(current_user))["nomcomplet"], + "sco_version": sco_version.SCOVERSION, + "sco_fullversion": scu.get_scodoc_version(), + }, + ) + except requests.exceptions.ConnectionError as exc: + raise ScoValueError( + """ + Impossible de joindre le serveur d'assistance (scodoc.org). + Veuillez contacter le service informatique de votre établissement pour + corriger la configuration de ScoDoc. Dans la plupart des cas, il + s'agit d'un proxy mal configuré. + """ + ) from exc return r From ef408e5d8eb97f924c4bef98c66b33a2fdb34878 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 28 Feb 2022 11:00:24 +0100 Subject: [PATCH 126/287] Gestion calcul moy gen et capit. BUT si ECTS manquants --- app/comp/moy_sem.py | 11 +++-------- app/comp/res_common.py | 5 ++--- app/models/ues.py | 6 ++++-- app/scodoc/sco_edit_ue.py | 9 +++++---- app/static/css/scodoc.css | 5 ++++- app/templates/pn/form_ues.html | 3 ++- 6 files changed, 20 insertions(+), 19 deletions(-) diff --git a/app/comp/moy_sem.py b/app/comp/moy_sem.py index 6a44dbc00..2aec3b736 100644 --- a/app/comp/moy_sem.py +++ b/app/comp/moy_sem.py @@ -30,8 +30,7 @@ import numpy as np import pandas as pd -from flask import g, url_for -from app.scodoc.sco_exceptions import ScoValueError +from flask import flash def compute_sem_moys_apc_using_coefs( @@ -66,12 +65,8 @@ def compute_sem_moys_apc_using_ects( moy_gen = (etud_moy_ue_df * ects).sum(axis=1) / sum(ects) except TypeError: if None in ects: - raise ScoValueError( - f"""Calcul impossible: ECTS des UE manquants ! - voir la page du programme. - """ - ) + flash(f"""Calcul moyenne générale impossible: ECTS des UE manquants !""") + moy_gen = pd.Series(np.NaN, index=etud_moy_ue_df.index) else: raise return moy_gen diff --git a/app/comp/res_common.py b/app/comp/res_common.py index 7fa75c1b7..6a821ac69 100644 --- a/app/comp/res_common.py +++ b/app/comp/res_common.py @@ -259,9 +259,8 @@ class ResultatsSemestre(ResultatsCache): cur_moy_ue = self.etud_moy_ue[ue_id][etudid] moy_ue = cur_moy_ue is_capitalized = False # si l'UE prise en compte est une UE capitalisée - was_capitalized = ( - False # s'il y a precedemment une UE capitalisée (pas forcement meilleure) - ) + # s'il y a precedemment une UE capitalisée (pas forcement meilleure): + was_capitalized = False if etudid in self.validations.ue_capitalisees.index: ue_cap = self._get_etud_ue_cap(etudid, ue) if ue_cap and not np.isnan(ue_cap["moy_ue"]): diff --git a/app/models/ues.py b/app/models/ues.py index 09469fb05..2bed88a38 100644 --- a/app/models/ues.py +++ b/app/models/ues.py @@ -54,13 +54,15 @@ class UniteEns(db.Model): 'EXTERNE' if self.is_external else ''})>""" def to_dict(self): - """as a dict, with the same conversions as in ScoDoc7""" + """as a dict, with the same conversions as in ScoDoc7 + (except ECTS: keep None) + """ e = dict(self.__dict__) e.pop("_sa_instance_state", None) # ScoDoc7 output_formators e["ue_id"] = self.id e["numero"] = e["numero"] if e["numero"] else 0 - e["ects"] = e["ects"] if e["ects"] else 0.0 + e["ects"] = e["ects"] e["coefficient"] = e["coefficient"] if e["coefficient"] else 0.0 e["code_apogee"] = e["code_apogee"] or "" # pas de None return e diff --git a/app/scodoc/sco_edit_ue.py b/app/scodoc/sco_edit_ue.py index 8f9488557..73e77dbbd 100644 --- a/app/scodoc/sco_edit_ue.py +++ b/app/scodoc/sco_edit_ue.py @@ -89,6 +89,7 @@ _ueEditor = ndb.EditableTable( input_formators={ "type": ndb.int_null_is_zero, "is_external": ndb.bool_or_str, + "ects": ndb.float_null_is_null, }, output_formators={ "numero": ndb.int_null_is_zero, @@ -347,6 +348,7 @@ def ue_edit(ue_id=None, create=False, formation_id=None, default_semestre_idx=No "type": "float", "title": "ECTS", "explanation": "nombre de crédits ECTS", + "allow_null": not is_apc, # ects requis en APC }, ), ( @@ -933,10 +935,10 @@ def _ue_table_ues( cur_ue_semestre_id = None iue = 0 for ue in ues: - if ue["ects"]: - ue["ects_str"] = ", %g ECTS" % ue["ects"] - else: + if ue["ects"] is None: ue["ects_str"] = "" + else: + ue["ects_str"] = ", %g ECTS" % ue["ects"] if editable: klass = "span_apo_edit" else: @@ -1295,7 +1297,6 @@ def do_ue_edit(args, bypass_lock=False, dont_invalidate_cache=False): f"""Acronyme d'UE "{args['acronyme']}" déjà utilisé ! (chaque UE doit avoir un acronyme unique dans la formation)""" ) - # On ne peut pas supprimer le code UE: if "ue_code" in args and not args["ue_code"]: del args["ue_code"] diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css index bd99c80c6..3b80f7d6d 100644 --- a/app/static/css/scodoc.css +++ b/app/static/css/scodoc.css @@ -1671,7 +1671,10 @@ div.formation_list_modules ul.notes_module_list { padding-top: 5px; padding-bottom: 5px; } - +span.missing_ue_ects { + color: red; + font-weight: bold; +} li.module_malus span.formation_module_tit { color: red; font-weight: bold; diff --git a/app/templates/pn/form_ues.html b/app/templates/pn/form_ues.html index 0cd3e333b..98c590f7b 100644 --- a/app/templates/pn/form_ues.html +++ b/app/templates/pn/form_ues.html @@ -38,7 +38,8 @@ {% set virg = joiner(", ") %} ( {%- if ue.ue_code -%}{{ virg() }}code {{ue.ue_code}} {%- endif -%} - {{ virg() }}{{ue.ects or 0}} ECTS) + {{ virg() }}{{ue.ects if ue.ects is not none + else 'aucun'|safe}} ECTS) From e1db9c542bffc3b6c8620782457e9ee52200795b Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 28 Feb 2022 11:47:39 +0100 Subject: [PATCH 127/287] Messages flash flask sur ancioennes pages ScoDoc + warning ECTS BUT --- app/comp/moy_sem.py | 2 +- app/comp/res_common.py | 22 ++++++++++++++++------ app/scodoc/html_sco_header.py | 5 ++++- app/scodoc/sco_edit_ue.py | 2 ++ app/static/css/scodoc.css | 2 +- 5 files changed, 24 insertions(+), 9 deletions(-) diff --git a/app/comp/moy_sem.py b/app/comp/moy_sem.py index 2aec3b736..db42616c8 100644 --- a/app/comp/moy_sem.py +++ b/app/comp/moy_sem.py @@ -65,7 +65,7 @@ def compute_sem_moys_apc_using_ects( moy_gen = (etud_moy_ue_df * ects).sum(axis=1) / sum(ects) except TypeError: if None in ects: - flash(f"""Calcul moyenne générale impossible: ECTS des UE manquants !""") + flash("""Calcul moyenne générale impossible: ECTS des UE manquants !""") moy_gen = pd.Series(np.NaN, index=etud_moy_ue_df.index) else: raise diff --git a/app/comp/res_common.py b/app/comp/res_common.py index 6a821ac69..7d2eb5ae3 100644 --- a/app/comp/res_common.py +++ b/app/comp/res_common.py @@ -9,7 +9,7 @@ from functools import cached_property import numpy as np import pandas as pd -from flask import g, url_for +from flask import g, flash, url_for from app import log from app.comp.aux_stats import StatsMoyenne @@ -419,21 +419,31 @@ class NotesTableCompat(ResultatsSemestre): """Stats (moy/min/max) sur la moyenne générale""" return StatsMoyenne(self.etud_moy_gen) - def get_ues_stat_dict(self, filter_sport=False): # was get_ues() + def get_ues_stat_dict( + self, filter_sport=False, check_apc_ects=True + ) -> list[dict]: # was get_ues() """Liste des UEs, ordonnée par numero. Si filter_sport, retire les UE de type SPORT. Résultat: liste de dicts { champs UE U stats moyenne UE } """ - ues = [] - for ue in self.formsemestre.query_ues(with_sport=not filter_sport): + ues = self.formsemestre.query_ues(with_sport=not filter_sport) + ues_dict = [] + for ue in ues: d = ue.to_dict() if ue.type != UE_SPORT: moys = self.etud_moy_ue[ue.id] else: moys = None d.update(StatsMoyenne(moys).to_dict()) - ues.append(d) - return ues + ues_dict.append(d) + if check_apc_ects and self.is_apc and not hasattr(g, "checked_apc_ects"): + g.checked_apc_ects = True + if None in [ue.ects for ue in ues if ue.type != UE_SPORT]: + flash( + """Calcul moyenne générale impossible: ECTS des UE manquants !""", + category="danger", + ) + return ues_dict def get_modimpls_dict(self, ue_id=None) -> list[dict]: """Liste des modules pour une UE (ou toutes si ue_id==None), diff --git a/app/scodoc/html_sco_header.py b/app/scodoc/html_sco_header.py index 23a8b8340..653cdb80d 100644 --- a/app/scodoc/html_sco_header.py +++ b/app/scodoc/html_sco_header.py @@ -30,7 +30,7 @@ import html -from flask import g +from flask import render_template from flask import request from flask_login import current_user @@ -280,6 +280,9 @@ def sco_header( if not no_side_bar: H.append(html_sidebar.sidebar()) H.append("""

    """) + # En attendant le replacement complet de cette fonction, + # inclusion ici des messages flask + H.append(render_template("flashed_messages.html")) # # Barre menu semestre: H.append(formsemestre_page_title()) diff --git a/app/scodoc/sco_edit_ue.py b/app/scodoc/sco_edit_ue.py index 73e77dbbd..8cc3269a1 100644 --- a/app/scodoc/sco_edit_ue.py +++ b/app/scodoc/sco_edit_ue.py @@ -472,8 +472,10 @@ def ue_edit(ue_id=None, create=False, formation_id=None, default_semestre_idx=No "semestre_id": tf[2]["semestre_idx"], }, ) + flash("UE créée") else: do_ue_edit(tf[2]) + flash("UE modifiée") return flask.redirect( url_for( "notes.ue_table", diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css index 3b80f7d6d..b3a80640a 100644 --- a/app/static/css/scodoc.css +++ b/app/static/css/scodoc.css @@ -138,7 +138,7 @@ div.head_message { border-radius: 8px; font-family : arial, verdana, sans-serif ; font-weight: bold; - width: 40%; + width: 70%; text-align: center; } From 546e10c83a333cd215a103d72e5e12d1d1cc5ff2 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 28 Feb 2022 15:07:48 +0100 Subject: [PATCH 128/287] Finalise calcul moy. gen. indicative BUT --- app/comp/res_but.py | 2 +- app/comp/res_common.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/comp/res_but.py b/app/comp/res_but.py index f4cdda8ab..20e63cba0 100644 --- a/app/comp/res_but.py +++ b/app/comp/res_but.py @@ -108,7 +108,7 @@ class ResultatsSemestreBUT(NotesTableCompat): # ) self.etud_moy_gen = moy_sem.compute_sem_moys_apc_using_ects( self.etud_moy_ue, - [ue.ects for ue in self.ues], + [ue.ects for ue in self.ues if ue.type != UE_SPORT], formation_id=self.formsemestre.formation_id, ) # --- UE capitalisées diff --git a/app/comp/res_common.py b/app/comp/res_common.py index 7d2eb5ae3..8fa106f50 100644 --- a/app/comp/res_common.py +++ b/app/comp/res_common.py @@ -195,7 +195,7 @@ class ResultatsSemestre(ResultatsCache): if ue_cap["is_capitalized"]: recompute_mg = True coef = ue_cap["coef_ue"] - if not np.isnan(ue_cap["moy"]): + if not np.isnan(ue_cap["moy"]) and coef: sum_notes_ue += ue_cap["moy"] * coef sum_coefs_ue += coef From 5aa896f7932e27d551cdfcae1d36ec275855ba34 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 28 Feb 2022 15:08:32 +0100 Subject: [PATCH 129/287] Bonus Aisne St Quentin + fix bonus Ville d'Avray --- app/comp/bonus_spo.py | 61 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 9 deletions(-) diff --git a/app/comp/bonus_spo.py b/app/comp/bonus_spo.py index 18c57beb0..99738336e 100644 --- a/app/comp/bonus_spo.py +++ b/app/comp/bonus_spo.py @@ -228,6 +228,10 @@ class BonusSportAdditif(BonusSport): else: # necessaire pour éviter bonus négatifs ! bonus_moy_arr = np.clip(bonus_moy_arr, 0.0, 20.0, out=bonus_moy_arr) + self.bonus_additif(bonus_moy_arr) + + def bonus_additif(self, bonus_moy_arr: np.array): + "Set bonus_ues et bonus_moy_gen" # en APC, bonus_moy_arr est (nb_etuds, nb_ues_non_bonus) if self.formsemestre.formation.is_apc(): # Bonus sur les UE et None sur moyenne générale @@ -306,6 +310,47 @@ class BonusDirect(BonusSportAdditif): proportion_point = 1.0 +class BonusAisneStQuentin(BonusSportAdditif): + """Calcul bonus modules optionels (sport, culture), règle IUT Aisne St Quentin + +

    Les étudiants de l'IUT peuvent suivre des enseignements optionnels + de l'Université de St Quentin non rattachés à une unité d'enseignement. +

    +
      +
    • Si la note est >= 10 et < 12.1, bonus de 0.1 point
    • +
    • Si la note est >= 12.1 et < 14.1, bonus de 0.2 point
    • +
    • Si la note est >= 14.1 et < 16.1, bonus de 0.3 point
    • +
    • Si la note est >= 16.1 et < 18.1, bonus de 0.4 point
    • +
    • Si la note est >= 18.1, bonus de 0.5 point
    • +
    +

    + Ce bonus s'ajoute à la moyenne générale du semestre déjà obtenue par + l'étudiant (en BUT, s'ajoute à la moyenne de chaque UE). +

    + """ + + name = "bonus_iutstq" + displayed_name = "IUT de Saint-Quentin" + + def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan): + """calcul du bonus""" + if 0 in sem_modimpl_moys_inscrits.shape: + # pas d'étudiants ou pas d'UE ou pas de module... + return + # Calcule moyenne pondérée des notes de sport: + bonus_moy_arr = np.sum( + sem_modimpl_moys_inscrits * modimpl_coefs_etuds_no_nan, axis=1 + ) / np.sum(modimpl_coefs_etuds_no_nan, axis=1) + bonus_moy_arr[bonus_moy_arr < 10.0] = 0.0 + bonus_moy_arr[bonus_moy_arr >= 18.1] = 0.5 + bonus_moy_arr[bonus_moy_arr >= 16.1] = 0.4 + bonus_moy_arr[bonus_moy_arr >= 14.1] = 0.3 + bonus_moy_arr[bonus_moy_arr >= 12.1] = 0.2 + bonus_moy_arr[bonus_moy_arr >= 10] = 0.1 + + self.bonus_additif(bonus_moy_arr) + + class BonusAmiens(BonusSportAdditif): """Bonus IUT Amiens pour les modules optionnels (sport, culture, ...). @@ -774,21 +819,19 @@ class BonusVilleAvray(BonusSport): def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan): """calcul du bonus""" + if 0 in sem_modimpl_moys_inscrits.shape: + # pas d'étudiants ou pas d'UE ou pas de module... + return # Calcule moyenne pondérée des notes de sport: bonus_moy_arr = np.sum( sem_modimpl_moys_inscrits * modimpl_coefs_etuds_no_nan, axis=1 ) / np.sum(modimpl_coefs_etuds_no_nan, axis=1) - bonus_moy_arr[bonus_moy_arr >= 10.0] = 0.1 - bonus_moy_arr[bonus_moy_arr >= 12.0] = 0.2 + bonus_moy_arr[bonus_moy_arr < 10.0] = 0.0 bonus_moy_arr[bonus_moy_arr >= 16.0] = 0.3 + bonus_moy_arr[bonus_moy_arr >= 12.0] = 0.2 + bonus_moy_arr[bonus_moy_arr >= 10.0] = 0.1 - # Bonus moyenne générale, et 0 sur les UE - self.bonus_moy_gen = pd.Series(bonus_moy_arr, index=self.etuds_idx, dtype=float) - if self.bonus_max is not None: - # Seuil: bonus (sur moy. gen.) limité à bonus_max points - self.bonus_moy_gen = self.bonus_moy_gen.clip(upper=self.bonus_max) - - # Laisse bonus_ues à None, en APC le bonus moy. gen. sera réparti sur les UEs. + self.bonus_additif(bonus_moy_arr) class BonusIUTV(BonusSportAdditif): From f7c90397a890ed7c3f0806b9115b64c2aeb9ca3e Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 28 Feb 2022 15:12:32 +0100 Subject: [PATCH 130/287] Enhance scodoc7 decorator: FileStorage arguments --- app/decorators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/decorators.py b/app/decorators.py index 8ebf5deab..220ece566 100644 --- a/app/decorators.py +++ b/app/decorators.py @@ -193,7 +193,7 @@ def scodoc7func(func): # necessary for db ids and boolean values try: v = int(v) - except ValueError: + except (ValueError, TypeError): pass pos_arg_values.append(v) # current_app.logger.info("pos_arg_values=%s" % pos_arg_values) From bee7b74f170b4c5dd1d786c1eb5c56c51d753cdc Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 28 Feb 2022 15:18:21 +0100 Subject: [PATCH 131/287] =?UTF-8?q?Fichier=20oubli=C3=A9=20(flask=20flash)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/templates/flashed_messages.html | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 app/templates/flashed_messages.html diff --git a/app/templates/flashed_messages.html b/app/templates/flashed_messages.html new file mode 100644 index 000000000..5ded75245 --- /dev/null +++ b/app/templates/flashed_messages.html @@ -0,0 +1,9 @@ +{# Message flask : utilisé uniquement par les anciennes pages ScoDoc #} +{# -*- mode: jinja-html -*- #} +
    + {% with messages = get_flashed_messages(with_categories=true) %} + {% for category, message in messages %} + + {% endfor %} + {% endwith %} +
    \ No newline at end of file From 732a4c5ce51397a3035d8783ce3cbf535c6acf23 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 28 Feb 2022 16:25:18 +0100 Subject: [PATCH 132/287] code cleaning --- app/scodoc/sco_cache.py | 76 ++++++++--------------------------------- 1 file changed, 15 insertions(+), 61 deletions(-) diff --git a/app/scodoc/sco_cache.py b/app/scodoc/sco_cache.py index 5fd0cec68..6330849c5 100644 --- a/app/scodoc/sco_cache.py +++ b/app/scodoc/sco_cache.py @@ -33,17 +33,12 @@ """ -# API ScoDoc8 pour les caches: -# sco_cache.NotesTableCache.get( formsemestre_id) -# => sco_cache.NotesTableCache.get(formsemestre_id) +# API pour les caches: +# sco_cache.MyCache.get( formsemestre_id) +# => sco_cache.MyCache.get(formsemestre_id) # -# sco_core.inval_cache(formsemestre_id=None, pdfonly=False, formsemestre_id_list=None) -# => deprecated, NotesTableCache.invalidate_formsemestre(formsemestre_id=None, pdfonly=False) -# -# -# Nouvelles fonctions: -# sco_cache.NotesTableCache.delete(formsemestre_id) -# sco_cache.NotesTableCache.delete_many(formsemestre_id_list) +# sco_cache.MyCache.delete(formsemestre_id) +# sco_cache.MyCache.delete_many(formsemestre_id_list) # # Bulletins PDF: # sco_cache.SemBulletinsPDFCache.get(formsemestre_id, version) @@ -203,49 +198,6 @@ class SemInscriptionsCache(ScoDocCache): duration = 12 * 60 * 60 # ttl 12h -class NotesTableCache(ScoDocCache): - """Cache pour les NotesTable - Clé: formsemestre_id - Valeur: NotesTable instance - """ - - prefix = "NT" - - @classmethod - def get(cls, formsemestre_id, compute=True): - """Returns NotesTable for this formsemestre - Search in local cache (g.nt_cache) or global app cache (eg REDIS) - If not in cache: - If compute is True, build it and cache it - Else return None - """ - # try local cache (same request) - if not hasattr(g, "nt_cache"): - g.nt_cache = {} - else: - if formsemestre_id in g.nt_cache: - return g.nt_cache[formsemestre_id] - # try REDIS - key = cls._get_key(formsemestre_id) - nt = CACHE.get(key) - if nt: - g.nt_cache[formsemestre_id] = nt # cache locally (same request) - return nt - if not compute: - return None - # Recompute requested table: - from app.scodoc import notes_table - - t0 = time.time() - nt = notes_table.NotesTable(formsemestre_id) - t1 = time.time() - _ = cls.set(formsemestre_id, nt) # cache in REDIS - t2 = time.time() - log(f"cached formsemestre_id={formsemestre_id} ({(t1-t0):g}s +{(t2-t1):g}s)") - g.nt_cache[formsemestre_id] = nt - return nt - - def invalidate_formsemestre( # was inval_cache(formsemestre_id=None, pdfonly=False) formsemestre_id=None, pdfonly=False ): @@ -278,22 +230,24 @@ def invalidate_formsemestre( # was inval_cache(formsemestre_id=None, pdfonly=Fa if not pdfonly: # Delete cached notes and evaluations - NotesTableCache.delete_many(formsemestre_ids) if formsemestre_id: for fid in formsemestre_ids: EvaluationCache.invalidate_sem(fid) - if hasattr(g, "nt_cache") and fid in g.nt_cache: - del g.nt_cache[fid] + if ( + hasattr(g, "formsemestre_results_cache") + and fid in g.formsemestre_results_cache + ): + del g.formsemestre_results_cache[fid] + else: # optimization when we invalidate all evaluations: EvaluationCache.invalidate_all_sems() - if hasattr(g, "nt_cache"): - del g.nt_cache + if hasattr(g, "formsemestre_results_cache"): + del g.formsemestre_results_cache SemInscriptionsCache.delete_many(formsemestre_ids) - + ResultatsSemestreCache.delete_many(formsemestre_ids) + ValidationsSemestreCache.delete_many(formsemestre_ids) SemBulletinsPDFCache.invalidate_sems(formsemestre_ids) - ResultatsSemestreCache.delete_many(formsemestre_ids) - ValidationsSemestreCache.delete_many(formsemestre_ids) class DefferedSemCacheManager: From 8330009dcf1dedf6fb7ad3288375ae3e73171d84 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 28 Feb 2022 16:26:13 +0100 Subject: [PATCH 133/287] =?UTF-8?q?En=20BUT,=20remet=20S1=20si=20semestre?= =?UTF-8?q?=20non=20sp=C3=A9cifi=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/comp/res_sem.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/app/comp/res_sem.py b/app/comp/res_sem.py index 607ad1681..e27a157c1 100644 --- a/app/comp/res_sem.py +++ b/app/comp/res_sem.py @@ -8,11 +8,13 @@ """ from flask import g +from app import db from app.comp.jury import ValidationsSemestre from app.comp.res_common import ResultatsSemestre from app.comp.res_classic import ResultatsSemestreClassic from app.comp.res_but import ResultatsSemestreBUT from app.models.formsemestre import FormSemestre +from app.scodoc import sco_cache def load_formsemestre_results(formsemestre: FormSemestre) -> ResultatsSemestre: @@ -23,6 +25,13 @@ def load_formsemestre_results(formsemestre: FormSemestre) -> ResultatsSemestre: Search in local cache (g.formsemestre_result_cache) If not in cache, build it and cache it. """ + is_apc = formsemestre.formation.is_apc() + if is_apc and formsemestre.semestre_id == -1: + formsemestre.semestre_id = 1 + db.session.add(formsemestre) + db.session.commit() + sco_cache.invalidate_formsemestre(formsemestre.id) + # --- Try local cache (within the same request context) if not hasattr(g, "formsemestre_results_cache"): g.formsemestre_results_cache = {} @@ -30,11 +39,7 @@ def load_formsemestre_results(formsemestre: FormSemestre) -> ResultatsSemestre: if formsemestre.id in g.formsemestre_results_cache: return g.formsemestre_results_cache[formsemestre.id] - klass = ( - ResultatsSemestreBUT - if formsemestre.formation.is_apc() - else ResultatsSemestreClassic - ) + klass = ResultatsSemestreBUT if is_apc else ResultatsSemestreClassic g.formsemestre_results_cache[formsemestre.id] = klass(formsemestre) return g.formsemestre_results_cache[formsemestre.id] From 0e7f2f4deb160ead6d595fb6187871fdef8132ea Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 28 Feb 2022 16:27:27 +0100 Subject: [PATCH 134/287] flash --- app/scodoc/sco_dump_db.py | 2 ++ app/scodoc/sco_formsemestre_status.py | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/scodoc/sco_dump_db.py b/app/scodoc/sco_dump_db.py index f9521b292..4b55b41f6 100644 --- a/app/scodoc/sco_dump_db.py +++ b/app/scodoc/sco_dump_db.py @@ -51,6 +51,7 @@ import fcntl import subprocess import requests +from flask import flash from flask_login import current_user import app.scodoc.notesdb as ndb @@ -124,6 +125,7 @@ def sco_dump_and_send_db(): fcntl.flock(x, fcntl.LOCK_UN) log("sco_dump_and_send_db: done.") + flash("Données envoyées au serveur d'assistance") return "\n".join(H) + html_sco_header.sco_footer() diff --git a/app/scodoc/sco_formsemestre_status.py b/app/scodoc/sco_formsemestre_status.py index 4bfa7b725..2080e9572 100644 --- a/app/scodoc/sco_formsemestre_status.py +++ b/app/scodoc/sco_formsemestre_status.py @@ -987,7 +987,6 @@ Il y a des notes en attente ! Le classement des étudiants n'a qu'une valeur ind def formsemestre_status(formsemestre_id=None): """Tableau de bord semestre HTML""" # porté du DTML - cnx = ndb.GetDBConnexion() sem = sco_formsemestre.get_formsemestre(formsemestre_id, raise_soft_exc=True) modimpls = sco_moduleimpl.moduleimpl_withmodule_list( formsemestre_id=formsemestre_id From 8b5a99657106e9f9a67b2ab1f61262641fcce374 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 28 Feb 2022 16:28:08 +0100 Subject: [PATCH 135/287] Semestre BUT: ne propose pas indice -1 --- app/scodoc/sco_formsemestre_edit.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/scodoc/sco_formsemestre_edit.py b/app/scodoc/sco_formsemestre_edit.py index 81dbd5659..3e1c92fbb 100644 --- a/app/scodoc/sco_formsemestre_edit.py +++ b/app/scodoc/sco_formsemestre_edit.py @@ -213,7 +213,10 @@ def do_formsemestre_createwithmodules(edit=False): # en APC, ne permet pas de changer de semestre semestre_id_list = [formsemestre.semestre_id] else: - semestre_id_list = [-1] + list(range(1, NB_SEM + 1)) + semestre_id_list = list(range(1, NB_SEM + 1)) + if not formation.is_apc(): + # propose "pas de semestre" seulement en classique + semestre_id_list.insert(0, -1) semestre_id_labels = [] for sid in semestre_id_list: From e993599b39d15567d07db8cc8de87d9b0011cc89 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 28 Feb 2022 17:57:12 +0100 Subject: [PATCH 136/287] =?UTF-8?q?Restreint=20edition=20modules=20semestr?= =?UTF-8?q?es=20BUT=20aux=20module=20du=20m=C3=AAme=20sem.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/scodoc/sco_formsemestre_edit.py | 30 ++++++++++++++++++++--------- app/static/js/formsemestre_edit.js | 14 ++++++++++++++ 2 files changed, 35 insertions(+), 9 deletions(-) create mode 100644 app/static/js/formsemestre_edit.js diff --git a/app/scodoc/sco_formsemestre_edit.py b/app/scodoc/sco_formsemestre_edit.py index 3e1c92fbb..f056a3e62 100644 --- a/app/scodoc/sco_formsemestre_edit.py +++ b/app/scodoc/sco_formsemestre_edit.py @@ -78,7 +78,7 @@ def formsemestre_createwithmodules(): H = [ html_sco_header.sco_header( page_title="Création d'un semestre", - javascripts=["libjs/AutoSuggest.js"], + javascripts=["libjs/AutoSuggest.js", "js/formsemestre_edit.js"], cssstyles=["css/autosuggest_inquisitor.css"], bodyOnLoad="init_tf_form('')", ), @@ -99,7 +99,7 @@ def formsemestre_editwithmodules(formsemestre_id): H = [ html_sco_header.html_sem_header( "Modification du semestre", - javascripts=["libjs/AutoSuggest.js"], + javascripts=["libjs/AutoSuggest.js", "js/formsemestre_edit.js"], cssstyles=["css/autosuggest_inquisitor.css"], bodyOnLoad="init_tf_form('')", ) @@ -344,6 +344,9 @@ def do_formsemestre_createwithmodules(edit=False): "explanation": "en BUT, on ne peut pas modifier le semestre après création" if formation.is_apc() else "", + "attributes": ['onchange="change_semestre_id();"'] + if formation.is_apc() + else "", }, ), ) @@ -496,7 +499,8 @@ def do_formsemestre_createwithmodules(edit=False): { "input_type": "boolcheckbox", "title": "", - "explanation": "Autoriser tous les enseignants associés à un module à y créer des évaluations", + "explanation": """Autoriser tous les enseignants associés + à un module à y créer des évaluations""", }, ), ( @@ -537,11 +541,19 @@ def do_formsemestre_createwithmodules(edit=False): ] nbmod = 0 - if edit: - templ_sep = "
    " - else: - templ_sep = "" + for semestre_id in semestre_ids: + if formation.is_apc(): + # pour restreindre l'édition aux module du semestre sélectionné + tr_class = 'class="sem{semestre_id}"' + else: + tr_class = "" + if edit: + templ_sep = f"""""" + else: + templ_sep = ( + f"""""" + ) modform.append( ( "sep", @@ -591,12 +603,12 @@ def do_formsemestre_createwithmodules(edit=False): ) fcg += "" itemtemplate = ( - """" ) else: - itemtemplate = """""" + itemtemplate = f"""""" modform.append( ( "MI" + str(mod["module_id"]), diff --git a/app/static/js/formsemestre_edit.js b/app/static/js/formsemestre_edit.js new file mode 100644 index 000000000..3394d659c --- /dev/null +++ b/app/static/js/formsemestre_edit.js @@ -0,0 +1,14 @@ +// Formulaire formsemestre_createwithmodules + +function change_semestre_id() { + var semestre_id = $("#tf_semestre_id")[0].value; + for (var i = -1; i < 12; i++) { + $(".sem" + i).hide(); + } + $(".sem" + semestre_id).show(); +} + + +$(window).on('load', function () { + change_semestre_id(); +}); \ No newline at end of file From 842f73d692e6a38adffdfa900dd9cc8803326d94 Mon Sep 17 00:00:00 2001 From: Arthur ZHU Date: Mon, 28 Feb 2022 18:57:05 +0100 Subject: [PATCH 137/287] ajustement formulaires --- app/entreprises/forms.py | 96 ++++++++++--------- app/entreprises/routes.py | 20 ++-- .../entreprises/ajout_entreprise.html | 3 +- .../entreprises/ajout_historique.html | 3 + .../entreprises/envoi_offre_form.html | 3 + app/templates/entreprises/form.html | 3 + .../form_modification_entreprise.html | 3 + .../entreprises/import_contacts.html | 3 + .../entreprises/import_entreprises.html | 3 + 9 files changed, 84 insertions(+), 53 deletions(-) diff --git a/app/entreprises/forms.py b/app/entreprises/forms.py index e5e334c34..bb76a3c43 100644 --- a/app/entreprises/forms.py +++ b/app/entreprises/forms.py @@ -65,20 +65,20 @@ def _build_string_field(label, required=True, render_kw=None): class EntrepriseCreationForm(FlaskForm): siret = _build_string_field( - "SIRET", + "SIRET (*)", render_kw={"placeholder": "Numéro composé de 14 chiffres", "maxlength": "14"}, ) - nom_entreprise = _build_string_field("Nom de l'entreprise") - adresse = _build_string_field("Adresse de l'entreprise") - codepostal = _build_string_field("Code postal de l'entreprise") - ville = _build_string_field("Ville de l'entreprise") - pays = _build_string_field("Pays de l'entreprise") + nom_entreprise = _build_string_field("Nom de l'entreprise (*)") + adresse = _build_string_field("Adresse de l'entreprise (*)") + codepostal = _build_string_field("Code postal de l'entreprise (*)") + ville = _build_string_field("Ville de l'entreprise (*)") + pays = _build_string_field("Pays de l'entreprise", required=False) - nom_contact = _build_string_field("Nom du contact") - prenom_contact = _build_string_field("Prénom du contact") - telephone = _build_string_field("Téléphone du contact", required=False) + nom_contact = _build_string_field("Nom du contact (*)") + prenom_contact = _build_string_field("Prénom du contact (*)") + telephone = _build_string_field("Téléphone du contact (*)", required=False) mail = StringField( - "Mail du contact", + "Mail du contact (*)", validators=[Optional(), Email(message="Adresse e-mail invalide")], ) poste = _build_string_field("Poste du contact", required=False) @@ -121,14 +121,22 @@ class EntrepriseCreationForm(FlaskForm): class EntrepriseModificationForm(FlaskForm): - siret = StringField("SIRET", render_kw={"disabled": ""}) - nom = _build_string_field("Nom de l'entreprise") - adresse = _build_string_field("Adresse") - codepostal = _build_string_field("Code postal") - ville = _build_string_field("Ville") - pays = _build_string_field("Pays") + hidden_entreprise_siret = HiddenField() + siret = StringField("SIRET (*)") + nom = _build_string_field("Nom de l'entreprise (*)") + adresse = _build_string_field("Adresse (*)") + codepostal = _build_string_field("Code postal (*)") + ville = _build_string_field("Ville (*)") + pays = _build_string_field("Pays", required=False) submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE) + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.siret.render_kw = { + "disabled": "", + "value": self.hidden_entreprise_siret.data, + } + class MultiCheckboxField(SelectMultipleField): widget = ListWidget(prefix_label=False) @@ -136,22 +144,22 @@ class MultiCheckboxField(SelectMultipleField): class OffreCreationForm(FlaskForm): - intitule = _build_string_field("Intitulé") + intitule = _build_string_field("Intitulé (*)") description = TextAreaField( - "Description", validators=[DataRequired(message=CHAMP_REQUIS)] + "Description (*)", validators=[DataRequired(message=CHAMP_REQUIS)] ) type_offre = SelectField( - "Type de l'offre", + "Type de l'offre (*)", choices=[("Stage"), ("Alternance")], validators=[DataRequired(message=CHAMP_REQUIS)], ) missions = TextAreaField( - "Missions", validators=[DataRequired(message=CHAMP_REQUIS)] + "Missions (*)", validators=[DataRequired(message=CHAMP_REQUIS)] ) - duree = _build_string_field("Durée") + duree = _build_string_field("Durée (*)") depts = MultiCheckboxField("Départements", validators=[Optional()], coerce=int) expiration_date = DateField( - "Date expiration", validators=[DataRequired(message=CHAMP_REQUIS)] + "Date expiration (*)", validators=[DataRequired(message=CHAMP_REQUIS)] ) submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE) @@ -164,22 +172,22 @@ class OffreCreationForm(FlaskForm): class OffreModificationForm(FlaskForm): - intitule = _build_string_field("Intitulé") + intitule = _build_string_field("Intitulé (*)") description = TextAreaField( - "Description", validators=[DataRequired(message=CHAMP_REQUIS)] + "Description (*)", validators=[DataRequired(message=CHAMP_REQUIS)] ) type_offre = SelectField( - "Type de l'offre", + "Type de l'offre (*)", choices=[("Stage"), ("Alternance")], validators=[DataRequired(message=CHAMP_REQUIS)], ) missions = TextAreaField( - "Missions", validators=[DataRequired(message=CHAMP_REQUIS)] + "Missions (*)", validators=[DataRequired(message=CHAMP_REQUIS)] ) - duree = _build_string_field("Durée") + duree = _build_string_field("Durée (*)") depts = MultiCheckboxField("Départements", validators=[Optional()], coerce=int) expiration_date = DateField( - "Date expiration", validators=[DataRequired(message=CHAMP_REQUIS)] + "Date expiration (*)", validators=[DataRequired(message=CHAMP_REQUIS)] ) submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE) @@ -193,11 +201,11 @@ class OffreModificationForm(FlaskForm): class ContactCreationForm(FlaskForm): hidden_entreprise_id = HiddenField() - nom = _build_string_field("Nom") - prenom = _build_string_field("Prénom") - telephone = _build_string_field("Téléphone", required=False) + nom = _build_string_field("Nom (*)") + prenom = _build_string_field("Prénom (*)") + telephone = _build_string_field("Téléphone (*)", required=False) mail = StringField( - "Mail", + "Mail (*)", validators=[Optional(), Email(message="Adresse e-mail invalide")], ) poste = _build_string_field("Poste", required=False) @@ -232,11 +240,11 @@ class ContactCreationForm(FlaskForm): class ContactModificationForm(FlaskForm): hidden_contact_id = HiddenField() hidden_entreprise_id = HiddenField() - nom = _build_string_field("Nom") - prenom = _build_string_field("Prénom") - telephone = _build_string_field("Téléphone", required=False) + nom = _build_string_field("Nom (*)") + prenom = _build_string_field("Prénom (*)") + telephone = _build_string_field("Téléphone (*)", required=False) mail = StringField( - "Mail", + "Mail (*)", validators=[Optional(), Email(message="Adresse e-mail invalide")], ) poste = _build_string_field("Poste", required=False) @@ -271,18 +279,20 @@ class ContactModificationForm(FlaskForm): class HistoriqueCreationForm(FlaskForm): etudiant = _build_string_field( - "Étudiant", + "Étudiant (*)", render_kw={"placeholder": "Tapez le nom de l'étudiant"}, ) type_offre = SelectField( - "Type de l'offre", + "Type de l'offre (*)", choices=[("Stage"), ("Alternance")], validators=[DataRequired(message=CHAMP_REQUIS)], ) date_debut = DateField( - "Date début", validators=[DataRequired(message=CHAMP_REQUIS)] + "Date début (*)", validators=[DataRequired(message=CHAMP_REQUIS)] + ) + date_fin = DateField( + "Date fin (*)", validators=[DataRequired(message=CHAMP_REQUIS)] ) - date_fin = DateField("Date fin", validators=[DataRequired(message=CHAMP_REQUIS)]) submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE) def validate(self): @@ -315,7 +325,7 @@ class HistoriqueCreationForm(FlaskForm): class EnvoiOffreForm(FlaskForm): responsable = _build_string_field( - "Responsable de formation", + "Responsable de formation (*)", render_kw={"placeholder": "Tapez le nom du responsable de formation"}, ) submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE) @@ -336,7 +346,7 @@ class EnvoiOffreForm(FlaskForm): class AjoutFichierForm(FlaskForm): fichier = FileField( - "Fichier", + "Fichier (*)", validators=[ FileRequired(message=CHAMP_REQUIS), FileAllowed(["pdf", "docx"], "Fichier .pdf ou .docx uniquement"), @@ -355,7 +365,7 @@ class ValidationConfirmationForm(FlaskForm): class ImportForm(FlaskForm): fichier = FileField( - "Fichier", + "Fichier (*)", validators=[ FileRequired(message=CHAMP_REQUIS), FileAllowed(["xlsx"], "Fichier .xlsx uniquement"), diff --git a/app/entreprises/routes.py b/app/entreprises/routes.py index 301813341..be7f629fe 100644 --- a/app/entreprises/routes.py +++ b/app/entreprises/routes.py @@ -275,7 +275,7 @@ def add_entreprise(): adresse=form.adresse.data.strip(), codepostal=form.codepostal.data.strip(), ville=form.ville.data.strip(), - pays=form.pays.data.strip(), + pays=form.pays.data.strip() if form.pays.data.strip() else "FRANCE", ) db.session.add(entreprise) db.session.commit() @@ -326,14 +326,14 @@ def edit_entreprise(id): entreprise = Entreprise.query.filter_by(id=id, visible=True).first_or_404( description=f"entreprise {id} inconnue" ) - form = EntrepriseModificationForm() + form = EntrepriseModificationForm(hidden_entreprise_siret=entreprise.siret) if form.validate_on_submit(): nom_entreprise = f"{form.nom.data.strip()}" if entreprise.nom != form.nom.data.strip(): log = EntrepriseLog( authenticated_user=current_user.user_name, object=entreprise.id, - text=f"{nom_entreprise} - Modification du nom (ancien nom : {entreprise.nom})", + text=f"{nom_entreprise} - Modification du nom (ancien nom: {entreprise.nom})", ) entreprise.nom = form.nom.data.strip() db.session.add(log) @@ -341,7 +341,7 @@ def edit_entreprise(id): log = EntrepriseLog( authenticated_user=current_user.user_name, object=entreprise.id, - text=f"{nom_entreprise} - Modification de l'adresse (ancienne adresse : {entreprise.adresse})", + text=f"{nom_entreprise} - Modification de l'adresse (ancienne adresse: {entreprise.adresse})", ) entreprise.adresse = form.adresse.data.strip() db.session.add(log) @@ -349,7 +349,7 @@ def edit_entreprise(id): log = EntrepriseLog( authenticated_user=current_user.user_name, object=entreprise.id, - text=f"{nom_entreprise} - Modification du code postal (ancien code postal : {entreprise.codepostal})", + text=f"{nom_entreprise} - Modification du code postal (ancien code postal: {entreprise.codepostal})", ) entreprise.codepostal = form.codepostal.data.strip() db.session.add(log) @@ -357,17 +357,19 @@ def edit_entreprise(id): log = EntrepriseLog( authenticated_user=current_user.user_name, object=entreprise.id, - text=f"{nom_entreprise} - Modification de la ville (ancienne ville : {entreprise.ville})", + text=f"{nom_entreprise} - Modification de la ville (ancienne ville: {entreprise.ville})", ) entreprise.ville = form.ville.data.strip() db.session.add(log) - if entreprise.pays != form.pays.data.strip(): + if entreprise.pays != form.pays.data.strip() or not form.pays.data.strip(): log = EntrepriseLog( authenticated_user=current_user.user_name, object=entreprise.id, - text=f"{nom_entreprise} - Modification du pays (ancien pays : {entreprise.pays})", + text=f"{nom_entreprise} - Modification du pays (ancien pays: {entreprise.pays})", + ) + entreprise.pays = ( + form.pays.data.strip() if form.pays.data.strip() else "FRANCE" ) - entreprise.pays = form.pays.data.strip() db.session.add(log) db.session.commit() flash("L'entreprise a été modifié.") diff --git a/app/templates/entreprises/ajout_entreprise.html b/app/templates/entreprises/ajout_entreprise.html index fe597c550..0eead428d 100644 --- a/app/templates/entreprises/ajout_entreprise.html +++ b/app/templates/entreprises/ajout_entreprise.html @@ -8,7 +8,8 @@

    - Les champs s'auto complète selon le SIRET + Les champs s'auto complète selon le SIRET
    + (*) champs requis

    {{ wtf.quick_form(form, novalidate=True) }}
    diff --git a/app/templates/entreprises/ajout_historique.html b/app/templates/entreprises/ajout_historique.html index db659229f..678d3a725 100644 --- a/app/templates/entreprises/ajout_historique.html +++ b/app/templates/entreprises/ajout_historique.html @@ -13,6 +13,9 @@
    +

    + (*) champs requis +

    {{ wtf.quick_form(form, novalidate=True) }}
    diff --git a/app/templates/entreprises/envoi_offre_form.html b/app/templates/entreprises/envoi_offre_form.html index bfab89e4d..947086725 100644 --- a/app/templates/entreprises/envoi_offre_form.html +++ b/app/templates/entreprises/envoi_offre_form.html @@ -13,6 +13,9 @@
    +

    + (*) champs requis +

    {{ wtf.quick_form(form, novalidate=True) }}
    diff --git a/app/templates/entreprises/form.html b/app/templates/entreprises/form.html index d987f1ebe..071f84fda 100644 --- a/app/templates/entreprises/form.html +++ b/app/templates/entreprises/form.html @@ -11,6 +11,9 @@
    +

    + (*) champs requis +

    {{ wtf.quick_form(form, novalidate=True) }}
    diff --git a/app/templates/entreprises/form_modification_entreprise.html b/app/templates/entreprises/form_modification_entreprise.html index 47ce42e65..27483d5be 100644 --- a/app/templates/entreprises/form_modification_entreprise.html +++ b/app/templates/entreprises/form_modification_entreprise.html @@ -11,6 +11,9 @@
    +

    + (*) champs requis +

    {{ wtf.quick_form(form, novalidate=True) }}
    diff --git a/app/templates/entreprises/import_contacts.html b/app/templates/entreprises/import_contacts.html index 204a5e970..292a0e9ff 100644 --- a/app/templates/entreprises/import_contacts.html +++ b/app/templates/entreprises/import_contacts.html @@ -15,6 +15,9 @@
    +

    + (*) champs requis +

    {{ wtf.quick_form(form, novalidate=True) }}
    diff --git a/app/templates/entreprises/import_entreprises.html b/app/templates/entreprises/import_entreprises.html index 2539aeb68..0b6336603 100644 --- a/app/templates/entreprises/import_entreprises.html +++ b/app/templates/entreprises/import_entreprises.html @@ -15,6 +15,9 @@
    +

    + (*) champs requis +

    {{ wtf.quick_form(form, novalidate=True) }}
    From b56a20643d5366322c27839a542aeda604398d1e Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 28 Feb 2022 20:01:24 +0100 Subject: [PATCH 138/287] largeur colonne codes modules --- app/static/css/scodoc.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css index b3a80640a..d735077a4 100644 --- a/app/static/css/scodoc.css +++ b/app/static/css/scodoc.css @@ -1297,7 +1297,7 @@ th.formsemestre_status_inscrits { text-align: center; } td.formsemestre_status_code { - width: 2em; + /* width: 2em; */ padding-right: 1em; } From 13b40936b8cedce19b39b89455a314c8cb49af3e Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 28 Feb 2022 20:02:10 +0100 Subject: [PATCH 139/287] =?UTF-8?q?Nouveau=20calcul=20(correct=3F)=20de=20?= =?UTF-8?q?la=20moyenne=20de=20mati=C3=A8re=20en=20classic?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/comp/moy_mat.py | 6 ++-- app/comp/moy_ue.py | 67 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 67 insertions(+), 6 deletions(-) diff --git a/app/comp/moy_mat.py b/app/comp/moy_mat.py index e5ba903c2..0a7522637 100644 --- a/app/comp/moy_mat.py +++ b/app/comp/moy_mat.py @@ -40,13 +40,11 @@ def compute_mat_moys_classic( modimpl_mask = np.array( [m.module.matiere.id == matiere_id for m in formsemestre.modimpls_sorted] ) - etud_moy_gen, _, _ = moy_ue.compute_ue_moys_classic( - formsemestre, + etud_moy_mat = moy_ue.compute_mat_moys_classic( sem_matrix=sem_matrix, - ues=ues, modimpl_inscr_df=modimpl_inscr_df, modimpl_coefs=modimpl_coefs, modimpl_mask=modimpl_mask, ) - matiere_moy[matiere_id] = etud_moy_gen + matiere_moy[matiere_id] = etud_moy_mat return matiere_moy diff --git a/app/comp/moy_ue.py b/app/comp/moy_ue.py index 563fb3b1d..efbe7cd34 100644 --- a/app/comp/moy_ue.py +++ b/app/comp/moy_ue.py @@ -294,7 +294,8 @@ def compute_ue_moys_classic( modimpl_coefs: np.array, modimpl_mask: np.array, ) -> tuple[pd.Series, pd.DataFrame, pd.DataFrame]: - """Calcul de la moyenne d'UE en mode classique. + """Calcul de la moyenne d'UE et de la moy. générale en mode classique (DUT, LMD, ...). + La moyenne d'UE est un nombre (note/20), ou NI ou NA ou ERR NI non inscrit à (au moins un) module de cette UE NA pas de notes disponibles @@ -363,7 +364,7 @@ def compute_ue_moys_classic( modimpl_coefs_etuds_no_nan_stacked = np.stack( [modimpl_coefs_etuds_no_nan.T] * nb_ues ) - # nb_ue x nb_etuds x nb_mods : coefs prenant en compte NaN et inscriptions + # nb_ue x nb_etuds x nb_mods : coefs prenant en compte NaN et inscriptions: coefs = (modimpl_coefs_etuds_no_nan_stacked * ue_modules).swapaxes(1, 2) if coefs.dtype == np.object: # arrive sur des tableaux vides coefs = coefs.astype(np.float) @@ -408,6 +409,68 @@ def compute_ue_moys_classic( return etud_moy_gen_s, etud_moy_ue_df, etud_coef_ue_df +def compute_mat_moys_classic( + sem_matrix: np.array, + modimpl_inscr_df: pd.DataFrame, + modimpl_coefs: np.array, + modimpl_mask: np.array, +) -> pd.Series: + """Calcul de la moyenne sur un sous-enemble de modules en formation CLASSIQUE + + La moyenne est un nombre (note/20 ou NaN. + + Le masque modimpl_mask est un tableau de booléens (un par modimpl) qui + permet de sélectionner un sous-ensemble de modules (ceux de la matière d'intérêt). + + sem_matrix: notes moyennes aux modules (tous les étuds x tous les modimpls) + ndarray (etuds x modimpls) + (floats avec des NaN) + etuds : listes des étudiants (dim. 0 de la matrice) + modimpl_inscr_df: matrice d'inscription du semestre (etud x modimpl) + modimpl_coefs: vecteur des coefficients de modules + modimpl_mask: masque des modimpls à prendre en compte + + Résultat: + - moyennes: pd.Series, index etudid + """ + if (not len(modimpl_mask)) or ( + sem_matrix.shape[0] == 0 + ): # aucun module ou aucun étudiant + # etud_moy_gen_s, etud_moy_ue_df, etud_coef_ue_df + return pd.Series( + [0.0] * len(modimpl_inscr_df.index), index=modimpl_inscr_df.index + ) + # Restreint aux modules sélectionnés: + sem_matrix = sem_matrix[:, modimpl_mask] + modimpl_inscr = modimpl_inscr_df.values[:, modimpl_mask] + modimpl_coefs = modimpl_coefs[modimpl_mask] + + nb_etuds, nb_modules = sem_matrix.shape + assert len(modimpl_coefs) == nb_modules + + # Enlève les NaN du numérateur: + sem_matrix_no_nan = np.nan_to_num(sem_matrix, nan=0.0) + # Ne prend pas en compte les notes des étudiants non inscrits au module: + # Annule les notes: + sem_matrix_inscrits = np.where(modimpl_inscr, sem_matrix_no_nan, 0.0) + # Annule les coefs des modules où l'étudiant n'est pas inscrit: + modimpl_coefs_etuds = np.where( + modimpl_inscr, np.stack([modimpl_coefs.T] * nb_etuds), 0.0 + ) + # Annule les coefs des modules NaN (nb_etuds x nb_mods) + modimpl_coefs_etuds_no_nan = np.where( + np.isnan(sem_matrix), 0.0, modimpl_coefs_etuds + ) + if modimpl_coefs_etuds_no_nan.dtype == np.object: # arrive sur des tableaux vides + modimpl_coefs_etuds_no_nan = modimpl_coefs_etuds_no_nan.astype(np.float) + + etud_moy_mat = (modimpl_coefs_etuds_no_nan * sem_matrix_inscrits).sum( + axis=1 + ) / modimpl_coefs_etuds_no_nan.sum(axis=1) + + return pd.Series(etud_moy_mat, index=modimpl_inscr_df.index) + + def compute_malus( formsemestre: FormSemestre, sem_modimpl_moys: np.array, From 7edd0511835ca58d8bcb551541632808ac56b38a Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 1 Mar 2022 09:34:05 +0100 Subject: [PATCH 140/287] Fix: bonus St Quentin / Ville d'Avray --- app/comp/bonus_spo.py | 17 +++++++++++------ sco_version.py | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/app/comp/bonus_spo.py b/app/comp/bonus_spo.py index 99738336e..cb3d93e4f 100644 --- a/app/comp/bonus_spo.py +++ b/app/comp/bonus_spo.py @@ -338,9 +338,12 @@ class BonusAisneStQuentin(BonusSportAdditif): # pas d'étudiants ou pas d'UE ou pas de module... return # Calcule moyenne pondérée des notes de sport: - bonus_moy_arr = np.sum( - sem_modimpl_moys_inscrits * modimpl_coefs_etuds_no_nan, axis=1 - ) / np.sum(modimpl_coefs_etuds_no_nan, axis=1) + with np.errstate(invalid="ignore"): # ignore les 0/0 (-> NaN) + bonus_moy_arr = np.sum( + sem_modimpl_moys_inscrits * modimpl_coefs_etuds_no_nan, axis=1 + ) / np.sum(modimpl_coefs_etuds_no_nan, axis=1) + np.nan_to_num(bonus_moy_arr, nan=0.0, copy=False) + bonus_moy_arr[bonus_moy_arr < 10.0] = 0.0 bonus_moy_arr[bonus_moy_arr >= 18.1] = 0.5 bonus_moy_arr[bonus_moy_arr >= 16.1] = 0.4 @@ -823,9 +826,11 @@ class BonusVilleAvray(BonusSport): # pas d'étudiants ou pas d'UE ou pas de module... return # Calcule moyenne pondérée des notes de sport: - bonus_moy_arr = np.sum( - sem_modimpl_moys_inscrits * modimpl_coefs_etuds_no_nan, axis=1 - ) / np.sum(modimpl_coefs_etuds_no_nan, axis=1) + with np.errstate(invalid="ignore"): # ignore les 0/0 (-> NaN) + bonus_moy_arr = np.sum( + sem_modimpl_moys_inscrits * modimpl_coefs_etuds_no_nan, axis=1 + ) / np.sum(modimpl_coefs_etuds_no_nan, axis=1) + np.nan_to_num(bonus_moy_arr, nan=0.0, copy=False) bonus_moy_arr[bonus_moy_arr < 10.0] = 0.0 bonus_moy_arr[bonus_moy_arr >= 16.0] = 0.3 bonus_moy_arr[bonus_moy_arr >= 12.0] = 0.2 diff --git a/sco_version.py b/sco_version.py index b47a266d7..fbbf5bc82 100644 --- a/sco_version.py +++ b/sco_version.py @@ -1,7 +1,7 @@ # -*- mode: python -*- # -*- coding: utf-8 -*- -SCOVERSION = "9.1.66" +SCOVERSION = "9.1.67" SCONAME = "ScoDoc" From c5c0b510ec599a2486d4d39d9bc4519c7c51d41d Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 1 Mar 2022 09:48:37 +0100 Subject: [PATCH 141/287] filename export formations --- app/scodoc/sco_formations.py | 8 +++++++- app/scodoc/sco_utils.py | 21 ++++++++++++++++----- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/app/scodoc/sco_formations.py b/app/scodoc/sco_formations.py index caeeb707b..573c95dfb 100644 --- a/app/scodoc/sco_formations.py +++ b/app/scodoc/sco_formations.py @@ -151,8 +151,14 @@ def formation_export( if mod["ects"] is None: del mod["ects"] + filename = f"scodoc_formation_{formation.departement.acronym}_{formation.acronyme or ''}_v{formation.version}" return scu.sendResult( - F, name="formation", format=format, force_outer_xml_tag=False, attached=True + F, + name="formation", + format=format, + force_outer_xml_tag=False, + attached=True, + filename=filename, ) diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py index b3d99ac3e..7af19bc19 100644 --- a/app/scodoc/sco_utils.py +++ b/app/scodoc/sco_utils.py @@ -645,21 +645,30 @@ class ScoDocJSONEncoder(json.JSONEncoder): return json.JSONEncoder.default(self, o) -def sendJSON(data, attached=False): +def sendJSON(data, attached=False, filename=None): js = json.dumps(data, indent=1, cls=ScoDocJSONEncoder) return send_file( - js, filename="sco_data.json", mime=JSON_MIMETYPE, attached=attached + js, filename=filename or "sco_data.json", mime=JSON_MIMETYPE, attached=attached ) -def sendXML(data, tagname=None, force_outer_xml_tag=True, attached=False, quote=True): +def sendXML( + data, + tagname=None, + force_outer_xml_tag=True, + attached=False, + quote=True, + filename=None, +): if type(data) != list: data = [data] # always list-of-dicts if force_outer_xml_tag: data = [{tagname: data}] tagname += "_list" doc = sco_xml.simple_dictlist2xml(data, tagname=tagname, quote=quote) - return send_file(doc, filename="sco_data.xml", mime=XML_MIMETYPE, attached=attached) + return send_file( + doc, filename=filename or "sco_data.xml", mime=XML_MIMETYPE, attached=attached + ) def sendResult( @@ -669,6 +678,7 @@ def sendResult( force_outer_xml_tag=True, attached=False, quote_xml=True, + filename=None, ): if (format is None) or (format == "html"): return data @@ -679,9 +689,10 @@ def sendResult( force_outer_xml_tag=force_outer_xml_tag, attached=attached, quote=quote_xml, + filename=filename, ) elif format == "json": - return sendJSON(data, attached=attached) + return sendJSON(data, attached=attached, filename=filename) else: raise ValueError("invalid format: %s" % format) From 6943ccb8729823ad9f73e8b76e6f03ae5db2b8ad Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 1 Mar 2022 10:16:34 +0100 Subject: [PATCH 142/287] typo (sel. modules BUT) --- app/scodoc/sco_formsemestre_edit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scodoc/sco_formsemestre_edit.py b/app/scodoc/sco_formsemestre_edit.py index f056a3e62..7174cfc3d 100644 --- a/app/scodoc/sco_formsemestre_edit.py +++ b/app/scodoc/sco_formsemestre_edit.py @@ -545,7 +545,7 @@ def do_formsemestre_createwithmodules(edit=False): for semestre_id in semestre_ids: if formation.is_apc(): # pour restreindre l'édition aux module du semestre sélectionné - tr_class = 'class="sem{semestre_id}"' + tr_class = f'class="sem{semestre_id}"' else: tr_class = "" if edit: From 10c96ad683fa0ca1a899f160588e1e6b769023c8 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 1 Mar 2022 10:21:15 +0100 Subject: [PATCH 143/287] PE: check submitted template (utf8) --- app/pe/pe_view.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/pe/pe_view.py b/app/pe/pe_view.py index 5a98d375f..5af1a5754 100644 --- a/app/pe/pe_view.py +++ b/app/pe/pe_view.py @@ -36,6 +36,7 @@ """ from flask import send_file, request +from app.scodoc.sco_exceptions import ScoValueError import app.scodoc.sco_utils as scu from app.scodoc import sco_formsemestre @@ -97,8 +98,12 @@ def pe_view_sem_recap( template_latex = "" # template fourni via le formulaire Web if avis_tmpl_file: - template_latex = avis_tmpl_file.read().decode('utf-8') - template_latex = template_latex + try: + template_latex = avis_tmpl_file.read().decode("utf-8") + except UnicodeDecodeError as e: + raise ScoValueError( + "Données (template) invalides (caractères non UTF8 ?)" + ) from e else: # template indiqué dans préférences ScoDoc ? template_latex = pe_avislatex.get_code_latex_from_scodoc_preference( @@ -114,7 +119,7 @@ def pe_view_sem_recap( footer_latex = "" # template fourni via le formulaire Web if footer_tmpl_file: - footer_latex = footer_tmpl_file.read().decode('utf-8') + footer_latex = footer_tmpl_file.read().decode("utf-8") footer_latex = footer_latex else: footer_latex = pe_avislatex.get_code_latex_from_scodoc_preference( From f0e731d151fbb2a28e0e65a3a55650f0065ec27a Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 1 Mar 2022 10:33:53 +0100 Subject: [PATCH 144/287] Fix: bulletin classique quand coef UE None --- app/scodoc/sco_bulletins.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/scodoc/sco_bulletins.py b/app/scodoc/sco_bulletins.py index a5d84cf4f..47947bd36 100644 --- a/app/scodoc/sco_bulletins.py +++ b/app/scodoc/sco_bulletins.py @@ -323,9 +323,7 @@ def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"): if ue_status["coef_ue"] != None: u["coef_ue_txt"] = scu.fmt_coef(ue_status["coef_ue"]) else: - # C'est un bug: - log("u=" + pprint.pformat(u)) - raise Exception("invalid None coef for ue") + u["coef_ue_txt"] = "-" if ( dpv From 523ad7ad2a19caed963f9a5170ba6930a35afa67 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 1 Mar 2022 10:40:38 +0100 Subject: [PATCH 145/287] Modif bonus La Rochelle --- app/comp/bonus_spo.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/app/comp/bonus_spo.py b/app/comp/bonus_spo.py index cb3d93e4f..aa7697d5a 100644 --- a/app/comp/bonus_spo.py +++ b/app/comp/bonus_spo.py @@ -198,7 +198,10 @@ class BonusSportAdditif(BonusSport): à la moyenne générale du semestre déjà obtenue par l'étudiant. """ - seuil_moy_gen = 10.0 # seuls les points au dessus du seuil sont comptés + seuil_moy_gen = 10.0 # seuls les bonus au dessus du seuil sont pris en compte + seuil_comptage = ( + None # les points au dessus du seuil sont comptés (defaut: seuil_moy_gen) + ) proportion_point = 0.05 # multiplie les points au dessus du seuil def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan): @@ -211,10 +214,13 @@ class BonusSportAdditif(BonusSport): if 0 in sem_modimpl_moys_inscrits.shape: # pas d'étudiants ou pas d'UE ou pas de module... return + seuil_comptage = ( + self.seuil_moy_gen if self.seuil_comptage is None else self.seuil_comptage + ) bonus_moy_arr = np.sum( np.where( sem_modimpl_moys_inscrits > self.seuil_moy_gen, - (sem_modimpl_moys_inscrits - self.seuil_moy_gen) + (sem_modimpl_moys_inscrits - self.seuil_comptage) * self.proportion_point, 0.0, ), @@ -607,8 +613,9 @@ class BonusLaRochelle(BonusSportAdditif): name = "bonus_iutlr" displayed_name = "IUT de La Rochelle" - seuil_moy_gen = 10.0 # tous les points sont comptés - proportion_point = 0.01 + seuil_moy_gen = 10.0 # si bonus > 10, + seuil_comptage = 0.0 # tous les points sont comptés + proportion_point = 0.01 # 1% class BonusLeHavre(BonusSportMultiplicatif): From 626dc0157a5ebcad92d6bca3e68a7bbe5374930a Mon Sep 17 00:00:00 2001 From: Arthur ZHU Date: Tue, 1 Mar 2022 18:45:04 +0100 Subject: [PATCH 146/287] =?UTF-8?q?rendre=20expir=C3=A9e=20une=20offre?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/entreprises/forms.py | 8 +- app/entreprises/models.py | 29 +++---- app/entreprises/routes.py | 23 ++++- app/templates/entreprises/_offre.html | 8 +- ...b81be_tables_module_gestion_relations_.py} | 84 ++++++++----------- 5 files changed, 76 insertions(+), 76 deletions(-) rename migrations/versions/{717a8dfe2915_tables_module_gestion_relations_.py => af05f03b81be_tables_module_gestion_relations_.py} (87%) diff --git a/app/entreprises/forms.py b/app/entreprises/forms.py index bb76a3c43..0540c0802 100644 --- a/app/entreprises/forms.py +++ b/app/entreprises/forms.py @@ -158,9 +158,7 @@ class OffreCreationForm(FlaskForm): ) duree = _build_string_field("Durée (*)") depts = MultiCheckboxField("Départements", validators=[Optional()], coerce=int) - expiration_date = DateField( - "Date expiration (*)", validators=[DataRequired(message=CHAMP_REQUIS)] - ) + expiration_date = DateField("Date expiration", validators=[Optional()]) submit = SubmitField("Envoyer", render_kw=SUBMIT_MARGE) def __init__(self, *args, **kwargs): @@ -186,9 +184,7 @@ class OffreModificationForm(FlaskForm): ) duree = _build_string_field("Durée (*)") depts = MultiCheckboxField("Départements", validators=[Optional()], coerce=int) - expiration_date = DateField( - "Date expiration (*)", validators=[DataRequired(message=CHAMP_REQUIS)] - ) + expiration_date = DateField("Date expiration", validators=[Optional()]) submit = SubmitField("Modifier", render_kw=SUBMIT_MARGE) def __init__(self, *args, **kwargs): diff --git a/app/entreprises/models.py b/app/entreprises/models.py index 923b2445f..dd0b4ba44 100644 --- a/app/entreprises/models.py +++ b/app/entreprises/models.py @@ -9,7 +9,7 @@ class Entreprise(db.Model): adresse = db.Column(db.Text) codepostal = db.Column(db.Text) ville = db.Column(db.Text) - pays = db.Column(db.Text) + pays = db.Column(db.Text, default="FRANCE") visible = db.Column(db.Boolean, default=False) contacts = db.relationship( "EntrepriseContact", @@ -36,7 +36,7 @@ class Entreprise(db.Model): class EntrepriseContact(db.Model): - __tablename__ = "are_entreprise_contact" + __tablename__ = "are_contacts" id = db.Column(db.Integer, primary_key=True) entreprise_id = db.Column( db.Integer, db.ForeignKey("are_entreprises.id", ondelete="cascade") @@ -62,7 +62,7 @@ class EntrepriseContact(db.Model): class EntrepriseOffre(db.Model): - __tablename__ = "are_entreprise_offre" + __tablename__ = "are_offres" id = db.Column(db.Integer, primary_key=True) entreprise_id = db.Column( db.Integer, db.ForeignKey("are_entreprises.id", ondelete="cascade") @@ -74,6 +74,7 @@ class EntrepriseOffre(db.Model): missions = db.Column(db.Text) duree = db.Column(db.Text) expiration_date = db.Column(db.Date) + expired = db.Column(db.Boolean, default=False) def to_dict(self): return { @@ -86,7 +87,7 @@ class EntrepriseOffre(db.Model): class EntrepriseLog(db.Model): - __tablename__ = "are_entreprise_log" + __tablename__ = "are_logs" id = db.Column(db.Integer, primary_key=True) date = db.Column(db.DateTime(timezone=True), server_default=db.func.now()) authenticated_user = db.Column(db.Text) @@ -95,7 +96,7 @@ class EntrepriseLog(db.Model): class EntrepriseEtudiant(db.Model): - __tablename__ = "are_entreprise_etudiant" + __tablename__ = "are_etudiants" id = db.Column(db.Integer, primary_key=True) entreprise_id = db.Column( db.Integer, db.ForeignKey("are_entreprises.id", ondelete="cascade") @@ -109,35 +110,29 @@ class EntrepriseEtudiant(db.Model): class EntrepriseEnvoiOffre(db.Model): - __tablename__ = "are_entreprise_envoi_offre" + __tablename__ = "are_envoi_offre" id = db.Column(db.Integer, primary_key=True) sender_id = db.Column(db.Integer, db.ForeignKey("user.id", ondelete="cascade")) receiver_id = db.Column(db.Integer, db.ForeignKey("user.id", ondelete="cascade")) - offre_id = db.Column( - db.Integer, db.ForeignKey("are_entreprise_offre.id", ondelete="cascade") - ) + offre_id = db.Column(db.Integer, db.ForeignKey("are_offres.id", ondelete="cascade")) date_envoi = db.Column(db.DateTime(timezone=True), server_default=db.func.now()) class EntrepriseEnvoiOffreEtudiant(db.Model): - __tablename__ = "are_entreprise_envoi_offre_etudiant" + __tablename__ = "are_envoi_offre_etudiant" id = db.Column(db.Integer, primary_key=True) sender_id = db.Column(db.Integer, db.ForeignKey("user.id", ondelete="cascade")) receiver_id = db.Column( db.Integer, db.ForeignKey("identite.id", ondelete="cascade") ) - offre_id = db.Column( - db.Integer, db.ForeignKey("are_entreprise_offre.id", ondelete="cascade") - ) + offre_id = db.Column(db.Integer, db.ForeignKey("are_offres.id", ondelete="cascade")) date_envoi = db.Column(db.DateTime(timezone=True), server_default=db.func.now()) class EntrepriseOffreDepartement(db.Model): - __tablename__ = "are_entreprise_offre_departement" + __tablename__ = "are_offre_departement" id = db.Column(db.Integer, primary_key=True) - offre_id = db.Column( - db.Integer, db.ForeignKey("are_entreprise_offre.id", ondelete="cascade") - ) + offre_id = db.Column(db.Integer, db.ForeignKey("are_offres.id", ondelete="cascade")) dept_id = db.Column(db.Integer, db.ForeignKey("departement.id", ondelete="cascade")) diff --git a/app/entreprises/routes.py b/app/entreprises/routes.py index be7f629fe..a72b2eb80 100644 --- a/app/entreprises/routes.py +++ b/app/entreprises/routes.py @@ -131,7 +131,13 @@ def fiche_entreprise(id): offres_with_files = [] depts = are.get_depts() for offre in entreprise.offres: - if date.today() < offre.expiration_date: + if not offre.expired and ( + offre.expiration_date is None + or ( + offre.expiration_date is not None + and date.today() < offre.expiration_date + ) + ): offre_with_files = are.get_offre_files_and_depts(offre, depts) if offre_with_files is not None: offres_with_files.append(offre_with_files) @@ -249,7 +255,9 @@ def offres_expirees(id): offres_expirees_with_files = [] depts = are.get_depts() for offre in entreprise.offres: - if date.today() > offre.expiration_date: + if offre.expired or ( + offre.expiration_date is not None and date.today() > offre.expiration_date + ): offre_expiree_with_files = are.get_offre_files_and_depts(offre, depts) if offre_expiree_with_files is not None: offres_expirees_with_files.append(offre_expiree_with_files) @@ -624,6 +632,17 @@ def delete_offre_recue(id): return redirect(url_for("entreprises.offres_recues")) +@bp.route("/expired/", methods=["GET", "POST"]) +@permission_required(Permission.RelationsEntreprisesChange) +def expired(id): + offre = EntrepriseOffre.query.filter_by(id=id).first_or_404( + description=f"offre {id} inconnue" + ) + offre.expired = not offre.expired + db.session.commit() + return redirect(url_for("entreprises.fiche_entreprise", id=offre.entreprise_id)) + + @bp.route("/add_contact/", methods=["GET", "POST"]) @permission_required(Permission.RelationsEntreprisesChange) def add_contact(id): diff --git a/app/templates/entreprises/_offre.html b/app/templates/entreprises/_offre.html index 0176ddd2d..cff6f03ab 100644 --- a/app/templates/entreprises/_offre.html +++ b/app/templates/entreprises/_offre.html @@ -29,6 +29,12 @@ {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesSend, None) %} Envoyer l'offre {% endif %} + {% if current_user.has_permission(current_user.Permission.RelationsEntreprisesChange, None) %} + {% if not offre[0].expired %} + Rendre expirée + {% else %} + Rendre non expirée + {% endif %} + {% endif %}
    -
    \ No newline at end of file diff --git a/migrations/versions/717a8dfe2915_tables_module_gestion_relations_.py b/migrations/versions/af05f03b81be_tables_module_gestion_relations_.py similarity index 87% rename from migrations/versions/717a8dfe2915_tables_module_gestion_relations_.py rename to migrations/versions/af05f03b81be_tables_module_gestion_relations_.py index eb32d4c1d..7f23ca9fc 100644 --- a/migrations/versions/717a8dfe2915_tables_module_gestion_relations_.py +++ b/migrations/versions/af05f03b81be_tables_module_gestion_relations_.py @@ -1,8 +1,8 @@ """tables module gestion relations entreprises -Revision ID: 717a8dfe2915 +Revision ID: af05f03b81be Revises: b9aadc10227f -Create Date: 2022-02-22 20:18:57.171246 +Create Date: 2022-03-01 17:12:32.927643 """ from alembic import op @@ -10,7 +10,7 @@ import sqlalchemy as sa from sqlalchemy.dialects import postgresql # revision identifiers, used by Alembic. -revision = "717a8dfe2915" +revision = "af05f03b81be" down_revision = "b9aadc10227f" branch_labels = None depends_on = None @@ -18,20 +18,6 @@ depends_on = None def upgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.create_table( - "are_entreprise_log", - sa.Column("id", sa.Integer(), nullable=False), - sa.Column( - "date", - sa.DateTime(timezone=True), - server_default=sa.text("now()"), - nullable=True, - ), - sa.Column("authenticated_user", sa.Text(), nullable=True), - sa.Column("object", sa.Integer(), nullable=True), - sa.Column("text", sa.Text(), nullable=True), - sa.PrimaryKeyConstraint("id"), - ) op.create_table( "are_entreprises", sa.Column("id", sa.Integer(), nullable=False), @@ -44,6 +30,20 @@ def upgrade(): sa.Column("visible", sa.Boolean(), nullable=True), sa.PrimaryKeyConstraint("id"), ) + op.create_table( + "are_logs", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column( + "date", + sa.DateTime(timezone=True), + server_default=sa.text("now()"), + nullable=True, + ), + sa.Column("authenticated_user", sa.Text(), nullable=True), + sa.Column("object", sa.Integer(), nullable=True), + sa.Column("text", sa.Text(), nullable=True), + sa.PrimaryKeyConstraint("id"), + ) op.create_table( "are_preferences", sa.Column("id", sa.Integer(), nullable=False), @@ -52,7 +52,7 @@ def upgrade(): sa.PrimaryKeyConstraint("id"), ) op.create_table( - "are_entreprise_contact", + "are_contacts", sa.Column("id", sa.Integer(), nullable=False), sa.Column("entreprise_id", sa.Integer(), nullable=True), sa.Column("nom", sa.Text(), nullable=True), @@ -67,7 +67,7 @@ def upgrade(): sa.PrimaryKeyConstraint("id"), ) op.create_table( - "are_entreprise_etudiant", + "are_etudiants", sa.Column("id", sa.Integer(), nullable=False), sa.Column("entreprise_id", sa.Integer(), nullable=True), sa.Column("etudid", sa.Integer(), nullable=True), @@ -82,7 +82,7 @@ def upgrade(): sa.PrimaryKeyConstraint("id"), ) op.create_table( - "are_entreprise_offre", + "are_offres", sa.Column("id", sa.Integer(), nullable=False), sa.Column("entreprise_id", sa.Integer(), nullable=True), sa.Column( @@ -97,13 +97,14 @@ def upgrade(): sa.Column("missions", sa.Text(), nullable=True), sa.Column("duree", sa.Text(), nullable=True), sa.Column("expiration_date", sa.Date(), nullable=True), + sa.Column("expired", sa.Boolean(), nullable=True), sa.ForeignKeyConstraint( ["entreprise_id"], ["are_entreprises.id"], ondelete="cascade" ), sa.PrimaryKeyConstraint("id"), ) op.create_table( - "are_entreprise_envoi_offre", + "are_envoi_offre", sa.Column("id", sa.Integer(), nullable=False), sa.Column("sender_id", sa.Integer(), nullable=True), sa.Column("receiver_id", sa.Integer(), nullable=True), @@ -114,15 +115,13 @@ def upgrade(): server_default=sa.text("now()"), nullable=True, ), - sa.ForeignKeyConstraint( - ["offre_id"], ["are_entreprise_offre.id"], ondelete="cascade" - ), + sa.ForeignKeyConstraint(["offre_id"], ["are_offres.id"], ondelete="cascade"), sa.ForeignKeyConstraint(["receiver_id"], ["user.id"], ondelete="cascade"), sa.ForeignKeyConstraint(["sender_id"], ["user.id"], ondelete="cascade"), sa.PrimaryKeyConstraint("id"), ) op.create_table( - "are_entreprise_envoi_offre_etudiant", + "are_envoi_offre_etudiant", sa.Column("id", sa.Integer(), nullable=False), sa.Column("sender_id", sa.Integer(), nullable=True), sa.Column("receiver_id", sa.Integer(), nullable=True), @@ -133,44 +132,29 @@ def upgrade(): server_default=sa.text("now()"), nullable=True, ), - sa.ForeignKeyConstraint( - ["offre_id"], ["are_entreprise_offre.id"], ondelete="cascade" - ), + sa.ForeignKeyConstraint(["offre_id"], ["are_offres.id"], ondelete="cascade"), sa.ForeignKeyConstraint(["receiver_id"], ["identite.id"], ondelete="cascade"), sa.ForeignKeyConstraint(["sender_id"], ["user.id"], ondelete="cascade"), sa.PrimaryKeyConstraint("id"), ) op.create_table( - "are_entreprise_offre_departement", + "are_offre_departement", sa.Column("id", sa.Integer(), nullable=False), sa.Column("offre_id", sa.Integer(), nullable=True), sa.Column("dept_id", sa.Integer(), nullable=True), sa.ForeignKeyConstraint(["dept_id"], ["departement.id"], ondelete="cascade"), - sa.ForeignKeyConstraint( - ["offre_id"], ["are_entreprise_offre.id"], ondelete="cascade" - ), + sa.ForeignKeyConstraint(["offre_id"], ["are_offres.id"], ondelete="cascade"), sa.PrimaryKeyConstraint("id"), ) op.drop_table("entreprise_contact") op.drop_table("entreprise_correspondant") op.drop_index("ix_entreprises_dept_id", table_name="entreprises") op.drop_table("entreprises") - op.drop_index("ix_apc_competence_id_orebut", table_name="apc_competence") - op.create_index( - op.f("ix_apc_competence_id_orebut"), - "apc_competence", - ["id_orebut"], - unique=False, - ) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.drop_index(op.f("ix_apc_competence_id_orebut"), table_name="apc_competence") - op.create_index( - "ix_apc_competence_id_orebut", "apc_competence", ["id_orebut"], unique=False - ) op.create_table( "entreprises", sa.Column( @@ -258,13 +242,13 @@ def downgrade(): ), sa.PrimaryKeyConstraint("id", name="entreprise_contact_pkey"), ) - op.drop_table("are_entreprise_offre_departement") - op.drop_table("are_entreprise_envoi_offre_etudiant") - op.drop_table("are_entreprise_envoi_offre") - op.drop_table("are_entreprise_offre") - op.drop_table("are_entreprise_etudiant") - op.drop_table("are_entreprise_contact") + op.drop_table("are_offre_departement") + op.drop_table("are_envoi_offre_etudiant") + op.drop_table("are_envoi_offre") + op.drop_table("are_offres") + op.drop_table("are_etudiants") + op.drop_table("are_contacts") op.drop_table("are_preferences") + op.drop_table("are_logs") op.drop_table("are_entreprises") - op.drop_table("are_entreprise_log") # ### end Alembic commands ### From c0719df0c0f0777c79fa3ff27dbda6250c30e194 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 1 Mar 2022 19:27:03 +0100 Subject: [PATCH 147/287] noms modules sur menu saisie absences --- app/scodoc/sco_edit_module.py | 7 +++++-- app/views/absences.py | 5 ++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/scodoc/sco_edit_module.py b/app/scodoc/sco_edit_module.py index 9ea4e2fe7..63bcb72ab 100644 --- a/app/scodoc/sco_edit_module.py +++ b/app/scodoc/sco_edit_module.py @@ -562,7 +562,7 @@ def module_edit(module_id=None): "code", { "size": 10, - "explanation": "code du module (doit être unique dans la formation)", + "explanation": "code du module (issu du programme, exemple M1203 ou R2.01. Doit être unique dans la formation)", "allow_null": False, "validator": lambda val, field, formation_id=formation_id: check_module_code_unicity( val, field, formation_id, module_id=module_id @@ -701,7 +701,10 @@ def module_edit(module_id=None): { "title": "Code Apogée", "size": 25, - "explanation": "(optionnel) code élément pédagogique Apogée ou liste de codes ELP séparés par des virgules", + "explanation": """(optionnel) code élément pédagogique Apogée ou liste de codes ELP + séparés par des virgules (ce code est propre à chaque établissement, se rapprocher + du référent Apogée). + """, "validator": lambda val, _: len(val) < APO_CODE_STR_LEN, }, ), diff --git a/app/views/absences.py b/app/views/absences.py index cf8de2c18..bdbae1458 100644 --- a/app/views/absences.py +++ b/app/views/absences.py @@ -611,8 +611,7 @@ def SignaleAbsenceGrSemestre( """\n""" % { "modimpl_id": modimpl["moduleimpl_id"], - "modname": modimpl["module"]["code"] - or "" + "modname": (modimpl["module"]["code"] or "") + " " + (modimpl["module"]["abbrev"] or modimpl["module"]["titre"]), "sel": sel, @@ -624,7 +623,7 @@ def SignaleAbsenceGrSemestre( sel = "selected" # aucun module specifie H.append( """

    -Module concerné par ces absences (%(optionel_txt)s): +Module concerné par ces absences (%(optionel_txt)s):

    en cours%s
    %(label)sResponsableInscrire
    %(label)sResponsable
    %(label)sResponsableInscrire
    %(label)sResponsable
    %(label)s%(elem)s""" + f"""
    %(label)s%(elem)s""" + fcg + "
    %(label)s%(elem)s
    %(label)s%(elem)s
    ' % fontorange) H.append( - '' - % (modimpl["moduleimpl_id"], mod_descr, mod.code) + f"""""" ) H.append( '' diff --git a/app/scodoc/sco_up_to_date.py b/app/scodoc/sco_up_to_date.py index 152b05691..6404ef0ed 100644 --- a/app/scodoc/sco_up_to_date.py +++ b/app/scodoc/sco_up_to_date.py @@ -33,6 +33,8 @@ import json import requests import time from flask import current_app + +from app import log import app.scodoc.sco_utils as scu from sco_version import SCOVERSION, SCONAME @@ -43,7 +45,7 @@ def is_up_to_date() -> str: """ diag = "" try: - response = requests.get(scu.SCO_UP2DATE) + response = requests.get(scu.SCO_UP2DATE + "/" + SCOVERSION) except requests.exceptions.ConnectionError: current_app.logger.debug("is_up_to_date: %s", diag) return f"""
    Attention: installation de {SCONAME} non fonctionnelle.
    @@ -60,7 +62,6 @@ def is_up_to_date() -> str: voir la documentation. """ - if response.status_code != 200: current_app.logger.debug( f"is_up_to_date: invalid response code ({response.status_code})" @@ -75,12 +76,16 @@ def is_up_to_date() -> str: return f"""
    Attention: réponse invalide de {scu.SCO_WEBSITE}
    (erreur json).
    """ - # nb: si de nouveaux paquets sont publiés chaque jour, le décalage ne sera jamais signalé. - # mais en régime "normal", on aura une alerte après 24h sans mise à jour. - days_since_last_package = (time.time() - infos["publication_time"]) / (24 * 60 * 60) - if (infos["version"] != SCOVERSION) and (days_since_last_package > 1.0): + if infos["status"] != "ok": + # problème coté serveur, ignore discrètement + log(f"is_up_to_date: server {infos['status']}") + return "" + if (SCOVERSION != infos["last_version"]) and ( + (time.time() - infos["last_version_date"]) > (24 * 60 * 60) + ): + # nouvelle version publiée depuis plus de 24h ! return f"""
    Attention: {SCONAME} version ({SCOVERSION}) non à jour - ({infos["version"]} disponible).
    + ({infos["last_version"]} disponible).
    Contacter votre administrateur système (documentation).
    diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py index 03e02cbf6..6df7ed6eb 100644 --- a/app/scodoc/sco_utils.py +++ b/app/scodoc/sco_utils.py @@ -361,7 +361,7 @@ SCO_DEV_MAIL = "emmanuel.viennet@gmail.com" # SVP ne pas changer # Adresse pour l'envoi des dumps (pour assistance technnique): # ne pas changer (ou vous perdez le support) SCO_DUMP_UP_URL = "https://scodoc.org/scodoc-installmgr/upload-dump" -SCO_UP2DATE = "https://scodoc.org/scodoc-installmgr/last_stable_version" +SCO_UP2DATE = "https://scodoc.org/scodoc-installmgr/check_version" CSV_FIELDSEP = ";" CSV_LINESEP = "\n" CSV_MIMETYPE = "text/comma-separated-values" diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css index d8a7249c4..6c0b06b8f 100644 --- a/app/static/css/scodoc.css +++ b/app/static/css/scodoc.css @@ -2884,7 +2884,7 @@ div.othersemlist input { div#update_warning { - /* display: none; */ + display: none; border: 1px solid red; background-color: rgb(250,220,220); margin: 3ex; diff --git a/app/static/js/scodoc.js b/app/static/js/scodoc.js index b1c15017e..7cb5bb626 100644 --- a/app/static/js/scodoc.js +++ b/app/static/js/scodoc.js @@ -58,7 +58,12 @@ $(function () { if (update_div) { fetch('install_info').then( response => response.text() - ).then(text => update_div.innerHTML = text); + ).then(text => { + update_div.innerHTML = text; + if (text) { + update_div.style.display = "block"; + } + }); } }); diff --git a/app/templates/sco_page.html b/app/templates/sco_page.html index e1aa9e3c5..f1590302a 100644 --- a/app/templates/sco_page.html +++ b/app/templates/sco_page.html @@ -9,6 +9,7 @@ +{# #} {% endblock %} From 9032b1fa67ff555a34a4116e6dbd6de997102b78 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 21 Mar 2022 11:48:34 +0100 Subject: [PATCH 234/287] Exception speciale pour envoyer bug report --- app/__init__.py | 26 ++++++++++++++++++++- app/scodoc/sco_bulletins_standard.py | 7 +++++- app/scodoc/sco_dump_db.py | 35 +++++----------------------- app/scodoc/sco_exceptions.py | 5 +++- app/views/notes.py | 1 + app/views/scolar.py | 24 +++++++++++++++++-- sco_version.py | 2 +- 7 files changed, 65 insertions(+), 35 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 7521520e0..76760bd79 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -10,6 +10,7 @@ import traceback import logging from logging.handlers import SMTPHandler, WatchedFileHandler +from threading import Thread from flask import current_app, g, request from flask import Flask @@ -27,6 +28,7 @@ import sqlalchemy from app.scodoc.sco_exceptions import ( AccessDenied, + ScoBugCatcher, ScoGenError, ScoValueError, APIInvalidParams, @@ -77,6 +79,28 @@ def internal_server_error(exc): ) +def handle_sco_bug(exc): + """Un bug, en général rare, sur lequel les dev cherchent des + informations pour le corriger. + """ + Thread( + target=_async_dump, args=(current_app._get_current_object(), request.url) + ).start() + + return internal_server_error(exc) + + +def _async_dump(app, request_url: str): + from app.scodoc.sco_dump_db import sco_dump_and_send_db + + with app.app_context(): + ndb.open_db_connection() + try: + sco_dump_and_send_db("ScoBugCatcher", request_url=request_url) + except ScoValueError: + pass + + def handle_invalid_usage(error): response = jsonify(error.to_dict()) response.status_code = error.status_code @@ -196,7 +220,7 @@ def create_app(config_class=DevConfig): app.register_error_handler(ScoGenError, handle_sco_value_error) app.register_error_handler(ScoValueError, handle_sco_value_error) - + app.register_error_handler(ScoBugCatcher, handle_sco_bug) app.register_error_handler(AccessDenied, handle_access_denied) app.register_error_handler(500, internal_server_error) app.register_error_handler(503, postgresql_server_error) diff --git a/app/scodoc/sco_bulletins_standard.py b/app/scodoc/sco_bulletins_standard.py index f1b2b7cc7..e42a38847 100644 --- a/app/scodoc/sco_bulletins_standard.py +++ b/app/scodoc/sco_bulletins_standard.py @@ -49,6 +49,7 @@ Balises img: actuellement interdites. from reportlab.platypus import KeepTogether, Paragraph, Spacer, Table from reportlab.lib.units import cm, mm from reportlab.lib.colors import Color, blue +from app.scodoc.sco_exceptions import ScoBugCatcher import app.scodoc.sco_utils as scu from app.scodoc.sco_pdf import SU @@ -416,7 +417,11 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator): # Chaque UE: for ue in I["ues"]: ue_type = None - coef_ue = ue["coef_ue_txt"] if prefs["bul_show_ue_coef"] else "" + try: + coef_ue = ue["coef_ue_txt"] if prefs["bul_show_ue_coef"] else "" + except TypeError as exc: + raise ScoBugCatcher(f"ue={ue!r}") from exc + ue_descr = ue["ue_descr_txt"] rowstyle = "" plusminus = minuslink # diff --git a/app/scodoc/sco_dump_db.py b/app/scodoc/sco_dump_db.py index 190cec961..fd0b15c0d 100644 --- a/app/scodoc/sco_dump_db.py +++ b/app/scodoc/sco_dump_db.py @@ -51,14 +51,12 @@ import fcntl import subprocess import requests -from flask import flash, request +from flask import g, request from flask_login import current_user import app.scodoc.notesdb as ndb import app.scodoc.sco_utils as scu from app import log -from app.scodoc import html_sco_header -from app.scodoc import sco_preferences from app.scodoc import sco_users import sco_version from app.scodoc.sco_exceptions import ScoValueError @@ -68,8 +66,7 @@ SCO_DUMP_LOCK = "/tmp/scodump.lock" def sco_dump_and_send_db(message: str = "", request_url: str = ""): """Dump base de données et l'envoie anonymisée pour debug""" - H = [html_sco_header.sco_header(page_title="Assistance technique")] - # get currect (dept) DB name: + # get current (dept) DB name: cursor = ndb.SimpleQuery("SELECT current_database()", {}) db_name = cursor.fetchone()[0] ano_db_name = "ANO" + db_name @@ -96,27 +93,7 @@ def sco_dump_and_send_db(message: str = "", request_url: str = ""): # Send r = _send_db(ano_db_name, message, request_url) - if ( - r.status_code - == requests.codes.INSUFFICIENT_STORAGE # pylint: disable=no-member - ): - H.append( - """

    - Erreur: espace serveur trop plein. - Merci de contacter {0}

    """.format( - scu.SCO_DEV_MAIL - ) - ) - elif r.status_code == requests.codes.OK: # pylint: disable=no-member - H.append("""

    Opération effectuée.

    """) - else: - H.append( - """

    - Erreur: code {0} {1} - Merci de contacter {2}

    """.format( - r.status_code, r.reason, scu.SCO_DEV_MAIL - ) - ) + code = r.status_code finally: # Drop anonymized database @@ -125,8 +102,8 @@ def sco_dump_and_send_db(message: str = "", request_url: str = ""): fcntl.flock(x, fcntl.LOCK_UN) log("sco_dump_and_send_db: done.") - flash("Données envoyées au serveur d'assistance") - return "\n".join(H) + html_sco_header.sco_footer() + + return code def _duplicate_db(db_name, ano_db_name): @@ -195,7 +172,7 @@ def _send_db(ano_db_name: str, message: str = "", request_url: str = ""): scu.SCO_DUMP_UP_URL, files=files, data={ - "dept_name": sco_preferences.get_preference("DeptName"), + "dept_name": getattr(g, "scodoc_dept", "-"), "message": message or "", "request_url": request_url or request.url, "serial": _get_scodoc_serial(), diff --git a/app/scodoc/sco_exceptions.py b/app/scodoc/sco_exceptions.py index 394dbf1e5..35d2d9d6e 100644 --- a/app/scodoc/sco_exceptions.py +++ b/app/scodoc/sco_exceptions.py @@ -47,9 +47,12 @@ class ScoValueError(ScoException): self.dest_url = dest_url +class ScoBugCatcher(ScoException): + "bug avec enquete en cours" + + class NoteProcessError(ScoValueError): "Valeurs notes invalides" - pass class InvalidEtudId(NoteProcessError): diff --git a/app/views/notes.py b/app/views/notes.py index c8587c4fb..7a9e50673 100644 --- a/app/views/notes.py +++ b/app/views/notes.py @@ -73,6 +73,7 @@ from app.scodoc.scolog import logdb from app.scodoc.sco_exceptions import ( AccessDenied, + ScoBugCatcher, ScoException, ScoValueError, ScoInvalidIdType, diff --git a/app/views/scolar.py b/app/views/scolar.py index 67cb7b7b6..a25994bd9 100644 --- a/app/views/scolar.py +++ b/app/views/scolar.py @@ -30,7 +30,7 @@ issu de ScoDoc7 / ZScolar.py Emmanuel Viennet, 2021 """ -import os +import requests import time import flask @@ -2198,4 +2198,24 @@ def stat_bac(formsemestre_id): @scodoc7func def sco_dump_and_send_db(message="", request_url=""): "Send anonymized data to supervision" - return sco_dump_db.sco_dump_and_send_db(message, request_url) + + status_code = sco_dump_db.sco_dump_and_send_db(message, request_url) + H = [html_sco_header.sco_header(page_title="Assistance technique")] + if status_code == requests.codes.INSUFFICIENT_STORAGE: # pylint: disable=no-member + H.append( + """

    + Erreur: espace serveur trop plein. + Merci de contacter {0}

    """.format( + scu.SCO_DEV_MAIL + ) + ) + elif status_code == requests.codes.OK: # pylint: disable=no-member + H.append("""

    Opération effectuée.

    """) + else: + H.append( + f"""

    + Erreur: code {status_code} + Merci de contacter {scu.SCO_DEV_MAIL}

    """ + ) + flash("Données envoyées au serveur d'assistance") + return "\n".join(H) + html_sco_header.sco_footer() diff --git a/sco_version.py b/sco_version.py index 0cedeb3dc..547202122 100644 --- a/sco_version.py +++ b/sco_version.py @@ -1,7 +1,7 @@ # -*- mode: python -*- # -*- coding: utf-8 -*- -SCOVERSION = "9.1.82" +SCOVERSION = "9.1.83" SCONAME = "ScoDoc" From a902f6c1fe89c3fa036478eed096b9ddb883a2cf Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 21 Mar 2022 14:33:38 +0100 Subject: [PATCH 235/287] =?UTF-8?q?Affichage=20cas=20inscription=20non=20e?= =?UTF-8?q?nregistr=C3=A9e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/etudiants.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/etudiants.py b/app/models/etudiants.py index 3e8b91457..65c0701fe 100644 --- a/app/models/etudiants.py +++ b/app/models/etudiants.py @@ -289,10 +289,10 @@ class Identite(db.Model): log( f"*** situation inconsistante pour {self} (inscrit mais pas d'event)" ) - date_ins = "???" # ??? + situation += " (inscription non enregistrée)" # ??? else: date_ins = events[0].event_date - situation += date_ins.strftime(" le %d/%m/%Y") + situation += date_ins.strftime(" le %d/%m/%Y") else: situation = f"démission de {inscr.formsemestre.titre_mois()}" # Cherche la date de demission dans scolar_events: From 474f3347554b95e4c2d2d84d67b7024f427e8269 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 21 Mar 2022 19:41:14 +0100 Subject: [PATCH 236/287] Calcul des rangs / modules en formations classiques --- app/comp/res_classic.py | 19 ++++++++++++++++++- app/comp/res_common.py | 3 ++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/app/comp/res_classic.py b/app/comp/res_classic.py index 91614935d..b8f8ade02 100644 --- a/app/comp/res_classic.py +++ b/app/comp/res_classic.py @@ -15,7 +15,7 @@ from flask import g, url_for from app import db from app import log -from app.comp import moy_mat, moy_mod, moy_ue, inscr_mod +from app.comp import moy_mat, moy_mod, moy_sem, moy_ue, inscr_mod from app.comp.res_common import NotesTableCompat from app.comp.bonus_spo import BonusSport from app.models import ScoDocSiteConfig @@ -35,6 +35,7 @@ class ResultatsSemestreClassic(NotesTableCompat): "modimpl_coefs", "modimpl_idx", "sem_matrix", + "mod_rangs", ) def __init__(self, formsemestre): @@ -142,6 +143,22 @@ class ResultatsSemestreClassic(NotesTableCompat): if sco_preferences.get_preference("bul_show_matieres", self.formsemestre.id): self.compute_moyennes_matieres() + def compute_rangs(self): + """Calcul des rangs (classements) dans le semestre (moy. gen.), les UE + et les modules. + """ + # rangs moy gen et UEs sont calculées par la méthode commune à toutes les formations: + super().compute_rangs() + # les rangs des modules n'existent que dans les formations classiques: + self.mod_rangs = {} + for modimpl_result in self.modimpls_results.values(): + # ne prend que les rangs sous forme de chaines: + rangs = moy_sem.comp_ranks_series(modimpl_result.etuds_moy_module)[0] + self.mod_rangs[modimpl_result.moduleimpl_id] = ( + rangs, + modimpl_result.nb_inscrits_module, + ) + def get_etud_mod_moy(self, moduleimpl_id: int, etudid: int) -> float: """La moyenne de l'étudiant dans le moduleimpl Result: valeur float (peut être NaN) ou chaîne "NI" (non inscrit ou DEM) diff --git a/app/comp/res_common.py b/app/comp/res_common.py index fa2b9c30b..977d195d8 100644 --- a/app/comp/res_common.py +++ b/app/comp/res_common.py @@ -66,7 +66,7 @@ class ResultatsSemestre(ResultatsCache): """Moyennes de matières, si calculées. { matiere_id : Series, index etudid }""" def __repr__(self): - return f"<{self.__class__.__name__}(id={self.id}, formsemestre='{self.formsemestre}')>" + return f"<{self.__class__.__name__}(formsemestre='{self.formsemestre}')>" def compute(self): "Charge les notes et inscriptions et calcule toutes les moyennes" @@ -369,6 +369,7 @@ class NotesTableCompat(ResultatsSemestre): self.bonus_ues = None # virtuel self.ue_rangs = {u.id: (None, nb_etuds) for u in self.ues} self.mod_rangs = None # sera surchargé en Classic, mais pas en APC + """{ modimpl_id : (rangs, effectif) }""" self.moy_min = "NA" self.moy_max = "NA" self.moy_moy = "NA" From 590c52c138995c4a0d2dcde84e3e437610e9aced Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 21 Mar 2022 22:07:34 +0100 Subject: [PATCH 237/287] =?UTF-8?q?Ne=20r=C3=A9initialise=20pas=20syst?= =?UTF-8?q?=C3=A9matiquement=20les=20permissions=20des=20r=C3=B4les=20stan?= =?UTF-8?q?dards.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/__init__.py | 2 +- app/auth/models.py | 24 +++++++++++++++++------- app/auth/routes.py | 10 +++++++++- app/templates/configuration.html | 9 ++++++--- app/views/users.py | 2 +- tests/unit/test_users.py | 2 +- 6 files changed, 35 insertions(+), 14 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 76760bd79..a1862aaa7 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -366,7 +366,7 @@ def user_db_init(): current_app.logger.info("Init User's db") # Create roles: - Role.insert_roles() + Role.reset_standard_roles_permissions() current_app.logger.info("created initial roles") # Ensure that admin exists admin_mail = current_app.config.get("SCODOC_ADMIN_MAIL") diff --git a/app/auth/models.py b/app/auth/models.py index 544afc319..cfab21a9c 100644 --- a/app/auth/models.py +++ b/app/auth/models.py @@ -410,20 +410,30 @@ class Role(db.Model): return self.permissions & perm == perm @staticmethod - def insert_roles(): - """Create default roles""" + def reset_standard_roles_permissions(reset_permissions=True): + """Create default roles if missing, then, if reset_permissions, + reset their permissions to default values. + """ default_role = "Observateur" for role_name, permissions in SCO_ROLES_DEFAULTS.items(): role = Role.query.filter_by(name=role_name).first() if role is None: role = Role(name=role_name) - role.reset_permissions() - for perm in permissions: - role.add_permission(perm) - role.default = role.name == default_role - db.session.add(role) + role.default = role.name == default_role + db.session.add(role) + if reset_permissions: + role.reset_permissions() + for perm in permissions: + role.add_permission(perm) + db.session.add(role) + db.session.commit() + @staticmethod + def ensure_standard_roles(): + """Create default roles if missing""" + Role.reset_standard_roles_permissions(reset_permissions=False) + @staticmethod def get_named_role(name): """Returns existing role with given name, or None.""" diff --git a/app/auth/routes.py b/app/auth/routes.py index df3401515..24daa8ca0 100644 --- a/app/auth/routes.py +++ b/app/auth/routes.py @@ -19,7 +19,7 @@ from app.auth.forms import ( ResetPasswordForm, DeactivateUserForm, ) -from app.auth.models import Permission +from app.auth.models import Role from app.auth.models import User from app.auth.email import send_password_reset_email from app.decorators import admin_required @@ -121,3 +121,11 @@ def reset_password(token): flash(_("Votre mot de passe a été changé.")) return redirect(url_for("auth.login")) return render_template("auth/reset_password.html", form=form, user=user) + + +@bp.route("/reset_standard_roles_permissions", methods=["GET", "POST"]) +@admin_required +def reset_standard_roles_permissions(): + Role.reset_standard_roles_permissions() + flash("rôles standard réinitialisés !") + return redirect(url_for("scodoc.configuration")) diff --git a/app/templates/configuration.html b/app/templates/configuration.html index 823772de5..33912fbf9 100644 --- a/app/templates/configuration.html +++ b/app/templates/configuration.html @@ -36,12 +36,15 @@

    Gestion des images: logos, signatures, ...

    Ces images peuvent être intégrées dans les documents générés par ScoDoc: bulletins, PV, etc.
    -

    configuration des images et logos +

    configuration des images et logos

    Exports Apogée

    -

    configuration des codes de décision

    - +

    configuration des codes de décision

    + +

    Utilisateurs

    +

    remettre les permissions des + rôles standards à leurs valeurs par défaut (efface les modifications apportées)

    diff --git a/app/views/users.py b/app/views/users.py index 06157cbce..10f1124dd 100644 --- a/app/views/users.py +++ b/app/views/users.py @@ -153,7 +153,7 @@ def create_user_form(user_name=None, edit=0, all_roles=False): "form. création ou édition utilisateur" if user_name is not None: # scodoc7func converti en int ! user_name = str(user_name) - Role.insert_roles() # assure la mise à jour des rôles en base + Role.ensure_standard_roles() # assure la présence des rôles en base auth_dept = current_user.dept from_mail = current_app.config["SCODOC_MAIL_FROM"] # current_user.email initvalues = {} diff --git a/tests/unit/test_users.py b/tests/unit/test_users.py index 8c429386c..21b13fb42 100644 --- a/tests/unit/test_users.py +++ b/tests/unit/test_users.py @@ -40,7 +40,7 @@ def test_roles_permissions(test_client): role.remove_permission(perm) assert not role.has_permission(perm) # Default roles: - Role.insert_roles() + Role.reset_standard_roles_permissions() # Bien présents ? role_names = [r.name for r in Role.query.filter_by().all()] assert len(role_names) == len(SCO_ROLES_DEFAULTS) From b9a53f9c436946043514d67e65767ab4d2aa57c7 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 21 Mar 2022 22:29:55 +0100 Subject: [PATCH 238/287] Fix: fiche etudiant et jury : affichage des UEs en APC --- app/scodoc/sco_formsemestre_validation.py | 14 ++++++++------ app/scodoc/sco_parcours_dut.py | 4 +++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/app/scodoc/sco_formsemestre_validation.py b/app/scodoc/sco_formsemestre_validation.py index c83e1cc4d..43f10ad81 100644 --- a/app/scodoc/sco_formsemestre_validation.py +++ b/app/scodoc/sco_formsemestre_validation.py @@ -591,12 +591,14 @@ def formsemestre_recap_parcours_table( etud_ue_status = { ue["ue_id"]: nt.get_etud_ue_status(etudid, ue["ue_id"]) for ue in ues } - ues = [ - ue - for ue in ues - if etud_est_inscrit_ue(cnx, etudid, sem["formsemestre_id"], ue["ue_id"]) - or etud_ue_status[ue["ue_id"]]["is_capitalized"] - ] + if not nt.is_apc: + # formations classiques: filtre UE sur inscriptions (et garde UE capitalisées) + ues = [ + ue + for ue in ues + if etud_est_inscrit_ue(cnx, etudid, sem["formsemestre_id"], ue["ue_id"]) + or etud_ue_status[ue["ue_id"]]["is_capitalized"] + ] for ue in ues: H.append('
    ' % ue["acronyme"]) diff --git a/app/scodoc/sco_parcours_dut.py b/app/scodoc/sco_parcours_dut.py index fbf190c52..55110e5b0 100644 --- a/app/scodoc/sco_parcours_dut.py +++ b/app/scodoc/sco_parcours_dut.py @@ -1011,7 +1011,9 @@ def formsemestre_has_decisions(formsemestre_id): def etud_est_inscrit_ue(cnx, etudid, formsemestre_id, ue_id): - """Vrai si l'étudiant est inscrit à au moins un module de cette UE dans ce semestre""" + """Vrai si l'étudiant est inscrit à au moins un module de cette UE dans ce semestre. + Ne pas utiliser pour les formations APC ! + """ cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor) cursor.execute( """SELECT mi.* From b10fa09eb74363e1b45b6bc06e167472e8789ed3 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 22 Mar 2022 08:58:47 +0100 Subject: [PATCH 239/287] Fix: mod rang si aucune note dans le module --- app/comp/moy_sem.py | 6 +++++- app/comp/res_common.py | 2 +- sco_version.py | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/comp/moy_sem.py b/app/comp/moy_sem.py index 23e989d95..61b5fd15c 100644 --- a/app/comp/moy_sem.py +++ b/app/comp/moy_sem.py @@ -93,8 +93,12 @@ def comp_ranks_series(notes: pd.Series) -> (pd.Series, pd.Series): """Calcul rangs à partir d'une séries ("vecteur") de notes (index etudid, valeur numérique) en tenant compte des ex-aequos. - Result: Series { etudid : rang:str } où rang est une chaine decrivant le rang. + Result: couple (tuple) + Series { etudid : rang:str } où rang est une chaine decrivant le rang, + Series { etudid : rang:int } le rang comme un nombre """ + if (notes is None) or (len(notes) == 0): + return (pd.Series([], dtype=object), pd.Series([], dtype=int)) notes = notes.sort_values(ascending=False) # Serie, tri par ordre décroissant rangs_str = pd.Series(index=notes.index, dtype=str) # le rang est une chaîne rangs_int = pd.Series(index=notes.index, dtype=int) # le rang numérique pour tris diff --git a/app/comp/res_common.py b/app/comp/res_common.py index 977d195d8..737347479 100644 --- a/app/comp/res_common.py +++ b/app/comp/res_common.py @@ -133,7 +133,7 @@ class ResultatsSemestre(ResultatsCache): - En BUT: on considère que l'étudiant va (ou non) valider toutes les UEs des modules du parcours. XXX notion à implémenter, pour l'instant toutes les UE du semestre. - - En classique: toutes les UEs des modimpls auxquels l'étufdiant est inscrit sont + - En classique: toutes les UEs des modimpls auxquels l'étudiant est inscrit sont susceptibles d'être validées. Les UE "bonus" (sport) ne sont jamais "validables". diff --git a/sco_version.py b/sco_version.py index 547202122..6769973e2 100644 --- a/sco_version.py +++ b/sco_version.py @@ -1,7 +1,7 @@ # -*- mode: python -*- # -*- coding: utf-8 -*- -SCOVERSION = "9.1.83" +SCOVERSION = "9.1.84" SCONAME = "ScoDoc" From 8f8472eb3eec0bacd6898ec4e90ce939000d1ec2 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 22 Mar 2022 14:43:25 +0100 Subject: [PATCH 240/287] script to help debugging install network problems --- tools/check_network.py | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tools/check_network.py diff --git a/tools/check_network.py b/tools/check_network.py new file mode 100644 index 000000000..ceaafa5e0 --- /dev/null +++ b/tools/check_network.py @@ -0,0 +1,10 @@ +# test simple de connectivité pour tests + +import requests +import sco_version +import app.scodoc.sco_utils as scu + +response = requests.get(scu.SCO_UP2DATE + "/" + sco_version.SCOVERSION) + +print(response.status_code) +print(response.text) From 2e2338af631064a4abe552ae3d18f362b0511977 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 22 Mar 2022 19:18:25 +0100 Subject: [PATCH 241/287] Envoi bulletins PDF par mail. --- app/scodoc/sco_bulletins.py | 42 ++++++++-------------------- app/scodoc/sco_bulletins_standard.py | 8 ++---- app/views/notes.py | 25 +++++++++++------ 3 files changed, 31 insertions(+), 44 deletions(-) diff --git a/app/scodoc/sco_bulletins.py b/app/scodoc/sco_bulletins.py index 46101451e..c4b10c017 100644 --- a/app/scodoc/sco_bulletins.py +++ b/app/scodoc/sco_bulletins.py @@ -32,7 +32,7 @@ import email import time from flask import g, request -from flask import render_template, url_for +from flask import flash, render_template, url_for from flask_login import current_user from app import email @@ -817,7 +817,8 @@ def formsemestre_bulletinetud( if format not in {"html", "pdfmail"}: filename = scu.bul_filename(formsemestre, etud, format) return scu.send_file(bulletin, filename, mime=scu.get_mime_suffix(format)[0]) - + elif format == "pdfmail": + return "" H = [ _formsemestre_bulletinetud_header_html(etud, formsemestre, format, version), bulletin, @@ -851,7 +852,6 @@ def do_formsemestre_bulletinetud( etudid: int, version="long", # short, long, selectedevals format=None, - nohtml=False, xml_with_decisions=False, # force décisions dans XML force_publishing=False, # force publication meme si semestre non publié sur "portail" prefer_mail_perso=False, # mails envoyés sur adresse perso si non vide @@ -918,13 +918,6 @@ def do_formsemestre_bulletinetud( if not can_send_bulletin_by_mail(formsemestre.id): raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !") - if nohtml: - htm = "" # speed up if html version not needed - else: - htm, _ = sco_bulletins_generator.make_formsemestre_bulletinetud( - I, version=version, format="html" - ) - pdfdata, filename = sco_bulletins_generator.make_formsemestre_bulletinetud( I, version=version, format="pdf" ) @@ -935,28 +928,15 @@ def do_formsemestre_bulletinetud( recipient_addr = etud.get("email", "") or etud.get("emailperso", "") if not recipient_addr: - if nohtml: - h = "" # permet de compter les non-envois - else: - h = ( - "
    %s n'a pas d'adresse e-mail !
    " - % etud["nomprenom"] - ) + htm - return h, I["filigranne"] - # - mail_bulletin(formsemestre.id, I, pdfdata, filename, recipient_addr) - emaillink = '%s' % ( - recipient_addr, - recipient_addr, - ) - return ( - ('
    Message mail envoyé à %s
    ' % (emaillink)) - + htm, - I["filigranne"], - ) + flash(f"{etud['nomprenom']} n'a pas d'adresse e-mail !") + return False, I["filigranne"] + else: + mail_bulletin(formsemestre.id, I, pdfdata, filename, recipient_addr) + flash(f"mail envoyé à {recipient_addr}") - else: - raise ValueError("do_formsemestre_bulletinetud: invalid format (%s)" % format) + return True, I["filigranne"] + + raise ValueError("do_formsemestre_bulletinetud: invalid format (%s)" % format) def mail_bulletin(formsemestre_id, I, pdfdata, filename, recipient_addr): diff --git a/app/scodoc/sco_bulletins_standard.py b/app/scodoc/sco_bulletins_standard.py index e42a38847..e7c92ad78 100644 --- a/app/scodoc/sco_bulletins_standard.py +++ b/app/scodoc/sco_bulletins_standard.py @@ -49,6 +49,7 @@ Balises img: actuellement interdites. from reportlab.platypus import KeepTogether, Paragraph, Spacer, Table from reportlab.lib.units import cm, mm from reportlab.lib.colors import Color, blue +from app.models import FormSemestre from app.scodoc.sco_exceptions import ScoBugCatcher import app.scodoc.sco_utils as scu @@ -271,7 +272,7 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator): ) def build_bulletin_table(self): - """Génère la table centrale du bulletin de notes + """Génère la table centrale du bulletin de notes classique (pas BUT) Renvoie: col_keys, P, pdf_style, col_widths - col_keys: nom des colonnes de la table (clés) - table: liste de dicts de chaines de caractères @@ -417,10 +418,7 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator): # Chaque UE: for ue in I["ues"]: ue_type = None - try: - coef_ue = ue["coef_ue_txt"] if prefs["bul_show_ue_coef"] else "" - except TypeError as exc: - raise ScoBugCatcher(f"ue={ue!r}") from exc + coef_ue = ue["coef_ue_txt"] if prefs["bul_show_ue_coef"] else "" ue_descr = ue["ue_descr_txt"] rowstyle = "" diff --git a/app/views/notes.py b/app/views/notes.py index 7a9e50673..fd39f271c 100644 --- a/app/views/notes.py +++ b/app/views/notes.py @@ -36,7 +36,7 @@ import time from xml.etree import ElementTree import flask -from flask import abort, flash, jsonify, render_template, url_for +from flask import abort, flash, jsonify, redirect, render_template, url_for from flask import current_app, g, request from flask_login import current_user from werkzeug.utils import redirect @@ -359,7 +359,7 @@ def formsemestre_bulletinetud( ) if format == "oldjson": format = "json" - return sco_bulletins.formsemestre_bulletinetud( + r = sco_bulletins.formsemestre_bulletinetud( etud, formsemestre_id=formsemestre_id, format=format, @@ -368,6 +368,16 @@ def formsemestre_bulletinetud( force_publishing=force_publishing, prefer_mail_perso=prefer_mail_perso, ) + if format == "pdfmail": + return redirect( + url_for( + "notes.formsemestre_bulletinetud", + scodoc_dept=g.scodoc_dept, + etudid=etud.id, + formsemestre_id=formsemestre_id, + ) + ) + return r sco_publish( @@ -1955,23 +1965,22 @@ def formsemestre_bulletins_mailetuds( ) # Make each bulletin - nb_send = 0 + nb_sent = 0 for etudid in etudids: - h, _ = sco_bulletins.do_formsemestre_bulletinetud( + sent, _ = sco_bulletins.do_formsemestre_bulletinetud( formsemestre, etudid, version=version, prefer_mail_perso=prefer_mail_perso, format="pdfmail", - nohtml=True, ) - if h: - nb_send += 1 + if sent: + nb_sent += 1 # return ( html_sco_header.sco_header() + '

    %d bulletins sur %d envoyés par mail !

    continuer

    ' - % (nb_send, len(etudids), formsemestre_id) + % (nb_sent, len(etudids), formsemestre_id) + html_sco_header.sco_footer() ) From ba783227575d78e7e84feaa0c72d8098afedeb49 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 22 Mar 2022 22:14:45 +0100 Subject: [PATCH 242/287] Config: activation du module entreprises --- app/comp/bonus_spo.py | 1 - app/forms/main/config_main.py | 47 +++++++++++++++++++++------ app/models/config.py | 25 +++++++++++++++ app/scodoc/sco_utils.py | 7 +++++ app/static/css/scodoc.css | 5 +-- app/templates/base.html | 4 +-- app/templates/configuration.html | 54 ++++++++++++++++++++++---------- 7 files changed, 111 insertions(+), 32 deletions(-) diff --git a/app/comp/bonus_spo.py b/app/comp/bonus_spo.py index ece1d3611..5846e46f4 100644 --- a/app/comp/bonus_spo.py +++ b/app/comp/bonus_spo.py @@ -13,7 +13,6 @@ Les classes de Bonus fournissent deux méthodes: """ import datetime -import math import numpy as np import pandas as pd diff --git a/app/forms/main/config_main.py b/app/forms/main/config_main.py index d6536a8de..2c2aa3d5e 100644 --- a/app/forms/main/config_main.py +++ b/app/forms/main/config_main.py @@ -31,13 +31,14 @@ Formulaires configuration Exports Apogée (codes) from flask import flash, url_for, redirect, request, render_template from flask_wtf import FlaskForm -from wtforms import SelectField, SubmitField +from wtforms import BooleanField, SelectField, SubmitField import app from app.models import ScoDocSiteConfig +import app.scodoc.sco_utils as scu -class ScoDocConfigurationForm(FlaskForm): +class BonusConfigurationForm(FlaskForm): "Panneau de configuration des logos" bonus_sport_func_name = SelectField( label="Fonction de calcul des bonus sport&culture", @@ -46,31 +47,57 @@ class ScoDocConfigurationForm(FlaskForm): for (name, displayed_name) in ScoDocSiteConfig.get_bonus_sport_class_list() ], ) - submit = SubmitField("Valider") - cancel = SubmitField("Annuler", render_kw={"formnovalidate": True}) + submit_bonus = SubmitField("Valider") + cancel_bonus = SubmitField("Annuler", render_kw={"formnovalidate": True}) + + +class ScoDocConfigurationForm(FlaskForm): + "Panneau de configuration avancée" + enable_entreprises = BooleanField("activer le module entreprises") + submit_scodoc = SubmitField("Valider") + cancel_scodoc = SubmitField("Annuler", render_kw={"formnovalidate": True}) def configuration(): "Page de configuration principale" # nb: le contrôle d'accès (SuperAdmin) doit être fait dans la vue - form = ScoDocConfigurationForm( + form_bonus = BonusConfigurationForm( data={ "bonus_sport_func_name": ScoDocSiteConfig.get_bonus_sport_class_name(), } ) - if request.method == "POST" and form.cancel.data: # cancel button + form_scodoc = ScoDocConfigurationForm( + data={"enable_entreprises": ScoDocSiteConfig.is_entreprises_enabled()} + ) + if request.method == "POST" and ( + form_bonus.cancel_bonus.data or form_scodoc.cancel_scodoc.data + ): # cancel button return redirect(url_for("scodoc.index")) - if form.validate_on_submit(): + if form_bonus.submit_bonus.data and form_bonus.validate(): if ( - form.data["bonus_sport_func_name"] + form_bonus.data["bonus_sport_func_name"] != ScoDocSiteConfig.get_bonus_sport_class_name() ): - ScoDocSiteConfig.set_bonus_sport_class(form.data["bonus_sport_func_name"]) + ScoDocSiteConfig.set_bonus_sport_class( + form_bonus.data["bonus_sport_func_name"] + ) app.clear_scodoc_cache() flash(f"Fonction bonus sport&culture configurée.") return redirect(url_for("scodoc.index")) + elif form_scodoc.submit_scodoc.data and form_scodoc.validate(): + if ScoDocSiteConfig.enable_entreprises( + enabled=form_scodoc.data["enable_entreprises"] + ): + flash( + "Module entreprise " + + ("activé" if form_scodoc.data["enable_entreprises"] else "désactivé") + ) + return redirect(url_for("scodoc.index")) return render_template( "configuration.html", - form=form, + form_bonus=form_bonus, + form_scodoc=form_scodoc, + scu=scu, + title="Configuration", ) diff --git a/app/models/config.py b/app/models/config.py index 8a56d3879..1271beeb9 100644 --- a/app/models/config.py +++ b/app/models/config.py @@ -69,6 +69,7 @@ class ScoDocSiteConfig(db.Model): "INSTITUTION_ADDRESS": str, "INSTITUTION_CITY": str, "DEFAULT_PDF_FOOTER_TEMPLATE": str, + "enable_entreprises": bool, } def __init__(self, name, value): @@ -207,3 +208,27 @@ class ScoDocSiteConfig(db.Model): cfg.value = code_apo db.session.add(cfg) db.session.commit() + + @classmethod + def is_entreprises_enabled(cls) -> bool: + """True si on doit activer le module entreprise""" + cfg = ScoDocSiteConfig.query.filter_by(name="enable_entreprises").first() + if (cfg is None) or not cfg.value: + return False + return True + + @classmethod + def enable_entreprises(cls, enabled=True) -> bool: + """Active (ou déactive) le module entreprises. True si changement.""" + if enabled != ScoDocSiteConfig.is_entreprises_enabled(): + cfg = ScoDocSiteConfig.query.filter_by(name="enable_entreprises").first() + if cfg is None: + cfg = ScoDocSiteConfig( + name="enable_entreprises", value="on" if enabled else "" + ) + else: + cfg.value = "on" if enabled else "" + db.session.add(cfg) + db.session.commit() + return True + return False diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py index 6df7ed6eb..a0bb78c61 100644 --- a/app/scodoc/sco_utils.py +++ b/app/scodoc/sco_utils.py @@ -1038,3 +1038,10 @@ def objects_renumber(db, obj_list) -> None: obj.numero = i db.session.add(obj) db.session.commit() + + +# Pour accès depuis les templates jinja +def is_entreprises_enabled(): + from app.models import ScoDocSiteConfig + + return ScoDocSiteConfig.is_entreprises_enabled() diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css index 6c0b06b8f..086a130e4 100644 --- a/app/static/css/scodoc.css +++ b/app/static/css/scodoc.css @@ -872,9 +872,10 @@ a.discretelink:hover { div.sco_help { margin-top: 12px; - margin-bottom: 3px; + margin-bottom: 4px; + padding: 8px; + border-radius: 4px; font-style: italic; - color: navy; background-color: rgb(200,200,220); } diff --git a/app/templates/base.html b/app/templates/base.html index 658f41eb2..29f4455b0 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -8,7 +8,7 @@ {% endblock %} {% block title %} -{% if title %}{{ title }} - ScoDoc{% else %}Welcome to ScoDoc{% endif %} +{% if title %}{{ title }} - ScoDoc{% else %}ScoDoc{% endif %} {% endblock %} {% block navbar %} @@ -36,7 +36,7 @@ url_for('scolar.index_html', scodoc_dept=g.scodoc_dept) }}">Dept. {{ g.scodoc_dept }} {% endif %} - {% if not current_user.is_anonymous and current_user.has_permission(current_user.Permission.RelationsEntreprisesView, None) %} + {% if not current_user.is_anonymous and current_user.has_permission(current_user.Permission.RelationsEntreprisesView, None) and scu.is_entreprises_enabled() %}
  • Entreprises
  • {% endif %} diff --git a/app/templates/configuration.html b/app/templates/configuration.html index 33912fbf9..e6694e1d0 100644 --- a/app/templates/configuration.html +++ b/app/templates/configuration.html @@ -21,33 +21,53 @@ {% block app_content %} -
    - {{ form.hidden_tag() }} +

    Configuration générale

    +
    Les paramètres donnés ici s'appliquent à tout ScoDoc (tous les départements).
    -

    Configuration générale

    -
    Les paramètres donnés ici s'appliquent à tout ScoDoc (tous les départements):
    +
    +

    Calcul des "bonus" définis par l'établissement

    + + {{ form_bonus.hidden_tag() }}
    - {{ wtf.quick_form(form) }} + {{ wtf.quick_form(form_bonus) }}
    + -

    Gestion des images: logos, signatures, ...

    -
    Ces images peuvent être intégrées dans les documents - générés par ScoDoc: bulletins, PV, etc.
    -

    configuration des images et logos -

    +
    -

    Exports Apogée

    -

    configuration des codes de décision

    - -

    Utilisateurs

    -

    remettre les permissions des - rôles standards à leurs valeurs par défaut (efface les modifications apportées)

    +
    +

    Gestion des images: logos, signatures, ...

    +
    Ces images peuvent être intégrées dans les documents + générés par ScoDoc: bulletins, PV, etc.
    - +

    configuration des images et logos +

    +
    +
    +

    Exports Apogée

    +

    configuration des codes de décision

    +
    + +

    Utilisateurs

    +
    +

    remettre + les permissions des rôles standards à leurs valeurs par défaut (efface les modifications apportées) +

    +
    + +

    ScoDoc

    +
    + {{ form_scodoc.hidden_tag() }} +
    +
    + {{ wtf.quick_form(form_scodoc) }} +
    +
    + {% endblock %} {% block scripts %} From 9ecbb4dc9c6372d696948e4c83d018a8c9d1e8e0 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 22 Mar 2022 22:26:45 +0100 Subject: [PATCH 243/287] fusion entreprises --- sco_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sco_version.py b/sco_version.py index 583e820fb..6769973e2 100644 --- a/sco_version.py +++ b/sco_version.py @@ -1,7 +1,7 @@ # -*- mode: python -*- # -*- coding: utf-8 -*- -SCOVERSION = "9.1.84e" +SCOVERSION = "9.1.84" SCONAME = "ScoDoc" From 8086d75d34bc87bf8a9768ed9c0d807a138d3570 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 22 Mar 2022 22:33:06 +0100 Subject: [PATCH 244/287] Fix: si scu non defini dans template --- app/templates/base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/templates/base.html b/app/templates/base.html index 29f4455b0..724eac009 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -36,7 +36,7 @@ url_for('scolar.index_html', scodoc_dept=g.scodoc_dept) }}">Dept. {{ g.scodoc_dept }} {% endif %} - {% if not current_user.is_anonymous and current_user.has_permission(current_user.Permission.RelationsEntreprisesView, None) and scu.is_entreprises_enabled() %} + {% if not current_user.is_anonymous and current_user.has_permission(current_user.Permission.RelationsEntreprisesView, None) and scu and scu.is_entreprises_enabled() %}
  • Entreprises
  • {% endif %} From 27c46b39932c5de97a8e70595e3a650515c76d6d Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Wed, 23 Mar 2022 11:38:14 +0100 Subject: [PATCH 245/287] doc --- app/scodoc/sco_liste_notes.py | 7 ++++++- app/scodoc/sco_up_to_date.py | 2 ++ sco_version.py | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/scodoc/sco_liste_notes.py b/app/scodoc/sco_liste_notes.py index 3c41935ee..975eecea1 100644 --- a/app/scodoc/sco_liste_notes.py +++ b/app/scodoc/sco_liste_notes.py @@ -592,7 +592,12 @@ def _make_table_notes( if all_complete: eval_info = 'Evaluations prises en compte dans les moyennes' else: - eval_info = 'Les évaluations en vert et orange sont prises en compte dans les moyennes. Celles en rouge n\'ont pas toutes leurs notes.' + eval_info = """ + Les évaluations en vert et orange sont prises en compte dans les moyennes. + Celles en rouge n'ont pas toutes leurs notes.""" + if is_apc: + eval_info += " La moyenne indicative est la moyenne des moyennes d'UE, et n'est pas utilisée en BUT." + eval_info += """""" return html_form + eval_info + t + "

    " else: # Une seule evaluation: ajoute histogramme diff --git a/app/scodoc/sco_up_to_date.py b/app/scodoc/sco_up_to_date.py index 6404ef0ed..1ca56b80f 100644 --- a/app/scodoc/sco_up_to_date.py +++ b/app/scodoc/sco_up_to_date.py @@ -43,6 +43,8 @@ def is_up_to_date() -> str: """Check installed version vs last release. Returns html message, empty of ok. """ + if current_app.testing or current_app.debug: + return "
    Mode développement
    " diag = "" try: response = requests.get(scu.SCO_UP2DATE + "/" + SCOVERSION) diff --git a/sco_version.py b/sco_version.py index 6769973e2..469c31229 100644 --- a/sco_version.py +++ b/sco_version.py @@ -1,7 +1,7 @@ # -*- mode: python -*- # -*- coding: utf-8 -*- -SCOVERSION = "9.1.84" +SCOVERSION = "9.1.85" SCONAME = "ScoDoc" From 72a91f645f2e9a3736f38d02747493feb867325e Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Wed, 23 Mar 2022 12:39:52 +0100 Subject: [PATCH 246/287] Upgrade DataTables --- .../css/colReorder.bootstrap.css | 11 - .../css/colReorder.bootstrap.min.css | 1 - .../css/colReorder.dataTables.css | 11 - .../css/colReorder.dataTables.min.css | 1 - .../css/colReorder.foundation.css | 11 - .../css/colReorder.foundation.min.css | 1 - .../css/colReorder.jqueryui.css | 11 - .../css/colReorder.jqueryui.min.css | 1 - .../js/dataTables.colReorder.js | 1353 - .../js/dataTables.colReorder.min.js | 27 - .../css/dataTables.bootstrap.css | 184 - .../css/dataTables.bootstrap.min.css | 1 - .../css/dataTables.foundation.css | 118 - .../css/dataTables.foundation.min.css | 1 - .../css/dataTables.jqueryui.css | 482 - .../css/dataTables.jqueryui.min.css | 1 - .../css/dataTables.semanticui.css | 102 - .../css/dataTables.semanticui.min.css | 1 - .../css/jquery.dataTables.css | 455 - .../css/jquery.dataTables.min.css | 1 - .../css/jquery.dataTables_themeroller.css | 416 - .../images/sort_asc_disabled.png | Bin 148 -> 0 bytes .../images/sort_desc_disabled.png | Bin 146 -> 0 bytes .../js/dataTables.bootstrap.js | 182 - .../js/dataTables.bootstrap.min.js | 8 - .../js/dataTables.foundation.js | 174 - .../js/dataTables.foundation.min.js | 8 - .../js/dataTables.jqueryui.js | 164 - .../js/dataTables.jqueryui.min.js | 9 - .../js/dataTables.semanticui.js | 208 - .../js/dataTables.semanticui.min.js | 9 - .../js/jquery.dataTables.js | 15345 ----------- .../js/jquery.dataTables.min.js | 167 - .../css/dataTables.bootstrap.css | 0 .../css/dataTables.bootstrap.min.css | 0 .../css/dataTables.bootstrap4.css | 0 .../css/dataTables.bootstrap4.min.css | 0 .../css/dataTables.bootstrap5.css | 0 .../css/dataTables.bootstrap5.min.css | 0 .../css/dataTables.bulma.css | 0 .../css/dataTables.bulma.min.css | 0 .../css/dataTables.dataTables.css | 0 .../css/dataTables.dataTables.min.css | 0 .../css/dataTables.foundation.css | 0 .../css/dataTables.foundation.min.css | 0 .../css/dataTables.jqueryui.css | 0 .../css/dataTables.jqueryui.min.css | 0 .../css/dataTables.semanticui.css | 0 .../css/dataTables.semanticui.min.css | 0 .../css/jquery.dataTables.css | 0 .../css/jquery.dataTables.min.css | 0 .../images/sort_asc.png | Bin .../images/sort_asc_disabled.png | Bin .../images/sort_both.png | Bin .../images/sort_desc.png | Bin .../images/sort_desc_disabled.png | Bin .../js/dataTables.bootstrap.js | 0 .../js/dataTables.bootstrap.min.js | 0 .../js/dataTables.bootstrap4.js | 0 .../js/dataTables.bootstrap4.min.js | 0 .../js/dataTables.bootstrap5.js | 0 .../js/dataTables.bootstrap5.min.js | 0 .../DataTables-1.11.4/js/dataTables.bulma.js | 0 .../js/dataTables.bulma.min.js | 0 .../js/dataTables.dataTables.js | 0 .../js/dataTables.dataTables.min.js | 0 .../js/dataTables.foundation.js | 0 .../js/dataTables.foundation.min.js | 0 .../js/dataTables.jqueryui.js | 0 .../js/dataTables.jqueryui.min.js | 0 .../js/dataTables.semanticui.js | 0 .../js/dataTables.semanticui.min.js | 0 .../DataTables-1.11.4/js/jquery.dataTables.js | 0 .../js/jquery.dataTables.min.js | 0 .../css/fixedColumns.bootstrap.css | 44 - .../css/fixedColumns.bootstrap.min.css | 1 - .../css/fixedColumns.dataTables.css | 18 - .../css/fixedColumns.dataTables.min.css | 1 - .../css/fixedColumns.foundation.css | 27 - .../css/fixedColumns.foundation.min.css | 1 - .../css/fixedColumns.jqueryui.css | 8 - .../css/fixedColumns.jqueryui.min.css | 1 - .../js/dataTables.fixedColumns.js | 1623 -- .../js/dataTables.fixedColumns.min.js | 35 - .../css/fixedColumns.bootstrap.css | 0 .../css/fixedColumns.bootstrap.min.css | 0 .../css/fixedColumns.bootstrap4.css | 0 .../css/fixedColumns.bootstrap4.min.css | 0 .../css/fixedColumns.bootstrap5.css | 0 .../css/fixedColumns.bootstrap5.min.css | 0 .../css/fixedColumns.bulma.css | 0 .../css/fixedColumns.bulma.min.css | 0 .../css/fixedColumns.dataTables.css | 0 .../css/fixedColumns.dataTables.min.css | 0 .../css/fixedColumns.foundation.css | 0 .../css/fixedColumns.foundation.min.css | 0 .../css/fixedColumns.jqueryui.css | 0 .../css/fixedColumns.jqueryui.min.css | 0 .../css/fixedColumns.semanticui.css | 0 .../css/fixedColumns.semanticui.min.css | 0 .../js/dataTables.fixedColumns.js | 0 .../js/dataTables.fixedColumns.min.js | 0 .../js/fixedColumns.bootstrap.js | 0 .../js/fixedColumns.bootstrap.min.js | 0 .../js/fixedColumns.bootstrap4.js | 0 .../js/fixedColumns.bootstrap4.min.js | 0 .../js/fixedColumns.bootstrap5.js | 0 .../js/fixedColumns.bootstrap5.min.js | 0 .../js/fixedColumns.bulma.js | 0 .../js/fixedColumns.bulma.min.js | 0 .../js/fixedColumns.dataTables.js | 0 .../js/fixedColumns.dataTables.min.js | 0 .../js/fixedColumns.foundation.js | 0 .../js/fixedColumns.foundation.min.js | 0 .../js/fixedColumns.jqueryui.js | 0 .../js/fixedColumns.jqueryui.min.js | 0 .../js/fixedColumns.semanticui.js | 0 .../js/fixedColumns.semanticui.min.js | 0 .../css/fixedHeader.bootstrap.css | 20 - .../css/fixedHeader.bootstrap.min.css | 1 - .../css/fixedHeader.dataTables.css | 19 - .../css/fixedHeader.dataTables.min.css | 1 - .../css/fixedHeader.foundation.css | 20 - .../css/fixedHeader.foundation.min.css | 1 - .../css/fixedHeader.jqueryui.css | 15 - .../css/fixedHeader.jqueryui.min.css | 1 - .../js/dataTables.fixedHeader.js | 672 - .../js/dataTables.fixedHeader.min.js | 17 - .../css/fixedHeader.bootstrap.css | 0 .../css/fixedHeader.bootstrap.min.css | 0 .../css/fixedHeader.bootstrap4.css | 0 .../css/fixedHeader.bootstrap4.min.css | 0 .../css/fixedHeader.bootstrap5.css | 0 .../css/fixedHeader.bootstrap5.min.css | 0 .../css/fixedHeader.bulma.css | 0 .../css/fixedHeader.bulma.min.css | 0 .../css/fixedHeader.dataTables.css | 0 .../css/fixedHeader.dataTables.min.css | 0 .../css/fixedHeader.foundation.css | 0 .../css/fixedHeader.foundation.min.css | 0 .../css/fixedHeader.jqueryui.css | 0 .../css/fixedHeader.jqueryui.min.css | 0 .../css/fixedHeader.semanticui.css | 0 .../css/fixedHeader.semanticui.min.css | 0 .../js/dataTables.fixedHeader.js | 0 .../js/dataTables.fixedHeader.min.js | 0 .../js/fixedHeader.bootstrap.js | 0 .../js/fixedHeader.bootstrap.min.js | 0 .../js/fixedHeader.bootstrap4.js | 0 .../js/fixedHeader.bootstrap4.min.js | 0 .../js/fixedHeader.bootstrap5.js | 0 .../js/fixedHeader.bootstrap5.min.js | 0 .../FixedHeader-3.2.1/js/fixedHeader.bulma.js | 0 .../js/fixedHeader.bulma.min.js | 0 .../js/fixedHeader.dataTables.js | 0 .../js/fixedHeader.dataTables.min.js | 0 .../js/fixedHeader.foundation.js | 0 .../js/fixedHeader.foundation.min.js | 0 .../js/fixedHeader.jqueryui.js | 0 .../js/fixedHeader.jqueryui.min.js | 0 .../js/fixedHeader.semanticui.js | 0 .../js/fixedHeader.semanticui.min.js | 0 .../css/responsive.bootstrap.css | 181 - .../css/responsive.bootstrap.min.css | 1 - .../css/responsive.dataTables.css | 178 - .../css/responsive.dataTables.min.css | 1 - .../css/responsive.foundation.css | 181 - .../css/responsive.foundation.min.css | 1 - .../css/responsive.jqueryui.css | 178 - .../css/responsive.jqueryui.min.css | 1 - .../js/dataTables.responsive.js | 1255 - .../js/dataTables.responsive.min.js | 26 - .../js/responsive.bootstrap.min.js | 6 - .../js/responsive.foundation.js | 62 - .../js/responsive.foundation.min.js | 6 - .../js/responsive.jqueryui.min.js | 6 - .../css/responsive.bootstrap.css | 0 .../css/responsive.bootstrap.min.css | 0 .../css/responsive.bootstrap4.css | 0 .../css/responsive.bootstrap4.min.css | 0 .../css/responsive.bootstrap5.css | 0 .../css/responsive.bootstrap5.min.css | 0 .../Responsive-2.2.9/css/responsive.bulma.css | 0 .../css/responsive.bulma.min.css | 0 .../css/responsive.dataTables.css | 0 .../css/responsive.dataTables.min.css | 0 .../css/responsive.foundation.css | 0 .../css/responsive.foundation.min.css | 0 .../css/responsive.jqueryui.css | 0 .../css/responsive.jqueryui.min.css | 0 .../css/responsive.semanticui.css | 0 .../css/responsive.semanticui.min.css | 0 .../js/dataTables.responsive.js | 0 .../js/dataTables.responsive.min.js | 0 .../js/responsive.bootstrap.js | 0 .../js/responsive.bootstrap.min.js | 0 .../js/responsive.bootstrap4.js | 0 .../js/responsive.bootstrap4.min.js | 0 .../js/responsive.bootstrap5.js | 0 .../js/responsive.bootstrap5.min.js | 0 .../Responsive-2.2.9/js/responsive.bulma.js | 0 .../js/responsive.bulma.min.js | 0 .../js/responsive.dataTables.js | 0 .../js/responsive.dataTables.min.js | 0 .../js/responsive.foundation.js | 0 .../js/responsive.foundation.min.js | 0 .../js/responsive.jqueryui.js | 0 .../js/responsive.jqueryui.min.js | 0 .../js/responsive.semanticui.js | 0 .../js/responsive.semanticui.min.js | 0 .../css/searchBuilder.bootstrap.css | 0 .../css/searchBuilder.bootstrap.min.css | 0 .../css/searchBuilder.bootstrap4.css | 0 .../css/searchBuilder.bootstrap4.min.css | 0 .../css/searchBuilder.bootstrap5.css | 0 .../css/searchBuilder.bootstrap5.min.css | 0 .../css/searchBuilder.bulma.css | 0 .../css/searchBuilder.bulma.min.css | 0 .../css/searchBuilder.dataTables.css | 0 .../css/searchBuilder.dataTables.min.css | 0 .../css/searchBuilder.foundation.css | 0 .../css/searchBuilder.foundation.min.css | 0 .../css/searchBuilder.jqueryui.css | 0 .../css/searchBuilder.jqueryui.min.css | 0 .../css/searchBuilder.semanticui.css | 0 .../css/searchBuilder.semanticui.min.css | 0 .../js/dataTables.searchBuilder.js | 0 .../js/dataTables.searchBuilder.min.js | 0 .../js/searchBuilder.bootstrap.js | 0 .../js/searchBuilder.bootstrap.min.js | 0 .../js/searchBuilder.bootstrap4.js | 0 .../js/searchBuilder.bootstrap4.min.js | 0 .../js/searchBuilder.bootstrap5.js | 0 .../js/searchBuilder.bootstrap5.min.js | 0 .../js/searchBuilder.bulma.js | 0 .../js/searchBuilder.bulma.min.js | 0 .../js/searchBuilder.dataTables.js | 0 .../js/searchBuilder.dataTables.min.js | 0 .../js/searchBuilder.foundation.js | 0 .../js/searchBuilder.foundation.min.js | 0 .../js/searchBuilder.jqueryui.js | 0 .../js/searchBuilder.jqueryui.min.js | 0 .../js/searchBuilder.semanticui.js | 0 .../js/searchBuilder.semanticui.min.js | 0 app/static/DataTables/datatables.css | 531 +- app/static/DataTables/datatables.js | 10071 ++++--- app/static/DataTables/datatables.min.css | 14 +- app/static/DataTables/datatables.min.js | 772 +- .../DataTables-1.11.4/images/sort_asc.png | Bin 160 -> 0 bytes .../DataTables-1.11.4/images/sort_both.png | Bin 201 -> 0 bytes .../DataTables-1.11.4/images/sort_desc.png | Bin 158 -> 0 bytes .../js/responsive.bootstrap.js | 85 - .../js/responsive.jqueryui.js | 63 - app/static/DataTables2022/datatables.css | 930 - app/static/DataTables2022/datatables.js | 22407 ---------------- app/static/DataTables2022/datatables.min.css | 27 - app/static/DataTables2022/datatables.min.js | 538 - app/templates/entreprises/contacts.html | 4 +- app/templates/entreprises/entreprises.html | 4 +- .../entreprises/entreprises_validation.html | 4 +- 260 files changed, 7004 insertions(+), 52519 deletions(-) delete mode 100644 app/static/DataTables/ColReorder-1.3.3/css/colReorder.bootstrap.css delete mode 100644 app/static/DataTables/ColReorder-1.3.3/css/colReorder.bootstrap.min.css delete mode 100644 app/static/DataTables/ColReorder-1.3.3/css/colReorder.dataTables.css delete mode 100644 app/static/DataTables/ColReorder-1.3.3/css/colReorder.dataTables.min.css delete mode 100644 app/static/DataTables/ColReorder-1.3.3/css/colReorder.foundation.css delete mode 100644 app/static/DataTables/ColReorder-1.3.3/css/colReorder.foundation.min.css delete mode 100644 app/static/DataTables/ColReorder-1.3.3/css/colReorder.jqueryui.css delete mode 100644 app/static/DataTables/ColReorder-1.3.3/css/colReorder.jqueryui.min.css delete mode 100644 app/static/DataTables/ColReorder-1.3.3/js/dataTables.colReorder.js delete mode 100644 app/static/DataTables/ColReorder-1.3.3/js/dataTables.colReorder.min.js delete mode 100644 app/static/DataTables/DataTables-1.10.15/css/dataTables.bootstrap.css delete mode 100644 app/static/DataTables/DataTables-1.10.15/css/dataTables.bootstrap.min.css delete mode 100644 app/static/DataTables/DataTables-1.10.15/css/dataTables.foundation.css delete mode 100644 app/static/DataTables/DataTables-1.10.15/css/dataTables.foundation.min.css delete mode 100644 app/static/DataTables/DataTables-1.10.15/css/dataTables.jqueryui.css delete mode 100644 app/static/DataTables/DataTables-1.10.15/css/dataTables.jqueryui.min.css delete mode 100644 app/static/DataTables/DataTables-1.10.15/css/dataTables.semanticui.css delete mode 100644 app/static/DataTables/DataTables-1.10.15/css/dataTables.semanticui.min.css delete mode 100644 app/static/DataTables/DataTables-1.10.15/css/jquery.dataTables.css delete mode 100644 app/static/DataTables/DataTables-1.10.15/css/jquery.dataTables.min.css delete mode 100644 app/static/DataTables/DataTables-1.10.15/css/jquery.dataTables_themeroller.css delete mode 100644 app/static/DataTables/DataTables-1.10.15/images/sort_asc_disabled.png delete mode 100644 app/static/DataTables/DataTables-1.10.15/images/sort_desc_disabled.png delete mode 100644 app/static/DataTables/DataTables-1.10.15/js/dataTables.bootstrap.js delete mode 100644 app/static/DataTables/DataTables-1.10.15/js/dataTables.bootstrap.min.js delete mode 100644 app/static/DataTables/DataTables-1.10.15/js/dataTables.foundation.js delete mode 100644 app/static/DataTables/DataTables-1.10.15/js/dataTables.foundation.min.js delete mode 100644 app/static/DataTables/DataTables-1.10.15/js/dataTables.jqueryui.js delete mode 100644 app/static/DataTables/DataTables-1.10.15/js/dataTables.jqueryui.min.js delete mode 100644 app/static/DataTables/DataTables-1.10.15/js/dataTables.semanticui.js delete mode 100644 app/static/DataTables/DataTables-1.10.15/js/dataTables.semanticui.min.js delete mode 100644 app/static/DataTables/DataTables-1.10.15/js/jquery.dataTables.js delete mode 100644 app/static/DataTables/DataTables-1.10.15/js/jquery.dataTables.min.js rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/css/dataTables.bootstrap.css (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/css/dataTables.bootstrap.min.css (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/css/dataTables.bootstrap4.css (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/css/dataTables.bootstrap4.min.css (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/css/dataTables.bootstrap5.css (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/css/dataTables.bootstrap5.min.css (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/css/dataTables.bulma.css (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/css/dataTables.bulma.min.css (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/css/dataTables.dataTables.css (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/css/dataTables.dataTables.min.css (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/css/dataTables.foundation.css (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/css/dataTables.foundation.min.css (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/css/dataTables.jqueryui.css (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/css/dataTables.jqueryui.min.css (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/css/dataTables.semanticui.css (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/css/dataTables.semanticui.min.css (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/css/jquery.dataTables.css (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/css/jquery.dataTables.min.css (100%) rename app/static/DataTables/{DataTables-1.10.15 => DataTables-1.11.4}/images/sort_asc.png (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/images/sort_asc_disabled.png (100%) rename app/static/DataTables/{DataTables-1.10.15 => DataTables-1.11.4}/images/sort_both.png (100%) rename app/static/DataTables/{DataTables-1.10.15 => DataTables-1.11.4}/images/sort_desc.png (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/images/sort_desc_disabled.png (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/js/dataTables.bootstrap.js (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/js/dataTables.bootstrap.min.js (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/js/dataTables.bootstrap4.js (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/js/dataTables.bootstrap4.min.js (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/js/dataTables.bootstrap5.js (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/js/dataTables.bootstrap5.min.js (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/js/dataTables.bulma.js (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/js/dataTables.bulma.min.js (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/js/dataTables.dataTables.js (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/js/dataTables.dataTables.min.js (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/js/dataTables.foundation.js (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/js/dataTables.foundation.min.js (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/js/dataTables.jqueryui.js (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/js/dataTables.jqueryui.min.js (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/js/dataTables.semanticui.js (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/js/dataTables.semanticui.min.js (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/js/jquery.dataTables.js (100%) rename app/static/{DataTables2022 => DataTables}/DataTables-1.11.4/js/jquery.dataTables.min.js (100%) delete mode 100644 app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.bootstrap.css delete mode 100644 app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.bootstrap.min.css delete mode 100644 app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.dataTables.css delete mode 100644 app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.dataTables.min.css delete mode 100644 app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.foundation.css delete mode 100644 app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.foundation.min.css delete mode 100644 app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.jqueryui.css delete mode 100644 app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.jqueryui.min.css delete mode 100644 app/static/DataTables/FixedColumns-3.2.2/js/dataTables.fixedColumns.js delete mode 100644 app/static/DataTables/FixedColumns-3.2.2/js/dataTables.fixedColumns.min.js rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/css/fixedColumns.bootstrap.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/css/fixedColumns.bootstrap.min.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/css/fixedColumns.bootstrap4.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/css/fixedColumns.bootstrap4.min.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/css/fixedColumns.bootstrap5.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/css/fixedColumns.bootstrap5.min.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/css/fixedColumns.bulma.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/css/fixedColumns.bulma.min.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/css/fixedColumns.dataTables.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/css/fixedColumns.dataTables.min.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/css/fixedColumns.foundation.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/css/fixedColumns.foundation.min.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/css/fixedColumns.jqueryui.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/css/fixedColumns.jqueryui.min.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/css/fixedColumns.semanticui.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/css/fixedColumns.semanticui.min.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/js/dataTables.fixedColumns.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/js/dataTables.fixedColumns.min.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/js/fixedColumns.bootstrap.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/js/fixedColumns.bootstrap.min.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/js/fixedColumns.bootstrap4.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/js/fixedColumns.bootstrap4.min.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/js/fixedColumns.bootstrap5.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/js/fixedColumns.bootstrap5.min.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/js/fixedColumns.bulma.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/js/fixedColumns.bulma.min.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/js/fixedColumns.dataTables.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/js/fixedColumns.dataTables.min.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/js/fixedColumns.foundation.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/js/fixedColumns.foundation.min.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/js/fixedColumns.jqueryui.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/js/fixedColumns.jqueryui.min.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/js/fixedColumns.semanticui.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedColumns-4.0.1/js/fixedColumns.semanticui.min.js (100%) delete mode 100644 app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.bootstrap.css delete mode 100644 app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.bootstrap.min.css delete mode 100644 app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.dataTables.css delete mode 100644 app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.dataTables.min.css delete mode 100644 app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.foundation.css delete mode 100644 app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.foundation.min.css delete mode 100644 app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.jqueryui.css delete mode 100644 app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.jqueryui.min.css delete mode 100644 app/static/DataTables/FixedHeader-3.1.2/js/dataTables.fixedHeader.js delete mode 100644 app/static/DataTables/FixedHeader-3.1.2/js/dataTables.fixedHeader.min.js rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/css/fixedHeader.bootstrap.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/css/fixedHeader.bootstrap.min.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/css/fixedHeader.bootstrap4.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/css/fixedHeader.bootstrap4.min.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/css/fixedHeader.bootstrap5.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/css/fixedHeader.bootstrap5.min.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/css/fixedHeader.bulma.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/css/fixedHeader.bulma.min.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/css/fixedHeader.dataTables.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/css/fixedHeader.dataTables.min.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/css/fixedHeader.foundation.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/css/fixedHeader.foundation.min.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/css/fixedHeader.jqueryui.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/css/fixedHeader.jqueryui.min.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/css/fixedHeader.semanticui.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/css/fixedHeader.semanticui.min.css (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/js/dataTables.fixedHeader.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/js/dataTables.fixedHeader.min.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/js/fixedHeader.bootstrap.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/js/fixedHeader.bootstrap.min.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/js/fixedHeader.bootstrap4.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/js/fixedHeader.bootstrap4.min.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/js/fixedHeader.bootstrap5.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/js/fixedHeader.bootstrap5.min.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/js/fixedHeader.bulma.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/js/fixedHeader.bulma.min.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/js/fixedHeader.dataTables.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/js/fixedHeader.dataTables.min.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/js/fixedHeader.foundation.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/js/fixedHeader.foundation.min.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/js/fixedHeader.jqueryui.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/js/fixedHeader.jqueryui.min.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/js/fixedHeader.semanticui.js (100%) rename app/static/{DataTables2022 => DataTables}/FixedHeader-3.2.1/js/fixedHeader.semanticui.min.js (100%) delete mode 100644 app/static/DataTables/Responsive-2.1.1/css/responsive.bootstrap.css delete mode 100644 app/static/DataTables/Responsive-2.1.1/css/responsive.bootstrap.min.css delete mode 100644 app/static/DataTables/Responsive-2.1.1/css/responsive.dataTables.css delete mode 100644 app/static/DataTables/Responsive-2.1.1/css/responsive.dataTables.min.css delete mode 100644 app/static/DataTables/Responsive-2.1.1/css/responsive.foundation.css delete mode 100644 app/static/DataTables/Responsive-2.1.1/css/responsive.foundation.min.css delete mode 100644 app/static/DataTables/Responsive-2.1.1/css/responsive.jqueryui.css delete mode 100644 app/static/DataTables/Responsive-2.1.1/css/responsive.jqueryui.min.css delete mode 100644 app/static/DataTables/Responsive-2.1.1/js/dataTables.responsive.js delete mode 100644 app/static/DataTables/Responsive-2.1.1/js/dataTables.responsive.min.js delete mode 100644 app/static/DataTables/Responsive-2.1.1/js/responsive.bootstrap.min.js delete mode 100644 app/static/DataTables/Responsive-2.1.1/js/responsive.foundation.js delete mode 100644 app/static/DataTables/Responsive-2.1.1/js/responsive.foundation.min.js delete mode 100644 app/static/DataTables/Responsive-2.1.1/js/responsive.jqueryui.min.js rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/css/responsive.bootstrap.css (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/css/responsive.bootstrap.min.css (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/css/responsive.bootstrap4.css (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/css/responsive.bootstrap4.min.css (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/css/responsive.bootstrap5.css (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/css/responsive.bootstrap5.min.css (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/css/responsive.bulma.css (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/css/responsive.bulma.min.css (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/css/responsive.dataTables.css (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/css/responsive.dataTables.min.css (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/css/responsive.foundation.css (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/css/responsive.foundation.min.css (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/css/responsive.jqueryui.css (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/css/responsive.jqueryui.min.css (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/css/responsive.semanticui.css (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/css/responsive.semanticui.min.css (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/js/dataTables.responsive.js (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/js/dataTables.responsive.min.js (100%) rename app/static/DataTables/{Responsive-2.1.1 => Responsive-2.2.9}/js/responsive.bootstrap.js (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/js/responsive.bootstrap.min.js (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/js/responsive.bootstrap4.js (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/js/responsive.bootstrap4.min.js (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/js/responsive.bootstrap5.js (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/js/responsive.bootstrap5.min.js (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/js/responsive.bulma.js (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/js/responsive.bulma.min.js (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/js/responsive.dataTables.js (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/js/responsive.dataTables.min.js (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/js/responsive.foundation.js (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/js/responsive.foundation.min.js (100%) rename app/static/DataTables/{Responsive-2.1.1 => Responsive-2.2.9}/js/responsive.jqueryui.js (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/js/responsive.jqueryui.min.js (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/js/responsive.semanticui.js (100%) rename app/static/{DataTables2022 => DataTables}/Responsive-2.2.9/js/responsive.semanticui.min.js (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/css/searchBuilder.bootstrap.css (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/css/searchBuilder.bootstrap.min.css (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/css/searchBuilder.bootstrap4.css (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/css/searchBuilder.bootstrap4.min.css (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/css/searchBuilder.bootstrap5.css (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/css/searchBuilder.bootstrap5.min.css (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/css/searchBuilder.bulma.css (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/css/searchBuilder.bulma.min.css (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/css/searchBuilder.dataTables.css (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/css/searchBuilder.dataTables.min.css (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/css/searchBuilder.foundation.css (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/css/searchBuilder.foundation.min.css (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/css/searchBuilder.jqueryui.css (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/css/searchBuilder.jqueryui.min.css (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/css/searchBuilder.semanticui.css (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/css/searchBuilder.semanticui.min.css (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/js/dataTables.searchBuilder.js (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/js/dataTables.searchBuilder.min.js (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/js/searchBuilder.bootstrap.js (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/js/searchBuilder.bootstrap.min.js (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/js/searchBuilder.bootstrap4.js (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/js/searchBuilder.bootstrap4.min.js (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/js/searchBuilder.bootstrap5.js (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/js/searchBuilder.bootstrap5.min.js (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/js/searchBuilder.bulma.js (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/js/searchBuilder.bulma.min.js (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/js/searchBuilder.dataTables.js (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/js/searchBuilder.dataTables.min.js (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/js/searchBuilder.foundation.js (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/js/searchBuilder.foundation.min.js (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/js/searchBuilder.jqueryui.js (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/js/searchBuilder.jqueryui.min.js (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/js/searchBuilder.semanticui.js (100%) rename app/static/{DataTables2022 => DataTables}/SearchBuilder-1.3.1/js/searchBuilder.semanticui.min.js (100%) delete mode 100644 app/static/DataTables2022/DataTables-1.11.4/images/sort_asc.png delete mode 100644 app/static/DataTables2022/DataTables-1.11.4/images/sort_both.png delete mode 100644 app/static/DataTables2022/DataTables-1.11.4/images/sort_desc.png delete mode 100644 app/static/DataTables2022/Responsive-2.2.9/js/responsive.bootstrap.js delete mode 100644 app/static/DataTables2022/Responsive-2.2.9/js/responsive.jqueryui.js delete mode 100644 app/static/DataTables2022/datatables.css delete mode 100644 app/static/DataTables2022/datatables.js delete mode 100644 app/static/DataTables2022/datatables.min.css delete mode 100644 app/static/DataTables2022/datatables.min.js diff --git a/app/static/DataTables/ColReorder-1.3.3/css/colReorder.bootstrap.css b/app/static/DataTables/ColReorder-1.3.3/css/colReorder.bootstrap.css deleted file mode 100644 index 4d399a55e..000000000 --- a/app/static/DataTables/ColReorder-1.3.3/css/colReorder.bootstrap.css +++ /dev/null @@ -1,11 +0,0 @@ -table.DTCR_clonedTable.dataTable { - position: absolute !important; - background-color: rgba(255, 255, 255, 0.7); - z-index: 202; -} - -div.DTCR_pointer { - width: 1px; - background-color: #337ab7; - z-index: 201; -} diff --git a/app/static/DataTables/ColReorder-1.3.3/css/colReorder.bootstrap.min.css b/app/static/DataTables/ColReorder-1.3.3/css/colReorder.bootstrap.min.css deleted file mode 100644 index 5a84d69b8..000000000 --- a/app/static/DataTables/ColReorder-1.3.3/css/colReorder.bootstrap.min.css +++ /dev/null @@ -1 +0,0 @@ -table.DTCR_clonedTable.dataTable{position:absolute !important;background-color:rgba(255,255,255,0.7);z-index:202}div.DTCR_pointer{width:1px;background-color:#337ab7;z-index:201} diff --git a/app/static/DataTables/ColReorder-1.3.3/css/colReorder.dataTables.css b/app/static/DataTables/ColReorder-1.3.3/css/colReorder.dataTables.css deleted file mode 100644 index a2854c0aa..000000000 --- a/app/static/DataTables/ColReorder-1.3.3/css/colReorder.dataTables.css +++ /dev/null @@ -1,11 +0,0 @@ -table.DTCR_clonedTable.dataTable { - position: absolute !important; - background-color: rgba(255, 255, 255, 0.7); - z-index: 202; -} - -div.DTCR_pointer { - width: 1px; - background-color: #0259C4; - z-index: 201; -} diff --git a/app/static/DataTables/ColReorder-1.3.3/css/colReorder.dataTables.min.css b/app/static/DataTables/ColReorder-1.3.3/css/colReorder.dataTables.min.css deleted file mode 100644 index 4f83a4085..000000000 --- a/app/static/DataTables/ColReorder-1.3.3/css/colReorder.dataTables.min.css +++ /dev/null @@ -1 +0,0 @@ -table.DTCR_clonedTable.dataTable{position:absolute !important;background-color:rgba(255,255,255,0.7);z-index:202}div.DTCR_pointer{width:1px;background-color:#0259C4;z-index:201} diff --git a/app/static/DataTables/ColReorder-1.3.3/css/colReorder.foundation.css b/app/static/DataTables/ColReorder-1.3.3/css/colReorder.foundation.css deleted file mode 100644 index 2b66af0cd..000000000 --- a/app/static/DataTables/ColReorder-1.3.3/css/colReorder.foundation.css +++ /dev/null @@ -1,11 +0,0 @@ -table.DTCR_clonedTable.dataTable { - position: absolute !important; - background-color: rgba(255, 255, 255, 0.7); - z-index: 202; -} - -div.DTCR_pointer { - width: 1px; - background-color: #008CBA; - z-index: 201; -} diff --git a/app/static/DataTables/ColReorder-1.3.3/css/colReorder.foundation.min.css b/app/static/DataTables/ColReorder-1.3.3/css/colReorder.foundation.min.css deleted file mode 100644 index 36f780ed5..000000000 --- a/app/static/DataTables/ColReorder-1.3.3/css/colReorder.foundation.min.css +++ /dev/null @@ -1 +0,0 @@ -table.DTCR_clonedTable.dataTable{position:absolute !important;background-color:rgba(255,255,255,0.7);z-index:202}div.DTCR_pointer{width:1px;background-color:#008CBA;z-index:201} diff --git a/app/static/DataTables/ColReorder-1.3.3/css/colReorder.jqueryui.css b/app/static/DataTables/ColReorder-1.3.3/css/colReorder.jqueryui.css deleted file mode 100644 index a2854c0aa..000000000 --- a/app/static/DataTables/ColReorder-1.3.3/css/colReorder.jqueryui.css +++ /dev/null @@ -1,11 +0,0 @@ -table.DTCR_clonedTable.dataTable { - position: absolute !important; - background-color: rgba(255, 255, 255, 0.7); - z-index: 202; -} - -div.DTCR_pointer { - width: 1px; - background-color: #0259C4; - z-index: 201; -} diff --git a/app/static/DataTables/ColReorder-1.3.3/css/colReorder.jqueryui.min.css b/app/static/DataTables/ColReorder-1.3.3/css/colReorder.jqueryui.min.css deleted file mode 100644 index 4f83a4085..000000000 --- a/app/static/DataTables/ColReorder-1.3.3/css/colReorder.jqueryui.min.css +++ /dev/null @@ -1 +0,0 @@ -table.DTCR_clonedTable.dataTable{position:absolute !important;background-color:rgba(255,255,255,0.7);z-index:202}div.DTCR_pointer{width:1px;background-color:#0259C4;z-index:201} diff --git a/app/static/DataTables/ColReorder-1.3.3/js/dataTables.colReorder.js b/app/static/DataTables/ColReorder-1.3.3/js/dataTables.colReorder.js deleted file mode 100644 index 44cc58213..000000000 --- a/app/static/DataTables/ColReorder-1.3.3/js/dataTables.colReorder.js +++ /dev/null @@ -1,1353 +0,0 @@ -/*! ColReorder 1.3.3 - * ©2010-2015 SpryMedia Ltd - datatables.net/license - */ - -/** - * @summary ColReorder - * @description Provide the ability to reorder columns in a DataTable - * @version 1.3.3 - * @file dataTables.colReorder.js - * @author SpryMedia Ltd (www.sprymedia.co.uk) - * @contact www.sprymedia.co.uk/contact - * @copyright Copyright 2010-2014 SpryMedia Ltd. - * - * This source file is free software, available under the following license: - * MIT license - http://datatables.net/license/mit - * - * This source file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. - * - * For details please refer to: http://www.datatables.net - */ -(function( factory ){ - if ( typeof define === 'function' && define.amd ) { - // AMD - define( ['jquery', 'datatables.net'], function ( $ ) { - return factory( $, window, document ); - } ); - } - else if ( typeof exports === 'object' ) { - // CommonJS - module.exports = function (root, $) { - if ( ! root ) { - root = window; - } - - if ( ! $ || ! $.fn.dataTable ) { - $ = require('datatables.net')(root, $).$; - } - - return factory( $, root, root.document ); - }; - } - else { - // Browser - factory( jQuery, window, document ); - } -}(function( $, window, document, undefined ) { -'use strict'; -var DataTable = $.fn.dataTable; - - -/** - * Switch the key value pairing of an index array to be value key (i.e. the old value is now the - * key). For example consider [ 2, 0, 1 ] this would be returned as [ 1, 2, 0 ]. - * @method fnInvertKeyValues - * @param array aIn Array to switch around - * @returns array - */ -function fnInvertKeyValues( aIn ) -{ - var aRet=[]; - for ( var i=0, iLen=aIn.length ; i= iCols ) - { - this.oApi._fnLog( oSettings, 1, "ColReorder 'from' index is out of bounds: "+iFrom ); - return; - } - - if ( iTo < 0 || iTo >= iCols ) - { - this.oApi._fnLog( oSettings, 1, "ColReorder 'to' index is out of bounds: "+iTo ); - return; - } - - /* - * Calculate the new column array index, so we have a mapping between the old and new - */ - var aiMapping = []; - for ( i=0, iLen=iCols ; i this.s.fixed-1 && i < iLen - this.s.fixedRight ) - { - this._fnMouseListener( i, this.s.dt.aoColumns[i].nTh ); - } - - /* Mark the original column order for later reference */ - this.s.dt.aoColumns[i]._ColReorder_iOrigCol = i; - } - - /* State saving */ - this.s.dt.oApi._fnCallbackReg( this.s.dt, 'aoStateSaveParams', function (oS, oData) { - that._fnStateSave.call( that, oData ); - }, "ColReorder_State" ); - - /* An initial column order has been specified */ - var aiOrder = null; - if ( this.s.init.aiOrder ) - { - aiOrder = this.s.init.aiOrder.slice(); - } - - /* State loading, overrides the column order given */ - if ( this.s.dt.oLoadedState && typeof this.s.dt.oLoadedState.ColReorder != 'undefined' && - this.s.dt.oLoadedState.ColReorder.length == this.s.dt.aoColumns.length ) - { - aiOrder = this.s.dt.oLoadedState.ColReorder; - } - - /* If we have an order to apply - do so */ - if ( aiOrder ) - { - /* We might be called during or after the DataTables initialisation. If before, then we need - * to wait until the draw is done, if after, then do what we need to do right away - */ - if ( !that.s.dt._bInitComplete ) - { - var bDone = false; - $(table).on( 'draw.dt.colReorder', function () { - if ( !that.s.dt._bInitComplete && !bDone ) - { - bDone = true; - var resort = fnInvertKeyValues( aiOrder ); - that._fnOrderColumns.call( that, resort ); - } - } ); - } - else - { - var resort = fnInvertKeyValues( aiOrder ); - that._fnOrderColumns.call( that, resort ); - } - } - else { - this._fnSetColumnIndexes(); - } - - // Destroy clean up - $(table).on( 'destroy.dt.colReorder', function () { - $(table).off( 'destroy.dt.colReorder draw.dt.colReorder' ); - $(that.s.dt.nTHead).find( '*' ).off( '.ColReorder' ); - - $.each( that.s.dt.aoColumns, function (i, column) { - $(column.nTh).removeAttr('data-column-index'); - } ); - - that.s.dt._colReorder = null; - that.s = null; - } ); - }, - - - /** - * Set the column order from an array - * @method _fnOrderColumns - * @param array a An array of integers which dictate the column order that should be applied - * @returns void - * @private - */ - "_fnOrderColumns": function ( a ) - { - var changed = false; - - if ( a.length != this.s.dt.aoColumns.length ) - { - this.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, "ColReorder - array reorder does not "+ - "match known number of columns. Skipping." ); - return; - } - - for ( var i=0, iLen=a.length ; i') - .addClass( 'DTCR_pointer' ) - .css( { - position: 'absolute', - top: scrolling ? - $('div.dataTables_scroll', this.s.dt.nTableWrapper).offset().top : - $(this.s.dt.nTable).offset().top, - height : scrolling ? - $('div.dataTables_scroll', this.s.dt.nTableWrapper).height() : - $(this.s.dt.nTable).height() - } ) - .appendTo( 'body' ); - }, - - - /** - * Add a data attribute to the column headers, so we know the index of - * the row to be reordered. This allows fast detection of the index, and - * for this plug-in to work with FixedHeader which clones the nodes. - * @private - */ - "_fnSetColumnIndexes": function () - { - $.each( this.s.dt.aoColumns, function (i, column) { - $(column.nTh).attr('data-column-index', i); - } ); - }, - - - /** - * Get cursor position regardless of mouse or touch input - * @param {Event} e jQuery Event - * @param {string} prop Property to get - * @return {number} Value - */ - _fnCursorPosition: function ( e, prop ) { - if ( e.type.indexOf('touch') !== -1 ) { - return e.originalEvent.touches[0][ prop ]; - } - return e[ prop ]; - } -} ); - - - - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Static parameters - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -/** - * ColReorder default settings for initialisation - * @namespace - * @static - */ -ColReorder.defaults = { - /** - * Predefined ordering for the columns that will be applied automatically - * on initialisation. If not specified then the order that the columns are - * found to be in the HTML is the order used. - * @type array - * @default null - * @static - */ - aiOrder: null, - - /** - * Redraw the table's column ordering as the end user draws the column - * (`true`) or wait until the mouse is released (`false` - default). Note - * that this will perform a redraw on each reordering, which involves an - * Ajax request each time if you are using server-side processing in - * DataTables. - * @type boolean - * @default false - * @static - */ - bRealtime: true, - - /** - * Indicate how many columns should be fixed in position (counting from the - * left). This will typically be 1 if used, but can be as high as you like. - * @type int - * @default 0 - * @static - */ - iFixedColumnsLeft: 0, - - /** - * As `iFixedColumnsRight` but counting from the right. - * @type int - * @default 0 - * @static - */ - iFixedColumnsRight: 0, - - /** - * Callback function that is fired when columns are reordered. The `column- - * reorder` event is preferred over this callback - * @type function():void - * @default null - * @static - */ - fnReorderCallback: null -}; - - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Constants - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/** - * ColReorder version - * @constant version - * @type String - * @default As code - */ -ColReorder.version = "1.3.3"; - - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * DataTables interfaces - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -// Expose -$.fn.dataTable.ColReorder = ColReorder; -$.fn.DataTable.ColReorder = ColReorder; - - -// Register a new feature with DataTables -if ( typeof $.fn.dataTable == "function" && - typeof $.fn.dataTableExt.fnVersionCheck == "function" && - $.fn.dataTableExt.fnVersionCheck('1.10.8') ) -{ - $.fn.dataTableExt.aoFeatures.push( { - "fnInit": function( settings ) { - var table = settings.oInstance; - - if ( ! settings._colReorder ) { - var dtInit = settings.oInit; - var opts = dtInit.colReorder || dtInit.oColReorder || {}; - - new ColReorder( settings, opts ); - } - else { - table.oApi._fnLog( settings, 1, "ColReorder attempted to initialise twice. Ignoring second" ); - } - - return null; /* No node for DataTables to insert */ - }, - "cFeature": "R", - "sFeature": "ColReorder" - } ); -} -else { - alert( "Warning: ColReorder requires DataTables 1.10.8 or greater - www.datatables.net/download"); -} - - -// Attach a listener to the document which listens for DataTables initialisation -// events so we can automatically initialise -$(document).on( 'preInit.dt.colReorder', function (e, settings) { - if ( e.namespace !== 'dt' ) { - return; - } - - var init = settings.oInit.colReorder; - var defaults = DataTable.defaults.colReorder; - - if ( init || defaults ) { - var opts = $.extend( {}, init, defaults ); - - if ( init !== false ) { - new ColReorder( settings, opts ); - } - } -} ); - - -// API augmentation -$.fn.dataTable.Api.register( 'colReorder.reset()', function () { - return this.iterator( 'table', function ( ctx ) { - ctx._colReorder.fnReset(); - } ); -} ); - -$.fn.dataTable.Api.register( 'colReorder.order()', function ( set, original ) { - if ( set ) { - return this.iterator( 'table', function ( ctx ) { - ctx._colReorder.fnOrder( set, original ); - } ); - } - - return this.context.length ? - this.context[0]._colReorder.fnOrder() : - null; -} ); - -$.fn.dataTable.Api.register( 'colReorder.transpose()', function ( idx, dir ) { - return this.context.length && this.context[0]._colReorder ? - this.context[0]._colReorder.fnTranspose( idx, dir ) : - idx; -} ); - - -return ColReorder; -})); diff --git a/app/static/DataTables/ColReorder-1.3.3/js/dataTables.colReorder.min.js b/app/static/DataTables/ColReorder-1.3.3/js/dataTables.colReorder.min.js deleted file mode 100644 index 24d2c4938..000000000 --- a/app/static/DataTables/ColReorder-1.3.3/js/dataTables.colReorder.min.js +++ /dev/null @@ -1,27 +0,0 @@ -/*! - ColReorder 1.3.3 - ©2010-2015 SpryMedia Ltd - datatables.net/license -*/ -(function(f){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(o){return f(o,window,document)}):"object"===typeof exports?module.exports=function(o,l){o||(o=window);if(!l||!l.fn.dataTable)l=require("datatables.net")(o,l).$;return f(l,o,o.document)}:f(jQuery,window,document)})(function(f,o,l,r){function q(a){for(var b=[],d=0,e=a.length;db||b>=l)this.oApi._fnLog(a,1,"ColReorder 'from' index is out of bounds: "+b);else if(0>d||d>=l)this.oApi._fnLog(a,1,"ColReorder 'to' index is out of bounds: "+ -d);else{j=[];c=0;for(h=l;cthis.s.fixed-1&&eMath.pow(Math.pow(this._fnCursorPosition(a,"pageX")-this.s.mouse.startX,2)+Math.pow(this._fnCursorPosition(a,"pageY")-this.s.mouse.startY,2),0.5))return;this._fnCreateDragNode()}this.dom.drag.css({left:this._fnCursorPosition(a, -"pageX")-this.s.mouse.offsetX,top:this._fnCursorPosition(a,"pageY")-this.s.mouse.offsetY});for(var b=!1,d=this.s.mouse.toIndex,e=1,f=this.s.aoTargets.length;e").addClass("DTCR_pointer").css({position:"absolute",top:a?f("div.dataTables_scroll",this.s.dt.nTableWrapper).offset().top:f(this.s.dt.nTable).offset().top,height:a?f("div.dataTables_scroll",this.s.dt.nTableWrapper).height():f(this.s.dt.nTable).height()}).appendTo("body")},_fnSetColumnIndexes:function(){f.each(this.s.dt.aoColumns,function(a,b){f(b.nTh).attr("data-column-index",a)})},_fnCursorPosition:function(a, -b){return-1!==a.type.indexOf("touch")?a.originalEvent.touches[0][b]:a[b]}});i.defaults={aiOrder:null,bRealtime:!0,iFixedColumnsLeft:0,iFixedColumnsRight:0,fnReorderCallback:null};i.version="1.3.3";f.fn.dataTable.ColReorder=i;f.fn.DataTable.ColReorder=i;"function"==typeof f.fn.dataTable&&"function"==typeof f.fn.dataTableExt.fnVersionCheck&&f.fn.dataTableExt.fnVersionCheck("1.10.8")?f.fn.dataTableExt.aoFeatures.push({fnInit:function(a){var b=a.oInstance;a._colReorder?b.oApi._fnLog(a,1,"ColReorder attempted to initialise twice. Ignoring second"): -(b=a.oInit,new i(a,b.colReorder||b.oColReorder||{}));return null},cFeature:"R",sFeature:"ColReorder"}):alert("Warning: ColReorder requires DataTables 1.10.8 or greater - www.datatables.net/download");f(l).on("preInit.dt.colReorder",function(a,b){if("dt"===a.namespace){var d=b.oInit.colReorder,e=t.defaults.colReorder;if(d||e)e=f.extend({},d,e),!1!==d&&new i(b,e)}});f.fn.dataTable.Api.register("colReorder.reset()",function(){return this.iterator("table",function(a){a._colReorder.fnReset()})});f.fn.dataTable.Api.register("colReorder.order()", -function(a,b){return a?this.iterator("table",function(d){d._colReorder.fnOrder(a,b)}):this.context.length?this.context[0]._colReorder.fnOrder():null});f.fn.dataTable.Api.register("colReorder.transpose()",function(a,b){return this.context.length&&this.context[0]._colReorder?this.context[0]._colReorder.fnTranspose(a,b):a});return i}); diff --git a/app/static/DataTables/DataTables-1.10.15/css/dataTables.bootstrap.css b/app/static/DataTables/DataTables-1.10.15/css/dataTables.bootstrap.css deleted file mode 100644 index 2bbb3ef29..000000000 --- a/app/static/DataTables/DataTables-1.10.15/css/dataTables.bootstrap.css +++ /dev/null @@ -1,184 +0,0 @@ -table.dataTable { - clear: both; - margin-top: 6px !important; - margin-bottom: 6px !important; - max-width: none !important; - border-collapse: separate !important; -} -table.dataTable td, -table.dataTable th { - -webkit-box-sizing: content-box; - box-sizing: content-box; -} -table.dataTable td.dataTables_empty, -table.dataTable th.dataTables_empty { - text-align: center; -} -table.dataTable.nowrap th, -table.dataTable.nowrap td { - white-space: nowrap; -} - -div.dataTables_wrapper div.dataTables_length label { - font-weight: normal; - text-align: left; - white-space: nowrap; -} -div.dataTables_wrapper div.dataTables_length select { - width: 75px; - display: inline-block; -} -div.dataTables_wrapper div.dataTables_filter { - text-align: right; -} -div.dataTables_wrapper div.dataTables_filter label { - font-weight: normal; - white-space: nowrap; - text-align: left; -} -div.dataTables_wrapper div.dataTables_filter input { - margin-left: 0.5em; - display: inline-block; - width: auto; -} -div.dataTables_wrapper div.dataTables_info { - padding-top: 8px; - white-space: nowrap; -} -div.dataTables_wrapper div.dataTables_paginate { - margin: 0; - white-space: nowrap; - text-align: right; -} -div.dataTables_wrapper div.dataTables_paginate ul.pagination { - margin: 2px 0; - white-space: nowrap; -} -div.dataTables_wrapper div.dataTables_processing { - position: absolute; - top: 50%; - left: 50%; - width: 200px; - margin-left: -100px; - margin-top: -26px; - text-align: center; - padding: 1em 0; -} - -table.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting, -table.dataTable thead > tr > td.sorting_asc, -table.dataTable thead > tr > td.sorting_desc, -table.dataTable thead > tr > td.sorting { - padding-right: 30px; -} -table.dataTable thead > tr > th:active, -table.dataTable thead > tr > td:active { - outline: none; -} -table.dataTable thead .sorting, -table.dataTable thead .sorting_asc, -table.dataTable thead .sorting_desc, -table.dataTable thead .sorting_asc_disabled, -table.dataTable thead .sorting_desc_disabled { - cursor: pointer; - position: relative; -} -table.dataTable thead .sorting:after, -table.dataTable thead .sorting_asc:after, -table.dataTable thead .sorting_desc:after, -table.dataTable thead .sorting_asc_disabled:after, -table.dataTable thead .sorting_desc_disabled:after { - position: absolute; - bottom: 8px; - right: 8px; - display: block; - font-family: 'Glyphicons Halflings'; - opacity: 0.5; -} -table.dataTable thead .sorting:after { - opacity: 0.2; - content: "\e150"; - /* sort */ -} -table.dataTable thead .sorting_asc:after { - content: "\e155"; - /* sort-by-attributes */ -} -table.dataTable thead .sorting_desc:after { - content: "\e156"; - /* sort-by-attributes-alt */ -} -table.dataTable thead .sorting_asc_disabled:after, -table.dataTable thead .sorting_desc_disabled:after { - color: #eee; -} - -div.dataTables_scrollHead table.dataTable { - margin-bottom: 0 !important; -} - -div.dataTables_scrollBody > table { - border-top: none; - margin-top: 0 !important; - margin-bottom: 0 !important; -} -div.dataTables_scrollBody > table > thead .sorting:after, -div.dataTables_scrollBody > table > thead .sorting_asc:after, -div.dataTables_scrollBody > table > thead .sorting_desc:after { - display: none; -} -div.dataTables_scrollBody > table > tbody > tr:first-child > th, -div.dataTables_scrollBody > table > tbody > tr:first-child > td { - border-top: none; -} - -div.dataTables_scrollFoot > table { - margin-top: 0 !important; - border-top: none; -} - -@media screen and (max-width: 767px) { - div.dataTables_wrapper div.dataTables_length, - div.dataTables_wrapper div.dataTables_filter, - div.dataTables_wrapper div.dataTables_info, - div.dataTables_wrapper div.dataTables_paginate { - text-align: center; - } -} -table.dataTable.table-condensed > thead > tr > th { - padding-right: 20px; -} -table.dataTable.table-condensed .sorting:after, -table.dataTable.table-condensed .sorting_asc:after, -table.dataTable.table-condensed .sorting_desc:after { - top: 6px; - right: 6px; -} - -table.table-bordered.dataTable th, -table.table-bordered.dataTable td { - border-left-width: 0; -} -table.table-bordered.dataTable th:last-child, table.table-bordered.dataTable th:last-child, -table.table-bordered.dataTable td:last-child, -table.table-bordered.dataTable td:last-child { - border-right-width: 0; -} -table.table-bordered.dataTable tbody th, -table.table-bordered.dataTable tbody td { - border-bottom-width: 0; -} - -div.dataTables_scrollHead table.table-bordered { - border-bottom-width: 0; -} - -div.table-responsive > div.dataTables_wrapper > div.row { - margin: 0; -} -div.table-responsive > div.dataTables_wrapper > div.row > div[class^="col-"]:first-child { - padding-left: 0; -} -div.table-responsive > div.dataTables_wrapper > div.row > div[class^="col-"]:last-child { - padding-right: 0; -} diff --git a/app/static/DataTables/DataTables-1.10.15/css/dataTables.bootstrap.min.css b/app/static/DataTables/DataTables-1.10.15/css/dataTables.bootstrap.min.css deleted file mode 100644 index 66a70ab2f..000000000 --- a/app/static/DataTables/DataTables-1.10.15/css/dataTables.bootstrap.min.css +++ /dev/null @@ -1 +0,0 @@ -table.dataTable{clear:both;margin-top:6px !important;margin-bottom:6px !important;max-width:none !important;border-collapse:separate !important}table.dataTable td,table.dataTable th{-webkit-box-sizing:content-box;box-sizing:content-box}table.dataTable td.dataTables_empty,table.dataTable th.dataTables_empty{text-align:center}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}div.dataTables_wrapper div.dataTables_length label{font-weight:normal;text-align:left;white-space:nowrap}div.dataTables_wrapper div.dataTables_length select{width:75px;display:inline-block}div.dataTables_wrapper div.dataTables_filter{text-align:right}div.dataTables_wrapper div.dataTables_filter label{font-weight:normal;white-space:nowrap;text-align:left}div.dataTables_wrapper div.dataTables_filter input{margin-left:0.5em;display:inline-block;width:auto}div.dataTables_wrapper div.dataTables_info{padding-top:8px;white-space:nowrap}div.dataTables_wrapper div.dataTables_paginate{margin:0;white-space:nowrap;text-align:right}div.dataTables_wrapper div.dataTables_paginate ul.pagination{margin:2px 0;white-space:nowrap}div.dataTables_wrapper div.dataTables_processing{position:absolute;top:50%;left:50%;width:200px;margin-left:-100px;margin-top:-26px;text-align:center;padding:1em 0}table.dataTable thead>tr>th.sorting_asc,table.dataTable thead>tr>th.sorting_desc,table.dataTable thead>tr>th.sorting,table.dataTable thead>tr>td.sorting_asc,table.dataTable thead>tr>td.sorting_desc,table.dataTable thead>tr>td.sorting{padding-right:30px}table.dataTable thead>tr>th:active,table.dataTable thead>tr>td:active{outline:none}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{cursor:pointer;position:relative}table.dataTable thead .sorting:after,table.dataTable thead .sorting_asc:after,table.dataTable thead .sorting_desc:after,table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc_disabled:after{position:absolute;bottom:8px;right:8px;display:block;font-family:'Glyphicons Halflings';opacity:0.5}table.dataTable thead .sorting:after{opacity:0.2;content:"\e150"}table.dataTable thead .sorting_asc:after{content:"\e155"}table.dataTable thead .sorting_desc:after{content:"\e156"}table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc_disabled:after{color:#eee}div.dataTables_scrollHead table.dataTable{margin-bottom:0 !important}div.dataTables_scrollBody>table{border-top:none;margin-top:0 !important;margin-bottom:0 !important}div.dataTables_scrollBody>table>thead .sorting:after,div.dataTables_scrollBody>table>thead .sorting_asc:after,div.dataTables_scrollBody>table>thead .sorting_desc:after{display:none}div.dataTables_scrollBody>table>tbody>tr:first-child>th,div.dataTables_scrollBody>table>tbody>tr:first-child>td{border-top:none}div.dataTables_scrollFoot>table{margin-top:0 !important;border-top:none}@media screen and (max-width: 767px){div.dataTables_wrapper div.dataTables_length,div.dataTables_wrapper div.dataTables_filter,div.dataTables_wrapper div.dataTables_info,div.dataTables_wrapper div.dataTables_paginate{text-align:center}}table.dataTable.table-condensed>thead>tr>th{padding-right:20px}table.dataTable.table-condensed .sorting:after,table.dataTable.table-condensed .sorting_asc:after,table.dataTable.table-condensed .sorting_desc:after{top:6px;right:6px}table.table-bordered.dataTable th,table.table-bordered.dataTable td{border-left-width:0}table.table-bordered.dataTable th:last-child,table.table-bordered.dataTable th:last-child,table.table-bordered.dataTable td:last-child,table.table-bordered.dataTable td:last-child{border-right-width:0}table.table-bordered.dataTable tbody th,table.table-bordered.dataTable tbody td{border-bottom-width:0}div.dataTables_scrollHead table.table-bordered{border-bottom-width:0}div.table-responsive>div.dataTables_wrapper>div.row{margin:0}div.table-responsive>div.dataTables_wrapper>div.row>div[class^="col-"]:first-child{padding-left:0}div.table-responsive>div.dataTables_wrapper>div.row>div[class^="col-"]:last-child{padding-right:0} diff --git a/app/static/DataTables/DataTables-1.10.15/css/dataTables.foundation.css b/app/static/DataTables/DataTables-1.10.15/css/dataTables.foundation.css deleted file mode 100644 index 79848c958..000000000 --- a/app/static/DataTables/DataTables-1.10.15/css/dataTables.foundation.css +++ /dev/null @@ -1,118 +0,0 @@ -table.dataTable { - clear: both; - margin: 0.5em 0 !important; - max-width: none !important; - width: 100%; -} -table.dataTable td, -table.dataTable th { - -webkit-box-sizing: content-box; - box-sizing: content-box; -} -table.dataTable td.dataTables_empty, -table.dataTable th.dataTables_empty { - text-align: center; -} -table.dataTable.nowrap th, table.dataTable.nowrap td { - white-space: nowrap; -} - -div.dataTables_wrapper { - position: relative; -} -div.dataTables_wrapper div.dataTables_length label { - float: left; - text-align: left; - margin-bottom: 0; -} -div.dataTables_wrapper div.dataTables_length select { - width: 75px; - margin-bottom: 0; -} -div.dataTables_wrapper div.dataTables_filter label { - float: right; - margin-bottom: 0; -} -div.dataTables_wrapper div.dataTables_filter input { - display: inline-block !important; - width: auto !important; - margin-bottom: 0; - margin-left: 0.5em; -} -div.dataTables_wrapper div.dataTables_info { - padding-top: 2px; -} -div.dataTables_wrapper div.dataTables_paginate { - float: right; - margin: 0; -} -div.dataTables_wrapper div.dataTables_processing { - position: absolute; - top: 50%; - left: 50%; - width: 200px; - margin-left: -100px; - margin-top: -26px; - text-align: center; - padding: 1rem 0; -} - -table.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting, -table.dataTable thead > tr > td.sorting_asc, -table.dataTable thead > tr > td.sorting_desc, -table.dataTable thead > tr > td.sorting { - padding-right: 1.5rem; -} -table.dataTable thead > tr > th:active, -table.dataTable thead > tr > td:active { - outline: none; -} -table.dataTable thead .sorting, -table.dataTable thead .sorting_asc, -table.dataTable thead .sorting_desc, -table.dataTable thead .sorting_asc_disabled, -table.dataTable thead .sorting_desc_disabled { - cursor: pointer; -} -table.dataTable thead .sorting, -table.dataTable thead .sorting_asc, -table.dataTable thead .sorting_desc, -table.dataTable thead .sorting_asc_disabled, -table.dataTable thead .sorting_desc_disabled { - background-repeat: no-repeat; - background-position: center right; -} -table.dataTable thead .sorting { - background-image: url("../images/sort_both.png"); -} -table.dataTable thead .sorting_asc { - background-image: url("../images/sort_asc.png"); -} -table.dataTable thead .sorting_desc { - background-image: url("../images/sort_desc.png"); -} -table.dataTable thead .sorting_asc_disabled { - background-image: url("../images/sort_asc_disabled.png"); -} -table.dataTable thead .sorting_desc_disabled { - background-image: url("../images/sort_desc_disabled.png"); -} - -div.dataTables_scrollHead table { - margin-bottom: 0 !important; -} - -div.dataTables_scrollBody table { - border-top: none; - margin-top: 0 !important; - margin-bottom: 0 !important; -} -div.dataTables_scrollBody table tbody tr:first-child th, -div.dataTables_scrollBody table tbody tr:first-child td { - border-top: none; -} - -div.dataTables_scrollFoot table { - margin-top: 0 !important; - border-top: none; -} diff --git a/app/static/DataTables/DataTables-1.10.15/css/dataTables.foundation.min.css b/app/static/DataTables/DataTables-1.10.15/css/dataTables.foundation.min.css deleted file mode 100644 index 73af41efc..000000000 --- a/app/static/DataTables/DataTables-1.10.15/css/dataTables.foundation.min.css +++ /dev/null @@ -1 +0,0 @@ -table.dataTable{clear:both;margin:0.5em 0 !important;max-width:none !important;width:100%}table.dataTable td,table.dataTable th{-webkit-box-sizing:content-box;box-sizing:content-box}table.dataTable td.dataTables_empty,table.dataTable th.dataTables_empty{text-align:center}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}div.dataTables_wrapper{position:relative}div.dataTables_wrapper div.dataTables_length label{float:left;text-align:left;margin-bottom:0}div.dataTables_wrapper div.dataTables_length select{width:75px;margin-bottom:0}div.dataTables_wrapper div.dataTables_filter label{float:right;margin-bottom:0}div.dataTables_wrapper div.dataTables_filter input{display:inline-block !important;width:auto !important;margin-bottom:0;margin-left:0.5em}div.dataTables_wrapper div.dataTables_info{padding-top:2px}div.dataTables_wrapper div.dataTables_paginate{float:right;margin:0}div.dataTables_wrapper div.dataTables_processing{position:absolute;top:50%;left:50%;width:200px;margin-left:-100px;margin-top:-26px;text-align:center;padding:1rem 0}table.dataTable thead>tr>th.sorting_asc,table.dataTable thead>tr>th.sorting_desc,table.dataTable thead>tr>th.sorting,table.dataTable thead>tr>td.sorting_asc,table.dataTable thead>tr>td.sorting_desc,table.dataTable thead>tr>td.sorting{padding-right:1.5rem}table.dataTable thead>tr>th:active,table.dataTable thead>tr>td:active{outline:none}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{cursor:pointer}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{background-repeat:no-repeat;background-position:center right}table.dataTable thead .sorting{background-image:url("../images/sort_both.png")}table.dataTable thead .sorting_asc{background-image:url("../images/sort_asc.png")}table.dataTable thead .sorting_desc{background-image:url("../images/sort_desc.png")}table.dataTable thead .sorting_asc_disabled{background-image:url("../images/sort_asc_disabled.png")}table.dataTable thead .sorting_desc_disabled{background-image:url("../images/sort_desc_disabled.png")}div.dataTables_scrollHead table{margin-bottom:0 !important}div.dataTables_scrollBody table{border-top:none;margin-top:0 !important;margin-bottom:0 !important}div.dataTables_scrollBody table tbody tr:first-child th,div.dataTables_scrollBody table tbody tr:first-child td{border-top:none}div.dataTables_scrollFoot table{margin-top:0 !important;border-top:none} diff --git a/app/static/DataTables/DataTables-1.10.15/css/dataTables.jqueryui.css b/app/static/DataTables/DataTables-1.10.15/css/dataTables.jqueryui.css deleted file mode 100644 index dcc8f82f7..000000000 --- a/app/static/DataTables/DataTables-1.10.15/css/dataTables.jqueryui.css +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Table styles - */ -table.dataTable { - width: 100%; - margin: 0 auto; - clear: both; - border-collapse: separate; - border-spacing: 0; - /* - * Header and footer styles - */ - /* - * Body styles - */ -} -table.dataTable thead th, -table.dataTable tfoot th { - font-weight: bold; -} -table.dataTable thead th, -table.dataTable thead td { - padding: 10px 18px; -} -table.dataTable thead th:active, -table.dataTable thead td:active { - outline: none; -} -table.dataTable tfoot th, -table.dataTable tfoot td { - padding: 10px 18px 6px 18px; -} -table.dataTable tbody tr { - background-color: #ffffff; -} -table.dataTable tbody tr.selected { - background-color: #B0BED9; -} -table.dataTable tbody th, -table.dataTable tbody td { - padding: 8px 10px; -} -table.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td { - border-top: 1px solid #ddd; -} -table.dataTable.row-border tbody tr:first-child th, -table.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th, -table.dataTable.display tbody tr:first-child td { - border-top: none; -} -table.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td { - border-top: 1px solid #ddd; - border-right: 1px solid #ddd; -} -table.dataTable.cell-border tbody tr th:first-child, -table.dataTable.cell-border tbody tr td:first-child { - border-left: 1px solid #ddd; -} -table.dataTable.cell-border tbody tr:first-child th, -table.dataTable.cell-border tbody tr:first-child td { - border-top: none; -} -table.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd { - background-color: #f9f9f9; -} -table.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected { - background-color: #acbad4; -} -table.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover { - background-color: #f6f6f6; -} -table.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected { - background-color: #aab7d1; -} -table.dataTable.order-column tbody tr > .sorting_1, -table.dataTable.order-column tbody tr > .sorting_2, -table.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1, -table.dataTable.display tbody tr > .sorting_2, -table.dataTable.display tbody tr > .sorting_3 { - background-color: #fafafa; -} -table.dataTable.order-column tbody tr.selected > .sorting_1, -table.dataTable.order-column tbody tr.selected > .sorting_2, -table.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1, -table.dataTable.display tbody tr.selected > .sorting_2, -table.dataTable.display tbody tr.selected > .sorting_3 { - background-color: #acbad5; -} -table.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 { - background-color: #f1f1f1; -} -table.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 { - background-color: #f3f3f3; -} -table.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 { - background-color: whitesmoke; -} -table.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 { - background-color: #a6b4cd; -} -table.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 { - background-color: #a8b5cf; -} -table.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 { - background-color: #a9b7d1; -} -table.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 { - background-color: #fafafa; -} -table.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 { - background-color: #fcfcfc; -} -table.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 { - background-color: #fefefe; -} -table.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 { - background-color: #acbad5; -} -table.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 { - background-color: #aebcd6; -} -table.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 { - background-color: #afbdd8; -} -table.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 { - background-color: #eaeaea; -} -table.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 { - background-color: #ececec; -} -table.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 { - background-color: #efefef; -} -table.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 { - background-color: #a2aec7; -} -table.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 { - background-color: #a3b0c9; -} -table.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 { - background-color: #a5b2cb; -} -table.dataTable.no-footer { - border-bottom: 1px solid #111; -} -table.dataTable.nowrap th, table.dataTable.nowrap td { - white-space: nowrap; -} -table.dataTable.compact thead th, -table.dataTable.compact thead td { - padding: 4px 17px 4px 4px; -} -table.dataTable.compact tfoot th, -table.dataTable.compact tfoot td { - padding: 4px; -} -table.dataTable.compact tbody th, -table.dataTable.compact tbody td { - padding: 4px; -} -table.dataTable th.dt-left, -table.dataTable td.dt-left { - text-align: left; -} -table.dataTable th.dt-center, -table.dataTable td.dt-center, -table.dataTable td.dataTables_empty { - text-align: center; -} -table.dataTable th.dt-right, -table.dataTable td.dt-right { - text-align: right; -} -table.dataTable th.dt-justify, -table.dataTable td.dt-justify { - text-align: justify; -} -table.dataTable th.dt-nowrap, -table.dataTable td.dt-nowrap { - white-space: nowrap; -} -table.dataTable thead th.dt-head-left, -table.dataTable thead td.dt-head-left, -table.dataTable tfoot th.dt-head-left, -table.dataTable tfoot td.dt-head-left { - text-align: left; -} -table.dataTable thead th.dt-head-center, -table.dataTable thead td.dt-head-center, -table.dataTable tfoot th.dt-head-center, -table.dataTable tfoot td.dt-head-center { - text-align: center; -} -table.dataTable thead th.dt-head-right, -table.dataTable thead td.dt-head-right, -table.dataTable tfoot th.dt-head-right, -table.dataTable tfoot td.dt-head-right { - text-align: right; -} -table.dataTable thead th.dt-head-justify, -table.dataTable thead td.dt-head-justify, -table.dataTable tfoot th.dt-head-justify, -table.dataTable tfoot td.dt-head-justify { - text-align: justify; -} -table.dataTable thead th.dt-head-nowrap, -table.dataTable thead td.dt-head-nowrap, -table.dataTable tfoot th.dt-head-nowrap, -table.dataTable tfoot td.dt-head-nowrap { - white-space: nowrap; -} -table.dataTable tbody th.dt-body-left, -table.dataTable tbody td.dt-body-left { - text-align: left; -} -table.dataTable tbody th.dt-body-center, -table.dataTable tbody td.dt-body-center { - text-align: center; -} -table.dataTable tbody th.dt-body-right, -table.dataTable tbody td.dt-body-right { - text-align: right; -} -table.dataTable tbody th.dt-body-justify, -table.dataTable tbody td.dt-body-justify { - text-align: justify; -} -table.dataTable tbody th.dt-body-nowrap, -table.dataTable tbody td.dt-body-nowrap { - white-space: nowrap; -} - -table.dataTable, -table.dataTable th, -table.dataTable td { - -webkit-box-sizing: content-box; - box-sizing: content-box; -} - -/* - * Control feature layout - */ -.dataTables_wrapper { - position: relative; - clear: both; - *zoom: 1; - zoom: 1; -} -.dataTables_wrapper .dataTables_length { - float: left; -} -.dataTables_wrapper .dataTables_filter { - float: right; - text-align: right; -} -.dataTables_wrapper .dataTables_filter input { - margin-left: 0.5em; -} -.dataTables_wrapper .dataTables_info { - clear: both; - float: left; - padding-top: 0.755em; -} -.dataTables_wrapper .dataTables_paginate { - float: right; - text-align: right; - padding-top: 0.25em; -} -.dataTables_wrapper .dataTables_paginate .paginate_button { - box-sizing: border-box; - display: inline-block; - min-width: 1.5em; - padding: 0.5em 1em; - margin-left: 2px; - text-align: center; - text-decoration: none !important; - cursor: pointer; - *cursor: hand; - color: #333 !important; - border: 1px solid transparent; - border-radius: 2px; -} -.dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover { - color: #333 !important; - border: 1px solid #979797; - background-color: white; - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc)); - /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%); - /* Chrome10+,Safari5.1+ */ - background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%); - /* FF3.6+ */ - background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%); - /* IE10+ */ - background: -o-linear-gradient(top, white 0%, #dcdcdc 100%); - /* Opera 11.10+ */ - background: linear-gradient(to bottom, white 0%, #dcdcdc 100%); - /* W3C */ -} -.dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active { - cursor: default; - color: #666 !important; - border: 1px solid transparent; - background: transparent; - box-shadow: none; -} -.dataTables_wrapper .dataTables_paginate .paginate_button:hover { - color: white !important; - border: 1px solid #111; - background-color: #585858; - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111)); - /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, #585858 0%, #111 100%); - /* Chrome10+,Safari5.1+ */ - background: -moz-linear-gradient(top, #585858 0%, #111 100%); - /* FF3.6+ */ - background: -ms-linear-gradient(top, #585858 0%, #111 100%); - /* IE10+ */ - background: -o-linear-gradient(top, #585858 0%, #111 100%); - /* Opera 11.10+ */ - background: linear-gradient(to bottom, #585858 0%, #111 100%); - /* W3C */ -} -.dataTables_wrapper .dataTables_paginate .paginate_button:active { - outline: none; - background-color: #2b2b2b; - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c)); - /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%); - /* Chrome10+,Safari5.1+ */ - background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%); - /* FF3.6+ */ - background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%); - /* IE10+ */ - background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%); - /* Opera 11.10+ */ - background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%); - /* W3C */ - box-shadow: inset 0 0 3px #111; -} -.dataTables_wrapper .dataTables_paginate .ellipsis { - padding: 0 1em; -} -.dataTables_wrapper .dataTables_processing { - position: absolute; - top: 50%; - left: 50%; - width: 100%; - height: 40px; - margin-left: -50%; - margin-top: -25px; - padding-top: 20px; - text-align: center; - font-size: 1.2em; - background-color: white; - background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0))); - background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); - background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); - background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); - background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); - background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); -} -.dataTables_wrapper .dataTables_length, -.dataTables_wrapper .dataTables_filter, -.dataTables_wrapper .dataTables_info, -.dataTables_wrapper .dataTables_processing, -.dataTables_wrapper .dataTables_paginate { - color: #333; -} -.dataTables_wrapper .dataTables_scroll { - clear: both; -} -.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody { - *margin-top: -1px; - -webkit-overflow-scrolling: touch; -} -.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > td, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > td { - vertical-align: middle; -} -.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > th > div.dataTables_sizing, -.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > td > div.dataTables_sizing, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > th > div.dataTables_sizing, -.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > td > div.dataTables_sizing { - height: 0; - overflow: hidden; - margin: 0 !important; - padding: 0 !important; -} -.dataTables_wrapper.no-footer .dataTables_scrollBody { - border-bottom: 1px solid #111; -} -.dataTables_wrapper.no-footer div.dataTables_scrollHead > table, -.dataTables_wrapper.no-footer div.dataTables_scrollBody > table { - border-bottom: none; -} -.dataTables_wrapper:after { - visibility: hidden; - display: block; - content: ""; - clear: both; - height: 0; -} - -@media screen and (max-width: 767px) { - .dataTables_wrapper .dataTables_info, - .dataTables_wrapper .dataTables_paginate { - float: none; - text-align: center; - } - .dataTables_wrapper .dataTables_paginate { - margin-top: 0.5em; - } -} -@media screen and (max-width: 640px) { - .dataTables_wrapper .dataTables_length, - .dataTables_wrapper .dataTables_filter { - float: none; - text-align: center; - } - .dataTables_wrapper .dataTables_filter { - margin-top: 0.5em; - } -} -table.dataTable thead th div.DataTables_sort_wrapper { - position: relative; -} -table.dataTable thead th div.DataTables_sort_wrapper span { - position: absolute; - top: 50%; - margin-top: -8px; - right: -18px; -} -table.dataTable thead th.ui-state-default, -table.dataTable tfoot th.ui-state-default { - border-left-width: 0; -} -table.dataTable thead th.ui-state-default:first-child, -table.dataTable tfoot th.ui-state-default:first-child { - border-left-width: 1px; -} - -/* - * Control feature layout - */ -.dataTables_wrapper .dataTables_paginate .fg-button { - box-sizing: border-box; - display: inline-block; - min-width: 1.5em; - padding: 0.5em; - margin-left: 2px; - text-align: center; - text-decoration: none !important; - cursor: pointer; - *cursor: hand; - border: 1px solid transparent; -} -.dataTables_wrapper .dataTables_paginate .fg-button:active { - outline: none; -} -.dataTables_wrapper .dataTables_paginate .fg-button:first-child { - border-top-left-radius: 3px; - border-bottom-left-radius: 3px; -} -.dataTables_wrapper .dataTables_paginate .fg-button:last-child { - border-top-right-radius: 3px; - border-bottom-right-radius: 3px; -} -.dataTables_wrapper .ui-widget-header { - font-weight: normal; -} -.dataTables_wrapper .ui-toolbar { - padding: 8px; -} -.dataTables_wrapper.no-footer .dataTables_scrollBody { - border-bottom: none; -} -.dataTables_wrapper .dataTables_length, -.dataTables_wrapper .dataTables_filter, -.dataTables_wrapper .dataTables_info, -.dataTables_wrapper .dataTables_processing, -.dataTables_wrapper .dataTables_paginate { - color: inherit; -} diff --git a/app/static/DataTables/DataTables-1.10.15/css/dataTables.jqueryui.min.css b/app/static/DataTables/DataTables-1.10.15/css/dataTables.jqueryui.min.css deleted file mode 100644 index fe64abca9..000000000 --- a/app/static/DataTables/DataTables-1.10.15/css/dataTables.jqueryui.min.css +++ /dev/null @@ -1 +0,0 @@ -table.dataTable{width:100%;margin:0 auto;clear:both;border-collapse:separate;border-spacing:0}table.dataTable thead th,table.dataTable tfoot th{font-weight:bold}table.dataTable thead th,table.dataTable thead td{padding:10px 18px}table.dataTable thead th:active,table.dataTable thead td:active{outline:none}table.dataTable tfoot th,table.dataTable tfoot td{padding:10px 18px 6px 18px}table.dataTable tbody tr{background-color:#ffffff}table.dataTable tbody tr.selected{background-color:#B0BED9}table.dataTable tbody th,table.dataTable tbody td{padding:8px 10px}table.dataTable.row-border tbody th,table.dataTable.row-border tbody td,table.dataTable.display tbody th,table.dataTable.display tbody td{border-top:1px solid #ddd}table.dataTable.row-border tbody tr:first-child th,table.dataTable.row-border tbody tr:first-child td,table.dataTable.display tbody tr:first-child th,table.dataTable.display tbody tr:first-child td{border-top:none}table.dataTable.cell-border tbody th,table.dataTable.cell-border tbody td{border-top:1px solid #ddd;border-right:1px solid #ddd}table.dataTable.cell-border tbody tr th:first-child,table.dataTable.cell-border tbody tr td:first-child{border-left:1px solid #ddd}table.dataTable.cell-border tbody tr:first-child th,table.dataTable.cell-border tbody tr:first-child td{border-top:none}table.dataTable.stripe tbody tr.odd,table.dataTable.display tbody tr.odd{background-color:#f9f9f9}table.dataTable.stripe tbody tr.odd.selected,table.dataTable.display tbody tr.odd.selected{background-color:#acbad4}table.dataTable.hover tbody tr:hover,table.dataTable.display tbody tr:hover{background-color:#f6f6f6}table.dataTable.hover tbody tr:hover.selected,table.dataTable.display tbody tr:hover.selected{background-color:#aab7d1}table.dataTable.order-column tbody tr>.sorting_1,table.dataTable.order-column tbody tr>.sorting_2,table.dataTable.order-column tbody tr>.sorting_3,table.dataTable.display tbody tr>.sorting_1,table.dataTable.display tbody tr>.sorting_2,table.dataTable.display tbody tr>.sorting_3{background-color:#fafafa}table.dataTable.order-column tbody tr.selected>.sorting_1,table.dataTable.order-column tbody tr.selected>.sorting_2,table.dataTable.order-column tbody tr.selected>.sorting_3,table.dataTable.display tbody tr.selected>.sorting_1,table.dataTable.display tbody tr.selected>.sorting_2,table.dataTable.display tbody tr.selected>.sorting_3{background-color:#acbad5}table.dataTable.display tbody tr.odd>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd>.sorting_1{background-color:#f1f1f1}table.dataTable.display tbody tr.odd>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd>.sorting_2{background-color:#f3f3f3}table.dataTable.display tbody tr.odd>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd>.sorting_3{background-color:whitesmoke}table.dataTable.display tbody tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_1{background-color:#a6b4cd}table.dataTable.display tbody tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_2{background-color:#a8b5cf}table.dataTable.display tbody tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_3{background-color:#a9b7d1}table.dataTable.display tbody tr.even>.sorting_1,table.dataTable.order-column.stripe tbody tr.even>.sorting_1{background-color:#fafafa}table.dataTable.display tbody tr.even>.sorting_2,table.dataTable.order-column.stripe tbody tr.even>.sorting_2{background-color:#fcfcfc}table.dataTable.display tbody tr.even>.sorting_3,table.dataTable.order-column.stripe tbody tr.even>.sorting_3{background-color:#fefefe}table.dataTable.display tbody tr.even.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_1{background-color:#acbad5}table.dataTable.display tbody tr.even.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_2{background-color:#aebcd6}table.dataTable.display tbody tr.even.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_3{background-color:#afbdd8}table.dataTable.display tbody tr:hover>.sorting_1,table.dataTable.order-column.hover tbody tr:hover>.sorting_1{background-color:#eaeaea}table.dataTable.display tbody tr:hover>.sorting_2,table.dataTable.order-column.hover tbody tr:hover>.sorting_2{background-color:#ececec}table.dataTable.display tbody tr:hover>.sorting_3,table.dataTable.order-column.hover tbody tr:hover>.sorting_3{background-color:#efefef}table.dataTable.display tbody tr:hover.selected>.sorting_1,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_1{background-color:#a2aec7}table.dataTable.display tbody tr:hover.selected>.sorting_2,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_2{background-color:#a3b0c9}table.dataTable.display tbody tr:hover.selected>.sorting_3,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_3{background-color:#a5b2cb}table.dataTable.no-footer{border-bottom:1px solid #111}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}table.dataTable.compact thead th,table.dataTable.compact thead td{padding:4px 17px 4px 4px}table.dataTable.compact tfoot th,table.dataTable.compact tfoot td{padding:4px}table.dataTable.compact tbody th,table.dataTable.compact tbody td{padding:4px}table.dataTable th.dt-left,table.dataTable td.dt-left{text-align:left}table.dataTable th.dt-center,table.dataTable td.dt-center,table.dataTable td.dataTables_empty{text-align:center}table.dataTable th.dt-right,table.dataTable td.dt-right{text-align:right}table.dataTable th.dt-justify,table.dataTable td.dt-justify{text-align:justify}table.dataTable th.dt-nowrap,table.dataTable td.dt-nowrap{white-space:nowrap}table.dataTable thead th.dt-head-left,table.dataTable thead td.dt-head-left,table.dataTable tfoot th.dt-head-left,table.dataTable tfoot td.dt-head-left{text-align:left}table.dataTable thead th.dt-head-center,table.dataTable thead td.dt-head-center,table.dataTable tfoot th.dt-head-center,table.dataTable tfoot td.dt-head-center{text-align:center}table.dataTable thead th.dt-head-right,table.dataTable thead td.dt-head-right,table.dataTable tfoot th.dt-head-right,table.dataTable tfoot td.dt-head-right{text-align:right}table.dataTable thead th.dt-head-justify,table.dataTable thead td.dt-head-justify,table.dataTable tfoot th.dt-head-justify,table.dataTable tfoot td.dt-head-justify{text-align:justify}table.dataTable thead th.dt-head-nowrap,table.dataTable thead td.dt-head-nowrap,table.dataTable tfoot th.dt-head-nowrap,table.dataTable tfoot td.dt-head-nowrap{white-space:nowrap}table.dataTable tbody th.dt-body-left,table.dataTable tbody td.dt-body-left{text-align:left}table.dataTable tbody th.dt-body-center,table.dataTable tbody td.dt-body-center{text-align:center}table.dataTable tbody th.dt-body-right,table.dataTable tbody td.dt-body-right{text-align:right}table.dataTable tbody th.dt-body-justify,table.dataTable tbody td.dt-body-justify{text-align:justify}table.dataTable tbody th.dt-body-nowrap,table.dataTable tbody td.dt-body-nowrap{white-space:nowrap}table.dataTable,table.dataTable th,table.dataTable td{-webkit-box-sizing:content-box;box-sizing:content-box}.dataTables_wrapper{position:relative;clear:both;*zoom:1;zoom:1}.dataTables_wrapper .dataTables_length{float:left}.dataTables_wrapper .dataTables_filter{float:right;text-align:right}.dataTables_wrapper .dataTables_filter input{margin-left:0.5em}.dataTables_wrapper .dataTables_info{clear:both;float:left;padding-top:0.755em}.dataTables_wrapper .dataTables_paginate{float:right;text-align:right;padding-top:0.25em}.dataTables_wrapper .dataTables_paginate .paginate_button{box-sizing:border-box;display:inline-block;min-width:1.5em;padding:0.5em 1em;margin-left:2px;text-align:center;text-decoration:none !important;cursor:pointer;*cursor:hand;color:#333 !important;border:1px solid transparent;border-radius:2px}.dataTables_wrapper .dataTables_paginate .paginate_button.current,.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{color:#333 !important;border:1px solid #979797;background-color:white;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #fff), color-stop(100%, #dcdcdc));background:-webkit-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-moz-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-ms-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-o-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:linear-gradient(to bottom, #fff 0%, #dcdcdc 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{cursor:default;color:#666 !important;border:1px solid transparent;background:transparent;box-shadow:none}.dataTables_wrapper .dataTables_paginate .paginate_button:hover{color:white !important;border:1px solid #111;background-color:#585858;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));background:-webkit-linear-gradient(top, #585858 0%, #111 100%);background:-moz-linear-gradient(top, #585858 0%, #111 100%);background:-ms-linear-gradient(top, #585858 0%, #111 100%);background:-o-linear-gradient(top, #585858 0%, #111 100%);background:linear-gradient(to bottom, #585858 0%, #111 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button:active{outline:none;background-color:#2b2b2b;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));background:-webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);box-shadow:inset 0 0 3px #111}.dataTables_wrapper .dataTables_paginate .ellipsis{padding:0 1em}.dataTables_wrapper .dataTables_processing{position:absolute;top:50%;left:50%;width:100%;height:40px;margin-left:-50%;margin-top:-25px;padding-top:20px;text-align:center;font-size:1.2em;background-color:white;background:-webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255,255,255,0)), color-stop(25%, rgba(255,255,255,0.9)), color-stop(75%, rgba(255,255,255,0.9)), color-stop(100%, rgba(255,255,255,0)));background:-webkit-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-moz-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-ms-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-o-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:linear-gradient(to right, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%)}.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter,.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_processing,.dataTables_wrapper .dataTables_paginate{color:#333}.dataTables_wrapper .dataTables_scroll{clear:both}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody{*margin-top:-1px;-webkit-overflow-scrolling:touch}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td{vertical-align:middle}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td>div.dataTables_sizing{height:0;overflow:hidden;margin:0 !important;padding:0 !important}.dataTables_wrapper.no-footer .dataTables_scrollBody{border-bottom:1px solid #111}.dataTables_wrapper.no-footer div.dataTables_scrollHead>table,.dataTables_wrapper.no-footer div.dataTables_scrollBody>table{border-bottom:none}.dataTables_wrapper:after{visibility:hidden;display:block;content:"";clear:both;height:0}@media screen and (max-width: 767px){.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_paginate{float:none;text-align:center}.dataTables_wrapper .dataTables_paginate{margin-top:0.5em}}@media screen and (max-width: 640px){.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter{float:none;text-align:center}.dataTables_wrapper .dataTables_filter{margin-top:0.5em}}table.dataTable thead th div.DataTables_sort_wrapper{position:relative}table.dataTable thead th div.DataTables_sort_wrapper span{position:absolute;top:50%;margin-top:-8px;right:-18px}table.dataTable thead th.ui-state-default,table.dataTable tfoot th.ui-state-default{border-left-width:0}table.dataTable thead th.ui-state-default:first-child,table.dataTable tfoot th.ui-state-default:first-child{border-left-width:1px}.dataTables_wrapper .dataTables_paginate .fg-button{box-sizing:border-box;display:inline-block;min-width:1.5em;padding:0.5em;margin-left:2px;text-align:center;text-decoration:none !important;cursor:pointer;*cursor:hand;border:1px solid transparent}.dataTables_wrapper .dataTables_paginate .fg-button:active{outline:none}.dataTables_wrapper .dataTables_paginate .fg-button:first-child{border-top-left-radius:3px;border-bottom-left-radius:3px}.dataTables_wrapper .dataTables_paginate .fg-button:last-child{border-top-right-radius:3px;border-bottom-right-radius:3px}.dataTables_wrapper .ui-widget-header{font-weight:normal}.dataTables_wrapper .ui-toolbar{padding:8px}.dataTables_wrapper.no-footer .dataTables_scrollBody{border-bottom:none}.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter,.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_processing,.dataTables_wrapper .dataTables_paginate{color:inherit} diff --git a/app/static/DataTables/DataTables-1.10.15/css/dataTables.semanticui.css b/app/static/DataTables/DataTables-1.10.15/css/dataTables.semanticui.css deleted file mode 100644 index 258384265..000000000 --- a/app/static/DataTables/DataTables-1.10.15/css/dataTables.semanticui.css +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Styling for DataTables with Semantic UI - */ -table.dataTable.table { - margin: 0; -} -table.dataTable.table thead th, -table.dataTable.table thead td { - position: relative; -} -table.dataTable.table thead th.sorting, table.dataTable.table thead th.sorting_asc, table.dataTable.table thead th.sorting_desc, -table.dataTable.table thead td.sorting, -table.dataTable.table thead td.sorting_asc, -table.dataTable.table thead td.sorting_desc { - padding-right: 20px; -} -table.dataTable.table thead th.sorting:after, table.dataTable.table thead th.sorting_asc:after, table.dataTable.table thead th.sorting_desc:after, -table.dataTable.table thead td.sorting:after, -table.dataTable.table thead td.sorting_asc:after, -table.dataTable.table thead td.sorting_desc:after { - position: absolute; - top: 12px; - right: 8px; - display: block; - font-family: Icons; -} -table.dataTable.table thead th.sorting:after, -table.dataTable.table thead td.sorting:after { - content: "\f0dc"; - color: #ddd; - font-size: 0.8em; -} -table.dataTable.table thead th.sorting_asc:after, -table.dataTable.table thead td.sorting_asc:after { - content: "\f0de"; -} -table.dataTable.table thead th.sorting_desc:after, -table.dataTable.table thead td.sorting_desc:after { - content: "\f0dd"; -} -table.dataTable.table td, -table.dataTable.table th { - -webkit-box-sizing: content-box; - box-sizing: content-box; -} -table.dataTable.table td.dataTables_empty, -table.dataTable.table th.dataTables_empty { - text-align: center; -} -table.dataTable.table.nowrap th, -table.dataTable.table.nowrap td { - white-space: nowrap; -} - -div.dataTables_wrapper div.dataTables_length select { - vertical-align: middle; - min-height: 2.7142em; -} -div.dataTables_wrapper div.dataTables_length .ui.selection.dropdown { - min-width: 0; -} -div.dataTables_wrapper div.dataTables_filter input { - margin-left: 0.5em; -} -div.dataTables_wrapper div.dataTables_info { - padding-top: 13px; - white-space: nowrap; -} -div.dataTables_wrapper div.dataTables_processing { - position: absolute; - top: 50%; - left: 50%; - width: 200px; - margin-left: -100px; - text-align: center; -} -div.dataTables_wrapper div.row.dt-table { - padding: 0; -} -div.dataTables_wrapper div.dataTables_scrollHead table.dataTable { - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; - border-bottom: none; -} -div.dataTables_wrapper div.dataTables_scrollBody thead .sorting:after, -div.dataTables_wrapper div.dataTables_scrollBody thead .sorting_asc:after, -div.dataTables_wrapper div.dataTables_scrollBody thead .sorting_desc:after { - display: none; -} -div.dataTables_wrapper div.dataTables_scrollBody table.dataTable { - border-radius: 0; - border-top: none; - border-bottom-width: 0; -} -div.dataTables_wrapper div.dataTables_scrollBody table.dataTable.no-footer { - border-bottom-width: 1px; -} -div.dataTables_wrapper div.dataTables_scrollFoot table.dataTable { - border-top-right-radius: 0; - border-top-left-radius: 0; - border-top: none; -} diff --git a/app/static/DataTables/DataTables-1.10.15/css/dataTables.semanticui.min.css b/app/static/DataTables/DataTables-1.10.15/css/dataTables.semanticui.min.css deleted file mode 100644 index c192a3420..000000000 --- a/app/static/DataTables/DataTables-1.10.15/css/dataTables.semanticui.min.css +++ /dev/null @@ -1 +0,0 @@ -table.dataTable.table{margin:0}table.dataTable.table thead th,table.dataTable.table thead td{position:relative}table.dataTable.table thead th.sorting,table.dataTable.table thead th.sorting_asc,table.dataTable.table thead th.sorting_desc,table.dataTable.table thead td.sorting,table.dataTable.table thead td.sorting_asc,table.dataTable.table thead td.sorting_desc{padding-right:20px}table.dataTable.table thead th.sorting:after,table.dataTable.table thead th.sorting_asc:after,table.dataTable.table thead th.sorting_desc:after,table.dataTable.table thead td.sorting:after,table.dataTable.table thead td.sorting_asc:after,table.dataTable.table thead td.sorting_desc:after{position:absolute;top:12px;right:8px;display:block;font-family:Icons}table.dataTable.table thead th.sorting:after,table.dataTable.table thead td.sorting:after{content:"\f0dc";color:#ddd;font-size:0.8em}table.dataTable.table thead th.sorting_asc:after,table.dataTable.table thead td.sorting_asc:after{content:"\f0de"}table.dataTable.table thead th.sorting_desc:after,table.dataTable.table thead td.sorting_desc:after{content:"\f0dd"}table.dataTable.table td,table.dataTable.table th{-webkit-box-sizing:content-box;box-sizing:content-box}table.dataTable.table td.dataTables_empty,table.dataTable.table th.dataTables_empty{text-align:center}table.dataTable.table.nowrap th,table.dataTable.table.nowrap td{white-space:nowrap}div.dataTables_wrapper div.dataTables_length select{vertical-align:middle;min-height:2.7142em}div.dataTables_wrapper div.dataTables_length .ui.selection.dropdown{min-width:0}div.dataTables_wrapper div.dataTables_filter input{margin-left:0.5em}div.dataTables_wrapper div.dataTables_info{padding-top:13px;white-space:nowrap}div.dataTables_wrapper div.dataTables_processing{position:absolute;top:50%;left:50%;width:200px;margin-left:-100px;text-align:center}div.dataTables_wrapper div.row.dt-table{padding:0}div.dataTables_wrapper div.dataTables_scrollHead table.dataTable{border-bottom-right-radius:0;border-bottom-left-radius:0;border-bottom:none}div.dataTables_wrapper div.dataTables_scrollBody thead .sorting:after,div.dataTables_wrapper div.dataTables_scrollBody thead .sorting_asc:after,div.dataTables_wrapper div.dataTables_scrollBody thead .sorting_desc:after{display:none}div.dataTables_wrapper div.dataTables_scrollBody table.dataTable{border-radius:0;border-top:none;border-bottom-width:0}div.dataTables_wrapper div.dataTables_scrollBody table.dataTable.no-footer{border-bottom-width:1px}div.dataTables_wrapper div.dataTables_scrollFoot table.dataTable{border-top-right-radius:0;border-top-left-radius:0;border-top:none} diff --git a/app/static/DataTables/DataTables-1.10.15/css/jquery.dataTables.css b/app/static/DataTables/DataTables-1.10.15/css/jquery.dataTables.css deleted file mode 100644 index 6c55f8b6d..000000000 --- a/app/static/DataTables/DataTables-1.10.15/css/jquery.dataTables.css +++ /dev/null @@ -1,455 +0,0 @@ -/* - * Table styles - */ -table.dataTable { - width: 100%; - margin: 0 auto; - clear: both; - border-collapse: separate; - border-spacing: 0; - /* - * Header and footer styles - */ - /* - * Body styles - */ -} -table.dataTable thead th, -table.dataTable tfoot th { - font-weight: bold; -} -table.dataTable thead th, -table.dataTable thead td { - padding: 10px 18px; - border-bottom: 1px solid #111; -} -table.dataTable thead th:active, -table.dataTable thead td:active { - outline: none; -} -table.dataTable tfoot th, -table.dataTable tfoot td { - padding: 10px 18px 6px 18px; - border-top: 1px solid #111; -} -table.dataTable thead .sorting, -table.dataTable thead .sorting_asc, -table.dataTable thead .sorting_desc, -table.dataTable thead .sorting_asc_disabled, -table.dataTable thead .sorting_desc_disabled { - cursor: pointer; - *cursor: hand; -} -table.dataTable thead .sorting, -table.dataTable thead .sorting_asc, -table.dataTable thead .sorting_desc, -table.dataTable thead .sorting_asc_disabled, -table.dataTable thead .sorting_desc_disabled { - background-repeat: no-repeat; - background-position: center right; -} -table.dataTable thead .sorting { - background-image: url("../images/sort_both.png"); -} -table.dataTable thead .sorting_asc { - background-image: url("../images/sort_asc.png"); -} -table.dataTable thead .sorting_desc { - background-image: url("../images/sort_desc.png"); -} -table.dataTable thead .sorting_asc_disabled { - background-image: url("../images/sort_asc_disabled.png"); -} -table.dataTable thead .sorting_desc_disabled { - background-image: url("../images/sort_desc_disabled.png"); -} -table.dataTable tbody tr { - background-color: #ffffff; -} -table.dataTable tbody tr.selected { - background-color: #B0BED9; -} -table.dataTable tbody th, -table.dataTable tbody td { - padding: 8px 10px; -} -table.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td { - border-top: 1px solid #ddd; -} -table.dataTable.row-border tbody tr:first-child th, -table.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th, -table.dataTable.display tbody tr:first-child td { - border-top: none; -} -table.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td { - border-top: 1px solid #ddd; - border-right: 1px solid #ddd; -} -table.dataTable.cell-border tbody tr th:first-child, -table.dataTable.cell-border tbody tr td:first-child { - border-left: 1px solid #ddd; -} -table.dataTable.cell-border tbody tr:first-child th, -table.dataTable.cell-border tbody tr:first-child td { - border-top: none; -} -table.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd { - background-color: #f9f9f9; -} -table.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected { - background-color: #acbad4; -} -table.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover { - background-color: #f6f6f6; -} -table.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected { - background-color: #aab7d1; -} -table.dataTable.order-column tbody tr > .sorting_1, -table.dataTable.order-column tbody tr > .sorting_2, -table.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1, -table.dataTable.display tbody tr > .sorting_2, -table.dataTable.display tbody tr > .sorting_3 { - background-color: #fafafa; -} -table.dataTable.order-column tbody tr.selected > .sorting_1, -table.dataTable.order-column tbody tr.selected > .sorting_2, -table.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1, -table.dataTable.display tbody tr.selected > .sorting_2, -table.dataTable.display tbody tr.selected > .sorting_3 { - background-color: #acbad5; -} -table.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 { - background-color: #f1f1f1; -} -table.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 { - background-color: #f3f3f3; -} -table.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 { - background-color: whitesmoke; -} -table.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 { - background-color: #a6b4cd; -} -table.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 { - background-color: #a8b5cf; -} -table.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 { - background-color: #a9b7d1; -} -table.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 { - background-color: #fafafa; -} -table.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 { - background-color: #fcfcfc; -} -table.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 { - background-color: #fefefe; -} -table.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 { - background-color: #acbad5; -} -table.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 { - background-color: #aebcd6; -} -table.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 { - background-color: #afbdd8; -} -table.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 { - background-color: #eaeaea; -} -table.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 { - background-color: #ececec; -} -table.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 { - background-color: #efefef; -} -table.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 { - background-color: #a2aec7; -} -table.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 { - background-color: #a3b0c9; -} -table.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 { - background-color: #a5b2cb; -} -table.dataTable.no-footer { - border-bottom: 1px solid #111; -} -table.dataTable.nowrap th, table.dataTable.nowrap td { - white-space: nowrap; -} -table.dataTable.compact thead th, -table.dataTable.compact thead td { - padding: 4px 17px 4px 4px; -} -table.dataTable.compact tfoot th, -table.dataTable.compact tfoot td { - padding: 4px; -} -table.dataTable.compact tbody th, -table.dataTable.compact tbody td { - padding: 4px; -} -table.dataTable th.dt-left, -table.dataTable td.dt-left { - text-align: left; -} -table.dataTable th.dt-center, -table.dataTable td.dt-center, -table.dataTable td.dataTables_empty { - text-align: center; -} -table.dataTable th.dt-right, -table.dataTable td.dt-right { - text-align: right; -} -table.dataTable th.dt-justify, -table.dataTable td.dt-justify { - text-align: justify; -} -table.dataTable th.dt-nowrap, -table.dataTable td.dt-nowrap { - white-space: nowrap; -} -table.dataTable thead th.dt-head-left, -table.dataTable thead td.dt-head-left, -table.dataTable tfoot th.dt-head-left, -table.dataTable tfoot td.dt-head-left { - text-align: left; -} -table.dataTable thead th.dt-head-center, -table.dataTable thead td.dt-head-center, -table.dataTable tfoot th.dt-head-center, -table.dataTable tfoot td.dt-head-center { - text-align: center; -} -table.dataTable thead th.dt-head-right, -table.dataTable thead td.dt-head-right, -table.dataTable tfoot th.dt-head-right, -table.dataTable tfoot td.dt-head-right { - text-align: right; -} -table.dataTable thead th.dt-head-justify, -table.dataTable thead td.dt-head-justify, -table.dataTable tfoot th.dt-head-justify, -table.dataTable tfoot td.dt-head-justify { - text-align: justify; -} -table.dataTable thead th.dt-head-nowrap, -table.dataTable thead td.dt-head-nowrap, -table.dataTable tfoot th.dt-head-nowrap, -table.dataTable tfoot td.dt-head-nowrap { - white-space: nowrap; -} -table.dataTable tbody th.dt-body-left, -table.dataTable tbody td.dt-body-left { - text-align: left; -} -table.dataTable tbody th.dt-body-center, -table.dataTable tbody td.dt-body-center { - text-align: center; -} -table.dataTable tbody th.dt-body-right, -table.dataTable tbody td.dt-body-right { - text-align: right; -} -table.dataTable tbody th.dt-body-justify, -table.dataTable tbody td.dt-body-justify { - text-align: justify; -} -table.dataTable tbody th.dt-body-nowrap, -table.dataTable tbody td.dt-body-nowrap { - white-space: nowrap; -} - -table.dataTable, -table.dataTable th, -table.dataTable td { - -webkit-box-sizing: content-box; - box-sizing: content-box; -} - -/* - * Control feature layout - */ -.dataTables_wrapper { - position: relative; - clear: both; - *zoom: 1; - zoom: 1; -} -.dataTables_wrapper .dataTables_length { - float: left; -} -.dataTables_wrapper .dataTables_filter { - float: right; - text-align: right; -} -.dataTables_wrapper .dataTables_filter input { - margin-left: 0.5em; -} -.dataTables_wrapper .dataTables_info { - clear: both; - float: left; - padding-top: 0.755em; -} -.dataTables_wrapper .dataTables_paginate { - float: right; - text-align: right; - padding-top: 0.25em; -} -.dataTables_wrapper .dataTables_paginate .paginate_button { - box-sizing: border-box; - display: inline-block; - min-width: 1.5em; - padding: 0.5em 1em; - margin-left: 2px; - text-align: center; - text-decoration: none !important; - cursor: pointer; - *cursor: hand; - color: #333 !important; - border: 1px solid transparent; - border-radius: 2px; -} -.dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover { - color: #333 !important; - border: 1px solid #979797; - background-color: white; - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc)); - /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%); - /* Chrome10+,Safari5.1+ */ - background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%); - /* FF3.6+ */ - background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%); - /* IE10+ */ - background: -o-linear-gradient(top, white 0%, #dcdcdc 100%); - /* Opera 11.10+ */ - background: linear-gradient(to bottom, white 0%, #dcdcdc 100%); - /* W3C */ -} -.dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active { - cursor: default; - color: #666 !important; - border: 1px solid transparent; - background: transparent; - box-shadow: none; -} -.dataTables_wrapper .dataTables_paginate .paginate_button:hover { - color: white !important; - border: 1px solid #111; - background-color: #585858; - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111)); - /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, #585858 0%, #111 100%); - /* Chrome10+,Safari5.1+ */ - background: -moz-linear-gradient(top, #585858 0%, #111 100%); - /* FF3.6+ */ - background: -ms-linear-gradient(top, #585858 0%, #111 100%); - /* IE10+ */ - background: -o-linear-gradient(top, #585858 0%, #111 100%); - /* Opera 11.10+ */ - background: linear-gradient(to bottom, #585858 0%, #111 100%); - /* W3C */ -} -.dataTables_wrapper .dataTables_paginate .paginate_button:active { - outline: none; - background-color: #2b2b2b; - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c)); - /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%); - /* Chrome10+,Safari5.1+ */ - background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%); - /* FF3.6+ */ - background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%); - /* IE10+ */ - background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%); - /* Opera 11.10+ */ - background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%); - /* W3C */ - box-shadow: inset 0 0 3px #111; -} -.dataTables_wrapper .dataTables_paginate .ellipsis { - padding: 0 1em; -} -.dataTables_wrapper .dataTables_processing { - position: absolute; - top: 50%; - left: 50%; - width: 100%; - height: 40px; - margin-left: -50%; - margin-top: -25px; - padding-top: 20px; - text-align: center; - font-size: 1.2em; - background-color: white; - background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0))); - background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); - background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); - background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); - background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); - background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); -} -.dataTables_wrapper .dataTables_length, -.dataTables_wrapper .dataTables_filter, -.dataTables_wrapper .dataTables_info, -.dataTables_wrapper .dataTables_processing, -.dataTables_wrapper .dataTables_paginate { - color: #333; -} -.dataTables_wrapper .dataTables_scroll { - clear: both; -} -.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody { - *margin-top: -1px; - -webkit-overflow-scrolling: touch; -} -.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > td, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > td { - vertical-align: middle; -} -.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > th > div.dataTables_sizing, -.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > td > div.dataTables_sizing, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > th > div.dataTables_sizing, -.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > td > div.dataTables_sizing { - height: 0; - overflow: hidden; - margin: 0 !important; - padding: 0 !important; -} -.dataTables_wrapper.no-footer .dataTables_scrollBody { - border-bottom: 1px solid #111; -} -.dataTables_wrapper.no-footer div.dataTables_scrollHead > table, -.dataTables_wrapper.no-footer div.dataTables_scrollBody > table { - border-bottom: none; -} -.dataTables_wrapper:after { - visibility: hidden; - display: block; - content: ""; - clear: both; - height: 0; -} - -@media screen and (max-width: 767px) { - .dataTables_wrapper .dataTables_info, - .dataTables_wrapper .dataTables_paginate { - float: none; - text-align: center; - } - .dataTables_wrapper .dataTables_paginate { - margin-top: 0.5em; - } -} -@media screen and (max-width: 640px) { - .dataTables_wrapper .dataTables_length, - .dataTables_wrapper .dataTables_filter { - float: none; - text-align: center; - } - .dataTables_wrapper .dataTables_filter { - margin-top: 0.5em; - } -} diff --git a/app/static/DataTables/DataTables-1.10.15/css/jquery.dataTables.min.css b/app/static/DataTables/DataTables-1.10.15/css/jquery.dataTables.min.css deleted file mode 100644 index 471c29329..000000000 --- a/app/static/DataTables/DataTables-1.10.15/css/jquery.dataTables.min.css +++ /dev/null @@ -1 +0,0 @@ -table.dataTable{width:100%;margin:0 auto;clear:both;border-collapse:separate;border-spacing:0}table.dataTable thead th,table.dataTable tfoot th{font-weight:bold}table.dataTable thead th,table.dataTable thead td{padding:10px 18px;border-bottom:1px solid #111}table.dataTable thead th:active,table.dataTable thead td:active{outline:none}table.dataTable tfoot th,table.dataTable tfoot td{padding:10px 18px 6px 18px;border-top:1px solid #111}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{cursor:pointer;*cursor:hand}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{background-repeat:no-repeat;background-position:center right}table.dataTable thead .sorting{background-image:url("../images/sort_both.png")}table.dataTable thead .sorting_asc{background-image:url("../images/sort_asc.png")}table.dataTable thead .sorting_desc{background-image:url("../images/sort_desc.png")}table.dataTable thead .sorting_asc_disabled{background-image:url("../images/sort_asc_disabled.png")}table.dataTable thead .sorting_desc_disabled{background-image:url("../images/sort_desc_disabled.png")}table.dataTable tbody tr{background-color:#ffffff}table.dataTable tbody tr.selected{background-color:#B0BED9}table.dataTable tbody th,table.dataTable tbody td{padding:8px 10px}table.dataTable.row-border tbody th,table.dataTable.row-border tbody td,table.dataTable.display tbody th,table.dataTable.display tbody td{border-top:1px solid #ddd}table.dataTable.row-border tbody tr:first-child th,table.dataTable.row-border tbody tr:first-child td,table.dataTable.display tbody tr:first-child th,table.dataTable.display tbody tr:first-child td{border-top:none}table.dataTable.cell-border tbody th,table.dataTable.cell-border tbody td{border-top:1px solid #ddd;border-right:1px solid #ddd}table.dataTable.cell-border tbody tr th:first-child,table.dataTable.cell-border tbody tr td:first-child{border-left:1px solid #ddd}table.dataTable.cell-border tbody tr:first-child th,table.dataTable.cell-border tbody tr:first-child td{border-top:none}table.dataTable.stripe tbody tr.odd,table.dataTable.display tbody tr.odd{background-color:#f9f9f9}table.dataTable.stripe tbody tr.odd.selected,table.dataTable.display tbody tr.odd.selected{background-color:#acbad4}table.dataTable.hover tbody tr:hover,table.dataTable.display tbody tr:hover{background-color:#f6f6f6}table.dataTable.hover tbody tr:hover.selected,table.dataTable.display tbody tr:hover.selected{background-color:#aab7d1}table.dataTable.order-column tbody tr>.sorting_1,table.dataTable.order-column tbody tr>.sorting_2,table.dataTable.order-column tbody tr>.sorting_3,table.dataTable.display tbody tr>.sorting_1,table.dataTable.display tbody tr>.sorting_2,table.dataTable.display tbody tr>.sorting_3{background-color:#fafafa}table.dataTable.order-column tbody tr.selected>.sorting_1,table.dataTable.order-column tbody tr.selected>.sorting_2,table.dataTable.order-column tbody tr.selected>.sorting_3,table.dataTable.display tbody tr.selected>.sorting_1,table.dataTable.display tbody tr.selected>.sorting_2,table.dataTable.display tbody tr.selected>.sorting_3{background-color:#acbad5}table.dataTable.display tbody tr.odd>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd>.sorting_1{background-color:#f1f1f1}table.dataTable.display tbody tr.odd>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd>.sorting_2{background-color:#f3f3f3}table.dataTable.display tbody tr.odd>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd>.sorting_3{background-color:whitesmoke}table.dataTable.display tbody tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_1{background-color:#a6b4cd}table.dataTable.display tbody tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_2{background-color:#a8b5cf}table.dataTable.display tbody tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_3{background-color:#a9b7d1}table.dataTable.display tbody tr.even>.sorting_1,table.dataTable.order-column.stripe tbody tr.even>.sorting_1{background-color:#fafafa}table.dataTable.display tbody tr.even>.sorting_2,table.dataTable.order-column.stripe tbody tr.even>.sorting_2{background-color:#fcfcfc}table.dataTable.display tbody tr.even>.sorting_3,table.dataTable.order-column.stripe tbody tr.even>.sorting_3{background-color:#fefefe}table.dataTable.display tbody tr.even.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_1{background-color:#acbad5}table.dataTable.display tbody tr.even.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_2{background-color:#aebcd6}table.dataTable.display tbody tr.even.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_3{background-color:#afbdd8}table.dataTable.display tbody tr:hover>.sorting_1,table.dataTable.order-column.hover tbody tr:hover>.sorting_1{background-color:#eaeaea}table.dataTable.display tbody tr:hover>.sorting_2,table.dataTable.order-column.hover tbody tr:hover>.sorting_2{background-color:#ececec}table.dataTable.display tbody tr:hover>.sorting_3,table.dataTable.order-column.hover tbody tr:hover>.sorting_3{background-color:#efefef}table.dataTable.display tbody tr:hover.selected>.sorting_1,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_1{background-color:#a2aec7}table.dataTable.display tbody tr:hover.selected>.sorting_2,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_2{background-color:#a3b0c9}table.dataTable.display tbody tr:hover.selected>.sorting_3,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_3{background-color:#a5b2cb}table.dataTable.no-footer{border-bottom:1px solid #111}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}table.dataTable.compact thead th,table.dataTable.compact thead td{padding:4px 17px 4px 4px}table.dataTable.compact tfoot th,table.dataTable.compact tfoot td{padding:4px}table.dataTable.compact tbody th,table.dataTable.compact tbody td{padding:4px}table.dataTable th.dt-left,table.dataTable td.dt-left{text-align:left}table.dataTable th.dt-center,table.dataTable td.dt-center,table.dataTable td.dataTables_empty{text-align:center}table.dataTable th.dt-right,table.dataTable td.dt-right{text-align:right}table.dataTable th.dt-justify,table.dataTable td.dt-justify{text-align:justify}table.dataTable th.dt-nowrap,table.dataTable td.dt-nowrap{white-space:nowrap}table.dataTable thead th.dt-head-left,table.dataTable thead td.dt-head-left,table.dataTable tfoot th.dt-head-left,table.dataTable tfoot td.dt-head-left{text-align:left}table.dataTable thead th.dt-head-center,table.dataTable thead td.dt-head-center,table.dataTable tfoot th.dt-head-center,table.dataTable tfoot td.dt-head-center{text-align:center}table.dataTable thead th.dt-head-right,table.dataTable thead td.dt-head-right,table.dataTable tfoot th.dt-head-right,table.dataTable tfoot td.dt-head-right{text-align:right}table.dataTable thead th.dt-head-justify,table.dataTable thead td.dt-head-justify,table.dataTable tfoot th.dt-head-justify,table.dataTable tfoot td.dt-head-justify{text-align:justify}table.dataTable thead th.dt-head-nowrap,table.dataTable thead td.dt-head-nowrap,table.dataTable tfoot th.dt-head-nowrap,table.dataTable tfoot td.dt-head-nowrap{white-space:nowrap}table.dataTable tbody th.dt-body-left,table.dataTable tbody td.dt-body-left{text-align:left}table.dataTable tbody th.dt-body-center,table.dataTable tbody td.dt-body-center{text-align:center}table.dataTable tbody th.dt-body-right,table.dataTable tbody td.dt-body-right{text-align:right}table.dataTable tbody th.dt-body-justify,table.dataTable tbody td.dt-body-justify{text-align:justify}table.dataTable tbody th.dt-body-nowrap,table.dataTable tbody td.dt-body-nowrap{white-space:nowrap}table.dataTable,table.dataTable th,table.dataTable td{-webkit-box-sizing:content-box;box-sizing:content-box}.dataTables_wrapper{position:relative;clear:both;*zoom:1;zoom:1}.dataTables_wrapper .dataTables_length{float:left}.dataTables_wrapper .dataTables_filter{float:right;text-align:right}.dataTables_wrapper .dataTables_filter input{margin-left:0.5em}.dataTables_wrapper .dataTables_info{clear:both;float:left;padding-top:0.755em}.dataTables_wrapper .dataTables_paginate{float:right;text-align:right;padding-top:0.25em}.dataTables_wrapper .dataTables_paginate .paginate_button{box-sizing:border-box;display:inline-block;min-width:1.5em;padding:0.5em 1em;margin-left:2px;text-align:center;text-decoration:none !important;cursor:pointer;*cursor:hand;color:#333 !important;border:1px solid transparent;border-radius:2px}.dataTables_wrapper .dataTables_paginate .paginate_button.current,.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{color:#333 !important;border:1px solid #979797;background-color:white;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #fff), color-stop(100%, #dcdcdc));background:-webkit-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-moz-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-ms-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-o-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:linear-gradient(to bottom, #fff 0%, #dcdcdc 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{cursor:default;color:#666 !important;border:1px solid transparent;background:transparent;box-shadow:none}.dataTables_wrapper .dataTables_paginate .paginate_button:hover{color:white !important;border:1px solid #111;background-color:#585858;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));background:-webkit-linear-gradient(top, #585858 0%, #111 100%);background:-moz-linear-gradient(top, #585858 0%, #111 100%);background:-ms-linear-gradient(top, #585858 0%, #111 100%);background:-o-linear-gradient(top, #585858 0%, #111 100%);background:linear-gradient(to bottom, #585858 0%, #111 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button:active{outline:none;background-color:#2b2b2b;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));background:-webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);box-shadow:inset 0 0 3px #111}.dataTables_wrapper .dataTables_paginate .ellipsis{padding:0 1em}.dataTables_wrapper .dataTables_processing{position:absolute;top:50%;left:50%;width:100%;height:40px;margin-left:-50%;margin-top:-25px;padding-top:20px;text-align:center;font-size:1.2em;background-color:white;background:-webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255,255,255,0)), color-stop(25%, rgba(255,255,255,0.9)), color-stop(75%, rgba(255,255,255,0.9)), color-stop(100%, rgba(255,255,255,0)));background:-webkit-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-moz-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-ms-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-o-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:linear-gradient(to right, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%)}.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter,.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_processing,.dataTables_wrapper .dataTables_paginate{color:#333}.dataTables_wrapper .dataTables_scroll{clear:both}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody{*margin-top:-1px;-webkit-overflow-scrolling:touch}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td{vertical-align:middle}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td>div.dataTables_sizing{height:0;overflow:hidden;margin:0 !important;padding:0 !important}.dataTables_wrapper.no-footer .dataTables_scrollBody{border-bottom:1px solid #111}.dataTables_wrapper.no-footer div.dataTables_scrollHead>table,.dataTables_wrapper.no-footer div.dataTables_scrollBody>table{border-bottom:none}.dataTables_wrapper:after{visibility:hidden;display:block;content:"";clear:both;height:0}@media screen and (max-width: 767px){.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_paginate{float:none;text-align:center}.dataTables_wrapper .dataTables_paginate{margin-top:0.5em}}@media screen and (max-width: 640px){.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter{float:none;text-align:center}.dataTables_wrapper .dataTables_filter{margin-top:0.5em}} diff --git a/app/static/DataTables/DataTables-1.10.15/css/jquery.dataTables_themeroller.css b/app/static/DataTables/DataTables-1.10.15/css/jquery.dataTables_themeroller.css deleted file mode 100644 index 1426a44a1..000000000 --- a/app/static/DataTables/DataTables-1.10.15/css/jquery.dataTables_themeroller.css +++ /dev/null @@ -1,416 +0,0 @@ -/* - * Table styles - */ -table.dataTable { - width: 100%; - margin: 0 auto; - clear: both; - border-collapse: separate; - border-spacing: 0; - /* - * Header and footer styles - */ - /* - * Body styles - */ -} -table.dataTable thead th, -table.dataTable thead td, -table.dataTable tfoot th, -table.dataTable tfoot td { - padding: 4px 10px; -} -table.dataTable thead th, -table.dataTable tfoot th { - font-weight: bold; -} -table.dataTable thead th:active, -table.dataTable thead td:active { - outline: none; -} -table.dataTable thead .sorting_asc, -table.dataTable thead .sorting_desc, -table.dataTable thead .sorting { - cursor: pointer; - *cursor: hand; -} -table.dataTable thead th div.DataTables_sort_wrapper { - position: relative; - padding-right: 10px; -} -table.dataTable thead th div.DataTables_sort_wrapper span { - position: absolute; - top: 50%; - margin-top: -8px; - right: -5px; -} -table.dataTable thead th.ui-state-default { - border-right-width: 0; -} -table.dataTable thead th.ui-state-default:last-child { - border-right-width: 1px; -} -table.dataTable tbody tr { - background-color: #ffffff; -} -table.dataTable tbody tr.selected { - background-color: #B0BED9; -} -table.dataTable tbody th, -table.dataTable tbody td { - padding: 8px 10px; -} -table.dataTable th.center, -table.dataTable td.center, -table.dataTable td.dataTables_empty { - text-align: center; -} -table.dataTable th.right, -table.dataTable td.right { - text-align: right; -} -table.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td { - border-top: 1px solid #ddd; -} -table.dataTable.row-border tbody tr:first-child th, -table.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th, -table.dataTable.display tbody tr:first-child td { - border-top: none; -} -table.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td { - border-top: 1px solid #ddd; - border-right: 1px solid #ddd; -} -table.dataTable.cell-border tbody tr th:first-child, -table.dataTable.cell-border tbody tr td:first-child { - border-left: 1px solid #ddd; -} -table.dataTable.cell-border tbody tr:first-child th, -table.dataTable.cell-border tbody tr:first-child td { - border-top: none; -} -table.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd { - background-color: #f9f9f9; -} -table.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected { - background-color: #abb9d3; -} -table.dataTable.hover tbody tr:hover, -table.dataTable.hover tbody tr.odd:hover, -table.dataTable.hover tbody tr.even:hover, table.dataTable.display tbody tr:hover, -table.dataTable.display tbody tr.odd:hover, -table.dataTable.display tbody tr.even:hover { - background-color: whitesmoke; -} -table.dataTable.hover tbody tr:hover.selected, -table.dataTable.hover tbody tr.odd:hover.selected, -table.dataTable.hover tbody tr.even:hover.selected, table.dataTable.display tbody tr:hover.selected, -table.dataTable.display tbody tr.odd:hover.selected, -table.dataTable.display tbody tr.even:hover.selected { - background-color: #a9b7d1; -} -table.dataTable.order-column tbody tr > .sorting_1, -table.dataTable.order-column tbody tr > .sorting_2, -table.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1, -table.dataTable.display tbody tr > .sorting_2, -table.dataTable.display tbody tr > .sorting_3 { - background-color: #f9f9f9; -} -table.dataTable.order-column tbody tr.selected > .sorting_1, -table.dataTable.order-column tbody tr.selected > .sorting_2, -table.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1, -table.dataTable.display tbody tr.selected > .sorting_2, -table.dataTable.display tbody tr.selected > .sorting_3 { - background-color: #acbad4; -} -table.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 { - background-color: #f1f1f1; -} -table.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 { - background-color: #f3f3f3; -} -table.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 { - background-color: whitesmoke; -} -table.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 { - background-color: #a6b3cd; -} -table.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 { - background-color: #a7b5ce; -} -table.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 { - background-color: #a9b6d0; -} -table.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 { - background-color: #f9f9f9; -} -table.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 { - background-color: #fbfbfb; -} -table.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 { - background-color: #fdfdfd; -} -table.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 { - background-color: #acbad4; -} -table.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 { - background-color: #adbbd6; -} -table.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 { - background-color: #afbdd8; -} -table.dataTable.display tbody tr:hover > .sorting_1, -table.dataTable.display tbody tr.odd:hover > .sorting_1, -table.dataTable.display tbody tr.even:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1, -table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_1, -table.dataTable.order-column.hover tbody tr.even:hover > .sorting_1 { - background-color: #eaeaea; -} -table.dataTable.display tbody tr:hover > .sorting_2, -table.dataTable.display tbody tr.odd:hover > .sorting_2, -table.dataTable.display tbody tr.even:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2, -table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_2, -table.dataTable.order-column.hover tbody tr.even:hover > .sorting_2 { - background-color: #ebebeb; -} -table.dataTable.display tbody tr:hover > .sorting_3, -table.dataTable.display tbody tr.odd:hover > .sorting_3, -table.dataTable.display tbody tr.even:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3, -table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_3, -table.dataTable.order-column.hover tbody tr.even:hover > .sorting_3 { - background-color: #eeeeee; -} -table.dataTable.display tbody tr:hover.selected > .sorting_1, -table.dataTable.display tbody tr.odd:hover.selected > .sorting_1, -table.dataTable.display tbody tr.even:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1, -table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_1, -table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_1 { - background-color: #a1aec7; -} -table.dataTable.display tbody tr:hover.selected > .sorting_2, -table.dataTable.display tbody tr.odd:hover.selected > .sorting_2, -table.dataTable.display tbody tr.even:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2, -table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_2, -table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_2 { - background-color: #a2afc8; -} -table.dataTable.display tbody tr:hover.selected > .sorting_3, -table.dataTable.display tbody tr.odd:hover.selected > .sorting_3, -table.dataTable.display tbody tr.even:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3, -table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_3, -table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_3 { - background-color: #a4b2cb; -} -table.dataTable.nowrap th, table.dataTable.nowrap td { - white-space: nowrap; -} -table.dataTable.compact thead th, -table.dataTable.compact thead td { - padding: 5px 9px; -} -table.dataTable.compact tfoot th, -table.dataTable.compact tfoot td { - padding: 5px 9px 3px 9px; -} -table.dataTable.compact tbody th, -table.dataTable.compact tbody td { - padding: 4px 5px; -} -table.dataTable th.dt-left, -table.dataTable td.dt-left { - text-align: left; -} -table.dataTable th.dt-center, -table.dataTable td.dt-center, -table.dataTable td.dataTables_empty { - text-align: center; -} -table.dataTable th.dt-right, -table.dataTable td.dt-right { - text-align: right; -} -table.dataTable th.dt-justify, -table.dataTable td.dt-justify { - text-align: justify; -} -table.dataTable th.dt-nowrap, -table.dataTable td.dt-nowrap { - white-space: nowrap; -} -table.dataTable thead th.dt-head-left, -table.dataTable thead td.dt-head-left, -table.dataTable tfoot th.dt-head-left, -table.dataTable tfoot td.dt-head-left { - text-align: left; -} -table.dataTable thead th.dt-head-center, -table.dataTable thead td.dt-head-center, -table.dataTable tfoot th.dt-head-center, -table.dataTable tfoot td.dt-head-center { - text-align: center; -} -table.dataTable thead th.dt-head-right, -table.dataTable thead td.dt-head-right, -table.dataTable tfoot th.dt-head-right, -table.dataTable tfoot td.dt-head-right { - text-align: right; -} -table.dataTable thead th.dt-head-justify, -table.dataTable thead td.dt-head-justify, -table.dataTable tfoot th.dt-head-justify, -table.dataTable tfoot td.dt-head-justify { - text-align: justify; -} -table.dataTable thead th.dt-head-nowrap, -table.dataTable thead td.dt-head-nowrap, -table.dataTable tfoot th.dt-head-nowrap, -table.dataTable tfoot td.dt-head-nowrap { - white-space: nowrap; -} -table.dataTable tbody th.dt-body-left, -table.dataTable tbody td.dt-body-left { - text-align: left; -} -table.dataTable tbody th.dt-body-center, -table.dataTable tbody td.dt-body-center { - text-align: center; -} -table.dataTable tbody th.dt-body-right, -table.dataTable tbody td.dt-body-right { - text-align: right; -} -table.dataTable tbody th.dt-body-justify, -table.dataTable tbody td.dt-body-justify { - text-align: justify; -} -table.dataTable tbody th.dt-body-nowrap, -table.dataTable tbody td.dt-body-nowrap { - white-space: nowrap; -} - -table.dataTable, -table.dataTable th, -table.dataTable td { - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box; -} - -/* - * Control feature layout - */ -.dataTables_wrapper { - position: relative; - clear: both; - *zoom: 1; - zoom: 1; -} -.dataTables_wrapper .dataTables_length { - float: left; -} -.dataTables_wrapper .dataTables_filter { - float: right; - text-align: right; -} -.dataTables_wrapper .dataTables_filter input { - margin-left: 0.5em; -} -.dataTables_wrapper .dataTables_info { - clear: both; - float: left; - padding-top: 0.55em; -} -.dataTables_wrapper .dataTables_paginate { - float: right; - text-align: right; -} -.dataTables_wrapper .dataTables_paginate .fg-button { - box-sizing: border-box; - display: inline-block; - min-width: 1.5em; - padding: 0.5em; - margin-left: 2px; - text-align: center; - text-decoration: none !important; - cursor: pointer; - *cursor: hand; - color: #333 !important; - border: 1px solid transparent; -} -.dataTables_wrapper .dataTables_paginate .fg-button:active { - outline: none; -} -.dataTables_wrapper .dataTables_paginate .fg-button:first-child { - border-top-left-radius: 3px; - border-bottom-left-radius: 3px; -} -.dataTables_wrapper .dataTables_paginate .fg-button:last-child { - border-top-right-radius: 3px; - border-bottom-right-radius: 3px; -} -.dataTables_wrapper .dataTables_processing { - position: absolute; - top: 50%; - left: 50%; - width: 100%; - height: 40px; - margin-left: -50%; - margin-top: -25px; - padding-top: 20px; - text-align: center; - font-size: 1.2em; - background-color: white; - background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0))); - /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); - /* Chrome10+,Safari5.1+ */ - background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); - /* FF3.6+ */ - background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); - /* IE10+ */ - background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); - /* Opera 11.10+ */ - background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); - /* W3C */ -} -.dataTables_wrapper .dataTables_length, -.dataTables_wrapper .dataTables_filter, -.dataTables_wrapper .dataTables_info, -.dataTables_wrapper .dataTables_processing, -.dataTables_wrapper .dataTables_paginate { - color: #333; -} -.dataTables_wrapper .dataTables_scroll { - clear: both; -} -.dataTables_wrapper .dataTables_scrollBody { - *margin-top: -1px; - -webkit-overflow-scrolling: touch; -} -.dataTables_wrapper .ui-widget-header { - font-weight: normal; -} -.dataTables_wrapper .ui-toolbar { - padding: 8px; -} -.dataTables_wrapper:after { - visibility: hidden; - display: block; - content: ""; - clear: both; - height: 0; -} - -@media screen and (max-width: 767px) { - .dataTables_wrapper .dataTables_length, - .dataTables_wrapper .dataTables_filter, - .dataTables_wrapper .dataTables_info, - .dataTables_wrapper .dataTables_paginate { - float: none; - text-align: center; - } - .dataTables_wrapper .dataTables_filter, - .dataTables_wrapper .dataTables_paginate { - margin-top: 0.5em; - } -} diff --git a/app/static/DataTables/DataTables-1.10.15/images/sort_asc_disabled.png b/app/static/DataTables/DataTables-1.10.15/images/sort_asc_disabled.png deleted file mode 100644 index fb11dfe24a6c564cb7ddf8bc96703ebb121df1e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S0wixl{&NRX(Vi}jAsXkC6BcOhI9!^3NY?Do zDX;f`c1`y6n0RgO@$!H7chZT&|Jn0dmaqO^XNm-CGtk!Ur<_=Jws3;%W$<+Mb6Mw<&;$T1GdZXL diff --git a/app/static/DataTables/DataTables-1.10.15/images/sort_desc_disabled.png b/app/static/DataTables/DataTables-1.10.15/images/sort_desc_disabled.png deleted file mode 100644 index c9fdd8a1502fda301682e907afde86bc450da10f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 146 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S0wixl{&NRXk)AG&AsXkC6C_xhx$boC`TY4@ zxy7GKb-~?6->j|Q{b@g3TV7E(Grjn^aLC2o)_ptHrtUEoT$S@q)~)7U@V;W{6)!%@ u>N?4t-1qslpJw9!O?PJ&w0Cby<'col-sm-6'f>>" + - "<'row'<'col-sm-12'tr>>" + - "<'row'<'col-sm-5'i><'col-sm-7'p>>", - renderer: 'bootstrap' -} ); - - -/* Default class modification */ -$.extend( DataTable.ext.classes, { - sWrapper: "dataTables_wrapper form-inline dt-bootstrap", - sFilterInput: "form-control input-sm", - sLengthSelect: "form-control input-sm", - sProcessing: "dataTables_processing panel panel-default" -} ); - - -/* Bootstrap paging button renderer */ -DataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, buttons, page, pages ) { - var api = new DataTable.Api( settings ); - var classes = settings.oClasses; - var lang = settings.oLanguage.oPaginate; - var aria = settings.oLanguage.oAria.paginate || {}; - var btnDisplay, btnClass, counter=0; - - var attach = function( container, buttons ) { - var i, ien, node, button; - var clickHandler = function ( e ) { - e.preventDefault(); - if ( !$(e.currentTarget).hasClass('disabled') && api.page() != e.data.action ) { - api.page( e.data.action ).draw( 'page' ); - } - }; - - for ( i=0, ien=buttons.length ; i 0 ? - '' : ' disabled'); - break; - - case 'previous': - btnDisplay = lang.sPrevious; - btnClass = button + (page > 0 ? - '' : ' disabled'); - break; - - case 'next': - btnDisplay = lang.sNext; - btnClass = button + (page < pages-1 ? - '' : ' disabled'); - break; - - case 'last': - btnDisplay = lang.sLast; - btnClass = button + (page < pages-1 ? - '' : ' disabled'); - break; - - default: - btnDisplay = button + 1; - btnClass = page === button ? - 'active' : ''; - break; - } - - if ( btnDisplay ) { - node = $('
  • ', { - 'class': classes.sPageButton+' '+btnClass, - 'id': idx === 0 && typeof button === 'string' ? - settings.sTableId +'_'+ button : - null - } ) - .append( $('', { - 'href': '#', - 'aria-controls': settings.sTableId, - 'aria-label': aria[ button ], - 'data-dt-idx': counter, - 'tabindex': settings.iTabIndex - } ) - .html( btnDisplay ) - ) - .appendTo( container ); - - settings.oApi._fnBindAction( - node, {action: button}, clickHandler - ); - - counter++; - } - } - } - }; - - // IE9 throws an 'unknown error' if document.activeElement is used - // inside an iframe or frame. - var activeEl; - - try { - // Because this approach is destroying and recreating the paging - // elements, focus is lost on the select button which is bad for - // accessibility. So we want to restore focus once the draw has - // completed - activeEl = $(host).find(document.activeElement).data('dt-idx'); - } - catch (e) {} - - attach( - $(host).empty().html('
  • ').appendTo($this); - } - oSettings.nTBody = tbody[0]; - - var tfoot = $this.children('tfoot'); - if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) { - // If we are a scrolling table, and no footer has been given, then we need to create - // a tfoot element for the caption element to be appended to - tfoot = $('').appendTo($this); - } - - if ( tfoot.length === 0 || tfoot.children().length === 0 ) { - $this.addClass( oClasses.sNoFooter ); - } - else if ( tfoot.length > 0 ) { - oSettings.nTFoot = tfoot[0]; - _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot ); - } - - /* Check if there is data passing into the constructor */ - if ( oInit.aaData ) { - for ( i=0 ; i/g; - - // This is not strict ISO8601 - Date.parse() is quite lax, although - // implementations differ between browsers. - var _re_date = /^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/; - - // Escape regular expression special characters - var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' ); - - // http://en.wikipedia.org/wiki/Foreign_exchange_market - // - \u20BD - Russian ruble. - // - \u20a9 - South Korean Won - // - \u20BA - Turkish Lira - // - \u20B9 - Indian Rupee - // - R - Brazil (R$) and South Africa - // - fr - Swiss Franc - // - kr - Swedish krona, Norwegian krone and Danish krone - // - \u2009 is thin space and \u202F is narrow no-break space, both used in many - // standards as thousands separators. - var _re_formatted_numeric = /[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi; - - - var _empty = function ( d ) { - return !d || d === true || d === '-' ? true : false; - }; - - - var _intVal = function ( s ) { - var integer = parseInt( s, 10 ); - return !isNaN(integer) && isFinite(s) ? integer : null; - }; - - // Convert from a formatted number with characters other than `.` as the - // decimal place, to a Javascript number - var _numToDecimal = function ( num, decimalPoint ) { - // Cache created regular expressions for speed as this function is called often - if ( ! _re_dic[ decimalPoint ] ) { - _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' ); - } - return typeof num === 'string' && decimalPoint !== '.' ? - num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) : - num; - }; - - - var _isNumber = function ( d, decimalPoint, formatted ) { - var strType = typeof d === 'string'; - - // If empty return immediately so there must be a number if it is a - // formatted string (this stops the string "k", or "kr", etc being detected - // as a formatted number for currency - if ( _empty( d ) ) { - return true; - } - - if ( decimalPoint && strType ) { - d = _numToDecimal( d, decimalPoint ); - } - - if ( formatted && strType ) { - d = d.replace( _re_formatted_numeric, '' ); - } - - return !isNaN( parseFloat(d) ) && isFinite( d ); - }; - - - // A string without HTML in it can be considered to be HTML still - var _isHtml = function ( d ) { - return _empty( d ) || typeof d === 'string'; - }; - - - var _htmlNumeric = function ( d, decimalPoint, formatted ) { - if ( _empty( d ) ) { - return true; - } - - var html = _isHtml( d ); - return ! html ? - null : - _isNumber( _stripHtml( d ), decimalPoint, formatted ) ? - true : - null; - }; - - - var _pluck = function ( a, prop, prop2 ) { - var out = []; - var i=0, ien=a.length; - - // Could have the test in the loop for slightly smaller code, but speed - // is essential here - if ( prop2 !== undefined ) { - for ( ; i') - .css( { - position: 'fixed', - top: 0, - left: $(window).scrollLeft()*-1, // allow for scrolling - height: 1, - width: 1, - overflow: 'hidden' - } ) - .append( - $('
    ') - .css( { - position: 'absolute', - top: 1, - left: 1, - width: 100, - overflow: 'scroll' - } ) - .append( - $('
    ') - .css( { - width: '100%', - height: 10 - } ) - ) - ) - .appendTo( 'body' ); - - var outer = n.children(); - var inner = outer.children(); - - // Numbers below, in order, are: - // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth - // - // IE6 XP: 100 100 100 83 - // IE7 Vista: 100 100 100 83 - // IE 8+ Windows: 83 83 100 83 - // Evergreen Windows: 83 83 100 83 - // Evergreen Mac with scrollbars: 85 85 100 85 - // Evergreen Mac without scrollbars: 100 100 100 100 - - // Get scrollbar width - browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth; - - // IE6/7 will oversize a width 100% element inside a scrolling element, to - // include the width of the scrollbar, while other browsers ensure the inner - // element is contained without forcing scrolling - browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100; - - // In rtl text layout, some browsers (most, but not all) will place the - // scrollbar on the left, rather than the right. - browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1; - - // IE8- don't provide height and width for getBoundingClientRect - browser.bBounding = n[0].getBoundingClientRect().width ? true : false; - - n.remove(); - } - - $.extend( settings.oBrowser, DataTable.__browser ); - settings.oScroll.iBarWidth = DataTable.__browser.barWidth; - } - - - /** - * Array.prototype reduce[Right] method, used for browsers which don't support - * JS 1.6. Done this way to reduce code size, since we iterate either way - * @param {object} settings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnReduce ( that, fn, init, start, end, inc ) - { - var - i = start, - value, - isSet = false; - - if ( init !== undefined ) { - value = init; - isSet = true; - } - - while ( i !== end ) { - if ( ! that.hasOwnProperty(i) ) { - continue; - } - - value = isSet ? - fn( value, that[i], i, that ) : - that[i]; - - isSet = true; - i += inc; - } - - return value; - } - - /** - * Add a column to the list used for the table with default values - * @param {object} oSettings dataTables settings object - * @param {node} nTh The th element for this column - * @memberof DataTable#oApi - */ - function _fnAddColumn( oSettings, nTh ) - { - // Add column to aoColumns array - var oDefaults = DataTable.defaults.column; - var iCol = oSettings.aoColumns.length; - var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, { - "nTh": nTh ? nTh : document.createElement('th'), - "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '', - "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol], - "mData": oDefaults.mData ? oDefaults.mData : iCol, - idx: iCol - } ); - oSettings.aoColumns.push( oCol ); - - // Add search object for column specific search. Note that the `searchCols[ iCol ]` - // passed into extend can be undefined. This allows the user to give a default - // with only some of the parameters defined, and also not give a default - var searchCols = oSettings.aoPreSearchCols; - searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] ); - - // Use the default column options function to initialise classes etc - _fnColumnOptions( oSettings, iCol, $(nTh).data() ); - } - - - /** - * Apply options for a column - * @param {object} oSettings dataTables settings object - * @param {int} iCol column index to consider - * @param {object} oOptions object with sType, bVisible and bSearchable etc - * @memberof DataTable#oApi - */ - function _fnColumnOptions( oSettings, iCol, oOptions ) - { - var oCol = oSettings.aoColumns[ iCol ]; - var oClasses = oSettings.oClasses; - var th = $(oCol.nTh); - - // Try to get width information from the DOM. We can't get it from CSS - // as we'd need to parse the CSS stylesheet. `width` option can override - if ( ! oCol.sWidthOrig ) { - // Width attribute - oCol.sWidthOrig = th.attr('width') || null; - - // Style attribute - var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/); - if ( t ) { - oCol.sWidthOrig = t[1]; - } - } - - /* User specified column options */ - if ( oOptions !== undefined && oOptions !== null ) - { - // Backwards compatibility - _fnCompatCols( oOptions ); - - // Map camel case parameters to their Hungarian counterparts - _fnCamelToHungarian( DataTable.defaults.column, oOptions ); - - /* Backwards compatibility for mDataProp */ - if ( oOptions.mDataProp !== undefined && !oOptions.mData ) - { - oOptions.mData = oOptions.mDataProp; - } - - if ( oOptions.sType ) - { - oCol._sManualType = oOptions.sType; - } - - // `class` is a reserved word in Javascript, so we need to provide - // the ability to use a valid name for the camel case input - if ( oOptions.className && ! oOptions.sClass ) - { - oOptions.sClass = oOptions.className; - } - - $.extend( oCol, oOptions ); - _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" ); - - /* iDataSort to be applied (backwards compatibility), but aDataSort will take - * priority if defined - */ - if ( oOptions.iDataSort !== undefined ) - { - oCol.aDataSort = [ oOptions.iDataSort ]; - } - _fnMap( oCol, oOptions, "aDataSort" ); - } - - /* Cache the data get and set functions for speed */ - var mDataSrc = oCol.mData; - var mData = _fnGetObjectDataFn( mDataSrc ); - var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null; - - var attrTest = function( src ) { - return typeof src === 'string' && src.indexOf('@') !== -1; - }; - oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && ( - attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter) - ); - oCol._setter = null; - - oCol.fnGetData = function (rowData, type, meta) { - var innerData = mData( rowData, type, undefined, meta ); - - return mRender && type ? - mRender( innerData, type, rowData, meta ) : - innerData; - }; - oCol.fnSetData = function ( rowData, val, meta ) { - return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta ); - }; - - // Indicate if DataTables should read DOM data as an object or array - // Used in _fnGetRowElements - if ( typeof mDataSrc !== 'number' ) { - oSettings._rowReadObject = true; - } - - /* Feature sorting overrides column specific when off */ - if ( !oSettings.oFeatures.bSort ) - { - oCol.bSortable = false; - th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called - } - - /* Check that the class assignment is correct for sorting */ - var bAsc = $.inArray('asc', oCol.asSorting) !== -1; - var bDesc = $.inArray('desc', oCol.asSorting) !== -1; - if ( !oCol.bSortable || (!bAsc && !bDesc) ) - { - oCol.sSortingClass = oClasses.sSortableNone; - oCol.sSortingClassJUI = ""; - } - else if ( bAsc && !bDesc ) - { - oCol.sSortingClass = oClasses.sSortableAsc; - oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed; - } - else if ( !bAsc && bDesc ) - { - oCol.sSortingClass = oClasses.sSortableDesc; - oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed; - } - else - { - oCol.sSortingClass = oClasses.sSortable; - oCol.sSortingClassJUI = oClasses.sSortJUI; - } - } - - - /** - * Adjust the table column widths for new data. Note: you would probably want to - * do a redraw after calling this function! - * @param {object} settings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnAdjustColumnSizing ( settings ) - { - /* Not interested in doing column width calculation if auto-width is disabled */ - if ( settings.oFeatures.bAutoWidth !== false ) - { - var columns = settings.aoColumns; - - _fnCalculateColumnWidths( settings ); - for ( var i=0 , iLen=columns.length ; i
    ').addClass( k ); - $('td', created) - .addClass( k ) - .html( r ) - [0].colSpan = _fnVisbleColumns( ctx ); - - rows.push( created[0] ); - } - }; - - addRow( data, klass ); - - if ( row._details ) { - row._details.detach(); - } - - row._details = $(rows); - - // If the children were already shown, that state should be retained - if ( row._detailsShow ) { - row._details.insertAfter( row.nTr ); - } - }; - - - var __details_remove = function ( api, idx ) - { - var ctx = api.context; - - if ( ctx.length ) { - var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ]; - - if ( row && row._details ) { - row._details.remove(); - - row._detailsShow = undefined; - row._details = undefined; - } - } - }; - - - var __details_display = function ( api, show ) { - var ctx = api.context; - - if ( ctx.length && api.length ) { - var row = ctx[0].aoData[ api[0] ]; - - if ( row._details ) { - row._detailsShow = show; - - if ( show ) { - row._details.insertAfter( row.nTr ); - } - else { - row._details.detach(); - } - - __details_events( ctx[0] ); - } - } - }; - - - var __details_events = function ( settings ) - { - var api = new _Api( settings ); - var namespace = '.dt.DT_details'; - var drawEvent = 'draw'+namespace; - var colvisEvent = 'column-visibility'+namespace; - var destroyEvent = 'destroy'+namespace; - var data = settings.aoData; - - api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent ); - - if ( _pluck( data, '_details' ).length > 0 ) { - // On each draw, insert the required elements into the document - api.on( drawEvent, function ( e, ctx ) { - if ( settings !== ctx ) { - return; - } - - api.rows( {page:'current'} ).eq(0).each( function (idx) { - // Internal data grab - var row = data[ idx ]; - - if ( row._detailsShow ) { - row._details.insertAfter( row.nTr ); - } - } ); - } ); - - // Column visibility change - update the colspan - api.on( colvisEvent, function ( e, ctx, idx, vis ) { - if ( settings !== ctx ) { - return; - } - - // Update the colspan for the details rows (note, only if it already has - // a colspan) - var row, visible = _fnVisbleColumns( ctx ); - - for ( var i=0, ien=data.length ; i=0 count from left, <0 count from right) - * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right) - * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right) - * "{string}:name" - column name - * "{string}" - jQuery selector on column header nodes - * - */ - - // can be an array of these items, comma separated list, or an array of comma - // separated lists - - var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/; - - - // r1 and r2 are redundant - but it means that the parameters match for the - // iterator callback in columns().data() - var __columnData = function ( settings, column, r1, r2, rows ) { - var a = []; - for ( var row=0, ien=rows.length ; row= 0 ? - selInt : // Count from left - columns.length + selInt // Count from right (+ because its a negative value) - ]; - } - - // Selector = function - if ( typeof s === 'function' ) { - var rows = _selector_row_indexes( settings, opts ); - - return $.map( columns, function (col, idx) { - return s( - idx, - __columnData( settings, idx, 0, 0, rows ), - nodes[ idx ] - ) ? idx : null; - } ); - } - - // jQuery or string selector - var match = typeof s === 'string' ? - s.match( __re_column_selector ) : - ''; - - if ( match ) { - switch( match[2] ) { - case 'visIdx': - case 'visible': - var idx = parseInt( match[1], 10 ); - // Visible index given, convert to column index - if ( idx < 0 ) { - // Counting from the right - var visColumns = $.map( columns, function (col,i) { - return col.bVisible ? i : null; - } ); - return [ visColumns[ visColumns.length + idx ] ]; - } - // Counting from the left - return [ _fnVisibleToColumnIndex( settings, idx ) ]; - - case 'name': - // match by name. `names` is column index complete and in order - return $.map( names, function (name, i) { - return name === match[1] ? i : null; - } ); - - default: - return []; - } - } - - // Cell in the table body - if ( s.nodeName && s._DT_CellIndex ) { - return [ s._DT_CellIndex.column ]; - } - - // jQuery selector on the TH elements for the columns - var jqResult = $( nodes ) - .filter( s ) - .map( function () { - return $.inArray( this, nodes ); // `nodes` is column index complete and in order - } ) - .toArray(); - - if ( jqResult.length || ! s.nodeName ) { - return jqResult; - } - - // Otherwise a node which might have a `dt-column` data attribute, or be - // a child or such an element - var host = $(s).closest('*[data-dt-column]'); - return host.length ? - [ host.data('dt-column') ] : - []; - }; - - return _selector_run( 'column', selector, run, settings, opts ); - }; - - - var __setColumnVis = function ( settings, column, vis ) { - var - cols = settings.aoColumns, - col = cols[ column ], - data = settings.aoData, - row, cells, i, ien, tr; - - // Get - if ( vis === undefined ) { - return col.bVisible; - } - - // Set - // No change - if ( col.bVisible === vis ) { - return; - } - - if ( vis ) { - // Insert column - // Need to decide if we should use appendChild or insertBefore - var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 ); - - for ( i=0, ien=data.length ; i iThat; - } - - return true; - }; - - - /** - * Check if a `
    -

    %s

    - """ - % ( + f""" -
    +

    """ - % request.base_url, - f"""Bulletin {sem["titremois"]} -
    """ - % sem, - """""", - """""" % time.strftime("%d/%m/%Y à %Hh%M"), - """""") - H.append( - '' - % ( - url_for( - "notes.formsemestre_bulletinetud", - scodoc_dept=g.scodoc_dept, - formsemestre_id=formsemestre.id, - etudid=etudid, - format="pdf", + +def _formsemestre_bulletinetud_header_html( + etud, + formsemestre: FormSemestre, + format=None, + version=None, +): + H = [ + html_sco_header.sco_header( + page_title=f"Bulletin de {etud.nomprenom}", + javascripts=[ + "js/bulletin.js", + "libjs/d3.v3.min.js", + "js/radar_bulletin.js", + ], + cssstyles=["css/radar_bulletin.css"], + ), + render_template( + "bul_head.html", + etud=etud, + format=format, + formsemestre=formsemestre, + menu_autres_operations=make_menu_autres_operations( + etud=etud, + formsemestre=formsemestre, + endpoint="notes.formsemestre_bulletinetud", version=version, ), - scu.ICON_PDF, - ) - ) - H.append("""
    établi le %s (notes sur 20) - """ - % formsemestre_id, - """""" % etudid, - """""" % format, - """ + + +
    établi le {time.strftime("%d/%m/%Y à %Hh%M")} (notes sur 20) + + + + """) # Menu endpoint = "notes.formsemestre_bulletinetud" + menu_autres_operations = make_menu_autres_operations( + formsemestre, etud, endpoint, version + ) - menuBul = [ + H.append("""""") + H.append( + '' + % ( + url_for( + "notes.formsemestre_bulletinetud", + scodoc_dept=g.scodoc_dept, + formsemestre_id=formsemestre.id, + etudid=etud.id, + format="pdf", + version=version, + ), + scu.ICON_PDF, + ) + ) + H.append("""

    {etud["nomprenom"]}

    + "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id + )}">{etud.nomprenom}
    Bulletin
    - +
    """) + H.append(menu_autres_operations) + H.append("""
    %s
    """) + # + H.append( + """
    %s + """ + % ( + url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id), + sco_photos.etud_photo_html(etud, title="fiche de " + etud.nomprenom), + ) + ) + H.append( + """
    + """ + ) + + return "".join(H) + + +def make_menu_autres_operations( + formsemestre: FormSemestre, etud: Identite, endpoint: str, version: str +) -> str: + etud_email = etud.get_first_email() or "" + etud_perso = etud.get_first_email("emailperso") or "" + menu_items = [ { "title": "Réglages bulletins", "endpoint": "notes.formsemestre_edit_options", @@ -1124,43 +1159,42 @@ def _formsemestre_bulletinetud_header_html( "endpoint": endpoint, "args": { "formsemestre_id": formsemestre.id, - "etudid": etudid, + "etudid": etud.id, "version": version, "format": "pdf", }, }, { - "title": "Envoi par mail à %s" % etud["email"], + "title": f"Envoi par mail à {etud_email}", "endpoint": endpoint, "args": { "formsemestre_id": formsemestre.id, - "etudid": etudid, + "etudid": etud.id, "version": version, "format": "pdfmail", }, # possible slt si on a un mail... - "enabled": etud["email"] and can_send_bulletin_by_mail(formsemestre.id), + "enabled": etud_email and can_send_bulletin_by_mail(formsemestre.id), }, { - "title": "Envoi par mail à %s (adr. personnelle)" % etud["emailperso"], + "title": f"Envoi par mail à {etud_perso} (adr. personnelle)", "endpoint": endpoint, "args": { "formsemestre_id": formsemestre.id, - "etudid": etudid, + "etudid": etud.id, "version": version, "format": "pdfmail", "prefer_mail_perso": 1, }, # possible slt si on a un mail... - "enabled": etud["emailperso"] - and can_send_bulletin_by_mail(formsemestre.id), + "enabled": etud_perso and can_send_bulletin_by_mail(formsemestre.id), }, { "title": "Version json", "endpoint": endpoint, "args": { "formsemestre_id": formsemestre.id, - "etudid": etudid, + "etudid": etud.id, "version": version, "format": "json", }, @@ -1170,7 +1204,7 @@ def _formsemestre_bulletinetud_header_html( "endpoint": endpoint, "args": { "formsemestre_id": formsemestre.id, - "etudid": etudid, + "etudid": etud.id, "version": version, "format": "xml", }, @@ -1180,7 +1214,7 @@ def _formsemestre_bulletinetud_header_html( "endpoint": "notes.appreciation_add_form", "args": { "formsemestre_id": formsemestre.id, - "etudid": etudid, + "etudid": etud.id, }, "enabled": ( formsemestre.can_be_edited_by(current_user) @@ -1192,7 +1226,7 @@ def _formsemestre_bulletinetud_header_html( "endpoint": "notes.formsemestre_ext_create_form", "args": { "formsemestre_id": formsemestre.id, - "etudid": etudid, + "etudid": etud.id, }, "enabled": current_user.has_permission(Permission.ScoImplement), }, @@ -1201,7 +1235,7 @@ def _formsemestre_bulletinetud_header_html( "endpoint": "notes.formsemestre_validate_previous_ue", "args": { "formsemestre_id": formsemestre.id, - "etudid": etudid, + "etudid": etud.id, }, "enabled": sco_permissions_check.can_validate_sem(formsemestre.id), }, @@ -1210,7 +1244,7 @@ def _formsemestre_bulletinetud_header_html( "endpoint": "notes.external_ue_create_form", "args": { "formsemestre_id": formsemestre.id, - "etudid": etudid, + "etudid": etud.id, }, "enabled": sco_permissions_check.can_validate_sem(formsemestre.id), }, @@ -1219,7 +1253,7 @@ def _formsemestre_bulletinetud_header_html( "endpoint": "notes.formsemestre_validation_etud_form", "args": { "formsemestre_id": formsemestre.id, - "etudid": etudid, + "etudid": etud.id, }, "enabled": sco_permissions_check.can_validate_sem(formsemestre.id), }, @@ -1228,43 +1262,44 @@ def _formsemestre_bulletinetud_header_html( "endpoint": "notes.formsemestre_pvjury_pdf", "args": { "formsemestre_id": formsemestre.id, - "etudid": etudid, + "etudid": etud.id, }, "enabled": True, }, ] + return htmlutils.make_menu("Autres opérations", menu_items, alone=True) - H.append("""
    """) - H.append(htmlutils.make_menu("Autres opérations", menuBul, alone=True)) - H.append("""
    %s
    """) - # - H.append( - """

    %s - """ - % ( - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid), - sco_photos.etud_photo_html(etud, title="fiche de " + etud["nom"]), - ) - ) - H.append( - """
    - """ - ) - - return "".join(H) + scu=scu, + time=time, + version=version, + ), + ] + return "\n".join(H) diff --git a/app/scodoc/sco_bulletins_generator.py b/app/scodoc/sco_bulletins_generator.py index ceeb0aac2..7f6a53c60 100644 --- a/app/scodoc/sco_bulletins_generator.py +++ b/app/scodoc/sco_bulletins_generator.py @@ -117,7 +117,7 @@ class BulletinGenerator: def get_filename(self): """Build a filename to be proposed to the web client""" sem = sco_formsemestre.get_formsemestre(self.infos["formsemestre_id"]) - return scu.bul_filename(sem, self.infos["etud"], "pdf") + return scu.bul_filename_old(sem, self.infos["etud"], "pdf") def generate(self, format="", stand_alone=True): """Return bulletin in specified format""" diff --git a/app/scodoc/sco_bulletins_json.py b/app/scodoc/sco_bulletins_json.py index ee57b60e7..ee0ddae27 100644 --- a/app/scodoc/sco_bulletins_json.py +++ b/app/scodoc/sco_bulletins_json.py @@ -138,7 +138,7 @@ def formsemestre_bulletinetud_published_dict( if not published: return d # stop ! - etat_inscription = etud.etat_inscription(formsemestre.id) + etat_inscription = etud.inscription_etat(formsemestre.id) if etat_inscription != scu.INSCRIT: d.update(dict_decision_jury(etudid, formsemestre_id, with_decisions=True)) return d diff --git a/app/scodoc/sco_etud.py b/app/scodoc/sco_etud.py index d019d2df2..48c6b82bf 100644 --- a/app/scodoc/sco_etud.py +++ b/app/scodoc/sco_etud.py @@ -33,8 +33,7 @@ import os import time from operator import itemgetter -from flask import url_for, g, request -from flask_mail import Message +from flask import url_for, g from app import email from app import log @@ -46,7 +45,6 @@ from app.scodoc.sco_exceptions import ScoGenError, ScoValueError from app.scodoc import safehtml from app.scodoc import sco_preferences from app.scodoc.scolog import logdb -from app.scodoc.TrivialFormulator import TrivialFormulator def format_etud_ident(etud): @@ -860,7 +858,7 @@ def list_scolog(etudid): return cursor.dictfetchall() -def fill_etuds_info(etuds, add_admission=True): +def fill_etuds_info(etuds: list[dict], add_admission=True): """etuds est une liste d'etudiants (mappings) Pour chaque etudiant, ajoute ou formatte les champs -> informations pour fiche etudiant ou listes diverses @@ -977,7 +975,10 @@ def etud_inscriptions_infos(etudid: int, ne="") -> dict: def descr_situation_etud(etudid: int, ne="") -> str: - """chaîne décrivant la situation actuelle de l'étudiant""" + """Chaîne décrivant la situation actuelle de l'étudiant + XXX Obsolete, utiliser Identite.descr_situation_etud() dans + les nouveaux codes + """ from app.scodoc import sco_formsemestre cnx = ndb.GetDBConnexion() diff --git a/app/scodoc/sco_photos.py b/app/scodoc/sco_photos.py index 80f3553e5..cf66a8526 100644 --- a/app/scodoc/sco_photos.py +++ b/app/scodoc/sco_photos.py @@ -351,7 +351,8 @@ def copy_portal_photo_to_fs(etud): """Copy the photo from portal (distant website) to local fs. Returns rel. path or None if copy failed, with a diagnostic message """ - sco_etud.format_etud_ident(etud) + if "nomprenom" not in etud: + sco_etud.format_etud_ident(etud) url = photo_portal_url(etud) if not url: return None, "%(nomprenom)s: pas de code NIP" % etud diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py index 196c2c210..b30c493ca 100644 --- a/app/scodoc/sco_utils.py +++ b/app/scodoc/sco_utils.py @@ -608,7 +608,7 @@ def is_valid_filename(filename): return VALID_EXP.match(filename) -def bul_filename(sem, etud, format): +def bul_filename_old(sem: dict, etud: dict, format): """Build a filename for this bulletin""" dt = time.strftime("%Y-%m-%d") filename = f"bul-{sem['titre_num']}-{dt}-{etud['nom']}.{format}" @@ -616,6 +616,14 @@ def bul_filename(sem, etud, format): return filename +def bul_filename(formsemestre, etud, format): + """Build a filename for this bulletin""" + dt = time.strftime("%Y-%m-%d") + filename = f"bul-{formsemestre.sem.titre_num}-{dt}-{etud.nom}.{format}" + filename = make_filename(filename) + return filename + + def flash_errors(form): """Flashes form errors (version sommaire)""" for field, errors in form.errors.items(): diff --git a/app/static/js/releve-but.js b/app/static/js/releve-but.js index 076fef1af..c7c649e51 100644 --- a/app/static/js/releve-but.js +++ b/app/static/js/releve-but.js @@ -41,7 +41,7 @@ class releveBUT extends HTMLElement { } set showData(data) { - this.showInformations(data); + // this.showInformations(data); this.showSemestre(data); this.showSynthese(data); this.showEvaluations(data); @@ -68,13 +68,7 @@ class releveBUT extends HTMLElement {
    - - - -
    - Photo de l'étudiant -
    -
    + diff --git a/app/templates/bul_head.html b/app/templates/bul_head.html new file mode 100644 index 000000000..5211fcd4f --- /dev/null +++ b/app/templates/bul_head.html @@ -0,0 +1,58 @@ +{# -*- mode: jinja-html -*- #} +{# L'en-tête des bulletins HTML #} +{# was _formsemestre_bulletinetud_header_html #} + + + + + + +
    +

    {{etud.nomprenom}}

    +
    + Bulletin {{formsemestre.titre_mois()}} +
    + + + + + + + +
    établi le {{time.strftime("%d/%m/%Y à %Hh%M")}} (notes sur 20) + + + + + + +
    {{menu_autres_operations|safe}}
    +
    {{scu.ICON_PDF|safe}} +
    +
    +
    {{etud.photo_html(title="fiche de " + etud["nom"])|safe}} +
    diff --git a/app/templates/but/bulletin.html b/app/templates/but/bulletin.html index ff0682fce..02a09e848 100644 --- a/app/templates/but/bulletin.html +++ b/app/templates/but/bulletin.html @@ -6,6 +6,8 @@ {% endblock %} {% block app_content %} +

    Totoro

    + From 2220b617b883319725b5e269a1c20d6d068898a5 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 7 Mar 2022 21:49:11 +0100 Subject: [PATCH 165/287] =?UTF-8?q?WIP:=20int=C3=A9gration=20bulletins?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/but/bulletin_but.py | 27 +++++++++--- app/models/etudiants.py | 1 + app/models/formsemestre.py | 14 +++++- app/scodoc/sco_bulletins.py | 8 ++-- app/scodoc/sco_bulletins_generator.py | 6 ++- app/scodoc/sco_formsemestre_status.py | 36 +++++----------- app/scodoc/sco_photos.py | 2 +- app/scodoc/sco_utils.py | 2 +- app/static/css/releve-but.css | 37 ++++++++++++---- app/static/css/scodoc.css | 4 +- app/static/js/releve-but.js | 15 ++++--- app/templates/bul_head.html | 4 ++ app/templates/but/bulletin.html | 2 +- app/templates/formsemestre_page_title.html | 50 ++++++++++++++++++++++ app/views/__init__.py | 37 +++++++++------- app/views/notes.py | 25 +++++++++-- 16 files changed, 193 insertions(+), 77 deletions(-) create mode 100644 app/templates/formsemestre_page_title.html diff --git a/app/but/bulletin_but.py b/app/but/bulletin_but.py index 4379fdac5..f64769fc9 100644 --- a/app/but/bulletin_but.py +++ b/app/but/bulletin_but.py @@ -111,9 +111,10 @@ class BulletinBUT: d["modules"] = self.etud_mods_results(etud, modimpls_spo) return d - def etud_mods_results(self, etud, modimpls) -> dict: + def etud_mods_results(self, etud, modimpls, version="long") -> dict: """dict synthèse résultats des modules indiqués, - avec évaluations de chacun.""" + avec évaluations de chacun (sauf si version == "short") + """ res = self.res d = {} # etud_idx = self.etud_index[etud.id] @@ -154,12 +155,14 @@ class BulletinBUT: "evaluations": [ self.etud_eval_results(etud, e) for e in modimpl.evaluations - if e.visibulletin + if (e.visibulletin or version == "long") and ( modimpl_results.evaluations_etat[e.id].is_complete or self.prefs["bul_show_all_evals"] ) - ], + ] + if version != "short" + else [], } return d @@ -217,9 +220,17 @@ class BulletinBUT: return f"Bonus de {fmt_note(bonus_vect.iloc[0])}" def bulletin_etud( - self, etud: Identite, formsemestre: FormSemestre, force_publishing=False + self, + etud: Identite, + formsemestre: FormSemestre, + force_publishing=False, + version="long", ) -> dict: """Le bulletin de l'étudiant dans ce semestre: dict pour la version JSON / HTML. + - version: + "long", "selectedevals": toutes les infos (notes des évaluations) + "short" : ne descend pas plus bas que les modules. + - Si force_publishing, rempli le bulletin même si bul_hide_xml est vrai (bulletins non publiés). """ @@ -282,8 +293,10 @@ class BulletinBUT: ) d.update( { - "ressources": self.etud_mods_results(etud, res.ressources), - "saes": self.etud_mods_results(etud, res.saes), + "ressources": self.etud_mods_results( + etud, res.ressources, version=version + ), + "saes": self.etud_mods_results(etud, res.saes, version=version), "ues": { ue.acronyme: self.etud_ue_results(etud, ue) for ue in res.ues diff --git a/app/models/etudiants.py b/app/models/etudiants.py index 953fb280a..060debc3b 100644 --- a/app/models/etudiants.py +++ b/app/models/etudiants.py @@ -160,6 +160,7 @@ class Identite(db.Model): "etudid": self.id, "nom": self.nom_disp(), "prenom": self.prenom, + "nomprenom": self.nomprenom, } if include_urls: d["fiche_url"] = url_for( diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py index ce162d249..d92c375fb 100644 --- a/app/models/formsemestre.py +++ b/app/models/formsemestre.py @@ -22,6 +22,7 @@ from app.scodoc import sco_codes_parcours from app.scodoc import sco_preferences from app.scodoc.sco_vdi import ApoEtapeVDI from app.scodoc.sco_permissions import Permission +from app.scodoc.sco_utils import MONTH_NAMES_ABBREV class FormSemestre(db.Model): @@ -162,8 +163,8 @@ class FormSemestre(db.Model): d["periode"] = 2 # typiquement, début en février: S2, S4... d["titre_num"] = self.titre_num() d["titreannee"] = self.titre_annee() - d["mois_debut"] = f"{self.date_debut.month} {self.date_debut.year}" - d["mois_fin"] = f"{self.date_fin.month} {self.date_fin.year}" + d["mois_debut"] = self.mois_debut() + d["mois_fin"] = self.mois_fin() d["titremois"] = "%s %s (%s - %s)" % ( d["titre_num"], self.modalite or "", @@ -293,6 +294,7 @@ class FormSemestre(db.Model): """chaîne "J. Dupond, X. Martin" ou "Jacques Dupond, Xavier Martin" """ + # was "nomcomplet" if not self.responsables: return "" if abbrev_prenom: @@ -304,6 +306,14 @@ class FormSemestre(db.Model): "2021 - 2022" return scu.annee_scolaire_repr(self.date_debut.year, self.date_debut.month) + def mois_debut(self) -> str: + "Oct 2021" + return f"{MONTH_NAMES_ABBREV[self.date_debut.month - 1]} {self.date_debut.year}" + + def mois_fin(self) -> str: + "Jul 2022" + return f"{MONTH_NAMES_ABBREV[self.date_fin.month - 1]} {self.date_debut.year}" + def session_id(self) -> str: """identifiant externe de semestre de formation Exemple: RT-DUT-FI-S1-ANNEE diff --git a/app/scodoc/sco_bulletins.py b/app/scodoc/sco_bulletins.py index 046c81468..b21404276 100644 --- a/app/scodoc/sco_bulletins.py +++ b/app/scodoc/sco_bulletins.py @@ -793,13 +793,14 @@ def etud_descr_situation_semestre( def formsemestre_bulletinetud( etudid=None, formsemestre_id=None, - format="html", + format=None, version="long", xml_with_decisions=False, force_publishing=False, # force publication meme si semestre non publie sur "portail" prefer_mail_perso=False, ): "page bulletin de notes" + format = format or "html" etud: Identite = Identite.query.get_or_404(etudid) formsemestre: FormSemestre = FormSemestre.query.get(formsemestre_id) if not formsemestre: @@ -879,7 +880,7 @@ def do_formsemestre_bulletinetud( formsemestre: FormSemestre, etudid: int, version="long", # short, long, selectedevals - format="html", + format=None, nohtml=False, xml_with_decisions=False, # force décisions dans XML force_publishing=False, # force publication meme si semestre non publié sur "portail" @@ -890,6 +891,7 @@ def do_formsemestre_bulletinetud( où bul est str ou bytes au format demandé (html, pdf, pdfmail, pdfpart, xml, json) et filigranne est un message à placer en "filigranne" (eg "Provisoire"). """ + format = format or "html" if format == "xml": bul = sco_bulletins_xml.make_xml_formsemestre_bulletinetud( formsemestre.id, @@ -1258,7 +1260,7 @@ def make_menu_autres_operations( "enabled": sco_permissions_check.can_validate_sem(formsemestre.id), }, { - "title": "Editer PV jury", + "title": "Éditer PV jury", "endpoint": "notes.formsemestre_pvjury_pdf", "args": { "formsemestre_id": formsemestre.id, diff --git a/app/scodoc/sco_bulletins_generator.py b/app/scodoc/sco_bulletins_generator.py index 7f6a53c60..2aeb792fb 100644 --- a/app/scodoc/sco_bulletins_generator.py +++ b/app/scodoc/sco_bulletins_generator.py @@ -297,7 +297,11 @@ def register_bulletin_class(klass): def bulletin_class_descriptions(): - return [x.description for x in BULLETIN_CLASSES.values()] + return [ + BULLETIN_CLASSES[class_name].description + for class_name in BULLETIN_CLASSES + if BULLETIN_CLASSES[class_name].list_in_menu + ] def bulletin_class_names() -> list[str]: diff --git a/app/scodoc/sco_formsemestre_status.py b/app/scodoc/sco_formsemestre_status.py index 2080e9572..11e665d92 100644 --- a/app/scodoc/sco_formsemestre_status.py +++ b/app/scodoc/sco_formsemestre_status.py @@ -31,7 +31,7 @@ from flask import current_app from flask import g from flask import request -from flask import url_for +from flask import render_template, url_for from flask_login import current_user from app import log @@ -411,7 +411,7 @@ def formsemestre_status_menubar(sem): "enabled": sco_permissions_check.can_validate_sem(formsemestre_id), }, { - "title": "Editer les PV et archiver les résultats", + "title": "Éditer les PV et archiver les résultats", "endpoint": "notes.formsemestre_archive", "args": {"formsemestre_id": formsemestre_id}, "enabled": sco_permissions_check.can_edit_pv(formsemestre_id), @@ -445,6 +445,7 @@ def retreive_formsemestre_from_request() -> int: """Cherche si on a de quoi déduire le semestre affiché à partir des arguments de la requête: formsemestre_id ou moduleimpl ou evaluation ou group_id ou partition_id + Returns None si pas défini. """ if request.method == "GET": args = request.args @@ -505,34 +506,17 @@ def formsemestre_page_title(): return "" try: formsemestre_id = int(formsemestre_id) - sem = sco_formsemestre.get_formsemestre(formsemestre_id).copy() + formsemestre = FormSemestre.query.get(formsemestre_id) except: log("can't find formsemestre_id %s" % formsemestre_id) return "" - fill_formsemestre(sem) - - h = f"""
    - - {formsemestre_status_menubar(sem)} -
    - """ + h = render_template( + "formsemestre_page_title.html", + formsemestre=formsemestre, + scu=scu, + sem_menu_bar=formsemestre_status_menubar(formsemestre.to_dict()), + ) return h diff --git a/app/scodoc/sco_photos.py b/app/scodoc/sco_photos.py index cf66a8526..0dfeaafe3 100644 --- a/app/scodoc/sco_photos.py +++ b/app/scodoc/sco_photos.py @@ -175,7 +175,7 @@ def etud_photo_is_local(etud: dict, size="small"): return photo_pathname(etud["photo_filename"], size=size) -def etud_photo_html(etud=None, etudid=None, title=None, size="small"): +def etud_photo_html(etud: dict = None, etudid=None, title=None, size="small"): """HTML img tag for the photo, either in small size (h90) or original size (size=="orig") """ diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py index b30c493ca..ba7fd504a 100644 --- a/app/scodoc/sco_utils.py +++ b/app/scodoc/sco_utils.py @@ -619,7 +619,7 @@ def bul_filename_old(sem: dict, etud: dict, format): def bul_filename(formsemestre, etud, format): """Build a filename for this bulletin""" dt = time.strftime("%Y-%m-%d") - filename = f"bul-{formsemestre.sem.titre_num}-{dt}-{etud.nom}.{format}" + filename = f"bul-{formsemestre.titre_num()}-{dt}-{etud.nom}.{format}" filename = make_filename(filename) return filename diff --git a/app/static/css/releve-but.css b/app/static/css/releve-but.css index 02cceb94c..d9756ace4 100644 --- a/app/static/css/releve-but.css +++ b/app/static/css/releve-but.css @@ -14,16 +14,25 @@ } main{ --couleurPrincipale: rgb(240,250,255); - --couleurFondTitresUE: rgb(206,255,235); - --couleurFondTitresRes: rgb(125, 170, 255); - --couleurFondTitresSAE: rgb(211, 255, 255); + --couleurFondTitresUE: #b6ebff; + --couleurFondTitresRes: #f8c844; + --couleurFondTitresSAE: #c6ffab; --couleurSecondaire: #fec; - --couleurIntense: #c09; - --couleurSurlignage: rgba(232, 255, 132, 0.47); + --couleurIntense: rgb(4, 16, 159);; + --couleurSurlignage: rgba(255, 253, 110, 0.49); max-width: 1000px; margin: auto; display: none; } +.releve a, .releve a:visited { + color: navy; + text-decoration: none; +} +.releve a:hover { + color: red; + text-decoration: underline; +} + .ready .wait{display: none;} .ready main{display: block;} h2{ @@ -152,12 +161,14 @@ section>div:nth-child(1){ column-gap: 4px; flex: none; } -.infoSemestre>div:nth-child(1){ - margin-right: auto; -} + .infoSemestre>div>div:nth-child(even){ text-align: right; } +.photo { + border: none; + margin-left: auto; +} .rang{ font-weight: bold; } @@ -213,7 +224,6 @@ section>div:nth-child(1){ scroll-margin-top: 60px; } .module, .ue { - background: var(--couleurSecondaire); color: #000; padding: 4px 32px; border-radius: 4px; @@ -225,6 +235,15 @@ section>div:nth-child(1){ cursor: pointer; position: relative; } +.ue { + background: var(--couleurFondTitresRes); +} +.module { + background: var(--couleurFondTitresRes); +} +.module h3 { + background: var(--couleurFondTitresRes); +} .module::before, .ue::before { content:url("data:image/svg+xml;utf8,"); width: 26px; diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css index a9390db24..31603a34b 100644 --- a/app/static/css/scodoc.css +++ b/app/static/css/scodoc.css @@ -1963,7 +1963,9 @@ table.notes_recapcomplet a:hover { div.notes_bulletin { margin-right: 5px; } - +div.bulletin_menubar { + margin-right: 2em; +} table.notes_bulletin { border-collapse: collapse; border: 2px solid rgb(100,100,240); diff --git a/app/static/js/releve-but.js b/app/static/js/releve-but.js index c7c649e51..97f97e29d 100644 --- a/app/static/js/releve-but.js +++ b/app/static/js/releve-but.js @@ -79,8 +79,8 @@ class releveBUT extends HTMLElement {
    -

    Semestre

    -
    +

    +
    @@ -97,7 +97,7 @@ class releveBUT extends HTMLElement {
    -

    Synthèse

    +

    Unités d'enseignement

    La moyenne des ressources dans une UE dépend des poids donnés aux évaluations.
    @@ -126,7 +126,7 @@ class releveBUT extends HTMLElement {
    -

    SAÉ

    +

    Situations d'apprentissage et d'évaluation (SAÉ)

    Liste @@ -192,7 +192,8 @@ class releveBUT extends HTMLElement { /* Information sur le semestre */ /*******************************/ showSemestre(data) { - this.shadow.querySelector("h2").innerHTML += data.semestre.numero; + + this.shadow.querySelector("#identite_etudiant").innerHTML = ` ${data.etudiant.nomprenom} `; this.shadow.querySelector(".dateInscription").innerHTML += this.ISOToDate(data.semestre.inscription); let output = `
    @@ -206,7 +207,9 @@ class releveBUT extends HTMLElement {
    Absences
    N.J. ${data.semestre.absences?.injustifie ?? "-"}
    Total ${data.semestre.absences?.total ?? "-"}
    -
    `; +
    + photo de l'étudiant + `; /*${data.semestre.groupes.map(groupe => { return `
    diff --git a/app/templates/bul_head.html b/app/templates/bul_head.html index 5211fcd4f..12df3c4f8 100644 --- a/app/templates/bul_head.html +++ b/app/templates/bul_head.html @@ -5,10 +5,12 @@ +{% if not is_apc %} +{% endif %}
    +{% if not is_apc %}

    {{etud.nomprenom}}

    +{% endif %}
    Bulletin
    {{etud.photo_html(title="fiche de " + etud["nom"])|safe}}
    diff --git a/app/templates/but/bulletin.html b/app/templates/but/bulletin.html index 02a09e848..c3e8c834e 100644 --- a/app/templates/but/bulletin.html +++ b/app/templates/but/bulletin.html @@ -6,8 +6,8 @@ {% endblock %} {% block app_content %} -

    Totoro

    +{% include 'bul_head.html' %} diff --git a/app/templates/formsemestre_page_title.html b/app/templates/formsemestre_page_title.html new file mode 100644 index 000000000..70fef579d --- /dev/null +++ b/app/templates/formsemestre_page_title.html @@ -0,0 +1,50 @@ +{# -*- mode: jinja-html -*- #} +{# Element HTML decrivant un semestre (barre de menu et infos) #} +{# was formsemestre_page_title #} + + \ No newline at end of file diff --git a/app/views/__init__.py b/app/views/__init__.py index 3d8af0777..f3c8e13d4 100644 --- a/app/views/__init__.py +++ b/app/views/__init__.py @@ -50,27 +50,29 @@ def close_dept_db_connection(arg): class ScoData: """Classe utilisée pour passer des valeurs aux vues (templates)""" - def __init__(self): + def __init__(self, etud=None, formsemestre=None): # Champs utilisés par toutes les pages ScoDoc (sidebar, en-tête) self.Permission = Permission self.scu = scu self.SCOVERSION = sco_version.SCOVERSION # -- Informations étudiant courant, si sélectionné: - etudid = g.get("etudid", None) - if not etudid: - if request.method == "GET": - etudid = request.args.get("etudid", None) - elif request.method == "POST": - etudid = request.form.get("etudid", None) - - if etudid: + if etud is None: + etudid = g.get("etudid", None) + if etudid is None: + if request.method == "GET": + etudid = request.args.get("etudid", None) + elif request.method == "POST": + etudid = request.form.get("etudid", None) + if etudid is not None: + etud = Identite.query.get_or_404(etudid) + self.etud = etud + if etud is not None: # Infos sur l'étudiant courant - self.etud = Identite.query.get_or_404(etudid) ins = self.etud.inscription_courante() if ins: self.etud_cur_sem = ins.formsemestre self.nbabs, self.nbabsjust = sco_abs.get_abs_count_in_interval( - etudid, + etud.id, self.etud_cur_sem.date_debut.isoformat(), self.etud_cur_sem.date_fin.isoformat(), ) @@ -80,17 +82,22 @@ class ScoData: else: self.etud = None # --- Informations sur semestre courant, si sélectionné - formsemestre_id = sco_formsemestre_status.retreive_formsemestre_from_request() - if formsemestre_id is None: + if formsemestre is None: + formsemestre_id = ( + sco_formsemestre_status.retreive_formsemestre_from_request() + ) + if formsemestre_id is not None: + formsemestre = FormSemestre.query.get_or_404(formsemestre_id) + if formsemestre is None: self.sem = None self.sem_menu_bar = None else: - self.sem = FormSemestre.query.get_or_404(formsemestre_id) + self.sem = formsemestre self.sem_menu_bar = sco_formsemestre_status.formsemestre_status_menubar( self.sem.to_dict() ) # --- Préférences - self.prefs = sco_preferences.SemPreferences(formsemestre_id) + self.prefs = sco_preferences.SemPreferences(formsemestre.id) from app.views import scodoc, notes, scolar, absences, users, pn_modules, refcomp diff --git a/app/views/notes.py b/app/views/notes.py index 6cbf0be43..5ca463b4c 100644 --- a/app/views/notes.py +++ b/app/views/notes.py @@ -32,6 +32,7 @@ Emmanuel Viennet, 2021 """ from operator import itemgetter +import time from xml.etree import ElementTree import flask @@ -276,7 +277,7 @@ sco_publish( def formsemestre_bulletinetud( etudid=None, formsemestre_id=None, - format="html", + format=None, version="long", xml_with_decisions=False, force_publishing=False, @@ -284,6 +285,7 @@ def formsemestre_bulletinetud( code_nip=None, code_ine=None, ): + format = format or "html" if not formsemestre_id: flask.abort(404, "argument manquant: formsemestre_id") if not isinstance(formsemestre_id, int): @@ -311,12 +313,16 @@ def formsemestre_bulletinetud( if format == "json": r = bulletin_but.BulletinBUT(formsemestre) return jsonify( - r.bulletin_etud(etud, formsemestre, force_publishing=force_publishing) + r.bulletin_etud( + etud, + formsemestre, + force_publishing=force_publishing, + version=version, + ) ) elif format == "html": return render_template( "but/bulletin.html", - title=f"Bul. {etud.nom} - BUT", bul_url=url_for( "notes.formsemestre_bulletinetud", scodoc_dept=g.scodoc_dept, @@ -324,8 +330,19 @@ def formsemestre_bulletinetud( etudid=etudid, format="json", force_publishing=1, # pour ScoDoc lui même + version=version, ), - sco=ScoData(), + etud=etud, + formsemestre=formsemestre, + is_apc=formsemestre.formation.is_apc(), + menu_autres_operations=sco_bulletins.make_menu_autres_operations( + formsemestre, etud, "notes.formsemestre_bulletinetud", version + ), + sco=ScoData(etud=etud), + scu=scu, + time=time, + title=f"Bul. {etud.nom} - BUT", + version=version, ) if not (etudid or code_nip or code_ine): From a09418329faf670fc29f1c6873496ab92682cc69 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 7 Mar 2022 23:43:48 +0100 Subject: [PATCH 166/287] =?UTF-8?q?Int=C3=A9gration=20bulletins=20html?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/scodoc/sco_bulletins.py | 47 ++++----------------- app/static/css/scodoc.css | 19 +++++---- app/templates/bul_foot.html | 34 +++++++++++++++ app/templates/bul_head.html | 73 +++++++++++++++------------------ app/templates/but/bulletin.html | 3 ++ app/views/notes.py | 2 + 6 files changed, 93 insertions(+), 85 deletions(-) create mode 100644 app/templates/bul_foot.html diff --git a/app/scodoc/sco_bulletins.py b/app/scodoc/sco_bulletins.py index b21404276..65dcb3a91 100644 --- a/app/scodoc/sco_bulletins.py +++ b/app/scodoc/sco_bulletins.py @@ -822,47 +822,16 @@ def formsemestre_bulletinetud( H = [ _formsemestre_bulletinetud_header_html(etud, formsemestre, format, version), bulletin, + render_template( + "bul_foot.html", + etud=etud, + formsemestre=formsemestre, + inscription_courante=etud.inscription_courante(), + inscription_str=etud.inscription_descr()["inscription_str"], + ), + html_sco_header.sco_footer(), ] - H.append("""

    Situation actuelle: """) - inscription_courante = etud.inscription_courante() - if inscription_courante: - H.append( - f"""""" - ) - inscription_descr = etud.inscription_descr() - H.append(inscription_descr["inscription_str"]) - if inscription_courante: - H.append("""""") - H.append("""

    """) - if formsemestre.modalite == "EXT": - H.append( - f"""

    - Éditer les validations d'UE dans ce semestre extérieur -

    """ - ) - # Place du diagramme radar - H.append( - """
    - - -
    """ - % (etudid, formsemestre_id) - ) - H.append('
    ') - - # --- Pied de page - H.append(html_sco_header.sco_footer()) - return "".join(H) diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css index 31603a34b..b5f2b325b 100644 --- a/app/static/css/scodoc.css +++ b/app/static/css/scodoc.css @@ -1963,7 +1963,18 @@ table.notes_recapcomplet a:hover { div.notes_bulletin { margin-right: 5px; } -div.bulletin_menubar { +div.bull_head { + display: grid; + justify-content: space-between; + grid-template-columns: auto auto; +} +div.bull_photo { + display: inline-block; + margin-right: 10px; +} +span.bulletin_menubar_but { + display: inline-block; + margin-left: 2em; margin-right: 2em; } table.notes_bulletin { @@ -2105,12 +2116,6 @@ a.bull_link:hover { text-decoration: underline; } -table.bull_head { - width: 100%; -} -td.bull_photo { - text-align: right; -} div.bulletin_menubar { padding-left: 25px; diff --git a/app/templates/bul_foot.html b/app/templates/bul_foot.html new file mode 100644 index 000000000..873b43c76 --- /dev/null +++ b/app/templates/bul_foot.html @@ -0,0 +1,34 @@ +{# -*- mode: jinja-html -*- #} +{# Pied des bulletins HTML #} + +

    Situation actuelle: +{% if inscription_courante %} +{{inscription_str}} +{% else %} + {{inscription_str}} +{% endif %} +

    + +{% if formsemestre.modalite == "EXT" %} +

    + Éditer les validations d'UE dans ce semestre extérieur +

    +{% endif %} + +{# Place du diagramme radar #} +
    + + +
    +
    + + diff --git a/app/templates/bul_head.html b/app/templates/bul_head.html index 12df3c4f8..d706ef9ae 100644 --- a/app/templates/bul_head.html +++ b/app/templates/bul_head.html @@ -2,9 +2,8 @@ {# L'en-tête des bulletins HTML #} {# was _formsemestre_bulletinetud_header_html #} - - - + {% if not is_apc %} - + {% endif %} - -
    +
    +
    {% if not is_apc %}

    {{etud.nomprenom}}

    {% endif %}
    - Bulletin + + + Bulletin + {{formsemestre.titre_mois()}} -
    - - - - - - - -
    établi le {{time.strftime("%d/%m/%Y à %Hh%M")}} (notes sur 20) - - - - - - -
    {{menu_autres_operations|safe}}
    -
    {{formsemestre.titre_mois() + }} + +
    + établi le {{time.strftime("%d/%m/%Y à %Hh%M")}} (notes sur 20) + + + + + {{menu_autres_operations|safe}} + {{scu.ICON_PDF|safe}} -
    + +
    -
    {{etud.photo_html(title="fiche de " + etud["nom"])|safe}} -
    +
    diff --git a/app/templates/but/bulletin.html b/app/templates/but/bulletin.html index c3e8c834e..d394f255b 100644 --- a/app/templates/but/bulletin.html +++ b/app/templates/but/bulletin.html @@ -11,6 +11,9 @@ + +{% include 'bul_foot.html' %} + ') + # H.append( + # '' + # ) # JS additionels for js in javascripts: H.append("""\n""" % js) diff --git a/app/scodoc/sco_formsemestre_status.py b/app/scodoc/sco_formsemestre_status.py index 11e665d92..ae9ce543d 100644 --- a/app/scodoc/sco_formsemestre_status.py +++ b/app/scodoc/sco_formsemestre_status.py @@ -1170,8 +1170,10 @@ def formsemestre_tableau_modules( H.append('
    %s{mod.code}%s %s
    ', { - 'valign': 'top', - 'colSpan': _fnVisbleColumns( oSettings ), - 'class': oSettings.oClasses.sRowEmpty - } ).html( sZero ) )[0]; - } - - /* Header and footer callbacks */ - _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0], - _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); - - _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0], - _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); - - var body = $(oSettings.nTBody); - - body.children().detach(); - body.append( $(anRows) ); - - /* Call all required callback functions for the end of a draw */ - _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] ); - - /* Draw is complete, sorting and filtering must be as well */ - oSettings.bSorted = false; - oSettings.bFiltered = false; - oSettings.bDrawing = false; - } - - - /** - * Redraw the table - taking account of the various features which are enabled - * @param {object} oSettings dataTables settings object - * @param {boolean} [holdPosition] Keep the current paging position. By default - * the paging is reset to the first page - * @memberof DataTable#oApi - */ - function _fnReDraw( settings, holdPosition ) - { - var - features = settings.oFeatures, - sort = features.bSort, - filter = features.bFilter; - - if ( sort ) { - _fnSort( settings ); - } - - if ( filter ) { - _fnFilterComplete( settings, settings.oPreviousSearch ); - } - else { - // No filtering, so we want to just use the display master - settings.aiDisplay = settings.aiDisplayMaster.slice(); - } - - if ( holdPosition !== true ) { - settings._iDisplayStart = 0; - } - - // Let any modules know about the draw hold position state (used by - // scrolling internally) - settings._drawHold = holdPosition; - - _fnDraw( settings ); - - settings._drawHold = false; - } - - - /** - * Add the options to the page HTML for the table - * @param {object} oSettings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnAddOptionsHtml ( oSettings ) - { - var classes = oSettings.oClasses; - var table = $(oSettings.nTable); - var holding = $('
    ').insertBefore( table ); // Holding element for speed - var features = oSettings.oFeatures; - - // All DataTables are wrapped in a div - var insert = $('
    ', { - id: oSettings.sTableId+'_wrapper', - 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter) - } ); - - oSettings.nHolding = holding[0]; - oSettings.nTableWrapper = insert[0]; - oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling; - - /* Loop over the user set positioning and place the elements as needed */ - var aDom = oSettings.sDom.split(''); - var featureNode, cOption, nNewNode, cNext, sAttr, j; - for ( var i=0 ; i')[0]; - - /* Check to see if we should append an id and/or a class name to the container */ - cNext = aDom[i+1]; - if ( cNext == "'" || cNext == '"' ) - { - sAttr = ""; - j = 2; - while ( aDom[i+j] != cNext ) - { - sAttr += aDom[i+j]; - j++; - } - - /* Replace jQuery UI constants @todo depreciated */ - if ( sAttr == "H" ) - { - sAttr = classes.sJUIHeader; - } - else if ( sAttr == "F" ) - { - sAttr = classes.sJUIFooter; - } - - /* The attribute can be in the format of "#id.class", "#id" or "class" This logic - * breaks the string into parts and applies them as needed - */ - if ( sAttr.indexOf('.') != -1 ) - { - var aSplit = sAttr.split('.'); - nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1); - nNewNode.className = aSplit[1]; - } - else if ( sAttr.charAt(0) == "#" ) - { - nNewNode.id = sAttr.substr(1, sAttr.length-1); - } - else - { - nNewNode.className = sAttr; - } - - i += j; /* Move along the position array */ - } - - insert.append( nNewNode ); - insert = $(nNewNode); - } - else if ( cOption == '>' ) - { - /* End container div */ - insert = insert.parent(); - } - // @todo Move options into their own plugins? - else if ( cOption == 'l' && features.bPaginate && features.bLengthChange ) - { - /* Length */ - featureNode = _fnFeatureHtmlLength( oSettings ); - } - else if ( cOption == 'f' && features.bFilter ) - { - /* Filter */ - featureNode = _fnFeatureHtmlFilter( oSettings ); - } - else if ( cOption == 'r' && features.bProcessing ) - { - /* pRocessing */ - featureNode = _fnFeatureHtmlProcessing( oSettings ); - } - else if ( cOption == 't' ) - { - /* Table */ - featureNode = _fnFeatureHtmlTable( oSettings ); - } - else if ( cOption == 'i' && features.bInfo ) - { - /* Info */ - featureNode = _fnFeatureHtmlInfo( oSettings ); - } - else if ( cOption == 'p' && features.bPaginate ) - { - /* Pagination */ - featureNode = _fnFeatureHtmlPaginate( oSettings ); - } - else if ( DataTable.ext.feature.length !== 0 ) - { - /* Plug-in features */ - var aoFeatures = DataTable.ext.feature; - for ( var k=0, kLen=aoFeatures.length ; k'; - - var str = language.sSearch; - str = str.match(/_INPUT_/) ? - str.replace('_INPUT_', input) : - str+input; - - var filter = $('
    ', { - 'id': ! features.f ? tableId+'_filter' : null, - 'class': classes.sFilter - } ) - .append( $('
    ').addClass( classes.sLength ); - if ( ! settings.aanFeatures.l ) { - div[0].id = tableId+'_length'; - } - - div.children().append( - settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML ) - ); - - // Can't use `select` variable as user might provide their own and the - // reference is broken by the use of outerHTML - $('select', div) - .val( settings._iDisplayLength ) - .on( 'change.DT', function(e) { - _fnLengthChange( settings, $(this).val() ); - _fnDraw( settings ); - } ); - - // Update node value whenever anything changes the table's length - $(settings.nTable).on( 'length.dt.DT', function (e, s, len) { - if ( settings === s ) { - $('select', div).val( len ); - } - } ); - - return div[0]; - } - - - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Note that most of the paging logic is done in - * DataTable.ext.pager - */ - - /** - * Generate the node required for default pagination - * @param {object} oSettings dataTables settings object - * @returns {node} Pagination feature node - * @memberof DataTable#oApi - */ - function _fnFeatureHtmlPaginate ( settings ) - { - var - type = settings.sPaginationType, - plugin = DataTable.ext.pager[ type ], - modern = typeof plugin === 'function', - redraw = function( settings ) { - _fnDraw( settings ); - }, - node = $('
    ').addClass( settings.oClasses.sPaging + type )[0], - features = settings.aanFeatures; - - if ( ! modern ) { - plugin.fnInit( settings, node, redraw ); - } - - /* Add a draw callback for the pagination on first instance, to update the paging display */ - if ( ! features.p ) - { - node.id = settings.sTableId+'_paginate'; - - settings.aoDrawCallback.push( { - "fn": function( settings ) { - if ( modern ) { - var - start = settings._iDisplayStart, - len = settings._iDisplayLength, - visRecords = settings.fnRecordsDisplay(), - all = len === -1, - page = all ? 0 : Math.ceil( start / len ), - pages = all ? 1 : Math.ceil( visRecords / len ), - buttons = plugin(page, pages), - i, ien; - - for ( i=0, ien=features.p.length ; i records ) - { - start = 0; - } - } - else if ( action == "first" ) - { - start = 0; - } - else if ( action == "previous" ) - { - start = len >= 0 ? - start - len : - 0; - - if ( start < 0 ) - { - start = 0; - } - } - else if ( action == "next" ) - { - if ( start + len < records ) - { - start += len; - } - } - else if ( action == "last" ) - { - start = Math.floor( (records-1) / len) * len; - } - else - { - _fnLog( settings, 0, "Unknown paging action: "+action, 5 ); - } - - var changed = settings._iDisplayStart !== start; - settings._iDisplayStart = start; - - if ( changed ) { - _fnCallbackFire( settings, null, 'page', [settings] ); - - if ( redraw ) { - _fnDraw( settings ); - } - } - - return changed; - } - - - - /** - * Generate the node required for the processing node - * @param {object} settings dataTables settings object - * @returns {node} Processing element - * @memberof DataTable#oApi - */ - function _fnFeatureHtmlProcessing ( settings ) - { - return $('
    ', { - 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null, - 'class': settings.oClasses.sProcessing - } ) - .html( settings.oLanguage.sProcessing ) - .insertBefore( settings.nTable )[0]; - } - - - /** - * Display or hide the processing indicator - * @param {object} settings dataTables settings object - * @param {bool} show Show the processing indicator (true) or not (false) - * @memberof DataTable#oApi - */ - function _fnProcessingDisplay ( settings, show ) - { - if ( settings.oFeatures.bProcessing ) { - $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' ); - } - - _fnCallbackFire( settings, null, 'processing', [settings, show] ); - } - - /** - * Add any control elements for the table - specifically scrolling - * @param {object} settings dataTables settings object - * @returns {node} Node to add to the DOM - * @memberof DataTable#oApi - */ - function _fnFeatureHtmlTable ( settings ) - { - var table = $(settings.nTable); - - // Add the ARIA grid role to the table - table.attr( 'role', 'grid' ); - - // Scrolling from here on in - var scroll = settings.oScroll; - - if ( scroll.sX === '' && scroll.sY === '' ) { - return settings.nTable; - } - - var scrollX = scroll.sX; - var scrollY = scroll.sY; - var classes = settings.oClasses; - var caption = table.children('caption'); - var captionSide = caption.length ? caption[0]._captionSide : null; - var headerClone = $( table[0].cloneNode(false) ); - var footerClone = $( table[0].cloneNode(false) ); - var footer = table.children('tfoot'); - var _div = '
    '; - var size = function ( s ) { - return !s ? null : _fnStringToCss( s ); - }; - - if ( ! footer.length ) { - footer = null; - } - - /* - * The HTML structure that we want to generate in this function is: - * div - scroller - * div - scroll head - * div - scroll head inner - * table - scroll head table - * thead - thead - * div - scroll body - * table - table (master table) - * thead - thead clone for sizing - * tbody - tbody - * div - scroll foot - * div - scroll foot inner - * table - scroll foot table - * tfoot - tfoot - */ - var scroller = $( _div, { 'class': classes.sScrollWrapper } ) - .append( - $(_div, { 'class': classes.sScrollHead } ) - .css( { - overflow: 'hidden', - position: 'relative', - border: 0, - width: scrollX ? size(scrollX) : '100%' - } ) - .append( - $(_div, { 'class': classes.sScrollHeadInner } ) - .css( { - 'box-sizing': 'content-box', - width: scroll.sXInner || '100%' - } ) - .append( - headerClone - .removeAttr('id') - .css( 'margin-left', 0 ) - .append( captionSide === 'top' ? caption : null ) - .append( - table.children('thead') - ) - ) - ) - ) - .append( - $(_div, { 'class': classes.sScrollBody } ) - .css( { - position: 'relative', - overflow: 'auto', - width: size( scrollX ) - } ) - .append( table ) - ); - - if ( footer ) { - scroller.append( - $(_div, { 'class': classes.sScrollFoot } ) - .css( { - overflow: 'hidden', - border: 0, - width: scrollX ? size(scrollX) : '100%' - } ) - .append( - $(_div, { 'class': classes.sScrollFootInner } ) - .append( - footerClone - .removeAttr('id') - .css( 'margin-left', 0 ) - .append( captionSide === 'bottom' ? caption : null ) - .append( - table.children('tfoot') - ) - ) - ) - ); - } - - var children = scroller.children(); - var scrollHead = children[0]; - var scrollBody = children[1]; - var scrollFoot = footer ? children[2] : null; - - // When the body is scrolled, then we also want to scroll the headers - if ( scrollX ) { - $(scrollBody).on( 'scroll.DT', function (e) { - var scrollLeft = this.scrollLeft; - - scrollHead.scrollLeft = scrollLeft; - - if ( footer ) { - scrollFoot.scrollLeft = scrollLeft; - } - } ); - } - - $(scrollBody).css( - scrollY && scroll.bCollapse ? 'max-height' : 'height', - scrollY - ); - - settings.nScrollHead = scrollHead; - settings.nScrollBody = scrollBody; - settings.nScrollFoot = scrollFoot; - - // On redraw - align columns - settings.aoDrawCallback.push( { - "fn": _fnScrollDraw, - "sName": "scrolling" - } ); - - return scroller[0]; - } - - - - /** - * Update the header, footer and body tables for resizing - i.e. column - * alignment. - * - * Welcome to the most horrible function DataTables. The process that this - * function follows is basically: - * 1. Re-create the table inside the scrolling div - * 2. Take live measurements from the DOM - * 3. Apply the measurements to align the columns - * 4. Clean up - * - * @param {object} settings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnScrollDraw ( settings ) - { - // Given that this is such a monster function, a lot of variables are use - // to try and keep the minimised size as small as possible - var - scroll = settings.oScroll, - scrollX = scroll.sX, - scrollXInner = scroll.sXInner, - scrollY = scroll.sY, - barWidth = scroll.iBarWidth, - divHeader = $(settings.nScrollHead), - divHeaderStyle = divHeader[0].style, - divHeaderInner = divHeader.children('div'), - divHeaderInnerStyle = divHeaderInner[0].style, - divHeaderTable = divHeaderInner.children('table'), - divBodyEl = settings.nScrollBody, - divBody = $(divBodyEl), - divBodyStyle = divBodyEl.style, - divFooter = $(settings.nScrollFoot), - divFooterInner = divFooter.children('div'), - divFooterTable = divFooterInner.children('table'), - header = $(settings.nTHead), - table = $(settings.nTable), - tableEl = table[0], - tableStyle = tableEl.style, - footer = settings.nTFoot ? $(settings.nTFoot) : null, - browser = settings.oBrowser, - ie67 = browser.bScrollOversize, - dtHeaderCells = _pluck( settings.aoColumns, 'nTh' ), - headerTrgEls, footerTrgEls, - headerSrcEls, footerSrcEls, - headerCopy, footerCopy, - headerWidths=[], footerWidths=[], - headerContent=[], footerContent=[], - idx, correction, sanityWidth, - zeroOut = function(nSizer) { - var style = nSizer.style; - style.paddingTop = "0"; - style.paddingBottom = "0"; - style.borderTopWidth = "0"; - style.borderBottomWidth = "0"; - style.height = 0; - }; - - // If the scrollbar visibility has changed from the last draw, we need to - // adjust the column sizes as the table width will have changed to account - // for the scrollbar - var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight; - - if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) { - settings.scrollBarVis = scrollBarVis; - _fnAdjustColumnSizing( settings ); - return; // adjust column sizing will call this function again - } - else { - settings.scrollBarVis = scrollBarVis; - } - - /* - * 1. Re-create the table inside the scrolling div - */ - - // Remove the old minimised thead and tfoot elements in the inner table - table.children('thead, tfoot').remove(); - - if ( footer ) { - footerCopy = footer.clone().prependTo( table ); - footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized - footerSrcEls = footerCopy.find('tr'); - } - - // Clone the current header and footer elements and then place it into the inner table - headerCopy = header.clone().prependTo( table ); - headerTrgEls = header.find('tr'); // original header is in its own table - headerSrcEls = headerCopy.find('tr'); - headerCopy.find('th, td').removeAttr('tabindex'); - - - /* - * 2. Take live measurements from the DOM - do not alter the DOM itself! - */ - - // Remove old sizing and apply the calculated column widths - // Get the unique column headers in the newly created (cloned) header. We want to apply the - // calculated sizes to this header - if ( ! scrollX ) - { - divBodyStyle.width = '100%'; - divHeader[0].style.width = '100%'; - } - - $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) { - idx = _fnVisibleToColumnIndex( settings, i ); - el.style.width = settings.aoColumns[idx].sWidth; - } ); - - if ( footer ) { - _fnApplyToChildren( function(n) { - n.style.width = ""; - }, footerSrcEls ); - } - - // Size the table as a whole - sanityWidth = table.outerWidth(); - if ( scrollX === "" ) { - // No x scrolling - tableStyle.width = "100%"; - - // IE7 will make the width of the table when 100% include the scrollbar - // - which is shouldn't. When there is a scrollbar we need to take this - // into account. - if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight || - divBody.css('overflow-y') == "scroll") - ) { - tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth); - } - - // Recalculate the sanity width - sanityWidth = table.outerWidth(); - } - else if ( scrollXInner !== "" ) { - // legacy x scroll inner has been given - use it - tableStyle.width = _fnStringToCss(scrollXInner); - - // Recalculate the sanity width - sanityWidth = table.outerWidth(); - } - - // Hidden header should have zero height, so remove padding and borders. Then - // set the width based on the real headers - - // Apply all styles in one pass - _fnApplyToChildren( zeroOut, headerSrcEls ); - - // Read all widths in next pass - _fnApplyToChildren( function(nSizer) { - headerContent.push( nSizer.innerHTML ); - headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); - }, headerSrcEls ); - - // Apply all widths in final pass - _fnApplyToChildren( function(nToSize, i) { - // Only apply widths to the DataTables detected header cells - this - // prevents complex headers from having contradictory sizes applied - if ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) { - nToSize.style.width = headerWidths[i]; - } - }, headerTrgEls ); - - $(headerSrcEls).height(0); - - /* Same again with the footer if we have one */ - if ( footer ) - { - _fnApplyToChildren( zeroOut, footerSrcEls ); - - _fnApplyToChildren( function(nSizer) { - footerContent.push( nSizer.innerHTML ); - footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); - }, footerSrcEls ); - - _fnApplyToChildren( function(nToSize, i) { - nToSize.style.width = footerWidths[i]; - }, footerTrgEls ); - - $(footerSrcEls).height(0); - } - - - /* - * 3. Apply the measurements - */ - - // "Hide" the header and footer that we used for the sizing. We need to keep - // the content of the cell so that the width applied to the header and body - // both match, but we want to hide it completely. We want to also fix their - // width to what they currently are - _fnApplyToChildren( function(nSizer, i) { - nSizer.innerHTML = '
    '+headerContent[i]+'
    '; - nSizer.style.width = headerWidths[i]; - }, headerSrcEls ); - - if ( footer ) - { - _fnApplyToChildren( function(nSizer, i) { - nSizer.innerHTML = '
    '+footerContent[i]+'
    '; - nSizer.style.width = footerWidths[i]; - }, footerSrcEls ); - } - - // Sanity check that the table is of a sensible width. If not then we are going to get - // misalignment - try to prevent this by not allowing the table to shrink below its min width - if ( table.outerWidth() < sanityWidth ) - { - // The min width depends upon if we have a vertical scrollbar visible or not */ - correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight || - divBody.css('overflow-y') == "scroll")) ? - sanityWidth+barWidth : - sanityWidth; - - // IE6/7 are a law unto themselves... - if ( ie67 && (divBodyEl.scrollHeight > - divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll") - ) { - tableStyle.width = _fnStringToCss( correction-barWidth ); - } - - // And give the user a warning that we've stopped the table getting too small - if ( scrollX === "" || scrollXInner !== "" ) { - _fnLog( settings, 1, 'Possible column misalignment', 6 ); - } - } - else - { - correction = '100%'; - } - - // Apply to the container elements - divBodyStyle.width = _fnStringToCss( correction ); - divHeaderStyle.width = _fnStringToCss( correction ); - - if ( footer ) { - settings.nScrollFoot.style.width = _fnStringToCss( correction ); - } - - - /* - * 4. Clean up - */ - if ( ! scrollY ) { - /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting - * the scrollbar height from the visible display, rather than adding it on. We need to - * set the height in order to sort this. Don't want to do it in any other browsers. - */ - if ( ie67 ) { - divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth ); - } - } - - /* Finally set the width's of the header and footer tables */ - var iOuterWidth = table.outerWidth(); - divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth ); - divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth ); - - // Figure out if there are scrollbar present - if so then we need a the header and footer to - // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar) - var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll"; - var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' ); - divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px"; - - if ( footer ) { - divFooterTable[0].style.width = _fnStringToCss( iOuterWidth ); - divFooterInner[0].style.width = _fnStringToCss( iOuterWidth ); - divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px"; - } - - // Correct DOM ordering for colgroup - comes before the thead - table.children('colgroup').insertBefore( table.children('thead') ); - - /* Adjust the position of the header in case we loose the y-scrollbar */ - divBody.scroll(); - - // If sorting or filtering has occurred, jump the scrolling back to the top - // only if we aren't holding the position - if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) { - divBodyEl.scrollTop = 0; - } - } - - - - /** - * Apply a given function to the display child nodes of an element array (typically - * TD children of TR rows - * @param {function} fn Method to apply to the objects - * @param array {nodes} an1 List of elements to look through for display children - * @param array {nodes} an2 Another list (identical structure to the first) - optional - * @memberof DataTable#oApi - */ - function _fnApplyToChildren( fn, an1, an2 ) - { - var index=0, i=0, iLen=an1.length; - var nNode1, nNode2; - - while ( i < iLen ) { - nNode1 = an1[i].firstChild; - nNode2 = an2 ? an2[i].firstChild : null; - - while ( nNode1 ) { - if ( nNode1.nodeType === 1 ) { - if ( an2 ) { - fn( nNode1, nNode2, index ); - } - else { - fn( nNode1, index ); - } - - index++; - } - - nNode1 = nNode1.nextSibling; - nNode2 = an2 ? nNode2.nextSibling : null; - } - - i++; - } - } - - - - var __re_html_remove = /<.*?>/g; - - - /** - * Calculate the width of columns for the table - * @param {object} oSettings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnCalculateColumnWidths ( oSettings ) - { - var - table = oSettings.nTable, - columns = oSettings.aoColumns, - scroll = oSettings.oScroll, - scrollY = scroll.sY, - scrollX = scroll.sX, - scrollXInner = scroll.sXInner, - columnCount = columns.length, - visibleColumns = _fnGetColumns( oSettings, 'bVisible' ), - headerCells = $('th', oSettings.nTHead), - tableWidthAttr = table.getAttribute('width'), // from DOM element - tableContainer = table.parentNode, - userInputs = false, - i, column, columnIdx, width, outerWidth, - browser = oSettings.oBrowser, - ie67 = browser.bScrollOversize; - - var styleWidth = table.style.width; - if ( styleWidth && styleWidth.indexOf('%') !== -1 ) { - tableWidthAttr = styleWidth; - } - - /* Convert any user input sizes into pixel sizes */ - for ( i=0 ; i').appendTo( tmpTable.find('tbody') ); - - // Clone the table header and footer - we can't use the header / footer - // from the cloned table, since if scrolling is active, the table's - // real header and footer are contained in different table tags - tmpTable.find('thead, tfoot').remove(); - tmpTable - .append( $(oSettings.nTHead).clone() ) - .append( $(oSettings.nTFoot).clone() ); - - // Remove any assigned widths from the footer (from scrolling) - tmpTable.find('tfoot th, tfoot td').css('width', ''); - - // Apply custom sizing to the cloned header - headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] ); - - for ( i=0 ; i').css( { - width: column.sWidthOrig, - margin: 0, - padding: 0, - border: 0, - height: 1 - } ) ); - } - } - - // Find the widest cell for each column and put it into the table - if ( oSettings.aoData.length ) { - for ( i=0 ; i').css( scrollX || scrollY ? - { - position: 'absolute', - top: 0, - left: 0, - height: 1, - right: 0, - overflow: 'hidden' - } : - {} - ) - .append( tmpTable ) - .appendTo( tableContainer ); - - // When scrolling (X or Y) we want to set the width of the table as - // appropriate. However, when not scrolling leave the table width as it - // is. This results in slightly different, but I think correct behaviour - if ( scrollX && scrollXInner ) { - tmpTable.width( scrollXInner ); - } - else if ( scrollX ) { - tmpTable.css( 'width', 'auto' ); - tmpTable.removeAttr('width'); - - // If there is no width attribute or style, then allow the table to - // collapse - if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) { - tmpTable.width( tableContainer.clientWidth ); - } - } - else if ( scrollY ) { - tmpTable.width( tableContainer.clientWidth ); - } - else if ( tableWidthAttr ) { - tmpTable.width( tableWidthAttr ); - } - - // Get the width of each column in the constructed table - we need to - // know the inner width (so it can be assigned to the other table's - // cells) and the outer width so we can calculate the full width of the - // table. This is safe since DataTables requires a unique cell for each - // column, but if ever a header can span multiple columns, this will - // need to be modified. - var total = 0; - for ( i=0 ; i') - .css( 'width', _fnStringToCss( width ) ) - .appendTo( parent || document.body ); - - var val = n[0].offsetWidth; - n.remove(); - - return val; - } - - - /** - * Get the widest node - * @param {object} settings dataTables settings object - * @param {int} colIdx column of interest - * @returns {node} widest table node - * @memberof DataTable#oApi - */ - function _fnGetWidestNode( settings, colIdx ) - { - var idx = _fnGetMaxLenString( settings, colIdx ); - if ( idx < 0 ) { - return null; - } - - var data = settings.aoData[ idx ]; - return ! data.nTr ? // Might not have been created when deferred rendering - $('
    ').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] : - data.anCells[ colIdx ]; - } - - - /** - * Get the maximum strlen for each data column - * @param {object} settings dataTables settings object - * @param {int} colIdx column of interest - * @returns {string} max string length for each column - * @memberof DataTable#oApi - */ - function _fnGetMaxLenString( settings, colIdx ) - { - var s, max=-1, maxIdx = -1; - - for ( var i=0, ien=settings.aoData.length ; i max ) { - max = s.length; - maxIdx = i; - } - } - - return maxIdx; - } - - - /** - * Append a CSS unit (only if required) to a string - * @param {string} value to css-ify - * @returns {string} value with css unit - * @memberof DataTable#oApi - */ - function _fnStringToCss( s ) - { - if ( s === null ) { - return '0px'; - } - - if ( typeof s == 'number' ) { - return s < 0 ? - '0px' : - s+'px'; - } - - // Check it has a unit character already - return s.match(/\d$/) ? - s+'px' : - s; - } - - - - function _fnSortFlatten ( settings ) - { - var - i, iLen, k, kLen, - aSort = [], - aiOrig = [], - aoColumns = settings.aoColumns, - aDataSort, iCol, sType, srcCol, - fixed = settings.aaSortingFixed, - fixedObj = $.isPlainObject( fixed ), - nestedSort = [], - add = function ( a ) { - if ( a.length && ! $.isArray( a[0] ) ) { - // 1D array - nestedSort.push( a ); - } - else { - // 2D array - $.merge( nestedSort, a ); - } - }; - - // Build the sort array, with pre-fix and post-fix options if they have been - // specified - if ( $.isArray( fixed ) ) { - add( fixed ); - } - - if ( fixedObj && fixed.pre ) { - add( fixed.pre ); - } - - add( settings.aaSorting ); - - if (fixedObj && fixed.post ) { - add( fixed.post ); - } - - for ( i=0 ; iy ? 1 : 0; - if ( test !== 0 ) { - return sort.dir === 'asc' ? test : -test; - } - } - - x = aiOrig[a]; - y = aiOrig[b]; - return xy ? 1 : 0; - } ); - } - else { - // Depreciated - remove in 1.11 (providing a plug-in option) - // Not all sort types have formatting methods, so we have to call their sorting - // methods. - displayMaster.sort( function ( a, b ) { - var - x, y, k, l, test, sort, fn, - len=aSort.length, - dataA = aoData[a]._aSortData, - dataB = aoData[b]._aSortData; - - for ( k=0 ; ky ? 1 : 0; - } ); - } - } - - /* Tell the draw function that we have sorted the data */ - oSettings.bSorted = true; - } - - - function _fnSortAria ( settings ) - { - var label; - var nextSort; - var columns = settings.aoColumns; - var aSort = _fnSortFlatten( settings ); - var oAria = settings.oLanguage.oAria; - - // ARIA attributes - need to loop all columns, to update all (removing old - // attributes as needed) - for ( var i=0, iLen=columns.length ; i/g, "" ); - var th = col.nTh; - - // IE7 is throwing an error when setting these properties with jQuery's - // attr() and removeAttr() methods... - th.removeAttribute('aria-sort'); - - /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */ - if ( col.bSortable ) { - if ( aSort.length > 0 && aSort[0].col == i ) { - th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" ); - nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0]; - } - else { - nextSort = asSorting[0]; - } - - label = sTitle + ( nextSort === "asc" ? - oAria.sSortAscending : - oAria.sSortDescending - ); - } - else { - label = sTitle; - } - - th.setAttribute('aria-label', label); - } - } - - - /** - * Function to run on user sort request - * @param {object} settings dataTables settings object - * @param {node} attachTo node to attach the handler to - * @param {int} colIdx column sorting index - * @param {boolean} [append=false] Append the requested sort to the existing - * sort if true (i.e. multi-column sort) - * @param {function} [callback] callback function - * @memberof DataTable#oApi - */ - function _fnSortListener ( settings, colIdx, append, callback ) - { - var col = settings.aoColumns[ colIdx ]; - var sorting = settings.aaSorting; - var asSorting = col.asSorting; - var nextSortIdx; - var next = function ( a, overflow ) { - var idx = a._idx; - if ( idx === undefined ) { - idx = $.inArray( a[1], asSorting ); - } - - return idx+1 < asSorting.length ? - idx+1 : - overflow ? - null : - 0; - }; - - // Convert to 2D array if needed - if ( typeof sorting[0] === 'number' ) { - sorting = settings.aaSorting = [ sorting ]; - } - - // If appending the sort then we are multi-column sorting - if ( append && settings.oFeatures.bSortMulti ) { - // Are we already doing some kind of sort on this column? - var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') ); - - if ( sortIdx !== -1 ) { - // Yes, modify the sort - nextSortIdx = next( sorting[sortIdx], true ); - - if ( nextSortIdx === null && sorting.length === 1 ) { - nextSortIdx = 0; // can't remove sorting completely - } - - if ( nextSortIdx === null ) { - sorting.splice( sortIdx, 1 ); - } - else { - sorting[sortIdx][1] = asSorting[ nextSortIdx ]; - sorting[sortIdx]._idx = nextSortIdx; - } - } - else { - // No sort on this column yet - sorting.push( [ colIdx, asSorting[0], 0 ] ); - sorting[sorting.length-1]._idx = 0; - } - } - else if ( sorting.length && sorting[0][0] == colIdx ) { - // Single column - already sorting on this column, modify the sort - nextSortIdx = next( sorting[0] ); - - sorting.length = 1; - sorting[0][1] = asSorting[ nextSortIdx ]; - sorting[0]._idx = nextSortIdx; - } - else { - // Single column - sort only on this column - sorting.length = 0; - sorting.push( [ colIdx, asSorting[0] ] ); - sorting[0]._idx = 0; - } - - // Run the sort by calling a full redraw - _fnReDraw( settings ); - - // callback used for async user interaction - if ( typeof callback == 'function' ) { - callback( settings ); - } - } - - - /** - * Attach a sort handler (click) to a node - * @param {object} settings dataTables settings object - * @param {node} attachTo node to attach the handler to - * @param {int} colIdx column sorting index - * @param {function} [callback] callback function - * @memberof DataTable#oApi - */ - function _fnSortAttachListener ( settings, attachTo, colIdx, callback ) - { - var col = settings.aoColumns[ colIdx ]; - - _fnBindAction( attachTo, {}, function (e) { - /* If the column is not sortable - don't to anything */ - if ( col.bSortable === false ) { - return; - } - - // If processing is enabled use a timeout to allow the processing - // display to be shown - otherwise to it synchronously - if ( settings.oFeatures.bProcessing ) { - _fnProcessingDisplay( settings, true ); - - setTimeout( function() { - _fnSortListener( settings, colIdx, e.shiftKey, callback ); - - // In server-side processing, the draw callback will remove the - // processing display - if ( _fnDataSource( settings ) !== 'ssp' ) { - _fnProcessingDisplay( settings, false ); - } - }, 0 ); - } - else { - _fnSortListener( settings, colIdx, e.shiftKey, callback ); - } - } ); - } - - - /** - * Set the sorting classes on table's body, Note: it is safe to call this function - * when bSort and bSortClasses are false - * @param {object} oSettings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnSortingClasses( settings ) - { - var oldSort = settings.aLastSort; - var sortClass = settings.oClasses.sSortColumn; - var sort = _fnSortFlatten( settings ); - var features = settings.oFeatures; - var i, ien, colIdx; - - if ( features.bSort && features.bSortClasses ) { - // Remove old sorting classes - for ( i=0, ien=oldSort.length ; i 0 && s.time < +new Date() - (duration*1000) ) { - callback(); - return; - } - - // Number of columns have changed - all bets are off, no restore of settings - if ( s.columns && columns.length !== s.columns.length ) { - callback(); - return; - } - - // Store the saved state so it might be accessed at any time - settings.oLoadedState = $.extend( true, {}, s ); - - // Restore key features - todo - for 1.11 this needs to be done by - // subscribed events - if ( s.start !== undefined ) { - settings._iDisplayStart = s.start; - settings.iInitDisplayStart = s.start; - } - if ( s.length !== undefined ) { - settings._iDisplayLength = s.length; - } - - // Order - if ( s.order !== undefined ) { - settings.aaSorting = []; - $.each( s.order, function ( i, col ) { - settings.aaSorting.push( col[0] >= columns.length ? - [ 0, col[1] ] : - col - ); - } ); - } - - // Search - if ( s.search !== undefined ) { - $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) ); - } - - // Columns - // - if ( s.columns ) { - for ( i=0, ien=s.columns.length ; i= end ) - { - start = end - len; - } - - // Keep the start record on the current page - start -= (start % len); - - if ( len === -1 || start < 0 ) - { - start = 0; - } - - settings._iDisplayStart = start; - } - - - function _fnRenderer( settings, type ) - { - var renderer = settings.renderer; - var host = DataTable.ext.renderer[type]; - - if ( $.isPlainObject( renderer ) && renderer[type] ) { - // Specific renderer for this type. If available use it, otherwise use - // the default. - return host[renderer[type]] || host._; - } - else if ( typeof renderer === 'string' ) { - // Common renderer - if there is one available for this type use it, - // otherwise use the default - return host[renderer] || host._; - } - - // Use the default - return host._; - } - - - /** - * Detect the data source being used for the table. Used to simplify the code - * a little (ajax) and to make it compress a little smaller. - * - * @param {object} settings dataTables settings object - * @returns {string} Data source - * @memberof DataTable#oApi - */ - function _fnDataSource ( settings ) - { - if ( settings.oFeatures.bServerSide ) { - return 'ssp'; - } - else if ( settings.ajax || settings.sAjaxSource ) { - return 'ajax'; - } - return 'dom'; - } - - - - - /** - * Computed structure of the DataTables API, defined by the options passed to - * `DataTable.Api.register()` when building the API. - * - * The structure is built in order to speed creation and extension of the Api - * objects since the extensions are effectively pre-parsed. - * - * The array is an array of objects with the following structure, where this - * base array represents the Api prototype base: - * - * [ - * { - * name: 'data' -- string - Property name - * val: function () {}, -- function - Api method (or undefined if just an object - * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result - * propExt: [ ... ] -- array - Array of Api object definitions to extend the property - * }, - * { - * name: 'row' - * val: {}, - * methodExt: [ ... ], - * propExt: [ - * { - * name: 'data' - * val: function () {}, - * methodExt: [ ... ], - * propExt: [ ... ] - * }, - * ... - * ] - * } - * ] - * - * @type {Array} - * @ignore - */ - var __apiStruct = []; - - - /** - * `Array.prototype` reference. - * - * @type object - * @ignore - */ - var __arrayProto = Array.prototype; - - - /** - * Abstraction for `context` parameter of the `Api` constructor to allow it to - * take several different forms for ease of use. - * - * Each of the input parameter types will be converted to a DataTables settings - * object where possible. - * - * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one - * of: - * - * * `string` - jQuery selector. Any DataTables' matching the given selector - * with be found and used. - * * `node` - `TABLE` node which has already been formed into a DataTable. - * * `jQuery` - A jQuery object of `TABLE` nodes. - * * `object` - DataTables settings object - * * `DataTables.Api` - API instance - * @return {array|null} Matching DataTables settings objects. `null` or - * `undefined` is returned if no matching DataTable is found. - * @ignore - */ - var _toSettings = function ( mixed ) - { - var idx, jq; - var settings = DataTable.settings; - var tables = $.map( settings, function (el, i) { - return el.nTable; - } ); - - if ( ! mixed ) { - return []; - } - else if ( mixed.nTable && mixed.oApi ) { - // DataTables settings object - return [ mixed ]; - } - else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) { - // Table node - idx = $.inArray( mixed, tables ); - return idx !== -1 ? [ settings[idx] ] : null; - } - else if ( mixed && typeof mixed.settings === 'function' ) { - return mixed.settings().toArray(); - } - else if ( typeof mixed === 'string' ) { - // jQuery selector - jq = $(mixed); - } - else if ( mixed instanceof $ ) { - // jQuery object (also DataTables instance) - jq = mixed; - } - - if ( jq ) { - return jq.map( function(i) { - idx = $.inArray( this, tables ); - return idx !== -1 ? settings[idx] : null; - } ).toArray(); - } - }; - - - /** - * DataTables API class - used to control and interface with one or more - * DataTables enhanced tables. - * - * The API class is heavily based on jQuery, presenting a chainable interface - * that you can use to interact with tables. Each instance of the API class has - * a "context" - i.e. the tables that it will operate on. This could be a single - * table, all tables on a page or a sub-set thereof. - * - * Additionally the API is designed to allow you to easily work with the data in - * the tables, retrieving and manipulating it as required. This is done by - * presenting the API class as an array like interface. The contents of the - * array depend upon the actions requested by each method (for example - * `rows().nodes()` will return an array of nodes, while `rows().data()` will - * return an array of objects or arrays depending upon your table's - * configuration). The API object has a number of array like methods (`push`, - * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`, - * `unique` etc) to assist your working with the data held in a table. - * - * Most methods (those which return an Api instance) are chainable, which means - * the return from a method call also has all of the methods available that the - * top level object had. For example, these two calls are equivalent: - * - * // Not chained - * api.row.add( {...} ); - * api.draw(); - * - * // Chained - * api.row.add( {...} ).draw(); - * - * @class DataTable.Api - * @param {array|object|string|jQuery} context DataTable identifier. This is - * used to define which DataTables enhanced tables this API will operate on. - * Can be one of: - * - * * `string` - jQuery selector. Any DataTables' matching the given selector - * with be found and used. - * * `node` - `TABLE` node which has already been formed into a DataTable. - * * `jQuery` - A jQuery object of `TABLE` nodes. - * * `object` - DataTables settings object - * @param {array} [data] Data to initialise the Api instance with. - * - * @example - * // Direct initialisation during DataTables construction - * var api = $('#example').DataTable(); - * - * @example - * // Initialisation using a DataTables jQuery object - * var api = $('#example').dataTable().api(); - * - * @example - * // Initialisation as a constructor - * var api = new $.fn.DataTable.Api( 'table.dataTable' ); - */ - _Api = function ( context, data ) - { - if ( ! (this instanceof _Api) ) { - return new _Api( context, data ); - } - - var settings = []; - var ctxSettings = function ( o ) { - var a = _toSettings( o ); - if ( a ) { - settings = settings.concat( a ); - } - }; - - if ( $.isArray( context ) ) { - for ( var i=0, ien=context.length ; i idx ? - new _Api( ctx[idx], this[idx] ) : - null; - }, - - - filter: function ( fn ) - { - var a = []; - - if ( __arrayProto.filter ) { - a = __arrayProto.filter.call( this, fn, this ); - } - else { - // Compatibility for browsers without EMCA-252-5 (JS 1.6) - for ( var i=0, ien=this.length ; i 0 ) { - return ctx[0].json; - } - - // else return undefined; - } ); - - - /** - * Get the data submitted in the last Ajax request - */ - _api_register( 'ajax.params()', function () { - var ctx = this.context; - - if ( ctx.length > 0 ) { - return ctx[0].oAjaxData; - } - - // else return undefined; - } ); - - - /** - * Reload tables from the Ajax data source. Note that this function will - * automatically re-draw the table when the remote data has been loaded. - * - * @param {boolean} [reset=true] Reset (default) or hold the current paging - * position. A full re-sort and re-filter is performed when this method is - * called, which is why the pagination reset is the default action. - * @returns {DataTables.Api} this - */ - _api_register( 'ajax.reload()', function ( callback, resetPaging ) { - return this.iterator( 'table', function (settings) { - __reload( settings, resetPaging===false, callback ); - } ); - } ); - - - /** - * Get the current Ajax URL. Note that this returns the URL from the first - * table in the current context. - * - * @return {string} Current Ajax source URL - *//** - * Set the Ajax URL. Note that this will set the URL for all tables in the - * current context. - * - * @param {string} url URL to set. - * @returns {DataTables.Api} this - */ - _api_register( 'ajax.url()', function ( url ) { - var ctx = this.context; - - if ( url === undefined ) { - // get - if ( ctx.length === 0 ) { - return undefined; - } - ctx = ctx[0]; - - return ctx.ajax ? - $.isPlainObject( ctx.ajax ) ? - ctx.ajax.url : - ctx.ajax : - ctx.sAjaxSource; - } - - // set - return this.iterator( 'table', function ( settings ) { - if ( $.isPlainObject( settings.ajax ) ) { - settings.ajax.url = url; - } - else { - settings.ajax = url; - } - // No need to consider sAjaxSource here since DataTables gives priority - // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any - // value of `sAjaxSource` redundant. - } ); - } ); - - - /** - * Load data from the newly set Ajax URL. Note that this method is only - * available when `ajax.url()` is used to set a URL. Additionally, this method - * has the same effect as calling `ajax.reload()` but is provided for - * convenience when setting a new URL. Like `ajax.reload()` it will - * automatically redraw the table once the remote data has been loaded. - * - * @returns {DataTables.Api} this - */ - _api_register( 'ajax.url().load()', function ( callback, resetPaging ) { - // Same as a reload, but makes sense to present it for easy access after a - // url change - return this.iterator( 'table', function ( ctx ) { - __reload( ctx, resetPaging===false, callback ); - } ); - } ); - - - - - var _selector_run = function ( type, selector, selectFn, settings, opts ) - { - var - out = [], res, - a, i, ien, j, jen, - selectorType = typeof selector; - - // Can't just check for isArray here, as an API or jQuery instance might be - // given with their array like look - if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) { - selector = [ selector ]; - } - - for ( i=0, ien=selector.length ; i 0 ) { - // Assign the first element to the first item in the instance - // and truncate the instance and context - inst[0] = inst[i]; - inst[0].length = 1; - inst.length = 1; - inst.context = [ inst.context[i] ]; - - return inst; - } - } - - // Not found - return an empty instance - inst.length = 0; - return inst; - }; - - - var _selector_row_indexes = function ( settings, opts ) - { - var - i, ien, tmp, a=[], - displayFiltered = settings.aiDisplay, - displayMaster = settings.aiDisplayMaster; - - var - search = opts.search, // none, applied, removed - order = opts.order, // applied, current, index (original - compatibility with 1.9) - page = opts.page; // all, current - - if ( _fnDataSource( settings ) == 'ssp' ) { - // In server-side processing mode, most options are irrelevant since - // rows not shown don't exist and the index order is the applied order - // Removed is a special case - for consistency just return an empty - // array - return search === 'removed' ? - [] : - _range( 0, displayMaster.length ); - } - else if ( page == 'current' ) { - // Current page implies that order=current and fitler=applied, since it is - // fairly senseless otherwise, regardless of what order and search actually - // are - for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i= 0 && search == 'applied') ) - { - a.push( i ); - } - } - } - } - - return a; - }; - - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Rows - * - * {} - no selector - use all available rows - * {integer} - row aoData index - * {node} - TR node - * {string} - jQuery selector to apply to the TR elements - * {array} - jQuery array of nodes, or simply an array of TR nodes - * - */ - - - var __row_selector = function ( settings, selector, opts ) - { - var rows; - var run = function ( sel ) { - var selInt = _intVal( sel ); - var i, ien; - - // Short cut - selector is a number and no options provided (default is - // all records, so no need to check if the index is in there, since it - // must be - dev error if the index doesn't exist). - if ( selInt !== null && ! opts ) { - return [ selInt ]; - } - - if ( ! rows ) { - rows = _selector_row_indexes( settings, opts ); - } - - if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) { - // Selector - integer - return [ selInt ]; - } - else if ( sel === null || sel === undefined || sel === '' ) { - // Selector - none - return rows; - } - - // Selector - function - if ( typeof sel === 'function' ) { - return $.map( rows, function (idx) { - var row = settings.aoData[ idx ]; - return sel( idx, row._aData, row.nTr ) ? idx : null; - } ); - } - - // Get nodes in the order from the `rows` array with null values removed - var nodes = _removeEmpty( - _pluck_order( settings.aoData, rows, 'nTr' ) - ); - - // Selector - node - if ( sel.nodeName ) { - if ( sel._DT_RowIndex !== undefined ) { - return [ sel._DT_RowIndex ]; // Property added by DT for fast lookup - } - else if ( sel._DT_CellIndex ) { - return [ sel._DT_CellIndex.row ]; - } - else { - var host = $(sel).closest('*[data-dt-row]'); - return host.length ? - [ host.data('dt-row') ] : - []; - } - } - - // ID selector. Want to always be able to select rows by id, regardless - // of if the tr element has been created or not, so can't rely upon - // jQuery here - hence a custom implementation. This does not match - // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything, - // but to select it using a CSS selector engine (like Sizzle or - // querySelect) it would need to need to be escaped for some characters. - // DataTables simplifies this for row selectors since you can select - // only a row. A # indicates an id any anything that follows is the id - - // unescaped. - if ( typeof sel === 'string' && sel.charAt(0) === '#' ) { - // get row index from id - var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ]; - if ( rowObj !== undefined ) { - return [ rowObj.idx ]; - } - - // need to fall through to jQuery in case there is DOM id that - // matches - } - - // Selector - jQuery selector string, array of nodes or jQuery object/ - // As jQuery's .filter() allows jQuery objects to be passed in filter, - // it also allows arrays, so this will cope with all three options - return $(nodes) - .filter( sel ) - .map( function () { - return this._DT_RowIndex; - } ) - .toArray(); - }; - - return _selector_run( 'row', selector, run, settings, opts ); - }; - - - _api_register( 'rows()', function ( selector, opts ) { - // argument shifting - if ( selector === undefined ) { - selector = ''; - } - else if ( $.isPlainObject( selector ) ) { - opts = selector; - selector = ''; - } - - opts = _selector_opts( opts ); - - var inst = this.iterator( 'table', function ( settings ) { - return __row_selector( settings, selector, opts ); - }, 1 ); - - // Want argument shifting here and in __row_selector? - inst.selector.rows = selector; - inst.selector.opts = opts; - - return inst; - } ); - - _api_register( 'rows().nodes()', function () { - return this.iterator( 'row', function ( settings, row ) { - return settings.aoData[ row ].nTr || undefined; - }, 1 ); - } ); - - _api_register( 'rows().data()', function () { - return this.iterator( true, 'rows', function ( settings, rows ) { - return _pluck_order( settings.aoData, rows, '_aData' ); - }, 1 ); - } ); - - _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) { - return this.iterator( 'row', function ( settings, row ) { - var r = settings.aoData[ row ]; - return type === 'search' ? r._aFilterData : r._aSortData; - }, 1 ); - } ); - - _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) { - return this.iterator( 'row', function ( settings, row ) { - _fnInvalidate( settings, row, src ); - } ); - } ); - - _api_registerPlural( 'rows().indexes()', 'row().index()', function () { - return this.iterator( 'row', function ( settings, row ) { - return row; - }, 1 ); - } ); - - _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) { - var a = []; - var context = this.context; - - // `iterator` will drop undefined values, but in this case we want them - for ( var i=0, ien=context.length ; i
    ` node is a DataTable table already or not. - * - * @param {node|jquery|string} table Table node, jQuery object or jQuery - * selector for the table to test. Note that if more than more than one - * table is passed on, only the first will be checked - * @returns {boolean} true the table given is a DataTable, or false otherwise - * @static - * @dtopt API-Static - * - * @example - * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) { - * $('#example').dataTable(); - * } - */ - DataTable.isDataTable = DataTable.fnIsDataTable = function ( table ) - { - var t = $(table).get(0); - var is = false; - - if ( table instanceof DataTable.Api ) { - return true; - } - - $.each( DataTable.settings, function (i, o) { - var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null; - var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null; - - if ( o.nTable === t || head === t || foot === t ) { - is = true; - } - } ); - - return is; - }; - - - /** - * Get all DataTable tables that have been initialised - optionally you can - * select to get only currently visible tables. - * - * @param {boolean} [visible=false] Flag to indicate if you want all (default) - * or visible tables only. - * @returns {array} Array of `table` nodes (not DataTable instances) which are - * DataTables - * @static - * @dtopt API-Static - * - * @example - * $.each( $.fn.dataTable.tables(true), function () { - * $(table).DataTable().columns.adjust(); - * } ); - */ - DataTable.tables = DataTable.fnTables = function ( visible ) - { - var api = false; - - if ( $.isPlainObject( visible ) ) { - api = visible.api; - visible = visible.visible; - } - - var a = $.map( DataTable.settings, function (o) { - if ( !visible || (visible && $(o.nTable).is(':visible')) ) { - return o.nTable; - } - } ); - - return api ? - new _Api( a ) : - a; - }; - - - /** - * Convert from camel case parameters to Hungarian notation. This is made public - * for the extensions to provide the same ability as DataTables core to accept - * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase - * parameters. - * - * @param {object} src The model object which holds all parameters that can be - * mapped. - * @param {object} user The object to convert from camel case to Hungarian. - * @param {boolean} force When set to `true`, properties which already have a - * Hungarian value in the `user` object will be overwritten. Otherwise they - * won't be. - */ - DataTable.camelToHungarian = _fnCamelToHungarian; - - - - /** - * - */ - _api_register( '$()', function ( selector, opts ) { - var - rows = this.rows( opts ).nodes(), // Get all rows - jqRows = $(rows); - - return $( [].concat( - jqRows.filter( selector ).toArray(), - jqRows.find( selector ).toArray() - ) ); - } ); - - - // jQuery functions to operate on the tables - $.each( [ 'on', 'one', 'off' ], function (i, key) { - _api_register( key+'()', function ( /* event, handler */ ) { - var args = Array.prototype.slice.call(arguments); - - // Add the `dt` namespace automatically if it isn't already present - args[0] = $.map( args[0].split( /\s/ ), function ( e ) { - return ! e.match(/\.dt\b/) ? - e+'.dt' : - e; - } ).join( ' ' ); - - var inst = $( this.tables().nodes() ); - inst[key].apply( inst, args ); - return this; - } ); - } ); - - - _api_register( 'clear()', function () { - return this.iterator( 'table', function ( settings ) { - _fnClearTable( settings ); - } ); - } ); - - - _api_register( 'settings()', function () { - return new _Api( this.context, this.context ); - } ); - - - _api_register( 'init()', function () { - var ctx = this.context; - return ctx.length ? ctx[0].oInit : null; - } ); - - - _api_register( 'data()', function () { - return this.iterator( 'table', function ( settings ) { - return _pluck( settings.aoData, '_aData' ); - } ).flatten(); - } ); - - - _api_register( 'destroy()', function ( remove ) { - remove = remove || false; - - return this.iterator( 'table', function ( settings ) { - var orig = settings.nTableWrapper.parentNode; - var classes = settings.oClasses; - var table = settings.nTable; - var tbody = settings.nTBody; - var thead = settings.nTHead; - var tfoot = settings.nTFoot; - var jqTable = $(table); - var jqTbody = $(tbody); - var jqWrapper = $(settings.nTableWrapper); - var rows = $.map( settings.aoData, function (r) { return r.nTr; } ); - var i, ien; - - // Flag to note that the table is currently being destroyed - no action - // should be taken - settings.bDestroying = true; - - // Fire off the destroy callbacks for plug-ins etc - _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] ); - - // If not being removed from the document, make all columns visible - if ( ! remove ) { - new _Api( settings ).columns().visible( true ); - } - - // Blitz all `DT` namespaced events (these are internal events, the - // lowercase, `dt` events are user subscribed and they are responsible - // for removing them - jqWrapper.off('.DT').find(':not(tbody *)').off('.DT'); - $(window).off('.DT-'+settings.sInstance); - - // When scrolling we had to break the table up - restore it - if ( table != thead.parentNode ) { - jqTable.children('thead').detach(); - jqTable.append( thead ); - } - - if ( tfoot && table != tfoot.parentNode ) { - jqTable.children('tfoot').detach(); - jqTable.append( tfoot ); - } - - settings.aaSorting = []; - settings.aaSortingFixed = []; - _fnSortingClasses( settings ); - - $( rows ).removeClass( settings.asStripeClasses.join(' ') ); - - $('th, td', thead).removeClass( classes.sSortable+' '+ - classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone - ); - - if ( settings.bJUI ) { - $('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach(); - $('th, td', thead).each( function () { - var wrapper = $('div.'+classes.sSortJUIWrapper, this); - $(this).append( wrapper.contents() ); - wrapper.detach(); - } ); - } - - // Add the TR elements back into the table in their original order - jqTbody.children().detach(); - jqTbody.append( rows ); - - // Remove the DataTables generated nodes, events and classes - var removedMethod = remove ? 'remove' : 'detach'; - jqTable[ removedMethod ](); - jqWrapper[ removedMethod ](); - - // If we need to reattach the table to the document - if ( ! remove && orig ) { - // insertBefore acts like appendChild if !arg[1] - orig.insertBefore( table, settings.nTableReinsertBefore ); - - // Restore the width of the original table - was read from the style property, - // so we can restore directly to that - jqTable - .css( 'width', settings.sDestroyWidth ) - .removeClass( classes.sTable ); - - // If the were originally stripe classes - then we add them back here. - // Note this is not fool proof (for example if not all rows had stripe - // classes - but it's a good effort without getting carried away - ien = settings.asDestroyStripes.length; - - if ( ien ) { - jqTbody.children().each( function (i) { - $(this).addClass( settings.asDestroyStripes[i % ien] ); - } ); - } - } - - /* Remove the settings object from the settings array */ - var idx = $.inArray( settings, DataTable.settings ); - if ( idx !== -1 ) { - DataTable.settings.splice( idx, 1 ); - } - } ); - } ); - - - // Add the `every()` method for rows, columns and cells in a compact form - $.each( [ 'column', 'row', 'cell' ], function ( i, type ) { - _api_register( type+'s().every()', function ( fn ) { - var opts = this.selector.opts; - var api = this; - - return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) { - // Rows and columns: - // arg1 - index - // arg2 - table counter - // arg3 - loop counter - // arg4 - undefined - // Cells: - // arg1 - row index - // arg2 - column index - // arg3 - table counter - // arg4 - loop counter - fn.call( - api[ type ]( - arg1, - type==='cell' ? arg2 : opts, - type==='cell' ? opts : undefined - ), - arg1, arg2, arg3, arg4 - ); - } ); - } ); - } ); - - - // i18n method for extensions to be able to use the language object from the - // DataTable - _api_register( 'i18n()', function ( token, def, plural ) { - var ctx = this.context[0]; - var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage ); - - if ( resolved === undefined ) { - resolved = def; - } - - if ( plural !== undefined && $.isPlainObject( resolved ) ) { - resolved = resolved[ plural ] !== undefined ? - resolved[ plural ] : - resolved._; - } - - return resolved.replace( '%d', plural ); // nb: plural might be undefined, - } ); - - /** - * Version string for plug-ins to check compatibility. Allowed format is - * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used - * only for non-release builds. See http://semver.org/ for more information. - * @member - * @type string - * @default Version number - */ - DataTable.version = "1.10.15"; - - /** - * Private data store, containing all of the settings objects that are - * created for the tables on a given page. - * - * Note that the `DataTable.settings` object is aliased to - * `jQuery.fn.dataTableExt` through which it may be accessed and - * manipulated, or `jQuery.fn.dataTable.settings`. - * @member - * @type array - * @default [] - * @private - */ - DataTable.settings = []; - - /** - * Object models container, for the various models that DataTables has - * available to it. These models define the objects that are used to hold - * the active state and configuration of the table. - * @namespace - */ - DataTable.models = {}; - - - - /** - * Template object for the way in which DataTables holds information about - * search information for the global filter and individual column filters. - * @namespace - */ - DataTable.models.oSearch = { - /** - * Flag to indicate if the filtering should be case insensitive or not - * @type boolean - * @default true - */ - "bCaseInsensitive": true, - - /** - * Applied search term - * @type string - * @default Empty string - */ - "sSearch": "", - - /** - * Flag to indicate if the search term should be interpreted as a - * regular expression (true) or not (false) and therefore and special - * regex characters escaped. - * @type boolean - * @default false - */ - "bRegex": false, - - /** - * Flag to indicate if DataTables is to use its smart filtering or not. - * @type boolean - * @default true - */ - "bSmart": true - }; - - - - - /** - * Template object for the way in which DataTables holds information about - * each individual row. This is the object format used for the settings - * aoData array. - * @namespace - */ - DataTable.models.oRow = { - /** - * TR element for the row - * @type node - * @default null - */ - "nTr": null, - - /** - * Array of TD elements for each row. This is null until the row has been - * created. - * @type array nodes - * @default [] - */ - "anCells": null, - - /** - * Data object from the original data source for the row. This is either - * an array if using the traditional form of DataTables, or an object if - * using mData options. The exact type will depend on the passed in - * data from the data source, or will be an array if using DOM a data - * source. - * @type array|object - * @default [] - */ - "_aData": [], - - /** - * Sorting data cache - this array is ostensibly the same length as the - * number of columns (although each index is generated only as it is - * needed), and holds the data that is used for sorting each column in the - * row. We do this cache generation at the start of the sort in order that - * the formatting of the sort data need be done only once for each cell - * per sort. This array should not be read from or written to by anything - * other than the master sorting methods. - * @type array - * @default null - * @private - */ - "_aSortData": null, - - /** - * Per cell filtering data cache. As per the sort data cache, used to - * increase the performance of the filtering in DataTables - * @type array - * @default null - * @private - */ - "_aFilterData": null, - - /** - * Filtering data cache. This is the same as the cell filtering cache, but - * in this case a string rather than an array. This is easily computed with - * a join on `_aFilterData`, but is provided as a cache so the join isn't - * needed on every search (memory traded for performance) - * @type array - * @default null - * @private - */ - "_sFilterRow": null, - - /** - * Cache of the class name that DataTables has applied to the row, so we - * can quickly look at this variable rather than needing to do a DOM check - * on className for the nTr property. - * @type string - * @default Empty string - * @private - */ - "_sRowStripe": "", - - /** - * Denote if the original data source was from the DOM, or the data source - * object. This is used for invalidating data, so DataTables can - * automatically read data from the original source, unless uninstructed - * otherwise. - * @type string - * @default null - * @private - */ - "src": null, - - /** - * Index in the aoData array. This saves an indexOf lookup when we have the - * object, but want to know the index - * @type integer - * @default -1 - * @private - */ - "idx": -1 - }; - - - /** - * Template object for the column information object in DataTables. This object - * is held in the settings aoColumns array and contains all the information that - * DataTables needs about each individual column. - * - * Note that this object is related to {@link DataTable.defaults.column} - * but this one is the internal data store for DataTables's cache of columns. - * It should NOT be manipulated outside of DataTables. Any configuration should - * be done through the initialisation options. - * @namespace - */ - DataTable.models.oColumn = { - /** - * Column index. This could be worked out on-the-fly with $.inArray, but it - * is faster to just hold it as a variable - * @type integer - * @default null - */ - "idx": null, - - /** - * A list of the columns that sorting should occur on when this column - * is sorted. That this property is an array allows multi-column sorting - * to be defined for a column (for example first name / last name columns - * would benefit from this). The values are integers pointing to the - * columns to be sorted on (typically it will be a single integer pointing - * at itself, but that doesn't need to be the case). - * @type array - */ - "aDataSort": null, - - /** - * Define the sorting directions that are applied to the column, in sequence - * as the column is repeatedly sorted upon - i.e. the first value is used - * as the sorting direction when the column if first sorted (clicked on). - * Sort it again (click again) and it will move on to the next index. - * Repeat until loop. - * @type array - */ - "asSorting": null, - - /** - * Flag to indicate if the column is searchable, and thus should be included - * in the filtering or not. - * @type boolean - */ - "bSearchable": null, - - /** - * Flag to indicate if the column is sortable or not. - * @type boolean - */ - "bSortable": null, - - /** - * Flag to indicate if the column is currently visible in the table or not - * @type boolean - */ - "bVisible": null, - - /** - * Store for manual type assignment using the `column.type` option. This - * is held in store so we can manipulate the column's `sType` property. - * @type string - * @default null - * @private - */ - "_sManualType": null, - - /** - * Flag to indicate if HTML5 data attributes should be used as the data - * source for filtering or sorting. True is either are. - * @type boolean - * @default false - * @private - */ - "_bAttrSrc": false, - - /** - * Developer definable function that is called whenever a cell is created (Ajax source, - * etc) or processed for input (DOM source). This can be used as a compliment to mRender - * allowing you to modify the DOM element (add background colour for example) when the - * element is available. - * @type function - * @param {element} nTd The TD node that has been created - * @param {*} sData The Data for the cell - * @param {array|object} oData The data for the whole row - * @param {int} iRow The row index for the aoData data store - * @default null - */ - "fnCreatedCell": null, - - /** - * Function to get data from a cell in a column. You should never - * access data directly through _aData internally in DataTables - always use - * the method attached to this property. It allows mData to function as - * required. This function is automatically assigned by the column - * initialisation method - * @type function - * @param {array|object} oData The data array/object for the array - * (i.e. aoData[]._aData) - * @param {string} sSpecific The specific data type you want to get - - * 'display', 'type' 'filter' 'sort' - * @returns {*} The data for the cell from the given row's data - * @default null - */ - "fnGetData": null, - - /** - * Function to set data for a cell in the column. You should never - * set the data directly to _aData internally in DataTables - always use - * this method. It allows mData to function as required. This function - * is automatically assigned by the column initialisation method - * @type function - * @param {array|object} oData The data array/object for the array - * (i.e. aoData[]._aData) - * @param {*} sValue Value to set - * @default null - */ - "fnSetData": null, - - /** - * Property to read the value for the cells in the column from the data - * source array / object. If null, then the default content is used, if a - * function is given then the return from the function is used. - * @type function|int|string|null - * @default null - */ - "mData": null, - - /** - * Partner property to mData which is used (only when defined) to get - * the data - i.e. it is basically the same as mData, but without the - * 'set' option, and also the data fed to it is the result from mData. - * This is the rendering method to match the data method of mData. - * @type function|int|string|null - * @default null - */ - "mRender": null, - - /** - * Unique header TH/TD element for this column - this is what the sorting - * listener is attached to (if sorting is enabled.) - * @type node - * @default null - */ - "nTh": null, - - /** - * Unique footer TH/TD element for this column (if there is one). Not used - * in DataTables as such, but can be used for plug-ins to reference the - * footer for each column. - * @type node - * @default null - */ - "nTf": null, - - /** - * The class to apply to all TD elements in the table's TBODY for the column - * @type string - * @default null - */ - "sClass": null, - - /** - * When DataTables calculates the column widths to assign to each column, - * it finds the longest string in each column and then constructs a - * temporary table and reads the widths from that. The problem with this - * is that "mmm" is much wider then "iiii", but the latter is a longer - * string - thus the calculation can go wrong (doing it properly and putting - * it into an DOM object and measuring that is horribly(!) slow). Thus as - * a "work around" we provide this option. It will append its value to the - * text that is found to be the longest string for the column - i.e. padding. - * @type string - */ - "sContentPadding": null, - - /** - * Allows a default value to be given for a column's data, and will be used - * whenever a null data source is encountered (this can be because mData - * is set to null, or because the data source itself is null). - * @type string - * @default null - */ - "sDefaultContent": null, - - /** - * Name for the column, allowing reference to the column by name as well as - * by index (needs a lookup to work by name). - * @type string - */ - "sName": null, - - /** - * Custom sorting data type - defines which of the available plug-ins in - * afnSortData the custom sorting will use - if any is defined. - * @type string - * @default std - */ - "sSortDataType": 'std', - - /** - * Class to be applied to the header element when sorting on this column - * @type string - * @default null - */ - "sSortingClass": null, - - /** - * Class to be applied to the header element when sorting on this column - - * when jQuery UI theming is used. - * @type string - * @default null - */ - "sSortingClassJUI": null, - - /** - * Title of the column - what is seen in the TH element (nTh). - * @type string - */ - "sTitle": null, - - /** - * Column sorting and filtering type - * @type string - * @default null - */ - "sType": null, - - /** - * Width of the column - * @type string - * @default null - */ - "sWidth": null, - - /** - * Width of the column when it was first "encountered" - * @type string - * @default null - */ - "sWidthOrig": null - }; - - - /* - * Developer note: The properties of the object below are given in Hungarian - * notation, that was used as the interface for DataTables prior to v1.10, however - * from v1.10 onwards the primary interface is camel case. In order to avoid - * breaking backwards compatibility utterly with this change, the Hungarian - * version is still, internally the primary interface, but is is not documented - * - hence the @name tags in each doc comment. This allows a Javascript function - * to create a map from Hungarian notation to camel case (going the other direction - * would require each property to be listed, which would at around 3K to the size - * of DataTables, while this method is about a 0.5K hit. - * - * Ultimately this does pave the way for Hungarian notation to be dropped - * completely, but that is a massive amount of work and will break current - * installs (therefore is on-hold until v2). - */ - - /** - * Initialisation options that can be given to DataTables at initialisation - * time. - * @namespace - */ - DataTable.defaults = { - /** - * An array of data to use for the table, passed in at initialisation which - * will be used in preference to any data which is already in the DOM. This is - * particularly useful for constructing tables purely in Javascript, for - * example with a custom Ajax call. - * @type array - * @default null - * - * @dtopt Option - * @name DataTable.defaults.data - * - * @example - * // Using a 2D array data source - * $(document).ready( function () { - * $('#example').dataTable( { - * "data": [ - * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'], - * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'], - * ], - * "columns": [ - * { "title": "Engine" }, - * { "title": "Browser" }, - * { "title": "Platform" }, - * { "title": "Version" }, - * { "title": "Grade" } - * ] - * } ); - * } ); - * - * @example - * // Using an array of objects as a data source (`data`) - * $(document).ready( function () { - * $('#example').dataTable( { - * "data": [ - * { - * "engine": "Trident", - * "browser": "Internet Explorer 4.0", - * "platform": "Win 95+", - * "version": 4, - * "grade": "X" - * }, - * { - * "engine": "Trident", - * "browser": "Internet Explorer 5.0", - * "platform": "Win 95+", - * "version": 5, - * "grade": "C" - * } - * ], - * "columns": [ - * { "title": "Engine", "data": "engine" }, - * { "title": "Browser", "data": "browser" }, - * { "title": "Platform", "data": "platform" }, - * { "title": "Version", "data": "version" }, - * { "title": "Grade", "data": "grade" } - * ] - * } ); - * } ); - */ - "aaData": null, - - - /** - * If ordering is enabled, then DataTables will perform a first pass sort on - * initialisation. You can define which column(s) the sort is performed - * upon, and the sorting direction, with this variable. The `sorting` array - * should contain an array for each column to be sorted initially containing - * the column's index and a direction string ('asc' or 'desc'). - * @type array - * @default [[0,'asc']] - * - * @dtopt Option - * @name DataTable.defaults.order - * - * @example - * // Sort by 3rd column first, and then 4th column - * $(document).ready( function() { - * $('#example').dataTable( { - * "order": [[2,'asc'], [3,'desc']] - * } ); - * } ); - * - * // No initial sorting - * $(document).ready( function() { - * $('#example').dataTable( { - * "order": [] - * } ); - * } ); - */ - "aaSorting": [[0,'asc']], - - - /** - * This parameter is basically identical to the `sorting` parameter, but - * cannot be overridden by user interaction with the table. What this means - * is that you could have a column (visible or hidden) which the sorting - * will always be forced on first - any sorting after that (from the user) - * will then be performed as required. This can be useful for grouping rows - * together. - * @type array - * @default null - * - * @dtopt Option - * @name DataTable.defaults.orderFixed - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "orderFixed": [[0,'asc']] - * } ); - * } ) - */ - "aaSortingFixed": [], - - - /** - * DataTables can be instructed to load data to display in the table from a - * Ajax source. This option defines how that Ajax call is made and where to. - * - * The `ajax` property has three different modes of operation, depending on - * how it is defined. These are: - * - * * `string` - Set the URL from where the data should be loaded from. - * * `object` - Define properties for `jQuery.ajax`. - * * `function` - Custom data get function - * - * `string` - * -------- - * - * As a string, the `ajax` property simply defines the URL from which - * DataTables will load data. - * - * `object` - * -------- - * - * As an object, the parameters in the object are passed to - * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control - * of the Ajax request. DataTables has a number of default parameters which - * you can override using this option. Please refer to the jQuery - * documentation for a full description of the options available, although - * the following parameters provide additional options in DataTables or - * require special consideration: - * - * * `data` - As with jQuery, `data` can be provided as an object, but it - * can also be used as a function to manipulate the data DataTables sends - * to the server. The function takes a single parameter, an object of - * parameters with the values that DataTables has readied for sending. An - * object may be returned which will be merged into the DataTables - * defaults, or you can add the items to the object that was passed in and - * not return anything from the function. This supersedes `fnServerParams` - * from DataTables 1.9-. - * - * * `dataSrc` - By default DataTables will look for the property `data` (or - * `aaData` for compatibility with DataTables 1.9-) when obtaining data - * from an Ajax source or for server-side processing - this parameter - * allows that property to be changed. You can use Javascript dotted - * object notation to get a data source for multiple levels of nesting, or - * it my be used as a function. As a function it takes a single parameter, - * the JSON returned from the server, which can be manipulated as - * required, with the returned value being that used by DataTables as the - * data source for the table. This supersedes `sAjaxDataProp` from - * DataTables 1.9-. - * - * * `success` - Should not be overridden it is used internally in - * DataTables. To manipulate / transform the data returned by the server - * use `ajax.dataSrc`, or use `ajax` as a function (see below). - * - * `function` - * ---------- - * - * As a function, making the Ajax call is left up to yourself allowing - * complete control of the Ajax request. Indeed, if desired, a method other - * than Ajax could be used to obtain the required data, such as Web storage - * or an AIR database. - * - * The function is given four parameters and no return is required. The - * parameters are: - * - * 1. _object_ - Data to send to the server - * 2. _function_ - Callback function that must be executed when the required - * data has been obtained. That data should be passed into the callback - * as the only parameter - * 3. _object_ - DataTables settings object for the table - * - * Note that this supersedes `fnServerData` from DataTables 1.9-. - * - * @type string|object|function - * @default null - * - * @dtopt Option - * @name DataTable.defaults.ajax - * @since 1.10.0 - * - * @example - * // Get JSON data from a file via Ajax. - * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default). - * $('#example').dataTable( { - * "ajax": "data.json" - * } ); - * - * @example - * // Get JSON data from a file via Ajax, using `dataSrc` to change - * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`) - * $('#example').dataTable( { - * "ajax": { - * "url": "data.json", - * "dataSrc": "tableData" - * } - * } ); - * - * @example - * // Get JSON data from a file via Ajax, using `dataSrc` to read data - * // from a plain array rather than an array in an object - * $('#example').dataTable( { - * "ajax": { - * "url": "data.json", - * "dataSrc": "" - * } - * } ); - * - * @example - * // Manipulate the data returned from the server - add a link to data - * // (note this can, should, be done using `render` for the column - this - * // is just a simple example of how the data can be manipulated). - * $('#example').dataTable( { - * "ajax": { - * "url": "data.json", - * "dataSrc": function ( json ) { - * for ( var i=0, ien=json.length ; iView message'; - * } - * return json; - * } - * } - * } ); - * - * @example - * // Add data to the request - * $('#example').dataTable( { - * "ajax": { - * "url": "data.json", - * "data": function ( d ) { - * return { - * "extra_search": $('#extra').val() - * }; - * } - * } - * } ); - * - * @example - * // Send request as POST - * $('#example').dataTable( { - * "ajax": { - * "url": "data.json", - * "type": "POST" - * } - * } ); - * - * @example - * // Get the data from localStorage (could interface with a form for - * // adding, editing and removing rows). - * $('#example').dataTable( { - * "ajax": function (data, callback, settings) { - * callback( - * JSON.parse( localStorage.getItem('dataTablesData') ) - * ); - * } - * } ); - */ - "ajax": null, - - - /** - * This parameter allows you to readily specify the entries in the length drop - * down menu that DataTables shows when pagination is enabled. It can be - * either a 1D array of options which will be used for both the displayed - * option and the value, or a 2D array which will use the array in the first - * position as the value, and the array in the second position as the - * displayed options (useful for language strings such as 'All'). - * - * Note that the `pageLength` property will be automatically set to the - * first value given in this array, unless `pageLength` is also provided. - * @type array - * @default [ 10, 25, 50, 100 ] - * - * @dtopt Option - * @name DataTable.defaults.lengthMenu - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]] - * } ); - * } ); - */ - "aLengthMenu": [ 10, 25, 50, 100 ], - - - /** - * The `columns` option in the initialisation parameter allows you to define - * details about the way individual columns behave. For a full list of - * column options that can be set, please see - * {@link DataTable.defaults.column}. Note that if you use `columns` to - * define your columns, you must have an entry in the array for every single - * column that you have in your table (these can be null if you don't which - * to specify any options). - * @member - * - * @name DataTable.defaults.column - */ - "aoColumns": null, - - /** - * Very similar to `columns`, `columnDefs` allows you to target a specific - * column, multiple columns, or all columns, using the `targets` property of - * each object in the array. This allows great flexibility when creating - * tables, as the `columnDefs` arrays can be of any length, targeting the - * columns you specifically want. `columnDefs` may use any of the column - * options available: {@link DataTable.defaults.column}, but it _must_ - * have `targets` defined in each object in the array. Values in the `targets` - * array may be: - *
      - *
    • a string - class name will be matched on the TH for the column
    • - *
    • 0 or a positive integer - column index counting from the left
    • - *
    • a negative integer - column index counting from the right
    • - *
    • the string "_all" - all columns (i.e. assign a default)
    • - *
    - * @member - * - * @name DataTable.defaults.columnDefs - */ - "aoColumnDefs": null, - - - /** - * Basically the same as `search`, this parameter defines the individual column - * filtering state at initialisation time. The array must be of the same size - * as the number of columns, and each element be an object with the parameters - * `search` and `escapeRegex` (the latter is optional). 'null' is also - * accepted and the default will be used. - * @type array - * @default [] - * - * @dtopt Option - * @name DataTable.defaults.searchCols - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "searchCols": [ - * null, - * { "search": "My filter" }, - * null, - * { "search": "^[0-9]", "escapeRegex": false } - * ] - * } ); - * } ) - */ - "aoSearchCols": [], - - - /** - * An array of CSS classes that should be applied to displayed rows. This - * array may be of any length, and DataTables will apply each class - * sequentially, looping when required. - * @type array - * @default null Will take the values determined by the `oClasses.stripe*` - * options - * - * @dtopt Option - * @name DataTable.defaults.stripeClasses - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ] - * } ); - * } ) - */ - "asStripeClasses": null, - - - /** - * Enable or disable automatic column width calculation. This can be disabled - * as an optimisation (it takes some time to calculate the widths) if the - * tables widths are passed in using `columns`. - * @type boolean - * @default true - * - * @dtopt Features - * @name DataTable.defaults.autoWidth - * - * @example - * $(document).ready( function () { - * $('#example').dataTable( { - * "autoWidth": false - * } ); - * } ); - */ - "bAutoWidth": true, - - - /** - * Deferred rendering can provide DataTables with a huge speed boost when you - * are using an Ajax or JS data source for the table. This option, when set to - * true, will cause DataTables to defer the creation of the table elements for - * each row until they are needed for a draw - saving a significant amount of - * time. - * @type boolean - * @default false - * - * @dtopt Features - * @name DataTable.defaults.deferRender - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "ajax": "sources/arrays.txt", - * "deferRender": true - * } ); - * } ); - */ - "bDeferRender": false, - - - /** - * Replace a DataTable which matches the given selector and replace it with - * one which has the properties of the new initialisation object passed. If no - * table matches the selector, then the new DataTable will be constructed as - * per normal. - * @type boolean - * @default false - * - * @dtopt Options - * @name DataTable.defaults.destroy - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "srollY": "200px", - * "paginate": false - * } ); - * - * // Some time later.... - * $('#example').dataTable( { - * "filter": false, - * "destroy": true - * } ); - * } ); - */ - "bDestroy": false, - - - /** - * Enable or disable filtering of data. Filtering in DataTables is "smart" in - * that it allows the end user to input multiple words (space separated) and - * will match a row containing those words, even if not in the order that was - * specified (this allow matching across multiple columns). Note that if you - * wish to use filtering in DataTables this must remain 'true' - to remove the - * default filtering input box and retain filtering abilities, please use - * {@link DataTable.defaults.dom}. - * @type boolean - * @default true - * - * @dtopt Features - * @name DataTable.defaults.searching - * - * @example - * $(document).ready( function () { - * $('#example').dataTable( { - * "searching": false - * } ); - * } ); - */ - "bFilter": true, - - - /** - * Enable or disable the table information display. This shows information - * about the data that is currently visible on the page, including information - * about filtered data if that action is being performed. - * @type boolean - * @default true - * - * @dtopt Features - * @name DataTable.defaults.info - * - * @example - * $(document).ready( function () { - * $('#example').dataTable( { - * "info": false - * } ); - * } ); - */ - "bInfo": true, - - - /** - * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some - * slightly different and additional mark-up from what DataTables has - * traditionally used). - * @type boolean - * @default false - * - * @dtopt Features - * @name DataTable.defaults.jQueryUI - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "jQueryUI": true - * } ); - * } ); - */ - "bJQueryUI": false, - - - /** - * Allows the end user to select the size of a formatted page from a select - * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`). - * @type boolean - * @default true - * - * @dtopt Features - * @name DataTable.defaults.lengthChange - * - * @example - * $(document).ready( function () { - * $('#example').dataTable( { - * "lengthChange": false - * } ); - * } ); - */ - "bLengthChange": true, - - - /** - * Enable or disable pagination. - * @type boolean - * @default true - * - * @dtopt Features - * @name DataTable.defaults.paging - * - * @example - * $(document).ready( function () { - * $('#example').dataTable( { - * "paging": false - * } ); - * } ); - */ - "bPaginate": true, - - - /** - * Enable or disable the display of a 'processing' indicator when the table is - * being processed (e.g. a sort). This is particularly useful for tables with - * large amounts of data where it can take a noticeable amount of time to sort - * the entries. - * @type boolean - * @default false - * - * @dtopt Features - * @name DataTable.defaults.processing - * - * @example - * $(document).ready( function () { - * $('#example').dataTable( { - * "processing": true - * } ); - * } ); - */ - "bProcessing": false, - - - /** - * Retrieve the DataTables object for the given selector. Note that if the - * table has already been initialised, this parameter will cause DataTables - * to simply return the object that has already been set up - it will not take - * account of any changes you might have made to the initialisation object - * passed to DataTables (setting this parameter to true is an acknowledgement - * that you understand this). `destroy` can be used to reinitialise a table if - * you need. - * @type boolean - * @default false - * - * @dtopt Options - * @name DataTable.defaults.retrieve - * - * @example - * $(document).ready( function() { - * initTable(); - * tableActions(); - * } ); - * - * function initTable () - * { - * return $('#example').dataTable( { - * "scrollY": "200px", - * "paginate": false, - * "retrieve": true - * } ); - * } - * - * function tableActions () - * { - * var table = initTable(); - * // perform API operations with oTable - * } - */ - "bRetrieve": false, - - - /** - * When vertical (y) scrolling is enabled, DataTables will force the height of - * the table's viewport to the given height at all times (useful for layout). - * However, this can look odd when filtering data down to a small data set, - * and the footer is left "floating" further down. This parameter (when - * enabled) will cause DataTables to collapse the table's viewport down when - * the result set will fit within the given Y height. - * @type boolean - * @default false - * - * @dtopt Options - * @name DataTable.defaults.scrollCollapse - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "scrollY": "200", - * "scrollCollapse": true - * } ); - * } ); - */ - "bScrollCollapse": false, - - - /** - * Configure DataTables to use server-side processing. Note that the - * `ajax` parameter must also be given in order to give DataTables a - * source to obtain the required data for each draw. - * @type boolean - * @default false - * - * @dtopt Features - * @dtopt Server-side - * @name DataTable.defaults.serverSide - * - * @example - * $(document).ready( function () { - * $('#example').dataTable( { - * "serverSide": true, - * "ajax": "xhr.php" - * } ); - * } ); - */ - "bServerSide": false, - - - /** - * Enable or disable sorting of columns. Sorting of individual columns can be - * disabled by the `sortable` option for each column. - * @type boolean - * @default true - * - * @dtopt Features - * @name DataTable.defaults.ordering - * - * @example - * $(document).ready( function () { - * $('#example').dataTable( { - * "ordering": false - * } ); - * } ); - */ - "bSort": true, - - - /** - * Enable or display DataTables' ability to sort multiple columns at the - * same time (activated by shift-click by the user). - * @type boolean - * @default true - * - * @dtopt Options - * @name DataTable.defaults.orderMulti - * - * @example - * // Disable multiple column sorting ability - * $(document).ready( function () { - * $('#example').dataTable( { - * "orderMulti": false - * } ); - * } ); - */ - "bSortMulti": true, - - - /** - * Allows control over whether DataTables should use the top (true) unique - * cell that is found for a single column, or the bottom (false - default). - * This is useful when using complex headers. - * @type boolean - * @default false - * - * @dtopt Options - * @name DataTable.defaults.orderCellsTop - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "orderCellsTop": true - * } ); - * } ); - */ - "bSortCellsTop": false, - - - /** - * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and - * `sorting\_3` to the columns which are currently being sorted on. This is - * presented as a feature switch as it can increase processing time (while - * classes are removed and added) so for large data sets you might want to - * turn this off. - * @type boolean - * @default true - * - * @dtopt Features - * @name DataTable.defaults.orderClasses - * - * @example - * $(document).ready( function () { - * $('#example').dataTable( { - * "orderClasses": false - * } ); - * } ); - */ - "bSortClasses": true, - - - /** - * Enable or disable state saving. When enabled HTML5 `localStorage` will be - * used to save table display information such as pagination information, - * display length, filtering and sorting. As such when the end user reloads - * the page the display display will match what thy had previously set up. - * - * Due to the use of `localStorage` the default state saving is not supported - * in IE6 or 7. If state saving is required in those browsers, use - * `stateSaveCallback` to provide a storage solution such as cookies. - * @type boolean - * @default false - * - * @dtopt Features - * @name DataTable.defaults.stateSave - * - * @example - * $(document).ready( function () { - * $('#example').dataTable( { - * "stateSave": true - * } ); - * } ); - */ - "bStateSave": false, - - - /** - * This function is called when a TR element is created (and all TD child - * elements have been inserted), or registered if using a DOM source, allowing - * manipulation of the TR element (adding classes etc). - * @type function - * @param {node} row "TR" element for the current row - * @param {array} data Raw data array for this row - * @param {int} dataIndex The index of this row in the internal aoData array - * - * @dtopt Callbacks - * @name DataTable.defaults.createdRow - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "createdRow": function( row, data, dataIndex ) { - * // Bold the grade for all 'A' grade browsers - * if ( data[4] == "A" ) - * { - * $('td:eq(4)', row).html( 'A' ); - * } - * } - * } ); - * } ); - */ - "fnCreatedRow": null, - - - /** - * This function is called on every 'draw' event, and allows you to - * dynamically modify any aspect you want about the created DOM. - * @type function - * @param {object} settings DataTables settings object - * - * @dtopt Callbacks - * @name DataTable.defaults.drawCallback - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "drawCallback": function( settings ) { - * alert( 'DataTables has redrawn the table' ); - * } - * } ); - * } ); - */ - "fnDrawCallback": null, - - - /** - * Identical to fnHeaderCallback() but for the table footer this function - * allows you to modify the table footer on every 'draw' event. - * @type function - * @param {node} foot "TR" element for the footer - * @param {array} data Full table data (as derived from the original HTML) - * @param {int} start Index for the current display starting point in the - * display array - * @param {int} end Index for the current display ending point in the - * display array - * @param {array int} display Index array to translate the visual position - * to the full data array - * - * @dtopt Callbacks - * @name DataTable.defaults.footerCallback - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "footerCallback": function( tfoot, data, start, end, display ) { - * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start; - * } - * } ); - * } ) - */ - "fnFooterCallback": null, - - - /** - * When rendering large numbers in the information element for the table - * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers - * to have a comma separator for the 'thousands' units (e.g. 1 million is - * rendered as "1,000,000") to help readability for the end user. This - * function will override the default method DataTables uses. - * @type function - * @member - * @param {int} toFormat number to be formatted - * @returns {string} formatted string for DataTables to show the number - * - * @dtopt Callbacks - * @name DataTable.defaults.formatNumber - * - * @example - * // Format a number using a single quote for the separator (note that - * // this can also be done with the language.thousands option) - * $(document).ready( function() { - * $('#example').dataTable( { - * "formatNumber": function ( toFormat ) { - * return toFormat.toString().replace( - * /\B(?=(\d{3})+(?!\d))/g, "'" - * ); - * }; - * } ); - * } ); - */ - "fnFormatNumber": function ( toFormat ) { - return toFormat.toString().replace( - /\B(?=(\d{3})+(?!\d))/g, - this.oLanguage.sThousands - ); - }, - - - /** - * This function is called on every 'draw' event, and allows you to - * dynamically modify the header row. This can be used to calculate and - * display useful information about the table. - * @type function - * @param {node} head "TR" element for the header - * @param {array} data Full table data (as derived from the original HTML) - * @param {int} start Index for the current display starting point in the - * display array - * @param {int} end Index for the current display ending point in the - * display array - * @param {array int} display Index array to translate the visual position - * to the full data array - * - * @dtopt Callbacks - * @name DataTable.defaults.headerCallback - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "fheaderCallback": function( head, data, start, end, display ) { - * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records"; - * } - * } ); - * } ) - */ - "fnHeaderCallback": null, - - - /** - * The information element can be used to convey information about the current - * state of the table. Although the internationalisation options presented by - * DataTables are quite capable of dealing with most customisations, there may - * be times where you wish to customise the string further. This callback - * allows you to do exactly that. - * @type function - * @param {object} oSettings DataTables settings object - * @param {int} start Starting position in data for the draw - * @param {int} end End position in data for the draw - * @param {int} max Total number of rows in the table (regardless of - * filtering) - * @param {int} total Total number of rows in the data set, after filtering - * @param {string} pre The string that DataTables has formatted using it's - * own rules - * @returns {string} The string to be displayed in the information element. - * - * @dtopt Callbacks - * @name DataTable.defaults.infoCallback - * - * @example - * $('#example').dataTable( { - * "infoCallback": function( settings, start, end, max, total, pre ) { - * return start +" to "+ end; - * } - * } ); - */ - "fnInfoCallback": null, - - - /** - * Called when the table has been initialised. Normally DataTables will - * initialise sequentially and there will be no need for this function, - * however, this does not hold true when using external language information - * since that is obtained using an async XHR call. - * @type function - * @param {object} settings DataTables settings object - * @param {object} json The JSON object request from the server - only - * present if client-side Ajax sourced data is used - * - * @dtopt Callbacks - * @name DataTable.defaults.initComplete - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "initComplete": function(settings, json) { - * alert( 'DataTables has finished its initialisation.' ); - * } - * } ); - * } ) - */ - "fnInitComplete": null, - - - /** - * Called at the very start of each table draw and can be used to cancel the - * draw by returning false, any other return (including undefined) results in - * the full draw occurring). - * @type function - * @param {object} settings DataTables settings object - * @returns {boolean} False will cancel the draw, anything else (including no - * return) will allow it to complete. - * - * @dtopt Callbacks - * @name DataTable.defaults.preDrawCallback - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "preDrawCallback": function( settings ) { - * if ( $('#test').val() == 1 ) { - * return false; - * } - * } - * } ); - * } ); - */ - "fnPreDrawCallback": null, - - - /** - * This function allows you to 'post process' each row after it have been - * generated for each table draw, but before it is rendered on screen. This - * function might be used for setting the row class name etc. - * @type function - * @param {node} row "TR" element for the current row - * @param {array} data Raw data array for this row - * @param {int} displayIndex The display index for the current table draw - * @param {int} displayIndexFull The index of the data in the full list of - * rows (after filtering) - * - * @dtopt Callbacks - * @name DataTable.defaults.rowCallback - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "rowCallback": function( row, data, displayIndex, displayIndexFull ) { - * // Bold the grade for all 'A' grade browsers - * if ( data[4] == "A" ) { - * $('td:eq(4)', row).html( 'A' ); - * } - * } - * } ); - * } ); - */ - "fnRowCallback": null, - - - /** - * __Deprecated__ The functionality provided by this parameter has now been - * superseded by that provided through `ajax`, which should be used instead. - * - * This parameter allows you to override the default function which obtains - * the data from the server so something more suitable for your application. - * For example you could use POST data, or pull information from a Gears or - * AIR database. - * @type function - * @member - * @param {string} source HTTP source to obtain the data from (`ajax`) - * @param {array} data A key/value pair object containing the data to send - * to the server - * @param {function} callback to be called on completion of the data get - * process that will draw the data on the page. - * @param {object} settings DataTables settings object - * - * @dtopt Callbacks - * @dtopt Server-side - * @name DataTable.defaults.serverData - * - * @deprecated 1.10. Please use `ajax` for this functionality now. - */ - "fnServerData": null, - - - /** - * __Deprecated__ The functionality provided by this parameter has now been - * superseded by that provided through `ajax`, which should be used instead. - * - * It is often useful to send extra data to the server when making an Ajax - * request - for example custom filtering information, and this callback - * function makes it trivial to send extra information to the server. The - * passed in parameter is the data set that has been constructed by - * DataTables, and you can add to this or modify it as you require. - * @type function - * @param {array} data Data array (array of objects which are name/value - * pairs) that has been constructed by DataTables and will be sent to the - * server. In the case of Ajax sourced data with server-side processing - * this will be an empty array, for server-side processing there will be a - * significant number of parameters! - * @returns {undefined} Ensure that you modify the data array passed in, - * as this is passed by reference. - * - * @dtopt Callbacks - * @dtopt Server-side - * @name DataTable.defaults.serverParams - * - * @deprecated 1.10. Please use `ajax` for this functionality now. - */ - "fnServerParams": null, - - - /** - * Load the table state. With this function you can define from where, and how, the - * state of a table is loaded. By default DataTables will load from `localStorage` - * but you might wish to use a server-side database or cookies. - * @type function - * @member - * @param {object} settings DataTables settings object - * @param {object} callback Callback that can be executed when done. It - * should be passed the loaded state object. - * @return {object} The DataTables state object to be loaded - * - * @dtopt Callbacks - * @name DataTable.defaults.stateLoadCallback - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "stateSave": true, - * "stateLoadCallback": function (settings, callback) { - * $.ajax( { - * "url": "/state_load", - * "dataType": "json", - * "success": function (json) { - * callback( json ); - * } - * } ); - * } - * } ); - * } ); - */ - "fnStateLoadCallback": function ( settings ) { - try { - return JSON.parse( - (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem( - 'DataTables_'+settings.sInstance+'_'+location.pathname - ) - ); - } catch (e) {} - }, - - - /** - * Callback which allows modification of the saved state prior to loading that state. - * This callback is called when the table is loading state from the stored data, but - * prior to the settings object being modified by the saved state. Note that for - * plug-in authors, you should use the `stateLoadParams` event to load parameters for - * a plug-in. - * @type function - * @param {object} settings DataTables settings object - * @param {object} data The state object that is to be loaded - * - * @dtopt Callbacks - * @name DataTable.defaults.stateLoadParams - * - * @example - * // Remove a saved filter, so filtering is never loaded - * $(document).ready( function() { - * $('#example').dataTable( { - * "stateSave": true, - * "stateLoadParams": function (settings, data) { - * data.oSearch.sSearch = ""; - * } - * } ); - * } ); - * - * @example - * // Disallow state loading by returning false - * $(document).ready( function() { - * $('#example').dataTable( { - * "stateSave": true, - * "stateLoadParams": function (settings, data) { - * return false; - * } - * } ); - * } ); - */ - "fnStateLoadParams": null, - - - /** - * Callback that is called when the state has been loaded from the state saving method - * and the DataTables settings object has been modified as a result of the loaded state. - * @type function - * @param {object} settings DataTables settings object - * @param {object} data The state object that was loaded - * - * @dtopt Callbacks - * @name DataTable.defaults.stateLoaded - * - * @example - * // Show an alert with the filtering value that was saved - * $(document).ready( function() { - * $('#example').dataTable( { - * "stateSave": true, - * "stateLoaded": function (settings, data) { - * alert( 'Saved filter was: '+data.oSearch.sSearch ); - * } - * } ); - * } ); - */ - "fnStateLoaded": null, - - - /** - * Save the table state. This function allows you to define where and how the state - * information for the table is stored By default DataTables will use `localStorage` - * but you might wish to use a server-side database or cookies. - * @type function - * @member - * @param {object} settings DataTables settings object - * @param {object} data The state object to be saved - * - * @dtopt Callbacks - * @name DataTable.defaults.stateSaveCallback - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "stateSave": true, - * "stateSaveCallback": function (settings, data) { - * // Send an Ajax request to the server with the state object - * $.ajax( { - * "url": "/state_save", - * "data": data, - * "dataType": "json", - * "method": "POST" - * "success": function () {} - * } ); - * } - * } ); - * } ); - */ - "fnStateSaveCallback": function ( settings, data ) { - try { - (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem( - 'DataTables_'+settings.sInstance+'_'+location.pathname, - JSON.stringify( data ) - ); - } catch (e) {} - }, - - - /** - * Callback which allows modification of the state to be saved. Called when the table - * has changed state a new state save is required. This method allows modification of - * the state saving object prior to actually doing the save, including addition or - * other state properties or modification. Note that for plug-in authors, you should - * use the `stateSaveParams` event to save parameters for a plug-in. - * @type function - * @param {object} settings DataTables settings object - * @param {object} data The state object to be saved - * - * @dtopt Callbacks - * @name DataTable.defaults.stateSaveParams - * - * @example - * // Remove a saved filter, so filtering is never saved - * $(document).ready( function() { - * $('#example').dataTable( { - * "stateSave": true, - * "stateSaveParams": function (settings, data) { - * data.oSearch.sSearch = ""; - * } - * } ); - * } ); - */ - "fnStateSaveParams": null, - - - /** - * Duration for which the saved state information is considered valid. After this period - * has elapsed the state will be returned to the default. - * Value is given in seconds. - * @type int - * @default 7200 (2 hours) - * - * @dtopt Options - * @name DataTable.defaults.stateDuration - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "stateDuration": 60*60*24; // 1 day - * } ); - * } ) - */ - "iStateDuration": 7200, - - - /** - * When enabled DataTables will not make a request to the server for the first - * page draw - rather it will use the data already on the page (no sorting etc - * will be applied to it), thus saving on an XHR at load time. `deferLoading` - * is used to indicate that deferred loading is required, but it is also used - * to tell DataTables how many records there are in the full table (allowing - * the information element and pagination to be displayed correctly). In the case - * where a filtering is applied to the table on initial load, this can be - * indicated by giving the parameter as an array, where the first element is - * the number of records available after filtering and the second element is the - * number of records without filtering (allowing the table information element - * to be shown correctly). - * @type int | array - * @default null - * - * @dtopt Options - * @name DataTable.defaults.deferLoading - * - * @example - * // 57 records available in the table, no filtering applied - * $(document).ready( function() { - * $('#example').dataTable( { - * "serverSide": true, - * "ajax": "scripts/server_processing.php", - * "deferLoading": 57 - * } ); - * } ); - * - * @example - * // 57 records after filtering, 100 without filtering (an initial filter applied) - * $(document).ready( function() { - * $('#example').dataTable( { - * "serverSide": true, - * "ajax": "scripts/server_processing.php", - * "deferLoading": [ 57, 100 ], - * "search": { - * "search": "my_filter" - * } - * } ); - * } ); - */ - "iDeferLoading": null, - - - /** - * Number of rows to display on a single page when using pagination. If - * feature enabled (`lengthChange`) then the end user will be able to override - * this to a custom setting using a pop-up menu. - * @type int - * @default 10 - * - * @dtopt Options - * @name DataTable.defaults.pageLength - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "pageLength": 50 - * } ); - * } ) - */ - "iDisplayLength": 10, - - - /** - * Define the starting point for data display when using DataTables with - * pagination. Note that this parameter is the number of records, rather than - * the page number, so if you have 10 records per page and want to start on - * the third page, it should be "20". - * @type int - * @default 0 - * - * @dtopt Options - * @name DataTable.defaults.displayStart - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "displayStart": 20 - * } ); - * } ) - */ - "iDisplayStart": 0, - - - /** - * By default DataTables allows keyboard navigation of the table (sorting, paging, - * and filtering) by adding a `tabindex` attribute to the required elements. This - * allows you to tab through the controls and press the enter key to activate them. - * The tabindex is default 0, meaning that the tab follows the flow of the document. - * You can overrule this using this parameter if you wish. Use a value of -1 to - * disable built-in keyboard navigation. - * @type int - * @default 0 - * - * @dtopt Options - * @name DataTable.defaults.tabIndex - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "tabIndex": 1 - * } ); - * } ); - */ - "iTabIndex": 0, - - - /** - * Classes that DataTables assigns to the various components and features - * that it adds to the HTML table. This allows classes to be configured - * during initialisation in addition to through the static - * {@link DataTable.ext.oStdClasses} object). - * @namespace - * @name DataTable.defaults.classes - */ - "oClasses": {}, - - - /** - * All strings that DataTables uses in the user interface that it creates - * are defined in this object, allowing you to modified them individually or - * completely replace them all as required. - * @namespace - * @name DataTable.defaults.language - */ - "oLanguage": { - /** - * Strings that are used for WAI-ARIA labels and controls only (these are not - * actually visible on the page, but will be read by screenreaders, and thus - * must be internationalised as well). - * @namespace - * @name DataTable.defaults.language.aria - */ - "oAria": { - /** - * ARIA label that is added to the table headers when the column may be - * sorted ascending by activing the column (click or return when focused). - * Note that the column header is prefixed to this string. - * @type string - * @default : activate to sort column ascending - * - * @dtopt Language - * @name DataTable.defaults.language.aria.sortAscending - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "aria": { - * "sortAscending": " - click/return to sort ascending" - * } - * } - * } ); - * } ); - */ - "sSortAscending": ": activate to sort column ascending", - - /** - * ARIA label that is added to the table headers when the column may be - * sorted descending by activing the column (click or return when focused). - * Note that the column header is prefixed to this string. - * @type string - * @default : activate to sort column ascending - * - * @dtopt Language - * @name DataTable.defaults.language.aria.sortDescending - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "aria": { - * "sortDescending": " - click/return to sort descending" - * } - * } - * } ); - * } ); - */ - "sSortDescending": ": activate to sort column descending" - }, - - /** - * Pagination string used by DataTables for the built-in pagination - * control types. - * @namespace - * @name DataTable.defaults.language.paginate - */ - "oPaginate": { - /** - * Text to use when using the 'full_numbers' type of pagination for the - * button to take the user to the first page. - * @type string - * @default First - * - * @dtopt Language - * @name DataTable.defaults.language.paginate.first - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "paginate": { - * "first": "First page" - * } - * } - * } ); - * } ); - */ - "sFirst": "First", - - - /** - * Text to use when using the 'full_numbers' type of pagination for the - * button to take the user to the last page. - * @type string - * @default Last - * - * @dtopt Language - * @name DataTable.defaults.language.paginate.last - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "paginate": { - * "last": "Last page" - * } - * } - * } ); - * } ); - */ - "sLast": "Last", - - - /** - * Text to use for the 'next' pagination button (to take the user to the - * next page). - * @type string - * @default Next - * - * @dtopt Language - * @name DataTable.defaults.language.paginate.next - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "paginate": { - * "next": "Next page" - * } - * } - * } ); - * } ); - */ - "sNext": "Next", - - - /** - * Text to use for the 'previous' pagination button (to take the user to - * the previous page). - * @type string - * @default Previous - * - * @dtopt Language - * @name DataTable.defaults.language.paginate.previous - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "paginate": { - * "previous": "Previous page" - * } - * } - * } ); - * } ); - */ - "sPrevious": "Previous" - }, - - /** - * This string is shown in preference to `zeroRecords` when the table is - * empty of data (regardless of filtering). Note that this is an optional - * parameter - if it is not given, the value of `zeroRecords` will be used - * instead (either the default or given value). - * @type string - * @default No data available in table - * - * @dtopt Language - * @name DataTable.defaults.language.emptyTable - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "emptyTable": "No data available in table" - * } - * } ); - * } ); - */ - "sEmptyTable": "No data available in table", - - - /** - * This string gives information to the end user about the information - * that is current on display on the page. The following tokens can be - * used in the string and will be dynamically replaced as the table - * display updates. This tokens can be placed anywhere in the string, or - * removed as needed by the language requires: - * - * * `\_START\_` - Display index of the first record on the current page - * * `\_END\_` - Display index of the last record on the current page - * * `\_TOTAL\_` - Number of records in the table after filtering - * * `\_MAX\_` - Number of records in the table without filtering - * * `\_PAGE\_` - Current page number - * * `\_PAGES\_` - Total number of pages of data in the table - * - * @type string - * @default Showing _START_ to _END_ of _TOTAL_ entries - * - * @dtopt Language - * @name DataTable.defaults.language.info - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "info": "Showing page _PAGE_ of _PAGES_" - * } - * } ); - * } ); - */ - "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries", - - - /** - * Display information string for when the table is empty. Typically the - * format of this string should match `info`. - * @type string - * @default Showing 0 to 0 of 0 entries - * - * @dtopt Language - * @name DataTable.defaults.language.infoEmpty - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "infoEmpty": "No entries to show" - * } - * } ); - * } ); - */ - "sInfoEmpty": "Showing 0 to 0 of 0 entries", - - - /** - * When a user filters the information in a table, this string is appended - * to the information (`info`) to give an idea of how strong the filtering - * is. The variable _MAX_ is dynamically updated. - * @type string - * @default (filtered from _MAX_ total entries) - * - * @dtopt Language - * @name DataTable.defaults.language.infoFiltered - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "infoFiltered": " - filtering from _MAX_ records" - * } - * } ); - * } ); - */ - "sInfoFiltered": "(filtered from _MAX_ total entries)", - - - /** - * If can be useful to append extra information to the info string at times, - * and this variable does exactly that. This information will be appended to - * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are - * being used) at all times. - * @type string - * @default Empty string - * - * @dtopt Language - * @name DataTable.defaults.language.infoPostFix - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "infoPostFix": "All records shown are derived from real information." - * } - * } ); - * } ); - */ - "sInfoPostFix": "", - - - /** - * This decimal place operator is a little different from the other - * language options since DataTables doesn't output floating point - * numbers, so it won't ever use this for display of a number. Rather, - * what this parameter does is modify the sort methods of the table so - * that numbers which are in a format which has a character other than - * a period (`.`) as a decimal place will be sorted numerically. - * - * Note that numbers with different decimal places cannot be shown in - * the same table and still be sortable, the table must be consistent. - * However, multiple different tables on the page can use different - * decimal place characters. - * @type string - * @default - * - * @dtopt Language - * @name DataTable.defaults.language.decimal - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "decimal": "," - * "thousands": "." - * } - * } ); - * } ); - */ - "sDecimal": "", - - - /** - * DataTables has a build in number formatter (`formatNumber`) which is - * used to format large numbers that are used in the table information. - * By default a comma is used, but this can be trivially changed to any - * character you wish with this parameter. - * @type string - * @default , - * - * @dtopt Language - * @name DataTable.defaults.language.thousands - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "thousands": "'" - * } - * } ); - * } ); - */ - "sThousands": ",", - - - /** - * Detail the action that will be taken when the drop down menu for the - * pagination length option is changed. The '_MENU_' variable is replaced - * with a default select list of 10, 25, 50 and 100, and can be replaced - * with a custom select box if required. - * @type string - * @default Show _MENU_ entries - * - * @dtopt Language - * @name DataTable.defaults.language.lengthMenu - * - * @example - * // Language change only - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "lengthMenu": "Display _MENU_ records" - * } - * } ); - * } ); - * - * @example - * // Language and options change - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "lengthMenu": 'Display records' - * } - * } ); - * } ); - */ - "sLengthMenu": "Show _MENU_ entries", - - - /** - * When using Ajax sourced data and during the first draw when DataTables is - * gathering the data, this message is shown in an empty row in the table to - * indicate to the end user the the data is being loaded. Note that this - * parameter is not used when loading data by server-side processing, just - * Ajax sourced data with client-side processing. - * @type string - * @default Loading... - * - * @dtopt Language - * @name DataTable.defaults.language.loadingRecords - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "loadingRecords": "Please wait - loading..." - * } - * } ); - * } ); - */ - "sLoadingRecords": "Loading...", - - - /** - * Text which is displayed when the table is processing a user action - * (usually a sort command or similar). - * @type string - * @default Processing... - * - * @dtopt Language - * @name DataTable.defaults.language.processing - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "processing": "DataTables is currently busy" - * } - * } ); - * } ); - */ - "sProcessing": "Processing...", - - - /** - * Details the actions that will be taken when the user types into the - * filtering input text box. The variable "_INPUT_", if used in the string, - * is replaced with the HTML text box for the filtering input allowing - * control over where it appears in the string. If "_INPUT_" is not given - * then the input box is appended to the string automatically. - * @type string - * @default Search: - * - * @dtopt Language - * @name DataTable.defaults.language.search - * - * @example - * // Input text box will be appended at the end automatically - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "search": "Filter records:" - * } - * } ); - * } ); - * - * @example - * // Specify where the filter should appear - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "search": "Apply filter _INPUT_ to table" - * } - * } ); - * } ); - */ - "sSearch": "Search:", - - - /** - * Assign a `placeholder` attribute to the search `input` element - * @type string - * @default - * - * @dtopt Language - * @name DataTable.defaults.language.searchPlaceholder - */ - "sSearchPlaceholder": "", - - - /** - * All of the language information can be stored in a file on the - * server-side, which DataTables will look up if this parameter is passed. - * It must store the URL of the language file, which is in a JSON format, - * and the object has the same properties as the oLanguage object in the - * initialiser object (i.e. the above parameters). Please refer to one of - * the example language files to see how this works in action. - * @type string - * @default Empty string - i.e. disabled - * - * @dtopt Language - * @name DataTable.defaults.language.url - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt" - * } - * } ); - * } ); - */ - "sUrl": "", - - - /** - * Text shown inside the table records when the is no information to be - * displayed after filtering. `emptyTable` is shown when there is simply no - * information in the table at all (regardless of filtering). - * @type string - * @default No matching records found - * - * @dtopt Language - * @name DataTable.defaults.language.zeroRecords - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "zeroRecords": "No records to display" - * } - * } ); - * } ); - */ - "sZeroRecords": "No matching records found" - }, - - - /** - * This parameter allows you to have define the global filtering state at - * initialisation time. As an object the `search` parameter must be - * defined, but all other parameters are optional. When `regex` is true, - * the search string will be treated as a regular expression, when false - * (default) it will be treated as a straight string. When `smart` - * DataTables will use it's smart filtering methods (to word match at - * any point in the data), when false this will not be done. - * @namespace - * @extends DataTable.models.oSearch - * - * @dtopt Options - * @name DataTable.defaults.search - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "search": {"search": "Initial search"} - * } ); - * } ) - */ - "oSearch": $.extend( {}, DataTable.models.oSearch ), - - - /** - * __Deprecated__ The functionality provided by this parameter has now been - * superseded by that provided through `ajax`, which should be used instead. - * - * By default DataTables will look for the property `data` (or `aaData` for - * compatibility with DataTables 1.9-) when obtaining data from an Ajax - * source or for server-side processing - this parameter allows that - * property to be changed. You can use Javascript dotted object notation to - * get a data source for multiple levels of nesting. - * @type string - * @default data - * - * @dtopt Options - * @dtopt Server-side - * @name DataTable.defaults.ajaxDataProp - * - * @deprecated 1.10. Please use `ajax` for this functionality now. - */ - "sAjaxDataProp": "data", - - - /** - * __Deprecated__ The functionality provided by this parameter has now been - * superseded by that provided through `ajax`, which should be used instead. - * - * You can instruct DataTables to load data from an external - * source using this parameter (use aData if you want to pass data in you - * already have). Simply provide a url a JSON object can be obtained from. - * @type string - * @default null - * - * @dtopt Options - * @dtopt Server-side - * @name DataTable.defaults.ajaxSource - * - * @deprecated 1.10. Please use `ajax` for this functionality now. - */ - "sAjaxSource": null, - - - /** - * This initialisation variable allows you to specify exactly where in the - * DOM you want DataTables to inject the various controls it adds to the page - * (for example you might want the pagination controls at the top of the - * table). DIV elements (with or without a custom class) can also be added to - * aid styling. The follow syntax is used: - *
      - *
    • The following options are allowed: - *
        - *
      • 'l' - Length changing
      • - *
      • 'f' - Filtering input
      • - *
      • 't' - The table!
      • - *
      • 'i' - Information
      • - *
      • 'p' - Pagination
      • - *
      • 'r' - pRocessing
      • - *
      - *
    • - *
    • The following constants are allowed: - *
        - *
      • 'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')
      • - *
      • 'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')
      • - *
      - *
    • - *
    • The following syntax is expected: - *
        - *
      • '<' and '>' - div elements
      • - *
      • '<"class" and '>' - div with a class
      • - *
      • '<"#id" and '>' - div with an ID
      • - *
      - *
    • - *
    • Examples: - *
        - *
      • '<"wrapper"flipt>'
      • - *
      • '<lf<t>ip>'
      • - *
      - *
    • - *
    - * @type string - * @default lfrtip (when `jQueryUI` is false)or - * <"H"lfr>t<"F"ip> (when `jQueryUI` is true) - * - * @dtopt Options - * @name DataTable.defaults.dom - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "dom": '<"top"i>rt<"bottom"flp><"clear">' - * } ); - * } ); - */ - "sDom": "lfrtip", - - - /** - * Search delay option. This will throttle full table searches that use the - * DataTables provided search input element (it does not effect calls to - * `dt-api search()`, providing a delay before the search is made. - * @type integer - * @default 0 - * - * @dtopt Options - * @name DataTable.defaults.searchDelay - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "searchDelay": 200 - * } ); - * } ) - */ - "searchDelay": null, - - - /** - * DataTables features six different built-in options for the buttons to - * display for pagination control: - * - * * `numbers` - Page number buttons only - * * `simple` - 'Previous' and 'Next' buttons only - * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers - * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons - * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers - * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers - * - * Further methods can be added using {@link DataTable.ext.oPagination}. - * @type string - * @default simple_numbers - * - * @dtopt Options - * @name DataTable.defaults.pagingType - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "pagingType": "full_numbers" - * } ); - * } ) - */ - "sPaginationType": "simple_numbers", - - - /** - * Enable horizontal scrolling. When a table is too wide to fit into a - * certain layout, or you have a large number of columns in the table, you - * can enable x-scrolling to show the table in a viewport, which can be - * scrolled. This property can be `true` which will allow the table to - * scroll horizontally when needed, or any CSS unit, or a number (in which - * case it will be treated as a pixel measurement). Setting as simply `true` - * is recommended. - * @type boolean|string - * @default blank string - i.e. disabled - * - * @dtopt Features - * @name DataTable.defaults.scrollX - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "scrollX": true, - * "scrollCollapse": true - * } ); - * } ); - */ - "sScrollX": "", - - - /** - * This property can be used to force a DataTable to use more width than it - * might otherwise do when x-scrolling is enabled. For example if you have a - * table which requires to be well spaced, this parameter is useful for - * "over-sizing" the table, and thus forcing scrolling. This property can by - * any CSS unit, or a number (in which case it will be treated as a pixel - * measurement). - * @type string - * @default blank string - i.e. disabled - * - * @dtopt Options - * @name DataTable.defaults.scrollXInner - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "scrollX": "100%", - * "scrollXInner": "110%" - * } ); - * } ); - */ - "sScrollXInner": "", - - - /** - * Enable vertical scrolling. Vertical scrolling will constrain the DataTable - * to the given height, and enable scrolling for any data which overflows the - * current viewport. This can be used as an alternative to paging to display - * a lot of data in a small area (although paging and scrolling can both be - * enabled at the same time). This property can be any CSS unit, or a number - * (in which case it will be treated as a pixel measurement). - * @type string - * @default blank string - i.e. disabled - * - * @dtopt Features - * @name DataTable.defaults.scrollY - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "scrollY": "200px", - * "paginate": false - * } ); - * } ); - */ - "sScrollY": "", - - - /** - * __Deprecated__ The functionality provided by this parameter has now been - * superseded by that provided through `ajax`, which should be used instead. - * - * Set the HTTP method that is used to make the Ajax call for server-side - * processing or Ajax sourced data. - * @type string - * @default GET - * - * @dtopt Options - * @dtopt Server-side - * @name DataTable.defaults.serverMethod - * - * @deprecated 1.10. Please use `ajax` for this functionality now. - */ - "sServerMethod": "GET", - - - /** - * DataTables makes use of renderers when displaying HTML elements for - * a table. These renderers can be added or modified by plug-ins to - * generate suitable mark-up for a site. For example the Bootstrap - * integration plug-in for DataTables uses a paging button renderer to - * display pagination buttons in the mark-up required by Bootstrap. - * - * For further information about the renderers available see - * DataTable.ext.renderer - * @type string|object - * @default null - * - * @name DataTable.defaults.renderer - * - */ - "renderer": null, - - - /** - * Set the data property name that DataTables should use to get a row's id - * to set as the `id` property in the node. - * @type string - * @default DT_RowId - * - * @name DataTable.defaults.rowId - */ - "rowId": "DT_RowId" - }; - - _fnHungarianMap( DataTable.defaults ); - - - - /* - * Developer note - See note in model.defaults.js about the use of Hungarian - * notation and camel case. - */ - - /** - * Column options that can be given to DataTables at initialisation time. - * @namespace - */ - DataTable.defaults.column = { - /** - * Define which column(s) an order will occur on for this column. This - * allows a column's ordering to take multiple columns into account when - * doing a sort or use the data from a different column. For example first - * name / last name columns make sense to do a multi-column sort over the - * two columns. - * @type array|int - * @default null Takes the value of the column index automatically - * - * @name DataTable.defaults.column.orderData - * @dtopt Columns - * - * @example - * // Using `columnDefs` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ - * { "orderData": [ 0, 1 ], "targets": [ 0 ] }, - * { "orderData": [ 1, 0 ], "targets": [ 1 ] }, - * { "orderData": 2, "targets": [ 2 ] } - * ] - * } ); - * } ); - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * { "orderData": [ 0, 1 ] }, - * { "orderData": [ 1, 0 ] }, - * { "orderData": 2 }, - * null, - * null - * ] - * } ); - * } ); - */ - "aDataSort": null, - "iDataSort": -1, - - - /** - * You can control the default ordering direction, and even alter the - * behaviour of the sort handler (i.e. only allow ascending ordering etc) - * using this parameter. - * @type array - * @default [ 'asc', 'desc' ] - * - * @name DataTable.defaults.column.orderSequence - * @dtopt Columns - * - * @example - * // Using `columnDefs` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ - * { "orderSequence": [ "asc" ], "targets": [ 1 ] }, - * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] }, - * { "orderSequence": [ "desc" ], "targets": [ 3 ] } - * ] - * } ); - * } ); - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * null, - * { "orderSequence": [ "asc" ] }, - * { "orderSequence": [ "desc", "asc", "asc" ] }, - * { "orderSequence": [ "desc" ] }, - * null - * ] - * } ); - * } ); - */ - "asSorting": [ 'asc', 'desc' ], - - - /** - * Enable or disable filtering on the data in this column. - * @type boolean - * @default true - * - * @name DataTable.defaults.column.searchable - * @dtopt Columns - * - * @example - * // Using `columnDefs` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ - * { "searchable": false, "targets": [ 0 ] } - * ] } ); - * } ); - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * { "searchable": false }, - * null, - * null, - * null, - * null - * ] } ); - * } ); - */ - "bSearchable": true, - - - /** - * Enable or disable ordering on this column. - * @type boolean - * @default true - * - * @name DataTable.defaults.column.orderable - * @dtopt Columns - * - * @example - * // Using `columnDefs` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ - * { "orderable": false, "targets": [ 0 ] } - * ] } ); - * } ); - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * { "orderable": false }, - * null, - * null, - * null, - * null - * ] } ); - * } ); - */ - "bSortable": true, - - - /** - * Enable or disable the display of this column. - * @type boolean - * @default true - * - * @name DataTable.defaults.column.visible - * @dtopt Columns - * - * @example - * // Using `columnDefs` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ - * { "visible": false, "targets": [ 0 ] } - * ] } ); - * } ); - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * { "visible": false }, - * null, - * null, - * null, - * null - * ] } ); - * } ); - */ - "bVisible": true, - - - /** - * Developer definable function that is called whenever a cell is created (Ajax source, - * etc) or processed for input (DOM source). This can be used as a compliment to mRender - * allowing you to modify the DOM element (add background colour for example) when the - * element is available. - * @type function - * @param {element} td The TD node that has been created - * @param {*} cellData The Data for the cell - * @param {array|object} rowData The data for the whole row - * @param {int} row The row index for the aoData data store - * @param {int} col The column index for aoColumns - * - * @name DataTable.defaults.column.createdCell - * @dtopt Columns - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ { - * "targets": [3], - * "createdCell": function (td, cellData, rowData, row, col) { - * if ( cellData == "1.7" ) { - * $(td).css('color', 'blue') - * } - * } - * } ] - * }); - * } ); - */ - "fnCreatedCell": null, - - - /** - * This parameter has been replaced by `data` in DataTables to ensure naming - * consistency. `dataProp` can still be used, as there is backwards - * compatibility in DataTables for this option, but it is strongly - * recommended that you use `data` in preference to `dataProp`. - * @name DataTable.defaults.column.dataProp - */ - - - /** - * This property can be used to read data from any data source property, - * including deeply nested objects / properties. `data` can be given in a - * number of different ways which effect its behaviour: - * - * * `integer` - treated as an array index for the data source. This is the - * default that DataTables uses (incrementally increased for each column). - * * `string` - read an object property from the data source. There are - * three 'special' options that can be used in the string to alter how - * DataTables reads the data from the source object: - * * `.` - Dotted Javascript notation. Just as you use a `.` in - * Javascript to read from nested objects, so to can the options - * specified in `data`. For example: `browser.version` or - * `browser.name`. If your object parameter name contains a period, use - * `\\` to escape it - i.e. `first\\.name`. - * * `[]` - Array notation. DataTables can automatically combine data - * from and array source, joining the data with the characters provided - * between the two brackets. For example: `name[, ]` would provide a - * comma-space separated list from the source array. If no characters - * are provided between the brackets, the original array source is - * returned. - * * `()` - Function notation. Adding `()` to the end of a parameter will - * execute a function of the name given. For example: `browser()` for a - * simple function on the data source, `browser.version()` for a - * function in a nested property or even `browser().version` to get an - * object property if the function called returns an object. Note that - * function notation is recommended for use in `render` rather than - * `data` as it is much simpler to use as a renderer. - * * `null` - use the original data source for the row rather than plucking - * data directly from it. This action has effects on two other - * initialisation options: - * * `defaultContent` - When null is given as the `data` option and - * `defaultContent` is specified for the column, the value defined by - * `defaultContent` will be used for the cell. - * * `render` - When null is used for the `data` option and the `render` - * option is specified for the column, the whole data source for the - * row is used for the renderer. - * * `function` - the function given will be executed whenever DataTables - * needs to set or get the data for a cell in the column. The function - * takes three parameters: - * * Parameters: - * * `{array|object}` The data source for the row - * * `{string}` The type call data requested - this will be 'set' when - * setting data or 'filter', 'display', 'type', 'sort' or undefined - * when gathering data. Note that when `undefined` is given for the - * type DataTables expects to get the raw data for the object back< - * * `{*}` Data to set when the second parameter is 'set'. - * * Return: - * * The return value from the function is not required when 'set' is - * the type of call, but otherwise the return is what will be used - * for the data requested. - * - * Note that `data` is a getter and setter option. If you just require - * formatting of data for output, you will likely want to use `render` which - * is simply a getter and thus simpler to use. - * - * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The - * name change reflects the flexibility of this property and is consistent - * with the naming of mRender. If 'mDataProp' is given, then it will still - * be used by DataTables, as it automatically maps the old name to the new - * if required. - * - * @type string|int|function|null - * @default null Use automatically calculated column index - * - * @name DataTable.defaults.column.data - * @dtopt Columns - * - * @example - * // Read table data from objects - * // JSON structure for each row: - * // { - * // "engine": {value}, - * // "browser": {value}, - * // "platform": {value}, - * // "version": {value}, - * // "grade": {value} - * // } - * $(document).ready( function() { - * $('#example').dataTable( { - * "ajaxSource": "sources/objects.txt", - * "columns": [ - * { "data": "engine" }, - * { "data": "browser" }, - * { "data": "platform" }, - * { "data": "version" }, - * { "data": "grade" } - * ] - * } ); - * } ); - * - * @example - * // Read information from deeply nested objects - * // JSON structure for each row: - * // { - * // "engine": {value}, - * // "browser": {value}, - * // "platform": { - * // "inner": {value} - * // }, - * // "details": [ - * // {value}, {value} - * // ] - * // } - * $(document).ready( function() { - * $('#example').dataTable( { - * "ajaxSource": "sources/deep.txt", - * "columns": [ - * { "data": "engine" }, - * { "data": "browser" }, - * { "data": "platform.inner" }, - * { "data": "platform.details.0" }, - * { "data": "platform.details.1" } - * ] - * } ); - * } ); - * - * @example - * // Using `data` as a function to provide different information for - * // sorting, filtering and display. In this case, currency (price) - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ { - * "targets": [ 0 ], - * "data": function ( source, type, val ) { - * if (type === 'set') { - * source.price = val; - * // Store the computed dislay and filter values for efficiency - * source.price_display = val=="" ? "" : "$"+numberFormat(val); - * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val; - * return; - * } - * else if (type === 'display') { - * return source.price_display; - * } - * else if (type === 'filter') { - * return source.price_filter; - * } - * // 'sort', 'type' and undefined all just use the integer - * return source.price; - * } - * } ] - * } ); - * } ); - * - * @example - * // Using default content - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ { - * "targets": [ 0 ], - * "data": null, - * "defaultContent": "Click to edit" - * } ] - * } ); - * } ); - * - * @example - * // Using array notation - outputting a list from an array - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ { - * "targets": [ 0 ], - * "data": "name[, ]" - * } ] - * } ); - * } ); - * - */ - "mData": null, - - - /** - * This property is the rendering partner to `data` and it is suggested that - * when you want to manipulate data for display (including filtering, - * sorting etc) without altering the underlying data for the table, use this - * property. `render` can be considered to be the the read only companion to - * `data` which is read / write (then as such more complex). Like `data` - * this option can be given in a number of different ways to effect its - * behaviour: - * - * * `integer` - treated as an array index for the data source. This is the - * default that DataTables uses (incrementally increased for each column). - * * `string` - read an object property from the data source. There are - * three 'special' options that can be used in the string to alter how - * DataTables reads the data from the source object: - * * `.` - Dotted Javascript notation. Just as you use a `.` in - * Javascript to read from nested objects, so to can the options - * specified in `data`. For example: `browser.version` or - * `browser.name`. If your object parameter name contains a period, use - * `\\` to escape it - i.e. `first\\.name`. - * * `[]` - Array notation. DataTables can automatically combine data - * from and array source, joining the data with the characters provided - * between the two brackets. For example: `name[, ]` would provide a - * comma-space separated list from the source array. If no characters - * are provided between the brackets, the original array source is - * returned. - * * `()` - Function notation. Adding `()` to the end of a parameter will - * execute a function of the name given. For example: `browser()` for a - * simple function on the data source, `browser.version()` for a - * function in a nested property or even `browser().version` to get an - * object property if the function called returns an object. - * * `object` - use different data for the different data types requested by - * DataTables ('filter', 'display', 'type' or 'sort'). The property names - * of the object is the data type the property refers to and the value can - * defined using an integer, string or function using the same rules as - * `render` normally does. Note that an `_` option _must_ be specified. - * This is the default value to use if you haven't specified a value for - * the data type requested by DataTables. - * * `function` - the function given will be executed whenever DataTables - * needs to set or get the data for a cell in the column. The function - * takes three parameters: - * * Parameters: - * * {array|object} The data source for the row (based on `data`) - * * {string} The type call data requested - this will be 'filter', - * 'display', 'type' or 'sort'. - * * {array|object} The full data source for the row (not based on - * `data`) - * * Return: - * * The return value from the function is what will be used for the - * data requested. - * - * @type string|int|function|object|null - * @default null Use the data source value. - * - * @name DataTable.defaults.column.render - * @dtopt Columns - * - * @example - * // Create a comma separated list from an array of objects - * $(document).ready( function() { - * $('#example').dataTable( { - * "ajaxSource": "sources/deep.txt", - * "columns": [ - * { "data": "engine" }, - * { "data": "browser" }, - * { - * "data": "platform", - * "render": "[, ].name" - * } - * ] - * } ); - * } ); - * - * @example - * // Execute a function to obtain data - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ { - * "targets": [ 0 ], - * "data": null, // Use the full data source object for the renderer's source - * "render": "browserName()" - * } ] - * } ); - * } ); - * - * @example - * // As an object, extracting different data for the different types - * // This would be used with a data source such as: - * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" } - * // Here the `phone` integer is used for sorting and type detection, while `phone_filter` - * // (which has both forms) is used for filtering for if a user inputs either format, while - * // the formatted phone number is the one that is shown in the table. - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ { - * "targets": [ 0 ], - * "data": null, // Use the full data source object for the renderer's source - * "render": { - * "_": "phone", - * "filter": "phone_filter", - * "display": "phone_display" - * } - * } ] - * } ); - * } ); - * - * @example - * // Use as a function to create a link from the data source - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ { - * "targets": [ 0 ], - * "data": "download_link", - * "render": function ( data, type, full ) { - * return 'Download'; - * } - * } ] - * } ); - * } ); - */ - "mRender": null, - - - /** - * Change the cell type created for the column - either TD cells or TH cells. This - * can be useful as TH cells have semantic meaning in the table body, allowing them - * to act as a header for a row (you may wish to add scope='row' to the TH elements). - * @type string - * @default td - * - * @name DataTable.defaults.column.cellType - * @dtopt Columns - * - * @example - * // Make the first column use TH cells - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ { - * "targets": [ 0 ], - * "cellType": "th" - * } ] - * } ); - * } ); - */ - "sCellType": "td", - - - /** - * Class to give to each cell in this column. - * @type string - * @default Empty string - * - * @name DataTable.defaults.column.class - * @dtopt Columns - * - * @example - * // Using `columnDefs` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ - * { "class": "my_class", "targets": [ 0 ] } - * ] - * } ); - * } ); - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * { "class": "my_class" }, - * null, - * null, - * null, - * null - * ] - * } ); - * } ); - */ - "sClass": "", - - /** - * When DataTables calculates the column widths to assign to each column, - * it finds the longest string in each column and then constructs a - * temporary table and reads the widths from that. The problem with this - * is that "mmm" is much wider then "iiii", but the latter is a longer - * string - thus the calculation can go wrong (doing it properly and putting - * it into an DOM object and measuring that is horribly(!) slow). Thus as - * a "work around" we provide this option. It will append its value to the - * text that is found to be the longest string for the column - i.e. padding. - * Generally you shouldn't need this! - * @type string - * @default Empty string - * - * @name DataTable.defaults.column.contentPadding - * @dtopt Columns - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * null, - * null, - * null, - * { - * "contentPadding": "mmm" - * } - * ] - * } ); - * } ); - */ - "sContentPadding": "", - - - /** - * Allows a default value to be given for a column's data, and will be used - * whenever a null data source is encountered (this can be because `data` - * is set to null, or because the data source itself is null). - * @type string - * @default null - * - * @name DataTable.defaults.column.defaultContent - * @dtopt Columns - * - * @example - * // Using `columnDefs` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ - * { - * "data": null, - * "defaultContent": "Edit", - * "targets": [ -1 ] - * } - * ] - * } ); - * } ); - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * null, - * null, - * null, - * { - * "data": null, - * "defaultContent": "Edit" - * } - * ] - * } ); - * } ); - */ - "sDefaultContent": null, - - - /** - * This parameter is only used in DataTables' server-side processing. It can - * be exceptionally useful to know what columns are being displayed on the - * client side, and to map these to database fields. When defined, the names - * also allow DataTables to reorder information from the server if it comes - * back in an unexpected order (i.e. if you switch your columns around on the - * client-side, your server-side code does not also need updating). - * @type string - * @default Empty string - * - * @name DataTable.defaults.column.name - * @dtopt Columns - * - * @example - * // Using `columnDefs` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ - * { "name": "engine", "targets": [ 0 ] }, - * { "name": "browser", "targets": [ 1 ] }, - * { "name": "platform", "targets": [ 2 ] }, - * { "name": "version", "targets": [ 3 ] }, - * { "name": "grade", "targets": [ 4 ] } - * ] - * } ); - * } ); - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * { "name": "engine" }, - * { "name": "browser" }, - * { "name": "platform" }, - * { "name": "version" }, - * { "name": "grade" } - * ] - * } ); - * } ); - */ - "sName": "", - - - /** - * Defines a data source type for the ordering which can be used to read - * real-time information from the table (updating the internally cached - * version) prior to ordering. This allows ordering to occur on user - * editable elements such as form inputs. - * @type string - * @default std - * - * @name DataTable.defaults.column.orderDataType - * @dtopt Columns - * - * @example - * // Using `columnDefs` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ - * { "orderDataType": "dom-text", "targets": [ 2, 3 ] }, - * { "type": "numeric", "targets": [ 3 ] }, - * { "orderDataType": "dom-select", "targets": [ 4 ] }, - * { "orderDataType": "dom-checkbox", "targets": [ 5 ] } - * ] - * } ); - * } ); - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * null, - * null, - * { "orderDataType": "dom-text" }, - * { "orderDataType": "dom-text", "type": "numeric" }, - * { "orderDataType": "dom-select" }, - * { "orderDataType": "dom-checkbox" } - * ] - * } ); - * } ); - */ - "sSortDataType": "std", - - - /** - * The title of this column. - * @type string - * @default null Derived from the 'TH' value for this column in the - * original HTML table. - * - * @name DataTable.defaults.column.title - * @dtopt Columns - * - * @example - * // Using `columnDefs` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ - * { "title": "My column title", "targets": [ 0 ] } - * ] - * } ); - * } ); - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * { "title": "My column title" }, - * null, - * null, - * null, - * null - * ] - * } ); - * } ); - */ - "sTitle": null, - - - /** - * The type allows you to specify how the data for this column will be - * ordered. Four types (string, numeric, date and html (which will strip - * HTML tags before ordering)) are currently available. Note that only date - * formats understood by Javascript's Date() object will be accepted as type - * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string', - * 'numeric', 'date' or 'html' (by default). Further types can be adding - * through plug-ins. - * @type string - * @default null Auto-detected from raw data - * - * @name DataTable.defaults.column.type - * @dtopt Columns - * - * @example - * // Using `columnDefs` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ - * { "type": "html", "targets": [ 0 ] } - * ] - * } ); - * } ); - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * { "type": "html" }, - * null, - * null, - * null, - * null - * ] - * } ); - * } ); - */ - "sType": null, - - - /** - * Defining the width of the column, this parameter may take any CSS value - * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not - * been given a specific width through this interface ensuring that the table - * remains readable. - * @type string - * @default null Automatic - * - * @name DataTable.defaults.column.width - * @dtopt Columns - * - * @example - * // Using `columnDefs` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ - * { "width": "20%", "targets": [ 0 ] } - * ] - * } ); - * } ); - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * { "width": "20%" }, - * null, - * null, - * null, - * null - * ] - * } ); - * } ); - */ - "sWidth": null - }; - - _fnHungarianMap( DataTable.defaults.column ); - - - - /** - * DataTables settings object - this holds all the information needed for a - * given table, including configuration, data and current application of the - * table options. DataTables does not have a single instance for each DataTable - * with the settings attached to that instance, but rather instances of the - * DataTable "class" are created on-the-fly as needed (typically by a - * $().dataTable() call) and the settings object is then applied to that - * instance. - * - * Note that this object is related to {@link DataTable.defaults} but this - * one is the internal data store for DataTables's cache of columns. It should - * NOT be manipulated outside of DataTables. Any configuration should be done - * through the initialisation options. - * @namespace - * @todo Really should attach the settings object to individual instances so we - * don't need to create new instances on each $().dataTable() call (if the - * table already exists). It would also save passing oSettings around and - * into every single function. However, this is a very significant - * architecture change for DataTables and will almost certainly break - * backwards compatibility with older installations. This is something that - * will be done in 2.0. - */ - DataTable.models.oSettings = { - /** - * Primary features of DataTables and their enablement state. - * @namespace - */ - "oFeatures": { - - /** - * Flag to say if DataTables should automatically try to calculate the - * optimum table and columns widths (true) or not (false). - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bAutoWidth": null, - - /** - * Delay the creation of TR and TD elements until they are actually - * needed by a driven page draw. This can give a significant speed - * increase for Ajax source and Javascript source data, but makes no - * difference at all fro DOM and server-side processing tables. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bDeferRender": null, - - /** - * Enable filtering on the table or not. Note that if this is disabled - * then there is no filtering at all on the table, including fnFilter. - * To just remove the filtering input use sDom and remove the 'f' option. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bFilter": null, - - /** - * Table information element (the 'Showing x of y records' div) enable - * flag. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bInfo": null, - - /** - * Present a user control allowing the end user to change the page size - * when pagination is enabled. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bLengthChange": null, - - /** - * Pagination enabled or not. Note that if this is disabled then length - * changing must also be disabled. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bPaginate": null, - - /** - * Processing indicator enable flag whenever DataTables is enacting a - * user request - typically an Ajax request for server-side processing. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bProcessing": null, - - /** - * Server-side processing enabled flag - when enabled DataTables will - * get all data from the server for every draw - there is no filtering, - * sorting or paging done on the client-side. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bServerSide": null, - - /** - * Sorting enablement flag. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bSort": null, - - /** - * Multi-column sorting - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bSortMulti": null, - - /** - * Apply a class to the columns which are being sorted to provide a - * visual highlight or not. This can slow things down when enabled since - * there is a lot of DOM interaction. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bSortClasses": null, - - /** - * State saving enablement flag. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bStateSave": null - }, - - - /** - * Scrolling settings for a table. - * @namespace - */ - "oScroll": { - /** - * When the table is shorter in height than sScrollY, collapse the - * table container down to the height of the table (when true). - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bCollapse": null, - - /** - * Width of the scrollbar for the web-browser's platform. Calculated - * during table initialisation. - * @type int - * @default 0 - */ - "iBarWidth": 0, - - /** - * Viewport width for horizontal scrolling. Horizontal scrolling is - * disabled if an empty string. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type string - */ - "sX": null, - - /** - * Width to expand the table to when using x-scrolling. Typically you - * should not need to use this. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type string - * @deprecated - */ - "sXInner": null, - - /** - * Viewport height for vertical scrolling. Vertical scrolling is disabled - * if an empty string. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type string - */ - "sY": null - }, - - /** - * Language information for the table. - * @namespace - * @extends DataTable.defaults.oLanguage - */ - "oLanguage": { - /** - * Information callback function. See - * {@link DataTable.defaults.fnInfoCallback} - * @type function - * @default null - */ - "fnInfoCallback": null - }, - - /** - * Browser support parameters - * @namespace - */ - "oBrowser": { - /** - * Indicate if the browser incorrectly calculates width:100% inside a - * scrolling element (IE6/7) - * @type boolean - * @default false - */ - "bScrollOversize": false, - - /** - * Determine if the vertical scrollbar is on the right or left of the - * scrolling container - needed for rtl language layout, although not - * all browsers move the scrollbar (Safari). - * @type boolean - * @default false - */ - "bScrollbarLeft": false, - - /** - * Flag for if `getBoundingClientRect` is fully supported or not - * @type boolean - * @default false - */ - "bBounding": false, - - /** - * Browser scrollbar width - * @type integer - * @default 0 - */ - "barWidth": 0 - }, - - - "ajax": null, - - - /** - * Array referencing the nodes which are used for the features. The - * parameters of this object match what is allowed by sDom - i.e. - *
      - *
    • 'l' - Length changing
    • - *
    • 'f' - Filtering input
    • - *
    • 't' - The table!
    • - *
    • 'i' - Information
    • - *
    • 'p' - Pagination
    • - *
    • 'r' - pRocessing
    • - *
    - * @type array - * @default [] - */ - "aanFeatures": [], - - /** - * Store data information - see {@link DataTable.models.oRow} for detailed - * information. - * @type array - * @default [] - */ - "aoData": [], - - /** - * Array of indexes which are in the current display (after filtering etc) - * @type array - * @default [] - */ - "aiDisplay": [], - - /** - * Array of indexes for display - no filtering - * @type array - * @default [] - */ - "aiDisplayMaster": [], - - /** - * Map of row ids to data indexes - * @type object - * @default {} - */ - "aIds": {}, - - /** - * Store information about each column that is in use - * @type array - * @default [] - */ - "aoColumns": [], - - /** - * Store information about the table's header - * @type array - * @default [] - */ - "aoHeader": [], - - /** - * Store information about the table's footer - * @type array - * @default [] - */ - "aoFooter": [], - - /** - * Store the applied global search information in case we want to force a - * research or compare the old search to a new one. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @namespace - * @extends DataTable.models.oSearch - */ - "oPreviousSearch": {}, - - /** - * Store the applied search for each column - see - * {@link DataTable.models.oSearch} for the format that is used for the - * filtering information for each column. - * @type array - * @default [] - */ - "aoPreSearchCols": [], - - /** - * Sorting that is applied to the table. Note that the inner arrays are - * used in the following manner: - *
      - *
    • Index 0 - column number
    • - *
    • Index 1 - current sorting direction
    • - *
    - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type array - * @todo These inner arrays should really be objects - */ - "aaSorting": null, - - /** - * Sorting that is always applied to the table (i.e. prefixed in front of - * aaSorting). - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type array - * @default [] - */ - "aaSortingFixed": [], - - /** - * Classes to use for the striping of a table. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type array - * @default [] - */ - "asStripeClasses": null, - - /** - * If restoring a table - we should restore its striping classes as well - * @type array - * @default [] - */ - "asDestroyStripes": [], - - /** - * If restoring a table - we should restore its width - * @type int - * @default 0 - */ - "sDestroyWidth": 0, - - /** - * Callback functions array for every time a row is inserted (i.e. on a draw). - * @type array - * @default [] - */ - "aoRowCallback": [], - - /** - * Callback functions for the header on each draw. - * @type array - * @default [] - */ - "aoHeaderCallback": [], - - /** - * Callback function for the footer on each draw. - * @type array - * @default [] - */ - "aoFooterCallback": [], - - /** - * Array of callback functions for draw callback functions - * @type array - * @default [] - */ - "aoDrawCallback": [], - - /** - * Array of callback functions for row created function - * @type array - * @default [] - */ - "aoRowCreatedCallback": [], - - /** - * Callback functions for just before the table is redrawn. A return of - * false will be used to cancel the draw. - * @type array - * @default [] - */ - "aoPreDrawCallback": [], - - /** - * Callback functions for when the table has been initialised. - * @type array - * @default [] - */ - "aoInitComplete": [], - - - /** - * Callbacks for modifying the settings to be stored for state saving, prior to - * saving state. - * @type array - * @default [] - */ - "aoStateSaveParams": [], - - /** - * Callbacks for modifying the settings that have been stored for state saving - * prior to using the stored values to restore the state. - * @type array - * @default [] - */ - "aoStateLoadParams": [], - - /** - * Callbacks for operating on the settings object once the saved state has been - * loaded - * @type array - * @default [] - */ - "aoStateLoaded": [], - - /** - * Cache the table ID for quick access - * @type string - * @default Empty string - */ - "sTableId": "", - - /** - * The TABLE node for the main table - * @type node - * @default null - */ - "nTable": null, - - /** - * Permanent ref to the thead element - * @type node - * @default null - */ - "nTHead": null, - - /** - * Permanent ref to the tfoot element - if it exists - * @type node - * @default null - */ - "nTFoot": null, - - /** - * Permanent ref to the tbody element - * @type node - * @default null - */ - "nTBody": null, - - /** - * Cache the wrapper node (contains all DataTables controlled elements) - * @type node - * @default null - */ - "nTableWrapper": null, - - /** - * Indicate if when using server-side processing the loading of data - * should be deferred until the second draw. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - * @default false - */ - "bDeferLoading": false, - - /** - * Indicate if all required information has been read in - * @type boolean - * @default false - */ - "bInitialised": false, - - /** - * Information about open rows. Each object in the array has the parameters - * 'nTr' and 'nParent' - * @type array - * @default [] - */ - "aoOpenRows": [], - - /** - * Dictate the positioning of DataTables' control elements - see - * {@link DataTable.model.oInit.sDom}. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type string - * @default null - */ - "sDom": null, - - /** - * Search delay (in mS) - * @type integer - * @default null - */ - "searchDelay": null, - - /** - * Which type of pagination should be used. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type string - * @default two_button - */ - "sPaginationType": "two_button", - - /** - * The state duration (for `stateSave`) in seconds. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type int - * @default 0 - */ - "iStateDuration": 0, - - /** - * Array of callback functions for state saving. Each array element is an - * object with the following parameters: - *
      - *
    • function:fn - function to call. Takes two parameters, oSettings - * and the JSON string to save that has been thus far created. Returns - * a JSON string to be inserted into a json object - * (i.e. '"param": [ 0, 1, 2]')
    • - *
    • string:sName - name of callback
    • - *
    - * @type array - * @default [] - */ - "aoStateSave": [], - - /** - * Array of callback functions for state loading. Each array element is an - * object with the following parameters: - *
      - *
    • function:fn - function to call. Takes two parameters, oSettings - * and the object stored. May return false to cancel state loading
    • - *
    • string:sName - name of callback
    • - *
    - * @type array - * @default [] - */ - "aoStateLoad": [], - - /** - * State that was saved. Useful for back reference - * @type object - * @default null - */ - "oSavedState": null, - - /** - * State that was loaded. Useful for back reference - * @type object - * @default null - */ - "oLoadedState": null, - - /** - * Source url for AJAX data for the table. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type string - * @default null - */ - "sAjaxSource": null, - - /** - * Property from a given object from which to read the table data from. This - * can be an empty string (when not server-side processing), in which case - * it is assumed an an array is given directly. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type string - */ - "sAjaxDataProp": null, - - /** - * Note if draw should be blocked while getting data - * @type boolean - * @default true - */ - "bAjaxDataGet": true, - - /** - * The last jQuery XHR object that was used for server-side data gathering. - * This can be used for working with the XHR information in one of the - * callbacks - * @type object - * @default null - */ - "jqXHR": null, - - /** - * JSON returned from the server in the last Ajax request - * @type object - * @default undefined - */ - "json": undefined, - - /** - * Data submitted as part of the last Ajax request - * @type object - * @default undefined - */ - "oAjaxData": undefined, - - /** - * Function to get the server-side data. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type function - */ - "fnServerData": null, - - /** - * Functions which are called prior to sending an Ajax request so extra - * parameters can easily be sent to the server - * @type array - * @default [] - */ - "aoServerParams": [], - - /** - * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if - * required). - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type string - */ - "sServerMethod": null, - - /** - * Format numbers for display. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type function - */ - "fnFormatNumber": null, - - /** - * List of options that can be used for the user selectable length menu. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type array - * @default [] - */ - "aLengthMenu": null, - - /** - * Counter for the draws that the table does. Also used as a tracker for - * server-side processing - * @type int - * @default 0 - */ - "iDraw": 0, - - /** - * Indicate if a redraw is being done - useful for Ajax - * @type boolean - * @default false - */ - "bDrawing": false, - - /** - * Draw index (iDraw) of the last error when parsing the returned data - * @type int - * @default -1 - */ - "iDrawError": -1, - - /** - * Paging display length - * @type int - * @default 10 - */ - "_iDisplayLength": 10, - - /** - * Paging start point - aiDisplay index - * @type int - * @default 0 - */ - "_iDisplayStart": 0, - - /** - * Server-side processing - number of records in the result set - * (i.e. before filtering), Use fnRecordsTotal rather than - * this property to get the value of the number of records, regardless of - * the server-side processing setting. - * @type int - * @default 0 - * @private - */ - "_iRecordsTotal": 0, - - /** - * Server-side processing - number of records in the current display set - * (i.e. after filtering). Use fnRecordsDisplay rather than - * this property to get the value of the number of records, regardless of - * the server-side processing setting. - * @type boolean - * @default 0 - * @private - */ - "_iRecordsDisplay": 0, - - /** - * Flag to indicate if jQuery UI marking and classes should be used. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bJUI": null, - - /** - * The classes to use for the table - * @type object - * @default {} - */ - "oClasses": {}, - - /** - * Flag attached to the settings object so you can check in the draw - * callback if filtering has been done in the draw. Deprecated in favour of - * events. - * @type boolean - * @default false - * @deprecated - */ - "bFiltered": false, - - /** - * Flag attached to the settings object so you can check in the draw - * callback if sorting has been done in the draw. Deprecated in favour of - * events. - * @type boolean - * @default false - * @deprecated - */ - "bSorted": false, - - /** - * Indicate that if multiple rows are in the header and there is more than - * one unique cell per column, if the top one (true) or bottom one (false) - * should be used for sorting / title by DataTables. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bSortCellsTop": null, - - /** - * Initialisation object that is used for the table - * @type object - * @default null - */ - "oInit": null, - - /** - * Destroy callback functions - for plug-ins to attach themselves to the - * destroy so they can clean up markup and events. - * @type array - * @default [] - */ - "aoDestroyCallback": [], - - - /** - * Get the number of records in the current record set, before filtering - * @type function - */ - "fnRecordsTotal": function () - { - return _fnDataSource( this ) == 'ssp' ? - this._iRecordsTotal * 1 : - this.aiDisplayMaster.length; - }, - - /** - * Get the number of records in the current record set, after filtering - * @type function - */ - "fnRecordsDisplay": function () - { - return _fnDataSource( this ) == 'ssp' ? - this._iRecordsDisplay * 1 : - this.aiDisplay.length; - }, - - /** - * Get the display end point - aiDisplay index - * @type function - */ - "fnDisplayEnd": function () - { - var - len = this._iDisplayLength, - start = this._iDisplayStart, - calc = start + len, - records = this.aiDisplay.length, - features = this.oFeatures, - paginate = features.bPaginate; - - if ( features.bServerSide ) { - return paginate === false || len === -1 ? - start + records : - Math.min( start+len, this._iRecordsDisplay ); - } - else { - return ! paginate || calc>records || len===-1 ? - records : - calc; - } - }, - - /** - * The DataTables object for this table - * @type object - * @default null - */ - "oInstance": null, - - /** - * Unique identifier for each instance of the DataTables object. If there - * is an ID on the table node, then it takes that value, otherwise an - * incrementing internal counter is used. - * @type string - * @default null - */ - "sInstance": null, - - /** - * tabindex attribute value that is added to DataTables control elements, allowing - * keyboard navigation of the table and its controls. - */ - "iTabIndex": 0, - - /** - * DIV container for the footer scrolling table if scrolling - */ - "nScrollHead": null, - - /** - * DIV container for the footer scrolling table if scrolling - */ - "nScrollFoot": null, - - /** - * Last applied sort - * @type array - * @default [] - */ - "aLastSort": [], - - /** - * Stored plug-in instances - * @type object - * @default {} - */ - "oPlugins": {}, - - /** - * Function used to get a row's id from the row's data - * @type function - * @default null - */ - "rowIdFn": null, - - /** - * Data location where to store a row's id - * @type string - * @default null - */ - "rowId": null - }; - - /** - * Extension object for DataTables that is used to provide all extension - * options. - * - * Note that the `DataTable.ext` object is available through - * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is - * also aliased to `jQuery.fn.dataTableExt` for historic reasons. - * @namespace - * @extends DataTable.models.ext - */ - - - /** - * DataTables extensions - * - * This namespace acts as a collection area for plug-ins that can be used to - * extend DataTables capabilities. Indeed many of the build in methods - * use this method to provide their own capabilities (sorting methods for - * example). - * - * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy - * reasons - * - * @namespace - */ - DataTable.ext = _ext = { - /** - * Buttons. For use with the Buttons extension for DataTables. This is - * defined here so other extensions can define buttons regardless of load - * order. It is _not_ used by DataTables core. - * - * @type object - * @default {} - */ - buttons: {}, - - - /** - * Element class names - * - * @type object - * @default {} - */ - classes: {}, - - - /** - * DataTables build type (expanded by the download builder) - * - * @type string - */ - builder: "-source-", - - - /** - * Error reporting. - * - * How should DataTables report an error. Can take the value 'alert', - * 'throw', 'none' or a function. - * - * @type string|function - * @default alert - */ - errMode: "alert", - - - /** - * Feature plug-ins. - * - * This is an array of objects which describe the feature plug-ins that are - * available to DataTables. These feature plug-ins are then available for - * use through the `dom` initialisation option. - * - * Each feature plug-in is described by an object which must have the - * following properties: - * - * * `fnInit` - function that is used to initialise the plug-in, - * * `cFeature` - a character so the feature can be enabled by the `dom` - * instillation option. This is case sensitive. - * - * The `fnInit` function has the following input parameters: - * - * 1. `{object}` DataTables settings object: see - * {@link DataTable.models.oSettings} - * - * And the following return is expected: - * - * * {node|null} The element which contains your feature. Note that the - * return may also be void if your plug-in does not require to inject any - * DOM elements into DataTables control (`dom`) - for example this might - * be useful when developing a plug-in which allows table control via - * keyboard entry - * - * @type array - * - * @example - * $.fn.dataTable.ext.features.push( { - * "fnInit": function( oSettings ) { - * return new TableTools( { "oDTSettings": oSettings } ); - * }, - * "cFeature": "T" - * } ); - */ - feature: [], - - - /** - * Row searching. - * - * This method of searching is complimentary to the default type based - * searching, and a lot more comprehensive as it allows you complete control - * over the searching logic. Each element in this array is a function - * (parameters described below) that is called for every row in the table, - * and your logic decides if it should be included in the searching data set - * or not. - * - * Searching functions have the following input parameters: - * - * 1. `{object}` DataTables settings object: see - * {@link DataTable.models.oSettings} - * 2. `{array|object}` Data for the row to be processed (same as the - * original format that was passed in as the data source, or an array - * from a DOM data source - * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which - * can be useful to retrieve the `TR` element if you need DOM interaction. - * - * And the following return is expected: - * - * * {boolean} Include the row in the searched result set (true) or not - * (false) - * - * Note that as with the main search ability in DataTables, technically this - * is "filtering", since it is subtractive. However, for consistency in - * naming we call it searching here. - * - * @type array - * @default [] - * - * @example - * // The following example shows custom search being applied to the - * // fourth column (i.e. the data[3] index) based on two input values - * // from the end-user, matching the data in a certain range. - * $.fn.dataTable.ext.search.push( - * function( settings, data, dataIndex ) { - * var min = document.getElementById('min').value * 1; - * var max = document.getElementById('max').value * 1; - * var version = data[3] == "-" ? 0 : data[3]*1; - * - * if ( min == "" && max == "" ) { - * return true; - * } - * else if ( min == "" && version < max ) { - * return true; - * } - * else if ( min < version && "" == max ) { - * return true; - * } - * else if ( min < version && version < max ) { - * return true; - * } - * return false; - * } - * ); - */ - search: [], - - - /** - * Selector extensions - * - * The `selector` option can be used to extend the options available for the - * selector modifier options (`selector-modifier` object data type) that - * each of the three built in selector types offer (row, column and cell + - * their plural counterparts). For example the Select extension uses this - * mechanism to provide an option to select only rows, columns and cells - * that have been marked as selected by the end user (`{selected: true}`), - * which can be used in conjunction with the existing built in selector - * options. - * - * Each property is an array to which functions can be pushed. The functions - * take three attributes: - * - * * Settings object for the host table - * * Options object (`selector-modifier` object type) - * * Array of selected item indexes - * - * The return is an array of the resulting item indexes after the custom - * selector has been applied. - * - * @type object - */ - selector: { - cell: [], - column: [], - row: [] - }, - - - /** - * Internal functions, exposed for used in plug-ins. - * - * Please note that you should not need to use the internal methods for - * anything other than a plug-in (and even then, try to avoid if possible). - * The internal function may change between releases. - * - * @type object - * @default {} - */ - internal: {}, - - - /** - * Legacy configuration options. Enable and disable legacy options that - * are available in DataTables. - * - * @type object - */ - legacy: { - /** - * Enable / disable DataTables 1.9 compatible server-side processing - * requests - * - * @type boolean - * @default null - */ - ajax: null - }, - - - /** - * Pagination plug-in methods. - * - * Each entry in this object is a function and defines which buttons should - * be shown by the pagination rendering method that is used for the table: - * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the - * buttons are displayed in the document, while the functions here tell it - * what buttons to display. This is done by returning an array of button - * descriptions (what each button will do). - * - * Pagination types (the four built in options and any additional plug-in - * options defined here) can be used through the `paginationType` - * initialisation parameter. - * - * The functions defined take two parameters: - * - * 1. `{int} page` The current page index - * 2. `{int} pages` The number of pages in the table - * - * Each function is expected to return an array where each element of the - * array can be one of: - * - * * `first` - Jump to first page when activated - * * `last` - Jump to last page when activated - * * `previous` - Show previous page when activated - * * `next` - Show next page when activated - * * `{int}` - Show page of the index given - * * `{array}` - A nested array containing the above elements to add a - * containing 'DIV' element (might be useful for styling). - * - * Note that DataTables v1.9- used this object slightly differently whereby - * an object with two functions would be defined for each plug-in. That - * ability is still supported by DataTables 1.10+ to provide backwards - * compatibility, but this option of use is now decremented and no longer - * documented in DataTables 1.10+. - * - * @type object - * @default {} - * - * @example - * // Show previous, next and current page buttons only - * $.fn.dataTableExt.oPagination.current = function ( page, pages ) { - * return [ 'previous', page, 'next' ]; - * }; - */ - pager: {}, - - - renderer: { - pageButton: {}, - header: {} - }, - - - /** - * Ordering plug-ins - custom data source - * - * The extension options for ordering of data available here is complimentary - * to the default type based ordering that DataTables typically uses. It - * allows much greater control over the the data that is being used to - * order a column, but is necessarily therefore more complex. - * - * This type of ordering is useful if you want to do ordering based on data - * live from the DOM (for example the contents of an 'input' element) rather - * than just the static string that DataTables knows of. - * - * The way these plug-ins work is that you create an array of the values you - * wish to be ordering for the column in question and then return that - * array. The data in the array much be in the index order of the rows in - * the table (not the currently ordering order!). Which order data gathering - * function is run here depends on the `dt-init columns.orderDataType` - * parameter that is used for the column (if any). - * - * The functions defined take two parameters: - * - * 1. `{object}` DataTables settings object: see - * {@link DataTable.models.oSettings} - * 2. `{int}` Target column index - * - * Each function is expected to return an array: - * - * * `{array}` Data for the column to be ordering upon - * - * @type array - * - * @example - * // Ordering using `input` node values - * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col ) - * { - * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) { - * return $('input', td).val(); - * } ); - * } - */ - order: {}, - - - /** - * Type based plug-ins. - * - * Each column in DataTables has a type assigned to it, either by automatic - * detection or by direct assignment using the `type` option for the column. - * The type of a column will effect how it is ordering and search (plug-ins - * can also make use of the column type if required). - * - * @namespace - */ - type: { - /** - * Type detection functions. - * - * The functions defined in this object are used to automatically detect - * a column's type, making initialisation of DataTables super easy, even - * when complex data is in the table. - * - * The functions defined take two parameters: - * - * 1. `{*}` Data from the column cell to be analysed - * 2. `{settings}` DataTables settings object. This can be used to - * perform context specific type detection - for example detection - * based on language settings such as using a comma for a decimal - * place. Generally speaking the options from the settings will not - * be required - * - * Each function is expected to return: - * - * * `{string|null}` Data type detected, or null if unknown (and thus - * pass it on to the other type detection functions. - * - * @type array - * - * @example - * // Currency type detection plug-in: - * $.fn.dataTable.ext.type.detect.push( - * function ( data, settings ) { - * // Check the numeric part - * if ( ! $.isNumeric( data.substring(1) ) ) { - * return null; - * } - * - * // Check prefixed by currency - * if ( data.charAt(0) == '$' || data.charAt(0) == '£' ) { - * return 'currency'; - * } - * return null; - * } - * ); - */ - detect: [], - - - /** - * Type based search formatting. - * - * The type based searching functions can be used to pre-format the - * data to be search on. For example, it can be used to strip HTML - * tags or to de-format telephone numbers for numeric only searching. - * - * Note that is a search is not defined for a column of a given type, - * no search formatting will be performed. - * - * Pre-processing of searching data plug-ins - When you assign the sType - * for a column (or have it automatically detected for you by DataTables - * or a type detection plug-in), you will typically be using this for - * custom sorting, but it can also be used to provide custom searching - * by allowing you to pre-processing the data and returning the data in - * the format that should be searched upon. This is done by adding - * functions this object with a parameter name which matches the sType - * for that target column. This is the corollary of afnSortData - * for searching data. - * - * The functions defined take a single parameter: - * - * 1. `{*}` Data from the column cell to be prepared for searching - * - * Each function is expected to return: - * - * * `{string|null}` Formatted string that will be used for the searching. - * - * @type object - * @default {} - * - * @example - * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) { - * return d.replace(/\n/g," ").replace( /<.*?>/g, "" ); - * } - */ - search: {}, - - - /** - * Type based ordering. - * - * The column type tells DataTables what ordering to apply to the table - * when a column is sorted upon. The order for each type that is defined, - * is defined by the functions available in this object. - * - * Each ordering option can be described by three properties added to - * this object: - * - * * `{type}-pre` - Pre-formatting function - * * `{type}-asc` - Ascending order function - * * `{type}-desc` - Descending order function - * - * All three can be used together, only `{type}-pre` or only - * `{type}-asc` and `{type}-desc` together. It is generally recommended - * that only `{type}-pre` is used, as this provides the optimal - * implementation in terms of speed, although the others are provided - * for compatibility with existing Javascript sort functions. - * - * `{type}-pre`: Functions defined take a single parameter: - * - * 1. `{*}` Data from the column cell to be prepared for ordering - * - * And return: - * - * * `{*}` Data to be sorted upon - * - * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort - * functions, taking two parameters: - * - * 1. `{*}` Data to compare to the second parameter - * 2. `{*}` Data to compare to the first parameter - * - * And returning: - * - * * `{*}` Ordering match: <0 if first parameter should be sorted lower - * than the second parameter, ===0 if the two parameters are equal and - * >0 if the first parameter should be sorted height than the second - * parameter. - * - * @type object - * @default {} - * - * @example - * // Numeric ordering of formatted numbers with a pre-formatter - * $.extend( $.fn.dataTable.ext.type.order, { - * "string-pre": function(x) { - * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" ); - * return parseFloat( a ); - * } - * } ); - * - * @example - * // Case-sensitive string ordering, with no pre-formatting method - * $.extend( $.fn.dataTable.ext.order, { - * "string-case-asc": function(x,y) { - * return ((x < y) ? -1 : ((x > y) ? 1 : 0)); - * }, - * "string-case-desc": function(x,y) { - * return ((x < y) ? 1 : ((x > y) ? -1 : 0)); - * } - * } ); - */ - order: {} - }, - - /** - * Unique DataTables instance counter - * - * @type int - * @private - */ - _unique: 0, - - - // - // Depreciated - // The following properties are retained for backwards compatiblity only. - // The should not be used in new projects and will be removed in a future - // version - // - - /** - * Version check function. - * @type function - * @depreciated Since 1.10 - */ - fnVersionCheck: DataTable.fnVersionCheck, - - - /** - * Index for what 'this' index API functions should use - * @type int - * @deprecated Since v1.10 - */ - iApiIndex: 0, - - - /** - * jQuery UI class container - * @type object - * @deprecated Since v1.10 - */ - oJUIClasses: {}, - - - /** - * Software version - * @type string - * @deprecated Since v1.10 - */ - sVersion: DataTable.version - }; - - - // - // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts - // - $.extend( _ext, { - afnFiltering: _ext.search, - aTypes: _ext.type.detect, - ofnSearch: _ext.type.search, - oSort: _ext.type.order, - afnSortData: _ext.order, - aoFeatures: _ext.feature, - oApi: _ext.internal, - oStdClasses: _ext.classes, - oPagination: _ext.pager - } ); - - - $.extend( DataTable.ext.classes, { - "sTable": "dataTable", - "sNoFooter": "no-footer", - - /* Paging buttons */ - "sPageButton": "paginate_button", - "sPageButtonActive": "current", - "sPageButtonDisabled": "disabled", - - /* Striping classes */ - "sStripeOdd": "odd", - "sStripeEven": "even", - - /* Empty row */ - "sRowEmpty": "dataTables_empty", - - /* Features */ - "sWrapper": "dataTables_wrapper", - "sFilter": "dataTables_filter", - "sInfo": "dataTables_info", - "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */ - "sLength": "dataTables_length", - "sProcessing": "dataTables_processing", - - /* Sorting */ - "sSortAsc": "sorting_asc", - "sSortDesc": "sorting_desc", - "sSortable": "sorting", /* Sortable in both directions */ - "sSortableAsc": "sorting_asc_disabled", - "sSortableDesc": "sorting_desc_disabled", - "sSortableNone": "sorting_disabled", - "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */ - - /* Filtering */ - "sFilterInput": "", - - /* Page length */ - "sLengthSelect": "", - - /* Scrolling */ - "sScrollWrapper": "dataTables_scroll", - "sScrollHead": "dataTables_scrollHead", - "sScrollHeadInner": "dataTables_scrollHeadInner", - "sScrollBody": "dataTables_scrollBody", - "sScrollFoot": "dataTables_scrollFoot", - "sScrollFootInner": "dataTables_scrollFootInner", - - /* Misc */ - "sHeaderTH": "", - "sFooterTH": "", - - // Deprecated - "sSortJUIAsc": "", - "sSortJUIDesc": "", - "sSortJUI": "", - "sSortJUIAscAllowed": "", - "sSortJUIDescAllowed": "", - "sSortJUIWrapper": "", - "sSortIcon": "", - "sJUIHeader": "", - "sJUIFooter": "" - } ); - - - (function() { - - // Reused strings for better compression. Closure compiler appears to have a - // weird edge case where it is trying to expand strings rather than use the - // variable version. This results in about 200 bytes being added, for very - // little preference benefit since it this run on script load only. - var _empty = ''; - _empty = ''; - - var _stateDefault = _empty + 'ui-state-default'; - var _sortIcon = _empty + 'css_right ui-icon ui-icon-'; - var _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix'; - - $.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, { - /* Full numbers paging buttons */ - "sPageButton": "fg-button ui-button "+_stateDefault, - "sPageButtonActive": "ui-state-disabled", - "sPageButtonDisabled": "ui-state-disabled", - - /* Features */ - "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+ - "ui-buttonset-multi paging_", /* Note that the type is postfixed */ - - /* Sorting */ - "sSortAsc": _stateDefault+" sorting_asc", - "sSortDesc": _stateDefault+" sorting_desc", - "sSortable": _stateDefault+" sorting", - "sSortableAsc": _stateDefault+" sorting_asc_disabled", - "sSortableDesc": _stateDefault+" sorting_desc_disabled", - "sSortableNone": _stateDefault+" sorting_disabled", - "sSortJUIAsc": _sortIcon+"triangle-1-n", - "sSortJUIDesc": _sortIcon+"triangle-1-s", - "sSortJUI": _sortIcon+"carat-2-n-s", - "sSortJUIAscAllowed": _sortIcon+"carat-1-n", - "sSortJUIDescAllowed": _sortIcon+"carat-1-s", - "sSortJUIWrapper": "DataTables_sort_wrapper", - "sSortIcon": "DataTables_sort_icon", - - /* Scrolling */ - "sScrollHead": "dataTables_scrollHead "+_stateDefault, - "sScrollFoot": "dataTables_scrollFoot "+_stateDefault, - - /* Misc */ - "sHeaderTH": _stateDefault, - "sFooterTH": _stateDefault, - "sJUIHeader": _headerFooter+" ui-corner-tl ui-corner-tr", - "sJUIFooter": _headerFooter+" ui-corner-bl ui-corner-br" - } ); - - }()); - - - - var extPagination = DataTable.ext.pager; - - function _numbers ( page, pages ) { - var - numbers = [], - buttons = extPagination.numbers_length, - half = Math.floor( buttons / 2 ), - i = 1; - - if ( pages <= buttons ) { - numbers = _range( 0, pages ); - } - else if ( page <= half ) { - numbers = _range( 0, buttons-2 ); - numbers.push( 'ellipsis' ); - numbers.push( pages-1 ); - } - else if ( page >= pages - 1 - half ) { - numbers = _range( pages-(buttons-2), pages ); - numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6 - numbers.splice( 0, 0, 0 ); - } - else { - numbers = _range( page-half+2, page+half-1 ); - numbers.push( 'ellipsis' ); - numbers.push( pages-1 ); - numbers.splice( 0, 0, 'ellipsis' ); - numbers.splice( 0, 0, 0 ); - } - - numbers.DT_el = 'span'; - return numbers; - } - - - $.extend( extPagination, { - simple: function ( page, pages ) { - return [ 'previous', 'next' ]; - }, - - full: function ( page, pages ) { - return [ 'first', 'previous', 'next', 'last' ]; - }, - - numbers: function ( page, pages ) { - return [ _numbers(page, pages) ]; - }, - - simple_numbers: function ( page, pages ) { - return [ 'previous', _numbers(page, pages), 'next' ]; - }, - - full_numbers: function ( page, pages ) { - return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ]; - }, - - first_last_numbers: function (page, pages) { - return ['first', _numbers(page, pages), 'last']; - }, - - // For testing and plug-ins to use - _numbers: _numbers, - - // Number of number buttons (including ellipsis) to show. _Must be odd!_ - numbers_length: 7 - } ); - - - $.extend( true, DataTable.ext.renderer, { - pageButton: { - _: function ( settings, host, idx, buttons, page, pages ) { - var classes = settings.oClasses; - var lang = settings.oLanguage.oPaginate; - var aria = settings.oLanguage.oAria.paginate || {}; - var btnDisplay, btnClass, counter=0; - - var attach = function( container, buttons ) { - var i, ien, node, button; - var clickHandler = function ( e ) { - _fnPageChange( settings, e.data.action, true ); - }; - - for ( i=0, ien=buttons.length ; i' ) - .appendTo( container ); - attach( inner, button ); - } - else { - btnDisplay = null; - btnClass = ''; - - switch ( button ) { - case 'ellipsis': - container.append(''); - break; - - case 'first': - btnDisplay = lang.sFirst; - btnClass = button + (page > 0 ? - '' : ' '+classes.sPageButtonDisabled); - break; - - case 'previous': - btnDisplay = lang.sPrevious; - btnClass = button + (page > 0 ? - '' : ' '+classes.sPageButtonDisabled); - break; - - case 'next': - btnDisplay = lang.sNext; - btnClass = button + (page < pages-1 ? - '' : ' '+classes.sPageButtonDisabled); - break; - - case 'last': - btnDisplay = lang.sLast; - btnClass = button + (page < pages-1 ? - '' : ' '+classes.sPageButtonDisabled); - break; - - default: - btnDisplay = button + 1; - btnClass = page === button ? - classes.sPageButtonActive : ''; - break; - } - - if ( btnDisplay !== null ) { - node = $('', { - 'class': classes.sPageButton+' '+btnClass, - 'aria-controls': settings.sTableId, - 'aria-label': aria[ button ], - 'data-dt-idx': counter, - 'tabindex': settings.iTabIndex, - 'id': idx === 0 && typeof button === 'string' ? - settings.sTableId +'_'+ button : - null - } ) - .html( btnDisplay ) - .appendTo( container ); - - _fnBindAction( - node, {action: button}, clickHandler - ); - - counter++; - } - } - } - }; - - // IE9 throws an 'unknown error' if document.activeElement is used - // inside an iframe or frame. Try / catch the error. Not good for - // accessibility, but neither are frames. - var activeEl; - - try { - // Because this approach is destroying and recreating the paging - // elements, focus is lost on the select button which is bad for - // accessibility. So we want to restore focus once the draw has - // completed - activeEl = $(host).find(document.activeElement).data('dt-idx'); - } - catch (e) {} - - attach( $(host).empty(), buttons ); - - if ( activeEl !== undefined ) { - $(host).find( '[data-dt-idx='+activeEl+']' ).focus(); - } - } - } - } ); - - - - // Built in type detection. See model.ext.aTypes for information about - // what is required from this methods. - $.extend( DataTable.ext.type.detect, [ - // Plain numbers - first since V8 detects some plain numbers as dates - // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...). - function ( d, settings ) - { - var decimal = settings.oLanguage.sDecimal; - return _isNumber( d, decimal ) ? 'num'+decimal : null; - }, - - // Dates (only those recognised by the browser's Date.parse) - function ( d, settings ) - { - // V8 tries _very_ hard to make a string passed into `Date.parse()` - // valid, so we need to use a regex to restrict date formats. Use a - // plug-in for anything other than ISO8601 style strings - if ( d && !(d instanceof Date) && ! _re_date.test(d) ) { - return null; - } - var parsed = Date.parse(d); - return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null; - }, - - // Formatted numbers - function ( d, settings ) - { - var decimal = settings.oLanguage.sDecimal; - return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null; - }, - - // HTML numeric - function ( d, settings ) - { - var decimal = settings.oLanguage.sDecimal; - return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null; - }, - - // HTML numeric, formatted - function ( d, settings ) - { - var decimal = settings.oLanguage.sDecimal; - return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null; - }, - - // HTML (this is strict checking - there must be html) - function ( d, settings ) - { - return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ? - 'html' : null; - } - ] ); - - - - // Filter formatting functions. See model.ext.ofnSearch for information about - // what is required from these methods. - // - // Note that additional search methods are added for the html numbers and - // html formatted numbers by `_addNumericSort()` when we know what the decimal - // place is - - - $.extend( DataTable.ext.type.search, { - html: function ( data ) { - return _empty(data) ? - data : - typeof data === 'string' ? - data - .replace( _re_new_lines, " " ) - .replace( _re_html, "" ) : - ''; - }, - - string: function ( data ) { - return _empty(data) ? - data : - typeof data === 'string' ? - data.replace( _re_new_lines, " " ) : - data; - } - } ); - - - - var __numericReplace = function ( d, decimalPlace, re1, re2 ) { - if ( d !== 0 && (!d || d === '-') ) { - return -Infinity; - } - - // If a decimal place other than `.` is used, it needs to be given to the - // function so we can detect it and replace with a `.` which is the only - // decimal place Javascript recognises - it is not locale aware. - if ( decimalPlace ) { - d = _numToDecimal( d, decimalPlace ); - } - - if ( d.replace ) { - if ( re1 ) { - d = d.replace( re1, '' ); - } - - if ( re2 ) { - d = d.replace( re2, '' ); - } - } - - return d * 1; - }; - - - // Add the numeric 'deformatting' functions for sorting and search. This is done - // in a function to provide an easy ability for the language options to add - // additional methods if a non-period decimal place is used. - function _addNumericSort ( decimalPlace ) { - $.each( - { - // Plain numbers - "num": function ( d ) { - return __numericReplace( d, decimalPlace ); - }, - - // Formatted numbers - "num-fmt": function ( d ) { - return __numericReplace( d, decimalPlace, _re_formatted_numeric ); - }, - - // HTML numeric - "html-num": function ( d ) { - return __numericReplace( d, decimalPlace, _re_html ); - }, - - // HTML numeric, formatted - "html-num-fmt": function ( d ) { - return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric ); - } - }, - function ( key, fn ) { - // Add the ordering method - _ext.type.order[ key+decimalPlace+'-pre' ] = fn; - - // For HTML types add a search formatter that will strip the HTML - if ( key.match(/^html\-/) ) { - _ext.type.search[ key+decimalPlace ] = _ext.type.search.html; - } - } - ); - } - - - // Default sort methods - $.extend( _ext.type.order, { - // Dates - "date-pre": function ( d ) { - return Date.parse( d ) || -Infinity; - }, - - // html - "html-pre": function ( a ) { - return _empty(a) ? - '' : - a.replace ? - a.replace( /<.*?>/g, "" ).toLowerCase() : - a+''; - }, - - // string - "string-pre": function ( a ) { - // This is a little complex, but faster than always calling toString, - // http://jsperf.com/tostring-v-check - return _empty(a) ? - '' : - typeof a === 'string' ? - a.toLowerCase() : - ! a.toString ? - '' : - a.toString(); - }, - - // string-asc and -desc are retained only for compatibility with the old - // sort methods - "string-asc": function ( x, y ) { - return ((x < y) ? -1 : ((x > y) ? 1 : 0)); - }, - - "string-desc": function ( x, y ) { - return ((x < y) ? 1 : ((x > y) ? -1 : 0)); - } - } ); - - - // Numeric sorting types - order doesn't matter here - _addNumericSort( '' ); - - - $.extend( true, DataTable.ext.renderer, { - header: { - _: function ( settings, cell, column, classes ) { - // No additional mark-up required - // Attach a sort listener to update on sort - note that using the - // `DT` namespace will allow the event to be removed automatically - // on destroy, while the `dt` namespaced event is the one we are - // listening for - $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { - if ( settings !== ctx ) { // need to check this this is the host - return; // table, not a nested one - } - - var colIdx = column.idx; - - cell - .removeClass( - column.sSortingClass +' '+ - classes.sSortAsc +' '+ - classes.sSortDesc - ) - .addClass( columns[ colIdx ] == 'asc' ? - classes.sSortAsc : columns[ colIdx ] == 'desc' ? - classes.sSortDesc : - column.sSortingClass - ); - } ); - }, - - jqueryui: function ( settings, cell, column, classes ) { - $('
    ') - .addClass( classes.sSortJUIWrapper ) - .append( cell.contents() ) - .append( $('') - .addClass( classes.sSortIcon+' '+column.sSortingClassJUI ) - ) - .appendTo( cell ); - - // Attach a sort listener to update on sort - $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { - if ( settings !== ctx ) { - return; - } - - var colIdx = column.idx; - - cell - .removeClass( classes.sSortAsc +" "+classes.sSortDesc ) - .addClass( columns[ colIdx ] == 'asc' ? - classes.sSortAsc : columns[ colIdx ] == 'desc' ? - classes.sSortDesc : - column.sSortingClass - ); - - cell - .find( 'span.'+classes.sSortIcon ) - .removeClass( - classes.sSortJUIAsc +" "+ - classes.sSortJUIDesc +" "+ - classes.sSortJUI +" "+ - classes.sSortJUIAscAllowed +" "+ - classes.sSortJUIDescAllowed - ) - .addClass( columns[ colIdx ] == 'asc' ? - classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ? - classes.sSortJUIDesc : - column.sSortingClassJUI - ); - } ); - } - } - } ); - - /* - * Public helper functions. These aren't used internally by DataTables, or - * called by any of the options passed into DataTables, but they can be used - * externally by developers working with DataTables. They are helper functions - * to make working with DataTables a little bit easier. - */ - - var __htmlEscapeEntities = function ( d ) { - return typeof d === 'string' ? - d.replace(//g, '>').replace(/"/g, '"') : - d; - }; - - /** - * Helpers for `columns.render`. - * - * The options defined here can be used with the `columns.render` initialisation - * option to provide a display renderer. The following functions are defined: - * - * * `number` - Will format numeric data (defined by `columns.data`) for - * display, retaining the original unformatted data for sorting and filtering. - * It takes 5 parameters: - * * `string` - Thousands grouping separator - * * `string` - Decimal point indicator - * * `integer` - Number of decimal points to show - * * `string` (optional) - Prefix. - * * `string` (optional) - Postfix (/suffix). - * * `text` - Escape HTML to help prevent XSS attacks. It has no optional - * parameters. - * - * @example - * // Column definition using the number renderer - * { - * data: "salary", - * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' ) - * } - * - * @namespace - */ - DataTable.render = { - number: function ( thousands, decimal, precision, prefix, postfix ) { - return { - display: function ( d ) { - if ( typeof d !== 'number' && typeof d !== 'string' ) { - return d; - } - - var negative = d < 0 ? '-' : ''; - var flo = parseFloat( d ); - - // If NaN then there isn't much formatting that we can do - just - // return immediately, escaping any HTML (this was supposed to - // be a number after all) - if ( isNaN( flo ) ) { - return __htmlEscapeEntities( d ); - } - - flo = flo.toFixed( precision ); - d = Math.abs( flo ); - - var intPart = parseInt( d, 10 ); - var floatPart = precision ? - decimal+(d - intPart).toFixed( precision ).substring( 2 ): - ''; - - return negative + (prefix||'') + - intPart.toString().replace( - /\B(?=(\d{3})+(?!\d))/g, thousands - ) + - floatPart + - (postfix||''); - } - }; - }, - - text: function () { - return { - display: __htmlEscapeEntities - }; - } - }; - - - /* - * This is really a good bit rubbish this method of exposing the internal methods - * publicly... - To be fixed in 2.0 using methods on the prototype - */ - - - /** - * Create a wrapper function for exporting an internal functions to an external API. - * @param {string} fn API function name - * @returns {function} wrapped function - * @memberof DataTable#internal - */ - function _fnExternApiFunc (fn) - { - return function() { - var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat( - Array.prototype.slice.call(arguments) - ); - return DataTable.ext.internal[fn].apply( this, args ); - }; - } - - - /** - * Reference to internal functions for use by plug-in developers. Note that - * these methods are references to internal functions and are considered to be - * private. If you use these methods, be aware that they are liable to change - * between versions. - * @namespace - */ - $.extend( DataTable.ext.internal, { - _fnExternApiFunc: _fnExternApiFunc, - _fnBuildAjax: _fnBuildAjax, - _fnAjaxUpdate: _fnAjaxUpdate, - _fnAjaxParameters: _fnAjaxParameters, - _fnAjaxUpdateDraw: _fnAjaxUpdateDraw, - _fnAjaxDataSrc: _fnAjaxDataSrc, - _fnAddColumn: _fnAddColumn, - _fnColumnOptions: _fnColumnOptions, - _fnAdjustColumnSizing: _fnAdjustColumnSizing, - _fnVisibleToColumnIndex: _fnVisibleToColumnIndex, - _fnColumnIndexToVisible: _fnColumnIndexToVisible, - _fnVisbleColumns: _fnVisbleColumns, - _fnGetColumns: _fnGetColumns, - _fnColumnTypes: _fnColumnTypes, - _fnApplyColumnDefs: _fnApplyColumnDefs, - _fnHungarianMap: _fnHungarianMap, - _fnCamelToHungarian: _fnCamelToHungarian, - _fnLanguageCompat: _fnLanguageCompat, - _fnBrowserDetect: _fnBrowserDetect, - _fnAddData: _fnAddData, - _fnAddTr: _fnAddTr, - _fnNodeToDataIndex: _fnNodeToDataIndex, - _fnNodeToColumnIndex: _fnNodeToColumnIndex, - _fnGetCellData: _fnGetCellData, - _fnSetCellData: _fnSetCellData, - _fnSplitObjNotation: _fnSplitObjNotation, - _fnGetObjectDataFn: _fnGetObjectDataFn, - _fnSetObjectDataFn: _fnSetObjectDataFn, - _fnGetDataMaster: _fnGetDataMaster, - _fnClearTable: _fnClearTable, - _fnDeleteIndex: _fnDeleteIndex, - _fnInvalidate: _fnInvalidate, - _fnGetRowElements: _fnGetRowElements, - _fnCreateTr: _fnCreateTr, - _fnBuildHead: _fnBuildHead, - _fnDrawHead: _fnDrawHead, - _fnDraw: _fnDraw, - _fnReDraw: _fnReDraw, - _fnAddOptionsHtml: _fnAddOptionsHtml, - _fnDetectHeader: _fnDetectHeader, - _fnGetUniqueThs: _fnGetUniqueThs, - _fnFeatureHtmlFilter: _fnFeatureHtmlFilter, - _fnFilterComplete: _fnFilterComplete, - _fnFilterCustom: _fnFilterCustom, - _fnFilterColumn: _fnFilterColumn, - _fnFilter: _fnFilter, - _fnFilterCreateSearch: _fnFilterCreateSearch, - _fnEscapeRegex: _fnEscapeRegex, - _fnFilterData: _fnFilterData, - _fnFeatureHtmlInfo: _fnFeatureHtmlInfo, - _fnUpdateInfo: _fnUpdateInfo, - _fnInfoMacros: _fnInfoMacros, - _fnInitialise: _fnInitialise, - _fnInitComplete: _fnInitComplete, - _fnLengthChange: _fnLengthChange, - _fnFeatureHtmlLength: _fnFeatureHtmlLength, - _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate, - _fnPageChange: _fnPageChange, - _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing, - _fnProcessingDisplay: _fnProcessingDisplay, - _fnFeatureHtmlTable: _fnFeatureHtmlTable, - _fnScrollDraw: _fnScrollDraw, - _fnApplyToChildren: _fnApplyToChildren, - _fnCalculateColumnWidths: _fnCalculateColumnWidths, - _fnThrottle: _fnThrottle, - _fnConvertToWidth: _fnConvertToWidth, - _fnGetWidestNode: _fnGetWidestNode, - _fnGetMaxLenString: _fnGetMaxLenString, - _fnStringToCss: _fnStringToCss, - _fnSortFlatten: _fnSortFlatten, - _fnSort: _fnSort, - _fnSortAria: _fnSortAria, - _fnSortListener: _fnSortListener, - _fnSortAttachListener: _fnSortAttachListener, - _fnSortingClasses: _fnSortingClasses, - _fnSortData: _fnSortData, - _fnSaveState: _fnSaveState, - _fnLoadState: _fnLoadState, - _fnSettingsFromNode: _fnSettingsFromNode, - _fnLog: _fnLog, - _fnMap: _fnMap, - _fnBindAction: _fnBindAction, - _fnCallbackReg: _fnCallbackReg, - _fnCallbackFire: _fnCallbackFire, - _fnLengthOverflow: _fnLengthOverflow, - _fnRenderer: _fnRenderer, - _fnDataSource: _fnDataSource, - _fnRowAttributes: _fnRowAttributes, - _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant - // in 1.10, so this dead-end function is - // added to prevent errors - } ); - - - // jQuery access - $.fn.dataTable = DataTable; - - // Provide access to the host jQuery object (circular reference) - DataTable.$ = $; - - // Legacy aliases - $.fn.dataTableSettings = DataTable.settings; - $.fn.dataTableExt = DataTable.ext; - - // With a capital `D` we return a DataTables API instance rather than a - // jQuery object - $.fn.DataTable = function ( opts ) { - return $(this).dataTable( opts ).api(); - }; - - // All properties that are available to $.fn.dataTable should also be - // available on $.fn.DataTable - $.each( DataTable, function ( prop, val ) { - $.fn.DataTable[ prop ] = val; - } ); - - - // Information about events fired by DataTables - for documentation. - /** - * Draw event, fired whenever the table is redrawn on the page, at the same - * point as fnDrawCallback. This may be useful for binding events or - * performing calculations when the table is altered at all. - * @name DataTable#draw.dt - * @event - * @param {event} e jQuery event object - * @param {object} o DataTables settings object {@link DataTable.models.oSettings} - */ - - /** - * Search event, fired when the searching applied to the table (using the - * built-in global search, or column filters) is altered. - * @name DataTable#search.dt - * @event - * @param {event} e jQuery event object - * @param {object} o DataTables settings object {@link DataTable.models.oSettings} - */ - - /** - * Page change event, fired when the paging of the table is altered. - * @name DataTable#page.dt - * @event - * @param {event} e jQuery event object - * @param {object} o DataTables settings object {@link DataTable.models.oSettings} - */ - - /** - * Order event, fired when the ordering applied to the table is altered. - * @name DataTable#order.dt - * @event - * @param {event} e jQuery event object - * @param {object} o DataTables settings object {@link DataTable.models.oSettings} - */ - - /** - * DataTables initialisation complete event, fired when the table is fully - * drawn, including Ajax data loaded, if Ajax data is required. - * @name DataTable#init.dt - * @event - * @param {event} e jQuery event object - * @param {object} oSettings DataTables settings object - * @param {object} json The JSON object request from the server - only - * present if client-side Ajax sourced data is used - */ - - /** - * State save event, fired when the table has changed state a new state save - * is required. This event allows modification of the state saving object - * prior to actually doing the save, including addition or other state - * properties (for plug-ins) or modification of a DataTables core property. - * @name DataTable#stateSaveParams.dt - * @event - * @param {event} e jQuery event object - * @param {object} oSettings DataTables settings object - * @param {object} json The state information to be saved - */ - - /** - * State load event, fired when the table is loading state from the stored - * data, but prior to the settings object being modified by the saved state - * - allowing modification of the saved state is required or loading of - * state for a plug-in. - * @name DataTable#stateLoadParams.dt - * @event - * @param {event} e jQuery event object - * @param {object} oSettings DataTables settings object - * @param {object} json The saved state information - */ - - /** - * State loaded event, fired when state has been loaded from stored data and - * the settings object has been modified by the loaded data. - * @name DataTable#stateLoaded.dt - * @event - * @param {event} e jQuery event object - * @param {object} oSettings DataTables settings object - * @param {object} json The saved state information - */ - - /** - * Processing event, fired when DataTables is doing some kind of processing - * (be it, order, searcg or anything else). It can be used to indicate to - * the end user that there is something happening, or that something has - * finished. - * @name DataTable#processing.dt - * @event - * @param {event} e jQuery event object - * @param {object} oSettings DataTables settings object - * @param {boolean} bShow Flag for if DataTables is doing processing or not - */ - - /** - * Ajax (XHR) event, fired whenever an Ajax request is completed from a - * request to made to the server for new data. This event is called before - * DataTables processed the returned data, so it can also be used to pre- - * process the data returned from the server, if needed. - * - * Note that this trigger is called in `fnServerData`, if you override - * `fnServerData` and which to use this event, you need to trigger it in you - * success function. - * @name DataTable#xhr.dt - * @event - * @param {event} e jQuery event object - * @param {object} o DataTables settings object {@link DataTable.models.oSettings} - * @param {object} json JSON returned from the server - * - * @example - * // Use a custom property returned from the server in another DOM element - * $('#table').dataTable().on('xhr.dt', function (e, settings, json) { - * $('#status').html( json.status ); - * } ); - * - * @example - * // Pre-process the data returned from the server - * $('#table').dataTable().on('xhr.dt', function (e, settings, json) { - * for ( var i=0, ien=json.aaData.length ; i").css({position:"fixed",top:0,left:-1*h(E).scrollLeft(),height:1,width:1,overflow:"hidden"}).append(h("
    ").css({position:"absolute", -top:1,left:1,width:100,overflow:"scroll"}).append(h("
    ").css({width:"100%",height:10}))).appendTo("body"),d=c.children(),e=d.children();b.barWidth=d[0].offsetWidth-d[0].clientWidth;b.bScrollOversize=100===e[0].offsetWidth&&100!==d[0].clientWidth;b.bScrollbarLeft=1!==Math.round(e.offset().left);b.bBounding=c[0].getBoundingClientRect().width?!0:!1;c.remove()}h.extend(a.oBrowser,m.__browser);a.oScroll.iBarWidth=m.__browser.barWidth}function jb(a,b,c,d,e,f){var g,j=!1;c!==k&&(g=c,j=!0);for(;d!== -e;)a.hasOwnProperty(d)&&(g=j?b(g,a[d],d,a):a[d],j=!0,d+=f);return g}function Ga(a,b){var c=m.defaults.column,d=a.aoColumns.length,c=h.extend({},m.models.oColumn,c,{nTh:b?b:H.createElement("th"),sTitle:c.sTitle?c.sTitle:b?b.innerHTML:"",aDataSort:c.aDataSort?c.aDataSort:[d],mData:c.mData?c.mData:d,idx:d});a.aoColumns.push(c);c=a.aoPreSearchCols;c[d]=h.extend({},m.models.oSearch,c[d]);la(a,d,h(b).data())}function la(a,b,c){var b=a.aoColumns[b],d=a.oClasses,e=h(b.nTh);if(!b.sWidthOrig){b.sWidthOrig= -e.attr("width")||null;var f=(e.attr("style")||"").match(/width:\s*(\d+[pxem%]+)/);f&&(b.sWidthOrig=f[1])}c!==k&&null!==c&&(hb(c),J(m.defaults.column,c),c.mDataProp!==k&&!c.mData&&(c.mData=c.mDataProp),c.sType&&(b._sManualType=c.sType),c.className&&!c.sClass&&(c.sClass=c.className),h.extend(b,c),F(b,c,"sWidth","sWidthOrig"),c.iDataSort!==k&&(b.aDataSort=[c.iDataSort]),F(b,c,"aDataSort"));var g=b.mData,j=R(g),i=b.mRender?R(b.mRender):null,c=function(a){return"string"===typeof a&&-1!==a.indexOf("@")}; -b._bAttrSrc=h.isPlainObject(g)&&(c(g.sort)||c(g.type)||c(g.filter));b._setter=null;b.fnGetData=function(a,b,c){var d=j(a,b,k,c);return i&&b?i(d,b,a,c):d};b.fnSetData=function(a,b,c){return S(g)(a,b,c)};"number"!==typeof g&&(a._rowReadObject=!0);a.oFeatures.bSort||(b.bSortable=!1,e.addClass(d.sSortableNone));a=-1!==h.inArray("asc",b.asSorting);c=-1!==h.inArray("desc",b.asSorting);!b.bSortable||!a&&!c?(b.sSortingClass=d.sSortableNone,b.sSortingClassJUI=""):a&&!c?(b.sSortingClass=d.sSortableAsc,b.sSortingClassJUI= -d.sSortJUIAscAllowed):!a&&c?(b.sSortingClass=d.sSortableDesc,b.sSortingClassJUI=d.sSortJUIDescAllowed):(b.sSortingClass=d.sSortable,b.sSortingClassJUI=d.sSortJUI)}function Z(a){if(!1!==a.oFeatures.bAutoWidth){var b=a.aoColumns;Ha(a);for(var c=0,d=b.length;cq[f])d(l.length+q[f],n);else if("string"===typeof q[f]){j=0;for(i=l.length;jb&&a[e]--; -1!=d&&c===k&&a.splice(d,1)}function da(a,b,c,d){var e=a.aoData[b],f,g=function(c,d){for(;c.childNodes.length;)c.removeChild(c.firstChild); -c.innerHTML=B(a,b,d,"display")};if("dom"===c||(!c||"auto"===c)&&"dom"===e.src)e._aData=Ka(a,e,d,d===k?k:e._aData).data;else{var j=e.anCells;if(j)if(d!==k)g(j[d],d);else{c=0;for(f=j.length;c").appendTo(g));b=0;for(c=l.length;btr").attr("role","row");h(g).find(">tr>th, >tr>td").addClass(n.sHeaderTH);h(j).find(">tr>th, >tr>td").addClass(n.sFooterTH); -if(null!==j){a=a.aoFooter[0];b=0;for(c=a.length;b=a.fnRecordsDisplay()?0:g,a.iInitDisplayStart= --1);var g=a._iDisplayStart,n=a.fnDisplayEnd();if(a.bDeferLoading)a.bDeferLoading=!1,a.iDraw++,C(a,!1);else if(j){if(!a.bDestroying&&!nb(a))return}else a.iDraw++;if(0!==i.length){f=j?a.aoData.length:n;for(j=j?0:g;j",{"class":e?d[0]:""}).append(h("
    ").appendTo(q));o.nTBody=b[0];b=q.children("tfoot");if(b.length===0&&a.length>0&&(o.oScroll.sX!==""||o.oScroll.sY!==""))b=h("").appendTo(q);if(b.length===0||b.children().length===0)q.addClass(u.sNoFooter);else if(b.length>0){o.nTFoot=b[0];ea(o.aoFooter,o.nTFoot)}if(g.aaData)for(j=0;j/g,cc=/^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/,dc=RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\|\\$|\\^|\\-)","g"),Za=/[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi,M=function(a){return!a||!0===a||"-"===a?!0:!1},Qb=function(a){var b=parseInt(a,10);return!isNaN(b)&& -isFinite(a)?b:null},Rb=function(a,b){$a[b]||($a[b]=RegExp(Sa(b),"g"));return"string"===typeof a&&"."!==b?a.replace(/\./g,"").replace($a[b],"."):a},ab=function(a,b,c){var d="string"===typeof a;if(M(a))return!0;b&&d&&(a=Rb(a,b));c&&d&&(a=a.replace(Za,""));return!isNaN(parseFloat(a))&&isFinite(a)},Sb=function(a,b,c){return M(a)?!0:!(M(a)||"string"===typeof a)?null:ab(a.replace(Ca,""),b,c)?!0:null},D=function(a,b,c){var d=[],e=0,f=a.length;if(c!==k)for(;ea.length)){b=a.slice().sort();for(var c=b[0],d=1,e=b.length;d")[0],$b=xa.textContent!==k,bc= -/<.*?>/g,Qa=m.util.throttle,Ub=[],w=Array.prototype,ec=function(a){var b,c,d=m.settings,e=h.map(d,function(a){return a.nTable});if(a){if(a.nTable&&a.oApi)return[a];if(a.nodeName&&"table"===a.nodeName.toLowerCase())return b=h.inArray(a,e),-1!==b?[d[b]]:null;if(a&&"function"===typeof a.settings)return a.settings().toArray();"string"===typeof a?c=h(a):a instanceof h&&(c=a)}else return[];if(c)return c.map(function(){b=h.inArray(this,e);return-1!==b?d[b]:null}).toArray()};t=function(a,b){if(!(this instanceof -t))return new t(a,b);var c=[],d=function(a){(a=ec(a))&&(c=c.concat(a))};if(h.isArray(a))for(var e=0,f=a.length;ea?new t(b[a],this[a]):null},filter:function(a){var b=[];if(w.filter)b=w.filter.call(this,a,this);else for(var c=0,d=this.length;c").addClass(b),h("td",c).addClass(b).html(a)[0].colSpan=ba(d),e.push(c[0]))};f(a,b);c._details&&c._details.detach();c._details=h(e);c._detailsShow&&c._details.insertAfter(c.nTr)}return this});p(["row().child.show()","row().child().show()"],function(){Wb(this,!0);return this});p(["row().child.hide()","row().child().hide()"],function(){Wb(this,!1); -return this});p(["row().child.remove()","row().child().remove()"],function(){eb(this);return this});p("row().child.isShown()",function(){var a=this.context;return a.length&&this.length?a[0].aoData[this[0]]._detailsShow||!1:!1});var fc=/^([^:]+):(name|visIdx|visible)$/,Xb=function(a,b,c,d,e){for(var c=[],d=0,f=e.length;d=0?b:g.length+b];if(typeof a==="function"){var e=Da(c,f);return h.map(g,function(b,f){return a(f,Xb(c,f,0,0,e),i[f])?f:null})}var k=typeof a==="string"?a.match(fc):"";if(k)switch(k[2]){case "visIdx":case "visible":b=parseInt(k[1],10);if(b<0){var m=h.map(g,function(a,b){return a.bVisible?b:null});return[m[m.length+b]]}return[$(c,b)];case "name":return h.map(j,function(a,b){return a=== -k[1]?b:null});default:return[]}if(a.nodeName&&a._DT_CellIndex)return[a._DT_CellIndex.column];b=h(i).filter(a).map(function(){return h.inArray(this,i)}).toArray();if(b.length||!a.nodeName)return b;b=h(a).closest("*[data-dt-column]");return b.length?[b.data("dt-column")]:[]},c,f)},1);c.selector.cols=a;c.selector.opts=b;return c});u("columns().header()","column().header()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTh},1)});u("columns().footer()","column().footer()", -function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTf},1)});u("columns().data()","column().data()",function(){return this.iterator("column-rows",Xb,1)});u("columns().dataSrc()","column().dataSrc()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].mData},1)});u("columns().cache()","column().cache()",function(a){return this.iterator("column-rows",function(b,c,d,e,f){return ja(b.aoData,f,"search"===a?"_aFilterData":"_aSortData",c)},1)});u("columns().nodes()", -"column().nodes()",function(){return this.iterator("column-rows",function(a,b,c,d,e){return ja(a.aoData,e,"anCells",b)},1)});u("columns().visible()","column().visible()",function(a,b){var c=this.iterator("column",function(b,c){if(a===k)return b.aoColumns[c].bVisible;var f=b.aoColumns,g=f[c],j=b.aoData,i,n,l;if(a!==k&&g.bVisible!==a){if(a){var m=h.inArray(!0,D(f,"bVisible"),c+1);i=0;for(n=j.length;id;return!0};m.isDataTable=m.fnIsDataTable=function(a){var b=h(a).get(0),c=!1;if(a instanceof m.Api)return!0;h.each(m.settings,function(a,e){var f=e.nScrollHead?h("table",e.nScrollHead)[0]:null,g=e.nScrollFoot?h("table",e.nScrollFoot)[0]:null;if(e.nTable===b||f===b||g===b)c=!0});return c};m.tables=m.fnTables=function(a){var b=!1;h.isPlainObject(a)&&(b=a.api,a=a.visible);var c=h.map(m.settings, -function(b){if(!a||a&&h(b.nTable).is(":visible"))return b.nTable});return b?new t(c):c};m.camelToHungarian=J;p("$()",function(a,b){var c=this.rows(b).nodes(),c=h(c);return h([].concat(c.filter(a).toArray(),c.find(a).toArray()))});h.each(["on","one","off"],function(a,b){p(b+"()",function(){var a=Array.prototype.slice.call(arguments);a[0]=h.map(a[0].split(/\s/),function(a){return!a.match(/\.dt\b/)?a+".dt":a}).join(" ");var d=h(this.tables().nodes());d[b].apply(d,a);return this})});p("clear()",function(){return this.iterator("table", -function(a){pa(a)})});p("settings()",function(){return new t(this.context,this.context)});p("init()",function(){var a=this.context;return a.length?a[0].oInit:null});p("data()",function(){return this.iterator("table",function(a){return D(a.aoData,"_aData")}).flatten()});p("destroy()",function(a){a=a||!1;return this.iterator("table",function(b){var c=b.nTableWrapper.parentNode,d=b.oClasses,e=b.nTable,f=b.nTBody,g=b.nTHead,j=b.nTFoot,i=h(e),f=h(f),k=h(b.nTableWrapper),l=h.map(b.aoData,function(a){return a.nTr}), -p;b.bDestroying=!0;s(b,"aoDestroyCallback","destroy",[b]);a||(new t(b)).columns().visible(!0);k.off(".DT").find(":not(tbody *)").off(".DT");h(E).off(".DT-"+b.sInstance);e!=g.parentNode&&(i.children("thead").detach(),i.append(g));j&&e!=j.parentNode&&(i.children("tfoot").detach(),i.append(j));b.aaSorting=[];b.aaSortingFixed=[];ya(b);h(l).removeClass(b.asStripeClasses.join(" "));h("th, td",g).removeClass(d.sSortable+" "+d.sSortableAsc+" "+d.sSortableDesc+" "+d.sSortableNone);b.bJUI&&(h("th span."+d.sSortIcon+ -", td span."+d.sSortIcon,g).detach(),h("th, td",g).each(function(){var a=h("div."+d.sSortJUIWrapper,this);h(this).append(a.contents());a.detach()}));f.children().detach();f.append(l);g=a?"remove":"detach";i[g]();k[g]();!a&&c&&(c.insertBefore(e,b.nTableReinsertBefore),i.css("width",b.sDestroyWidth).removeClass(d.sTable),(p=b.asDestroyStripes.length)&&f.children().each(function(a){h(this).addClass(b.asDestroyStripes[a%p])}));c=h.inArray(b,m.settings);-1!==c&&m.settings.splice(c,1)})});h.each(["column", -"row","cell"],function(a,b){p(b+"s().every()",function(a){var d=this.selector.opts,e=this;return this.iterator(b,function(f,g,h,i,m){a.call(e[b](g,"cell"===b?h:d,"cell"===b?d:k),g,h,i,m)})})});p("i18n()",function(a,b,c){var d=this.context[0],a=R(a)(d.oLanguage);a===k&&(a=b);c!==k&&h.isPlainObject(a)&&(a=a[c]!==k?a[c]:a._);return a.replace("%d",c)});m.version="1.10.15";m.settings=[];m.models={};m.models.oSearch={bCaseInsensitive:!0,sSearch:"",bRegex:!1,bSmart:!0};m.models.oRow={nTr:null,anCells:null, -_aData:[],_aSortData:null,_aFilterData:null,_sFilterRow:null,_sRowStripe:"",src:null,idx:-1};m.models.oColumn={idx:null,aDataSort:null,asSorting:null,bSearchable:null,bSortable:null,bVisible:null,_sManualType:null,_bAttrSrc:!1,fnCreatedCell:null,fnGetData:null,fnSetData:null,mData:null,mRender:null,nTh:null,nTf:null,sClass:null,sContentPadding:null,sDefaultContent:null,sName:null,sSortDataType:"std",sSortingClass:null,sSortingClassJUI:null,sTitle:null,sType:null,sWidth:null,sWidthOrig:null};m.defaults= -{aaData:null,aaSorting:[[0,"asc"]],aaSortingFixed:[],ajax:null,aLengthMenu:[10,25,50,100],aoColumns:null,aoColumnDefs:null,aoSearchCols:[],asStripeClasses:null,bAutoWidth:!0,bDeferRender:!1,bDestroy:!1,bFilter:!0,bInfo:!0,bJQueryUI:!1,bLengthChange:!0,bPaginate:!0,bProcessing:!1,bRetrieve:!1,bScrollCollapse:!1,bServerSide:!1,bSort:!0,bSortMulti:!0,bSortCellsTop:!1,bSortClasses:!0,bStateSave:!1,fnCreatedRow:null,fnDrawCallback:null,fnFooterCallback:null,fnFormatNumber:function(a){return a.toString().replace(/\B(?=(\d{3})+(?!\d))/g, -this.oLanguage.sThousands)},fnHeaderCallback:null,fnInfoCallback:null,fnInitComplete:null,fnPreDrawCallback:null,fnRowCallback:null,fnServerData:null,fnServerParams:null,fnStateLoadCallback:function(a){try{return JSON.parse((-1===a.iStateDuration?sessionStorage:localStorage).getItem("DataTables_"+a.sInstance+"_"+location.pathname))}catch(b){}},fnStateLoadParams:null,fnStateLoaded:null,fnStateSaveCallback:function(a,b){try{(-1===a.iStateDuration?sessionStorage:localStorage).setItem("DataTables_"+a.sInstance+ -"_"+location.pathname,JSON.stringify(b))}catch(c){}},fnStateSaveParams:null,iStateDuration:7200,iDeferLoading:null,iDisplayLength:10,iDisplayStart:0,iTabIndex:0,oClasses:{},oLanguage:{oAria:{sSortAscending:": activate to sort column ascending",sSortDescending:": activate to sort column descending"},oPaginate:{sFirst:"First",sLast:"Last",sNext:"Next",sPrevious:"Previous"},sEmptyTable:"No data available in table",sInfo:"Showing _START_ to _END_ of _TOTAL_ entries",sInfoEmpty:"Showing 0 to 0 of 0 entries", -sInfoFiltered:"(filtered from _MAX_ total entries)",sInfoPostFix:"",sDecimal:"",sThousands:",",sLengthMenu:"Show _MENU_ entries",sLoadingRecords:"Loading...",sProcessing:"Processing...",sSearch:"Search:",sSearchPlaceholder:"",sUrl:"",sZeroRecords:"No matching records found"},oSearch:h.extend({},m.models.oSearch),sAjaxDataProp:"data",sAjaxSource:null,sDom:"lfrtip",searchDelay:null,sPaginationType:"simple_numbers",sScrollX:"",sScrollXInner:"",sScrollY:"",sServerMethod:"GET",renderer:null,rowId:"DT_RowId"}; -Y(m.defaults);m.defaults.column={aDataSort:null,iDataSort:-1,asSorting:["asc","desc"],bSearchable:!0,bSortable:!0,bVisible:!0,fnCreatedCell:null,mData:null,mRender:null,sCellType:"td",sClass:"",sContentPadding:"",sDefaultContent:null,sName:"",sSortDataType:"std",sTitle:null,sType:null,sWidth:null};Y(m.defaults.column);m.models.oSettings={oFeatures:{bAutoWidth:null,bDeferRender:null,bFilter:null,bInfo:null,bLengthChange:null,bPaginate:null,bProcessing:null,bServerSide:null,bSort:null,bSortMulti:null, -bSortClasses:null,bStateSave:null},oScroll:{bCollapse:null,iBarWidth:0,sX:null,sXInner:null,sY:null},oLanguage:{fnInfoCallback:null},oBrowser:{bScrollOversize:!1,bScrollbarLeft:!1,bBounding:!1,barWidth:0},ajax:null,aanFeatures:[],aoData:[],aiDisplay:[],aiDisplayMaster:[],aIds:{},aoColumns:[],aoHeader:[],aoFooter:[],oPreviousSearch:{},aoPreSearchCols:[],aaSorting:null,aaSortingFixed:[],asStripeClasses:null,asDestroyStripes:[],sDestroyWidth:0,aoRowCallback:[],aoHeaderCallback:[],aoFooterCallback:[], -aoDrawCallback:[],aoRowCreatedCallback:[],aoPreDrawCallback:[],aoInitComplete:[],aoStateSaveParams:[],aoStateLoadParams:[],aoStateLoaded:[],sTableId:"",nTable:null,nTHead:null,nTFoot:null,nTBody:null,nTableWrapper:null,bDeferLoading:!1,bInitialised:!1,aoOpenRows:[],sDom:null,searchDelay:null,sPaginationType:"two_button",iStateDuration:0,aoStateSave:[],aoStateLoad:[],oSavedState:null,oLoadedState:null,sAjaxSource:null,sAjaxDataProp:null,bAjaxDataGet:!0,jqXHR:null,json:k,oAjaxData:k,fnServerData:null, -aoServerParams:[],sServerMethod:null,fnFormatNumber:null,aLengthMenu:null,iDraw:0,bDrawing:!1,iDrawError:-1,_iDisplayLength:10,_iDisplayStart:0,_iRecordsTotal:0,_iRecordsDisplay:0,bJUI:null,oClasses:{},bFiltered:!1,bSorted:!1,bSortCellsTop:null,oInit:null,aoDestroyCallback:[],fnRecordsTotal:function(){return"ssp"==y(this)?1*this._iRecordsTotal:this.aiDisplayMaster.length},fnRecordsDisplay:function(){return"ssp"==y(this)?1*this._iRecordsDisplay:this.aiDisplay.length},fnDisplayEnd:function(){var a= -this._iDisplayLength,b=this._iDisplayStart,c=b+a,d=this.aiDisplay.length,e=this.oFeatures,f=e.bPaginate;return e.bServerSide?!1===f||-1===a?b+d:Math.min(b+a,this._iRecordsDisplay):!f||c>d||-1===a?d:c},oInstance:null,sInstance:null,iTabIndex:0,nScrollHead:null,nScrollFoot:null,aLastSort:[],oPlugins:{},rowIdFn:null,rowId:null};m.ext=x={buttons:{},classes:{},builder:"-source-",errMode:"alert",feature:[],search:[],selector:{cell:[],column:[],row:[]},internal:{},legacy:{ajax:null},pager:{},renderer:{pageButton:{}, -header:{}},order:{},type:{detect:[],search:{},order:{}},_unique:0,fnVersionCheck:m.fnVersionCheck,iApiIndex:0,oJUIClasses:{},sVersion:m.version};h.extend(x,{afnFiltering:x.search,aTypes:x.type.detect,ofnSearch:x.type.search,oSort:x.type.order,afnSortData:x.order,aoFeatures:x.feature,oApi:x.internal,oStdClasses:x.classes,oPagination:x.pager});h.extend(m.ext.classes,{sTable:"dataTable",sNoFooter:"no-footer",sPageButton:"paginate_button",sPageButtonActive:"current",sPageButtonDisabled:"disabled",sStripeOdd:"odd", -sStripeEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_asc_disabled",sSortableDesc:"sorting_desc_disabled",sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sFilterInput:"",sLengthSelect:"",sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead", -sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sHeaderTH:"",sFooterTH:"",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:"",sSortJUIWrapper:"",sSortIcon:"",sJUIHeader:"",sJUIFooter:""});var Ea="",Ea="",G=Ea+"ui-state-default",ka=Ea+"css_right ui-icon ui-icon-",Yb=Ea+"fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix";h.extend(m.ext.oJUIClasses, -m.ext.classes,{sPageButton:"fg-button ui-button "+G,sPageButtonActive:"ui-state-disabled",sPageButtonDisabled:"ui-state-disabled",sPaging:"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi ui-buttonset-multi paging_",sSortAsc:G+" sorting_asc",sSortDesc:G+" sorting_desc",sSortable:G+" sorting",sSortableAsc:G+" sorting_asc_disabled",sSortableDesc:G+" sorting_desc_disabled",sSortableNone:G+" sorting_disabled",sSortJUIAsc:ka+"triangle-1-n",sSortJUIDesc:ka+"triangle-1-s",sSortJUI:ka+"carat-2-n-s", -sSortJUIAscAllowed:ka+"carat-1-n",sSortJUIDescAllowed:ka+"carat-1-s",sSortJUIWrapper:"DataTables_sort_wrapper",sSortIcon:"DataTables_sort_icon",sScrollHead:"dataTables_scrollHead "+G,sScrollFoot:"dataTables_scrollFoot "+G,sHeaderTH:G,sFooterTH:G,sJUIHeader:Yb+" ui-corner-tl ui-corner-tr",sJUIFooter:Yb+" ui-corner-bl ui-corner-br"});var Nb=m.ext.pager;h.extend(Nb,{simple:function(){return["previous","next"]},full:function(){return["first","previous","next","last"]},numbers:function(a,b){return[ia(a, -b)]},simple_numbers:function(a,b){return["previous",ia(a,b),"next"]},full_numbers:function(a,b){return["first","previous",ia(a,b),"next","last"]},first_last_numbers:function(a,b){return["first",ia(a,b),"last"]},_numbers:ia,numbers_length:7});h.extend(!0,m.ext.renderer,{pageButton:{_:function(a,b,c,d,e,f){var g=a.oClasses,j=a.oLanguage.oPaginate,i=a.oLanguage.oAria.paginate||{},m,l,p=0,r=function(b,d){var k,t,u,s,v=function(b){Va(a,b.data.action,true)};k=0;for(t=d.length;k").appendTo(b);r(u,s)}else{m=null;l="";switch(s){case "ellipsis":b.append('');break;case "first":m=j.sFirst;l=s+(e>0?"":" "+g.sPageButtonDisabled);break;case "previous":m=j.sPrevious;l=s+(e>0?"":" "+g.sPageButtonDisabled);break;case "next":m=j.sNext;l=s+(e",{"class":g.sPageButton+ -" "+l,"aria-controls":a.sTableId,"aria-label":i[s],"data-dt-idx":p,tabindex:a.iTabIndex,id:c===0&&typeof s==="string"?a.sTableId+"_"+s:null}).html(m).appendTo(b);Ya(u,{action:s},v);p++}}}},t;try{t=h(b).find(H.activeElement).data("dt-idx")}catch(u){}r(h(b).empty(),d);t!==k&&h(b).find("[data-dt-idx="+t+"]").focus()}}});h.extend(m.ext.type.detect,[function(a,b){var c=b.oLanguage.sDecimal;return ab(a,c)?"num"+c:null},function(a){if(a&&!(a instanceof Date)&&!cc.test(a))return null;var b=Date.parse(a); -return null!==b&&!isNaN(b)||M(a)?"date":null},function(a,b){var c=b.oLanguage.sDecimal;return ab(a,c,!0)?"num-fmt"+c:null},function(a,b){var c=b.oLanguage.sDecimal;return Sb(a,c)?"html-num"+c:null},function(a,b){var c=b.oLanguage.sDecimal;return Sb(a,c,!0)?"html-num-fmt"+c:null},function(a){return M(a)||"string"===typeof a&&-1!==a.indexOf("<")?"html":null}]);h.extend(m.ext.type.search,{html:function(a){return M(a)?a:"string"===typeof a?a.replace(Pb," ").replace(Ca,""):""},string:function(a){return M(a)? -a:"string"===typeof a?a.replace(Pb," "):a}});var Ba=function(a,b,c,d){if(0!==a&&(!a||"-"===a))return-Infinity;b&&(a=Rb(a,b));a.replace&&(c&&(a=a.replace(c,"")),d&&(a=a.replace(d,"")));return 1*a};h.extend(x.type.order,{"date-pre":function(a){return Date.parse(a)||-Infinity},"html-pre":function(a){return M(a)?"":a.replace?a.replace(/<.*?>/g,"").toLowerCase():a+""},"string-pre":function(a){return M(a)?"":"string"===typeof a?a.toLowerCase():!a.toString?"":a.toString()},"string-asc":function(a,b){return a< -b?-1:a>b?1:0},"string-desc":function(a,b){return ab?-1:0}});fb("");h.extend(!0,m.ext.renderer,{header:{_:function(a,b,c,d){h(a.nTable).on("order.dt.DT",function(e,f,g,h){if(a===f){e=c.idx;b.removeClass(c.sSortingClass+" "+d.sSortAsc+" "+d.sSortDesc).addClass(h[e]=="asc"?d.sSortAsc:h[e]=="desc"?d.sSortDesc:c.sSortingClass)}})},jqueryui:function(a,b,c,d){h("
    ").addClass(d.sSortJUIWrapper).append(b.contents()).append(h("").addClass(d.sSortIcon+" "+c.sSortingClassJUI)).appendTo(b); -h(a.nTable).on("order.dt.DT",function(e,f,g,h){if(a===f){e=c.idx;b.removeClass(d.sSortAsc+" "+d.sSortDesc).addClass(h[e]=="asc"?d.sSortAsc:h[e]=="desc"?d.sSortDesc:c.sSortingClass);b.find("span."+d.sSortIcon).removeClass(d.sSortJUIAsc+" "+d.sSortJUIDesc+" "+d.sSortJUI+" "+d.sSortJUIAscAllowed+" "+d.sSortJUIDescAllowed).addClass(h[e]=="asc"?d.sSortJUIAsc:h[e]=="desc"?d.sSortJUIDesc:c.sSortingClassJUI)}})}}});var Zb=function(a){return"string"===typeof a?a.replace(//g,">").replace(/"/g, -"""):a};m.render={number:function(a,b,c,d,e){return{display:function(f){if("number"!==typeof f&&"string"!==typeof f)return f;var g=0>f?"-":"",h=parseFloat(f);if(isNaN(h))return Zb(f);h=h.toFixed(c);f=Math.abs(h);h=parseInt(f,10);f=c?b+(f-h).toFixed(c).substring(2):"";return g+(d||"")+h.toString().replace(/\B(?=(\d{3})+(?!\d))/g,a)+f+(e||"")}}},text:function(){return{display:Zb}}};h.extend(m.ext.internal,{_fnExternApiFunc:Ob,_fnBuildAjax:ua,_fnAjaxUpdate:nb,_fnAjaxParameters:wb,_fnAjaxUpdateDraw:xb, -_fnAjaxDataSrc:va,_fnAddColumn:Ga,_fnColumnOptions:la,_fnAdjustColumnSizing:Z,_fnVisibleToColumnIndex:$,_fnColumnIndexToVisible:aa,_fnVisbleColumns:ba,_fnGetColumns:na,_fnColumnTypes:Ia,_fnApplyColumnDefs:kb,_fnHungarianMap:Y,_fnCamelToHungarian:J,_fnLanguageCompat:Fa,_fnBrowserDetect:ib,_fnAddData:N,_fnAddTr:oa,_fnNodeToDataIndex:function(a,b){return b._DT_RowIndex!==k?b._DT_RowIndex:null},_fnNodeToColumnIndex:function(a,b,c){return h.inArray(c,a.aoData[b].anCells)},_fnGetCellData:B,_fnSetCellData:lb, -_fnSplitObjNotation:La,_fnGetObjectDataFn:R,_fnSetObjectDataFn:S,_fnGetDataMaster:Ma,_fnClearTable:pa,_fnDeleteIndex:qa,_fnInvalidate:da,_fnGetRowElements:Ka,_fnCreateTr:Ja,_fnBuildHead:mb,_fnDrawHead:fa,_fnDraw:O,_fnReDraw:T,_fnAddOptionsHtml:pb,_fnDetectHeader:ea,_fnGetUniqueThs:ta,_fnFeatureHtmlFilter:rb,_fnFilterComplete:ga,_fnFilterCustom:Ab,_fnFilterColumn:zb,_fnFilter:yb,_fnFilterCreateSearch:Ra,_fnEscapeRegex:Sa,_fnFilterData:Bb,_fnFeatureHtmlInfo:ub,_fnUpdateInfo:Eb,_fnInfoMacros:Fb,_fnInitialise:ha, -_fnInitComplete:wa,_fnLengthChange:Ta,_fnFeatureHtmlLength:qb,_fnFeatureHtmlPaginate:vb,_fnPageChange:Va,_fnFeatureHtmlProcessing:sb,_fnProcessingDisplay:C,_fnFeatureHtmlTable:tb,_fnScrollDraw:ma,_fnApplyToChildren:I,_fnCalculateColumnWidths:Ha,_fnThrottle:Qa,_fnConvertToWidth:Gb,_fnGetWidestNode:Hb,_fnGetMaxLenString:Ib,_fnStringToCss:v,_fnSortFlatten:W,_fnSort:ob,_fnSortAria:Kb,_fnSortListener:Xa,_fnSortAttachListener:Oa,_fnSortingClasses:ya,_fnSortData:Jb,_fnSaveState:za,_fnLoadState:Lb,_fnSettingsFromNode:Aa, -_fnLog:K,_fnMap:F,_fnBindAction:Ya,_fnCallbackReg:z,_fnCallbackFire:s,_fnLengthOverflow:Ua,_fnRenderer:Pa,_fnDataSource:y,_fnRowAttributes:Na,_fnCalculateEnd:function(){}});h.fn.dataTable=m;m.$=h;h.fn.dataTableSettings=m.settings;h.fn.dataTableExt=m.ext;h.fn.DataTable=function(a){return h(this).dataTable(a).api()};h.each(m,function(a,b){h.fn.DataTable[a]=b});return h.fn.dataTable}); diff --git a/app/static/DataTables2022/DataTables-1.11.4/css/dataTables.bootstrap.css b/app/static/DataTables/DataTables-1.11.4/css/dataTables.bootstrap.css similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/css/dataTables.bootstrap.css rename to app/static/DataTables/DataTables-1.11.4/css/dataTables.bootstrap.css diff --git a/app/static/DataTables2022/DataTables-1.11.4/css/dataTables.bootstrap.min.css b/app/static/DataTables/DataTables-1.11.4/css/dataTables.bootstrap.min.css similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/css/dataTables.bootstrap.min.css rename to app/static/DataTables/DataTables-1.11.4/css/dataTables.bootstrap.min.css diff --git a/app/static/DataTables2022/DataTables-1.11.4/css/dataTables.bootstrap4.css b/app/static/DataTables/DataTables-1.11.4/css/dataTables.bootstrap4.css similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/css/dataTables.bootstrap4.css rename to app/static/DataTables/DataTables-1.11.4/css/dataTables.bootstrap4.css diff --git a/app/static/DataTables2022/DataTables-1.11.4/css/dataTables.bootstrap4.min.css b/app/static/DataTables/DataTables-1.11.4/css/dataTables.bootstrap4.min.css similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/css/dataTables.bootstrap4.min.css rename to app/static/DataTables/DataTables-1.11.4/css/dataTables.bootstrap4.min.css diff --git a/app/static/DataTables2022/DataTables-1.11.4/css/dataTables.bootstrap5.css b/app/static/DataTables/DataTables-1.11.4/css/dataTables.bootstrap5.css similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/css/dataTables.bootstrap5.css rename to app/static/DataTables/DataTables-1.11.4/css/dataTables.bootstrap5.css diff --git a/app/static/DataTables2022/DataTables-1.11.4/css/dataTables.bootstrap5.min.css b/app/static/DataTables/DataTables-1.11.4/css/dataTables.bootstrap5.min.css similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/css/dataTables.bootstrap5.min.css rename to app/static/DataTables/DataTables-1.11.4/css/dataTables.bootstrap5.min.css diff --git a/app/static/DataTables2022/DataTables-1.11.4/css/dataTables.bulma.css b/app/static/DataTables/DataTables-1.11.4/css/dataTables.bulma.css similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/css/dataTables.bulma.css rename to app/static/DataTables/DataTables-1.11.4/css/dataTables.bulma.css diff --git a/app/static/DataTables2022/DataTables-1.11.4/css/dataTables.bulma.min.css b/app/static/DataTables/DataTables-1.11.4/css/dataTables.bulma.min.css similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/css/dataTables.bulma.min.css rename to app/static/DataTables/DataTables-1.11.4/css/dataTables.bulma.min.css diff --git a/app/static/DataTables2022/DataTables-1.11.4/css/dataTables.dataTables.css b/app/static/DataTables/DataTables-1.11.4/css/dataTables.dataTables.css similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/css/dataTables.dataTables.css rename to app/static/DataTables/DataTables-1.11.4/css/dataTables.dataTables.css diff --git a/app/static/DataTables2022/DataTables-1.11.4/css/dataTables.dataTables.min.css b/app/static/DataTables/DataTables-1.11.4/css/dataTables.dataTables.min.css similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/css/dataTables.dataTables.min.css rename to app/static/DataTables/DataTables-1.11.4/css/dataTables.dataTables.min.css diff --git a/app/static/DataTables2022/DataTables-1.11.4/css/dataTables.foundation.css b/app/static/DataTables/DataTables-1.11.4/css/dataTables.foundation.css similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/css/dataTables.foundation.css rename to app/static/DataTables/DataTables-1.11.4/css/dataTables.foundation.css diff --git a/app/static/DataTables2022/DataTables-1.11.4/css/dataTables.foundation.min.css b/app/static/DataTables/DataTables-1.11.4/css/dataTables.foundation.min.css similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/css/dataTables.foundation.min.css rename to app/static/DataTables/DataTables-1.11.4/css/dataTables.foundation.min.css diff --git a/app/static/DataTables2022/DataTables-1.11.4/css/dataTables.jqueryui.css b/app/static/DataTables/DataTables-1.11.4/css/dataTables.jqueryui.css similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/css/dataTables.jqueryui.css rename to app/static/DataTables/DataTables-1.11.4/css/dataTables.jqueryui.css diff --git a/app/static/DataTables2022/DataTables-1.11.4/css/dataTables.jqueryui.min.css b/app/static/DataTables/DataTables-1.11.4/css/dataTables.jqueryui.min.css similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/css/dataTables.jqueryui.min.css rename to app/static/DataTables/DataTables-1.11.4/css/dataTables.jqueryui.min.css diff --git a/app/static/DataTables2022/DataTables-1.11.4/css/dataTables.semanticui.css b/app/static/DataTables/DataTables-1.11.4/css/dataTables.semanticui.css similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/css/dataTables.semanticui.css rename to app/static/DataTables/DataTables-1.11.4/css/dataTables.semanticui.css diff --git a/app/static/DataTables2022/DataTables-1.11.4/css/dataTables.semanticui.min.css b/app/static/DataTables/DataTables-1.11.4/css/dataTables.semanticui.min.css similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/css/dataTables.semanticui.min.css rename to app/static/DataTables/DataTables-1.11.4/css/dataTables.semanticui.min.css diff --git a/app/static/DataTables2022/DataTables-1.11.4/css/jquery.dataTables.css b/app/static/DataTables/DataTables-1.11.4/css/jquery.dataTables.css similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/css/jquery.dataTables.css rename to app/static/DataTables/DataTables-1.11.4/css/jquery.dataTables.css diff --git a/app/static/DataTables2022/DataTables-1.11.4/css/jquery.dataTables.min.css b/app/static/DataTables/DataTables-1.11.4/css/jquery.dataTables.min.css similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/css/jquery.dataTables.min.css rename to app/static/DataTables/DataTables-1.11.4/css/jquery.dataTables.min.css diff --git a/app/static/DataTables/DataTables-1.10.15/images/sort_asc.png b/app/static/DataTables/DataTables-1.11.4/images/sort_asc.png similarity index 100% rename from app/static/DataTables/DataTables-1.10.15/images/sort_asc.png rename to app/static/DataTables/DataTables-1.11.4/images/sort_asc.png diff --git a/app/static/DataTables2022/DataTables-1.11.4/images/sort_asc_disabled.png b/app/static/DataTables/DataTables-1.11.4/images/sort_asc_disabled.png similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/images/sort_asc_disabled.png rename to app/static/DataTables/DataTables-1.11.4/images/sort_asc_disabled.png diff --git a/app/static/DataTables/DataTables-1.10.15/images/sort_both.png b/app/static/DataTables/DataTables-1.11.4/images/sort_both.png similarity index 100% rename from app/static/DataTables/DataTables-1.10.15/images/sort_both.png rename to app/static/DataTables/DataTables-1.11.4/images/sort_both.png diff --git a/app/static/DataTables/DataTables-1.10.15/images/sort_desc.png b/app/static/DataTables/DataTables-1.11.4/images/sort_desc.png similarity index 100% rename from app/static/DataTables/DataTables-1.10.15/images/sort_desc.png rename to app/static/DataTables/DataTables-1.11.4/images/sort_desc.png diff --git a/app/static/DataTables2022/DataTables-1.11.4/images/sort_desc_disabled.png b/app/static/DataTables/DataTables-1.11.4/images/sort_desc_disabled.png similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/images/sort_desc_disabled.png rename to app/static/DataTables/DataTables-1.11.4/images/sort_desc_disabled.png diff --git a/app/static/DataTables2022/DataTables-1.11.4/js/dataTables.bootstrap.js b/app/static/DataTables/DataTables-1.11.4/js/dataTables.bootstrap.js similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/js/dataTables.bootstrap.js rename to app/static/DataTables/DataTables-1.11.4/js/dataTables.bootstrap.js diff --git a/app/static/DataTables2022/DataTables-1.11.4/js/dataTables.bootstrap.min.js b/app/static/DataTables/DataTables-1.11.4/js/dataTables.bootstrap.min.js similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/js/dataTables.bootstrap.min.js rename to app/static/DataTables/DataTables-1.11.4/js/dataTables.bootstrap.min.js diff --git a/app/static/DataTables2022/DataTables-1.11.4/js/dataTables.bootstrap4.js b/app/static/DataTables/DataTables-1.11.4/js/dataTables.bootstrap4.js similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/js/dataTables.bootstrap4.js rename to app/static/DataTables/DataTables-1.11.4/js/dataTables.bootstrap4.js diff --git a/app/static/DataTables2022/DataTables-1.11.4/js/dataTables.bootstrap4.min.js b/app/static/DataTables/DataTables-1.11.4/js/dataTables.bootstrap4.min.js similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/js/dataTables.bootstrap4.min.js rename to app/static/DataTables/DataTables-1.11.4/js/dataTables.bootstrap4.min.js diff --git a/app/static/DataTables2022/DataTables-1.11.4/js/dataTables.bootstrap5.js b/app/static/DataTables/DataTables-1.11.4/js/dataTables.bootstrap5.js similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/js/dataTables.bootstrap5.js rename to app/static/DataTables/DataTables-1.11.4/js/dataTables.bootstrap5.js diff --git a/app/static/DataTables2022/DataTables-1.11.4/js/dataTables.bootstrap5.min.js b/app/static/DataTables/DataTables-1.11.4/js/dataTables.bootstrap5.min.js similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/js/dataTables.bootstrap5.min.js rename to app/static/DataTables/DataTables-1.11.4/js/dataTables.bootstrap5.min.js diff --git a/app/static/DataTables2022/DataTables-1.11.4/js/dataTables.bulma.js b/app/static/DataTables/DataTables-1.11.4/js/dataTables.bulma.js similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/js/dataTables.bulma.js rename to app/static/DataTables/DataTables-1.11.4/js/dataTables.bulma.js diff --git a/app/static/DataTables2022/DataTables-1.11.4/js/dataTables.bulma.min.js b/app/static/DataTables/DataTables-1.11.4/js/dataTables.bulma.min.js similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/js/dataTables.bulma.min.js rename to app/static/DataTables/DataTables-1.11.4/js/dataTables.bulma.min.js diff --git a/app/static/DataTables2022/DataTables-1.11.4/js/dataTables.dataTables.js b/app/static/DataTables/DataTables-1.11.4/js/dataTables.dataTables.js similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/js/dataTables.dataTables.js rename to app/static/DataTables/DataTables-1.11.4/js/dataTables.dataTables.js diff --git a/app/static/DataTables2022/DataTables-1.11.4/js/dataTables.dataTables.min.js b/app/static/DataTables/DataTables-1.11.4/js/dataTables.dataTables.min.js similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/js/dataTables.dataTables.min.js rename to app/static/DataTables/DataTables-1.11.4/js/dataTables.dataTables.min.js diff --git a/app/static/DataTables2022/DataTables-1.11.4/js/dataTables.foundation.js b/app/static/DataTables/DataTables-1.11.4/js/dataTables.foundation.js similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/js/dataTables.foundation.js rename to app/static/DataTables/DataTables-1.11.4/js/dataTables.foundation.js diff --git a/app/static/DataTables2022/DataTables-1.11.4/js/dataTables.foundation.min.js b/app/static/DataTables/DataTables-1.11.4/js/dataTables.foundation.min.js similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/js/dataTables.foundation.min.js rename to app/static/DataTables/DataTables-1.11.4/js/dataTables.foundation.min.js diff --git a/app/static/DataTables2022/DataTables-1.11.4/js/dataTables.jqueryui.js b/app/static/DataTables/DataTables-1.11.4/js/dataTables.jqueryui.js similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/js/dataTables.jqueryui.js rename to app/static/DataTables/DataTables-1.11.4/js/dataTables.jqueryui.js diff --git a/app/static/DataTables2022/DataTables-1.11.4/js/dataTables.jqueryui.min.js b/app/static/DataTables/DataTables-1.11.4/js/dataTables.jqueryui.min.js similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/js/dataTables.jqueryui.min.js rename to app/static/DataTables/DataTables-1.11.4/js/dataTables.jqueryui.min.js diff --git a/app/static/DataTables2022/DataTables-1.11.4/js/dataTables.semanticui.js b/app/static/DataTables/DataTables-1.11.4/js/dataTables.semanticui.js similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/js/dataTables.semanticui.js rename to app/static/DataTables/DataTables-1.11.4/js/dataTables.semanticui.js diff --git a/app/static/DataTables2022/DataTables-1.11.4/js/dataTables.semanticui.min.js b/app/static/DataTables/DataTables-1.11.4/js/dataTables.semanticui.min.js similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/js/dataTables.semanticui.min.js rename to app/static/DataTables/DataTables-1.11.4/js/dataTables.semanticui.min.js diff --git a/app/static/DataTables2022/DataTables-1.11.4/js/jquery.dataTables.js b/app/static/DataTables/DataTables-1.11.4/js/jquery.dataTables.js similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/js/jquery.dataTables.js rename to app/static/DataTables/DataTables-1.11.4/js/jquery.dataTables.js diff --git a/app/static/DataTables2022/DataTables-1.11.4/js/jquery.dataTables.min.js b/app/static/DataTables/DataTables-1.11.4/js/jquery.dataTables.min.js similarity index 100% rename from app/static/DataTables2022/DataTables-1.11.4/js/jquery.dataTables.min.js rename to app/static/DataTables/DataTables-1.11.4/js/jquery.dataTables.min.js diff --git a/app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.bootstrap.css b/app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.bootstrap.css deleted file mode 100644 index 28ee2abe6..000000000 --- a/app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.bootstrap.css +++ /dev/null @@ -1,44 +0,0 @@ -table.DTFC_Cloned tr { - background-color: white; - margin-bottom: 0; -} - -div.DTFC_LeftHeadWrapper table, -div.DTFC_RightHeadWrapper table { - border-bottom: none !important; - margin-bottom: 0 !important; - background-color: white; -} - -div.DTFC_LeftBodyWrapper table, -div.DTFC_RightBodyWrapper table { - border-top: none; - margin: 0 !important; -} -div.DTFC_LeftBodyWrapper table thead .sorting:after, -div.DTFC_LeftBodyWrapper table thead .sorting_asc:after, -div.DTFC_LeftBodyWrapper table thead .sorting_desc:after, -div.DTFC_LeftBodyWrapper table thead .sorting:after, -div.DTFC_LeftBodyWrapper table thead .sorting_asc:after, -div.DTFC_LeftBodyWrapper table thead .sorting_desc:after, -div.DTFC_RightBodyWrapper table thead .sorting:after, -div.DTFC_RightBodyWrapper table thead .sorting_asc:after, -div.DTFC_RightBodyWrapper table thead .sorting_desc:after, -div.DTFC_RightBodyWrapper table thead .sorting:after, -div.DTFC_RightBodyWrapper table thead .sorting_asc:after, -div.DTFC_RightBodyWrapper table thead .sorting_desc:after { - display: none; -} -div.DTFC_LeftBodyWrapper table tbody tr:first-child th, -div.DTFC_LeftBodyWrapper table tbody tr:first-child td, -div.DTFC_RightBodyWrapper table tbody tr:first-child th, -div.DTFC_RightBodyWrapper table tbody tr:first-child td { - border-top: none; -} - -div.DTFC_LeftFootWrapper table, -div.DTFC_RightFootWrapper table { - border-top: none; - margin-top: 0 !important; - background-color: white; -} diff --git a/app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.bootstrap.min.css b/app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.bootstrap.min.css deleted file mode 100644 index d85ab4df7..000000000 --- a/app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.bootstrap.min.css +++ /dev/null @@ -1 +0,0 @@ -table.DTFC_Cloned tr{background-color:white;margin-bottom:0}div.DTFC_LeftHeadWrapper table,div.DTFC_RightHeadWrapper table{border-bottom:none !important;margin-bottom:0 !important;background-color:white}div.DTFC_LeftBodyWrapper table,div.DTFC_RightBodyWrapper table{border-top:none;margin:0 !important}div.DTFC_LeftBodyWrapper table thead .sorting:after,div.DTFC_LeftBodyWrapper table thead .sorting_asc:after,div.DTFC_LeftBodyWrapper table thead .sorting_desc:after,div.DTFC_LeftBodyWrapper table thead .sorting:after,div.DTFC_LeftBodyWrapper table thead .sorting_asc:after,div.DTFC_LeftBodyWrapper table thead .sorting_desc:after,div.DTFC_RightBodyWrapper table thead .sorting:after,div.DTFC_RightBodyWrapper table thead .sorting_asc:after,div.DTFC_RightBodyWrapper table thead .sorting_desc:after,div.DTFC_RightBodyWrapper table thead .sorting:after,div.DTFC_RightBodyWrapper table thead .sorting_asc:after,div.DTFC_RightBodyWrapper table thead .sorting_desc:after{display:none}div.DTFC_LeftBodyWrapper table tbody tr:first-child th,div.DTFC_LeftBodyWrapper table tbody tr:first-child td,div.DTFC_RightBodyWrapper table tbody tr:first-child th,div.DTFC_RightBodyWrapper table tbody tr:first-child td{border-top:none}div.DTFC_LeftFootWrapper table,div.DTFC_RightFootWrapper table{border-top:none;margin-top:0 !important;background-color:white} diff --git a/app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.dataTables.css b/app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.dataTables.css deleted file mode 100644 index 9b94ffa13..000000000 --- a/app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.dataTables.css +++ /dev/null @@ -1,18 +0,0 @@ -table.DTFC_Cloned thead, -table.DTFC_Cloned tfoot { - background-color: white; -} - -div.DTFC_Blocker { - background-color: white; -} - -div.DTFC_LeftWrapper table.dataTable, -div.DTFC_RightWrapper table.dataTable { - margin-bottom: 0; - z-index: 2; -} -div.DTFC_LeftWrapper table.dataTable.no-footer, -div.DTFC_RightWrapper table.dataTable.no-footer { - border-bottom: none; -} diff --git a/app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.dataTables.min.css b/app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.dataTables.min.css deleted file mode 100644 index 71e801b53..000000000 --- a/app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.dataTables.min.css +++ /dev/null @@ -1 +0,0 @@ -table.DTFC_Cloned thead,table.DTFC_Cloned tfoot{background-color:white}div.DTFC_Blocker{background-color:white}div.DTFC_LeftWrapper table.dataTable,div.DTFC_RightWrapper table.dataTable{margin-bottom:0;z-index:2}div.DTFC_LeftWrapper table.dataTable.no-footer,div.DTFC_RightWrapper table.dataTable.no-footer{border-bottom:none} diff --git a/app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.foundation.css b/app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.foundation.css deleted file mode 100644 index fc717eef5..000000000 --- a/app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.foundation.css +++ /dev/null @@ -1,27 +0,0 @@ -div.DTFC_LeftHeadWrapper table, -div.DTFC_LeftBodyWrapper table, -div.DTFC_LeftFootWrapper table { - border-right-width: 0; -} - -div.DTFC_RightHeadWrapper table, -div.DTFC_RightBodyWrapper table, -div.DTFC_RightFootWrapper table { - border-left-width: 0; -} - -div.DTFC_LeftHeadWrapper table, -div.DTFC_RightHeadWrapper table { - margin-bottom: 0 !important; -} - -div.DTFC_LeftBodyWrapper table, -div.DTFC_RightBodyWrapper table { - border-top: none; - margin: 0 !important; -} - -div.DTFC_LeftFootWrapper table, -div.DTFC_RightFootWrapper table { - margin-top: 0 !important; -} diff --git a/app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.foundation.min.css b/app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.foundation.min.css deleted file mode 100644 index c9937f818..000000000 --- a/app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.foundation.min.css +++ /dev/null @@ -1 +0,0 @@ -div.DTFC_LeftHeadWrapper table,div.DTFC_LeftBodyWrapper table,div.DTFC_LeftFootWrapper table{border-right-width:0}div.DTFC_RightHeadWrapper table,div.DTFC_RightBodyWrapper table,div.DTFC_RightFootWrapper table{border-left-width:0}div.DTFC_LeftHeadWrapper table,div.DTFC_RightHeadWrapper table{margin-bottom:0 !important}div.DTFC_LeftBodyWrapper table,div.DTFC_RightBodyWrapper table{border-top:none;margin:0 !important}div.DTFC_LeftFootWrapper table,div.DTFC_RightFootWrapper table{margin-top:0 !important} diff --git a/app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.jqueryui.css b/app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.jqueryui.css deleted file mode 100644 index d6a7ec9c7..000000000 --- a/app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.jqueryui.css +++ /dev/null @@ -1,8 +0,0 @@ -div.DTFC_LeftWrapper table.dataTable, -div.DTFC_RightWrapper table.dataTable { - z-index: 2; -} -div.DTFC_LeftWrapper table.dataTable.no-footer, -div.DTFC_RightWrapper table.dataTable.no-footer { - border-bottom: none; -} diff --git a/app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.jqueryui.min.css b/app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.jqueryui.min.css deleted file mode 100644 index 9926742c8..000000000 --- a/app/static/DataTables/FixedColumns-3.2.2/css/fixedColumns.jqueryui.min.css +++ /dev/null @@ -1 +0,0 @@ -div.DTFC_LeftWrapper table.dataTable,div.DTFC_RightWrapper table.dataTable{z-index:2}div.DTFC_LeftWrapper table.dataTable.no-footer,div.DTFC_RightWrapper table.dataTable.no-footer{border-bottom:none} diff --git a/app/static/DataTables/FixedColumns-3.2.2/js/dataTables.fixedColumns.js b/app/static/DataTables/FixedColumns-3.2.2/js/dataTables.fixedColumns.js deleted file mode 100644 index 0ac001bfd..000000000 --- a/app/static/DataTables/FixedColumns-3.2.2/js/dataTables.fixedColumns.js +++ /dev/null @@ -1,1623 +0,0 @@ -/*! FixedColumns 3.2.2 - * ©2010-2016 SpryMedia Ltd - datatables.net/license - */ - -/** - * @summary FixedColumns - * @description Freeze columns in place on a scrolling DataTable - * @version 3.2.2 - * @file dataTables.fixedColumns.js - * @author SpryMedia Ltd (www.sprymedia.co.uk) - * @contact www.sprymedia.co.uk/contact - * @copyright Copyright 2010-2016 SpryMedia Ltd. - * - * This source file is free software, available under the following license: - * MIT license - http://datatables.net/license/mit - * - * This source file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. - * - * For details please refer to: http://www.datatables.net - */ -(function( factory ){ - if ( typeof define === 'function' && define.amd ) { - // AMD - define( ['jquery', 'datatables.net'], function ( $ ) { - return factory( $, window, document ); - } ); - } - else if ( typeof exports === 'object' ) { - // CommonJS - module.exports = function (root, $) { - if ( ! root ) { - root = window; - } - - if ( ! $ || ! $.fn.dataTable ) { - $ = require('datatables.net')(root, $).$; - } - - return factory( $, root, root.document ); - }; - } - else { - // Browser - factory( jQuery, window, document ); - } -}(function( $, window, document, undefined ) { -'use strict'; -var DataTable = $.fn.dataTable; -var _firefoxScroll; - -/** - * When making use of DataTables' x-axis scrolling feature, you may wish to - * fix the left most column in place. This plug-in for DataTables provides - * exactly this option (note for non-scrolling tables, please use the - * FixedHeader plug-in, which can fix headers, footers and columns). Key - * features include: - * - * * Freezes the left or right most columns to the side of the table - * * Option to freeze two or more columns - * * Full integration with DataTables' scrolling options - * * Speed - FixedColumns is fast in its operation - * - * @class - * @constructor - * @global - * @param {object} dt DataTables instance. With DataTables 1.10 this can also - * be a jQuery collection, a jQuery selector, DataTables API instance or - * settings object. - * @param {object} [init={}] Configuration object for FixedColumns. Options are - * defined by {@link FixedColumns.defaults} - * - * @requires jQuery 1.7+ - * @requires DataTables 1.8.0+ - * - * @example - * var table = $('#example').dataTable( { - * "scrollX": "100%" - * } ); - * new $.fn.dataTable.fixedColumns( table ); - */ -var FixedColumns = function ( dt, init ) { - var that = this; - - /* Sanity check - you just know it will happen */ - if ( ! ( this instanceof FixedColumns ) ) { - alert( "FixedColumns warning: FixedColumns must be initialised with the 'new' keyword." ); - return; - } - - if ( init === undefined || init === true ) { - init = {}; - } - - // Use the DataTables Hungarian notation mapping method, if it exists to - // provide forwards compatibility for camel case variables - var camelToHungarian = $.fn.dataTable.camelToHungarian; - if ( camelToHungarian ) { - camelToHungarian( FixedColumns.defaults, FixedColumns.defaults, true ); - camelToHungarian( FixedColumns.defaults, init ); - } - - // v1.10 allows the settings object to be got form a number of sources - var dtSettings = new $.fn.dataTable.Api( dt ).settings()[0]; - - /** - * Settings object which contains customisable information for FixedColumns instance - * @namespace - * @extends FixedColumns.defaults - * @private - */ - this.s = { - /** - * DataTables settings objects - * @type object - * @default Obtained from DataTables instance - */ - "dt": dtSettings, - - /** - * Number of columns in the DataTable - stored for quick access - * @type int - * @default Obtained from DataTables instance - */ - "iTableColumns": dtSettings.aoColumns.length, - - /** - * Original outer widths of the columns as rendered by DataTables - used to calculate - * the FixedColumns grid bounding box - * @type array. - * @default [] - */ - "aiOuterWidths": [], - - /** - * Original inner widths of the columns as rendered by DataTables - used to apply widths - * to the columns - * @type array. - * @default [] - */ - "aiInnerWidths": [], - - - /** - * Is the document layout right-to-left - * @type boolean - */ - rtl: $(dtSettings.nTable).css('direction') === 'rtl' - }; - - - /** - * DOM elements used by the class instance - * @namespace - * @private - * - */ - this.dom = { - /** - * DataTables scrolling element - * @type node - * @default null - */ - "scroller": null, - - /** - * DataTables header table - * @type node - * @default null - */ - "header": null, - - /** - * DataTables body table - * @type node - * @default null - */ - "body": null, - - /** - * DataTables footer table - * @type node - * @default null - */ - "footer": null, - - /** - * Display grid elements - * @namespace - */ - "grid": { - /** - * Grid wrapper. This is the container element for the 3x3 grid - * @type node - * @default null - */ - "wrapper": null, - - /** - * DataTables scrolling element. This element is the DataTables - * component in the display grid (making up the main table - i.e. - * not the fixed columns). - * @type node - * @default null - */ - "dt": null, - - /** - * Left fixed column grid components - * @namespace - */ - "left": { - "wrapper": null, - "head": null, - "body": null, - "foot": null - }, - - /** - * Right fixed column grid components - * @namespace - */ - "right": { - "wrapper": null, - "head": null, - "body": null, - "foot": null - } - }, - - /** - * Cloned table nodes - * @namespace - */ - "clone": { - /** - * Left column cloned table nodes - * @namespace - */ - "left": { - /** - * Cloned header table - * @type node - * @default null - */ - "header": null, - - /** - * Cloned body table - * @type node - * @default null - */ - "body": null, - - /** - * Cloned footer table - * @type node - * @default null - */ - "footer": null - }, - - /** - * Right column cloned table nodes - * @namespace - */ - "right": { - /** - * Cloned header table - * @type node - * @default null - */ - "header": null, - - /** - * Cloned body table - * @type node - * @default null - */ - "body": null, - - /** - * Cloned footer table - * @type node - * @default null - */ - "footer": null - } - } - }; - - if ( dtSettings._oFixedColumns ) { - throw 'FixedColumns already initialised on this table'; - } - - /* Attach the instance to the DataTables instance so it can be accessed easily */ - dtSettings._oFixedColumns = this; - - /* Let's do it */ - if ( ! dtSettings._bInitComplete ) - { - dtSettings.oApi._fnCallbackReg( dtSettings, 'aoInitComplete', function () { - that._fnConstruct( init ); - }, 'FixedColumns' ); - } - else - { - this._fnConstruct( init ); - } -}; - - - -$.extend( FixedColumns.prototype , { - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Public methods - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - /** - * Update the fixed columns - including headers and footers. Note that FixedColumns will - * automatically update the display whenever the host DataTable redraws. - * @returns {void} - * @example - * var table = $('#example').dataTable( { - * "scrollX": "100%" - * } ); - * var fc = new $.fn.dataTable.fixedColumns( table ); - * - * // at some later point when the table has been manipulated.... - * fc.fnUpdate(); - */ - "fnUpdate": function () - { - this._fnDraw( true ); - }, - - - /** - * Recalculate the resizes of the 3x3 grid that FixedColumns uses for display of the table. - * This is useful if you update the width of the table container. Note that FixedColumns will - * perform this function automatically when the window.resize event is fired. - * @returns {void} - * @example - * var table = $('#example').dataTable( { - * "scrollX": "100%" - * } ); - * var fc = new $.fn.dataTable.fixedColumns( table ); - * - * // Resize the table container and then have FixedColumns adjust its layout.... - * $('#content').width( 1200 ); - * fc.fnRedrawLayout(); - */ - "fnRedrawLayout": function () - { - this._fnColCalc(); - this._fnGridLayout(); - this.fnUpdate(); - }, - - - /** - * Mark a row such that it's height should be recalculated when using 'semiauto' row - * height matching. This function will have no effect when 'none' or 'auto' row height - * matching is used. - * @param {Node} nTr TR element that should have it's height recalculated - * @returns {void} - * @example - * var table = $('#example').dataTable( { - * "scrollX": "100%" - * } ); - * var fc = new $.fn.dataTable.fixedColumns( table ); - * - * // manipulate the table - mark the row as needing an update then update the table - * // this allows the redraw performed by DataTables fnUpdate to recalculate the row - * // height - * fc.fnRecalculateHeight(); - * table.fnUpdate( $('#example tbody tr:eq(0)')[0], ["insert date", 1, 2, 3 ... ]); - */ - "fnRecalculateHeight": function ( nTr ) - { - delete nTr._DTTC_iHeight; - nTr.style.height = 'auto'; - }, - - - /** - * Set the height of a given row - provides cross browser compatibility - * @param {Node} nTarget TR element that should have it's height recalculated - * @param {int} iHeight Height in pixels to set - * @returns {void} - * @example - * var table = $('#example').dataTable( { - * "scrollX": "100%" - * } ); - * var fc = new $.fn.dataTable.fixedColumns( table ); - * - * // You may want to do this after manipulating a row in the fixed column - * fc.fnSetRowHeight( $('#example tbody tr:eq(0)')[0], 50 ); - */ - "fnSetRowHeight": function ( nTarget, iHeight ) - { - nTarget.style.height = iHeight+"px"; - }, - - - /** - * Get data index information about a row or cell in the table body. - * This function is functionally identical to fnGetPosition in DataTables, - * taking the same parameter (TH, TD or TR node) and returning exactly the - * the same information (data index information). THe difference between - * the two is that this method takes into account the fixed columns in the - * table, so you can pass in nodes from the master table, or the cloned - * tables and get the index position for the data in the main table. - * @param {node} node TR, TH or TD element to get the information about - * @returns {int} If nNode is given as a TR, then a single index is - * returned, or if given as a cell, an array of [row index, column index - * (visible), column index (all)] is given. - */ - "fnGetPosition": function ( node ) - { - var idx; - var inst = this.s.dt.oInstance; - - if ( ! $(node).parents('.DTFC_Cloned').length ) - { - // Not in a cloned table - return inst.fnGetPosition( node ); - } - else - { - // Its in the cloned table, so need to look up position - if ( node.nodeName.toLowerCase() === 'tr' ) { - idx = $(node).index(); - return inst.fnGetPosition( $('tr', this.s.dt.nTBody)[ idx ] ); - } - else - { - var colIdx = $(node).index(); - idx = $(node.parentNode).index(); - var row = inst.fnGetPosition( $('tr', this.s.dt.nTBody)[ idx ] ); - - return [ - row, - colIdx, - inst.oApi._fnVisibleToColumnIndex( this.s.dt, colIdx ) - ]; - } - } - }, - - - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Private methods (they are of course public in JS, but recommended as private) - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - /** - * Initialisation for FixedColumns - * @param {Object} oInit User settings for initialisation - * @returns {void} - * @private - */ - "_fnConstruct": function ( oInit ) - { - var i, iLen, iWidth, - that = this; - - /* Sanity checking */ - if ( typeof this.s.dt.oInstance.fnVersionCheck != 'function' || - this.s.dt.oInstance.fnVersionCheck( '1.8.0' ) !== true ) - { - alert( "FixedColumns "+FixedColumns.VERSION+" required DataTables 1.8.0 or later. "+ - "Please upgrade your DataTables installation" ); - return; - } - - if ( this.s.dt.oScroll.sX === "" ) - { - this.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, "FixedColumns is not needed (no "+ - "x-scrolling in DataTables enabled), so no action will be taken. Use 'FixedHeader' for "+ - "column fixing when scrolling is not enabled" ); - return; - } - - /* Apply the settings from the user / defaults */ - this.s = $.extend( true, this.s, FixedColumns.defaults, oInit ); - - /* Set up the DOM as we need it and cache nodes */ - var classes = this.s.dt.oClasses; - this.dom.grid.dt = $(this.s.dt.nTable).parents('div.'+classes.sScrollWrapper)[0]; - this.dom.scroller = $('div.'+classes.sScrollBody, this.dom.grid.dt )[0]; - - /* Set up the DOM that we want for the fixed column layout grid */ - this._fnColCalc(); - this._fnGridSetup(); - - /* Event handlers */ - var mouseController; - var mouseDown = false; - - // When the mouse is down (drag scroll) the mouse controller cannot - // change, as the browser keeps the original element as the scrolling one - $(this.s.dt.nTableWrapper).on( 'mousedown.DTFC', function () { - mouseDown = true; - - $(document).one( 'mouseup', function () { - mouseDown = false; - } ); - } ); - - // When the body is scrolled - scroll the left and right columns - $(this.dom.scroller) - .on( 'mouseover.DTFC touchstart.DTFC', function () { - if ( ! mouseDown ) { - mouseController = 'main'; - } - } ) - .on( 'scroll.DTFC', function (e) { - if ( ! mouseController && e.originalEvent ) { - mouseController = 'main'; - } - - if ( mouseController === 'main' ) { - if ( that.s.iLeftColumns > 0 ) { - that.dom.grid.left.liner.scrollTop = that.dom.scroller.scrollTop; - } - if ( that.s.iRightColumns > 0 ) { - that.dom.grid.right.liner.scrollTop = that.dom.scroller.scrollTop; - } - } - } ); - - var wheelType = 'onwheel' in document.createElement('div') ? - 'wheel.DTFC' : - 'mousewheel.DTFC'; - - if ( that.s.iLeftColumns > 0 ) { - // When scrolling the left column, scroll the body and right column - $(that.dom.grid.left.liner) - .on( 'mouseover.DTFC touchstart.DTFC', function () { - if ( ! mouseDown ) { - mouseController = 'left'; - } - } ) - .on( 'scroll.DTFC', function ( e ) { - if ( ! mouseController && e.originalEvent ) { - mouseController = 'left'; - } - - if ( mouseController === 'left' ) { - that.dom.scroller.scrollTop = that.dom.grid.left.liner.scrollTop; - if ( that.s.iRightColumns > 0 ) { - that.dom.grid.right.liner.scrollTop = that.dom.grid.left.liner.scrollTop; - } - } - } ) - .on( wheelType, function(e) { - // Pass horizontal scrolling through - var xDelta = e.type === 'wheel' ? - -e.originalEvent.deltaX : - e.originalEvent.wheelDeltaX; - that.dom.scroller.scrollLeft -= xDelta; - } ); - } - - if ( that.s.iRightColumns > 0 ) { - // When scrolling the right column, scroll the body and the left column - $(that.dom.grid.right.liner) - .on( 'mouseover.DTFC touchstart.DTFC', function () { - if ( ! mouseDown ) { - mouseController = 'right'; - } - } ) - .on( 'scroll.DTFC', function ( e ) { - if ( ! mouseController && e.originalEvent ) { - mouseController = 'right'; - } - - if ( mouseController === 'right' ) { - that.dom.scroller.scrollTop = that.dom.grid.right.liner.scrollTop; - if ( that.s.iLeftColumns > 0 ) { - that.dom.grid.left.liner.scrollTop = that.dom.grid.right.liner.scrollTop; - } - } - } ) - .on( wheelType, function(e) { - // Pass horizontal scrolling through - var xDelta = e.type === 'wheel' ? - -e.originalEvent.deltaX : - e.originalEvent.wheelDeltaX; - that.dom.scroller.scrollLeft -= xDelta; - } ); - } - - $(window).on( 'resize.DTFC', function () { - that._fnGridLayout.call( that ); - } ); - - var bFirstDraw = true; - var jqTable = $(this.s.dt.nTable); - - jqTable - .on( 'draw.dt.DTFC', function () { - that._fnColCalc(); - that._fnDraw.call( that, bFirstDraw ); - bFirstDraw = false; - } ) - .on( 'column-sizing.dt.DTFC', function () { - that._fnColCalc(); - that._fnGridLayout( that ); - } ) - .on( 'column-visibility.dt.DTFC', function ( e, settings, column, vis, recalc ) { - if ( recalc === undefined || recalc ) { - that._fnColCalc(); - that._fnGridLayout( that ); - that._fnDraw( true ); - } - } ) - .on( 'select.dt.DTFC deselect.dt.DTFC', function ( e, dt, type, indexes ) { - if ( e.namespace === 'dt' ) { - that._fnDraw( false ); - } - } ) - .on( 'destroy.dt.DTFC', function () { - jqTable.off( '.DTFC' ); - - $(that.dom.scroller).off( '.DTFC' ); - $(window).off( '.DTFC' ); - $(that.s.dt.nTableWrapper).off( '.DTFC' ); - - $(that.dom.grid.left.liner).off( '.DTFC '+wheelType ); - $(that.dom.grid.left.wrapper).remove(); - - $(that.dom.grid.right.liner).off( '.DTFC '+wheelType ); - $(that.dom.grid.right.wrapper).remove(); - } ); - - /* Get things right to start with - note that due to adjusting the columns, there must be - * another redraw of the main table. It doesn't need to be a full redraw however. - */ - this._fnGridLayout(); - this.s.dt.oInstance.fnDraw(false); - }, - - - /** - * Calculate the column widths for the grid layout - * @returns {void} - * @private - */ - "_fnColCalc": function () - { - var that = this; - var iLeftWidth = 0; - var iRightWidth = 0; - - this.s.aiInnerWidths = []; - this.s.aiOuterWidths = []; - - $.each( this.s.dt.aoColumns, function (i, col) { - var th = $(col.nTh); - var border; - - if ( ! th.filter(':visible').length ) { - that.s.aiInnerWidths.push( 0 ); - that.s.aiOuterWidths.push( 0 ); - } - else - { - // Inner width is used to assign widths to cells - // Outer width is used to calculate the container - var iWidth = th.outerWidth(); - - // When working with the left most-cell, need to add on the - // table's border to the outerWidth, since we need to take - // account of it, but it isn't in any cell - if ( that.s.aiOuterWidths.length === 0 ) { - border = $(that.s.dt.nTable).css('border-left-width'); - iWidth += typeof border === 'string' ? 1 : parseInt( border, 10 ); - } - - // Likewise with the final column on the right - if ( that.s.aiOuterWidths.length === that.s.dt.aoColumns.length-1 ) { - border = $(that.s.dt.nTable).css('border-right-width'); - iWidth += typeof border === 'string' ? 1 : parseInt( border, 10 ); - } - - that.s.aiOuterWidths.push( iWidth ); - that.s.aiInnerWidths.push( th.width() ); - - if ( i < that.s.iLeftColumns ) - { - iLeftWidth += iWidth; - } - - if ( that.s.iTableColumns-that.s.iRightColumns <= i ) - { - iRightWidth += iWidth; - } - } - } ); - - this.s.iLeftWidth = iLeftWidth; - this.s.iRightWidth = iRightWidth; - }, - - - /** - * Set up the DOM for the fixed column. The way the layout works is to create a 1x3 grid - * for the left column, the DataTable (for which we just reuse the scrolling element DataTable - * puts into the DOM) and the right column. In each of he two fixed column elements there is a - * grouping wrapper element and then a head, body and footer wrapper. In each of these we then - * place the cloned header, body or footer tables. This effectively gives as 3x3 grid structure. - * @returns {void} - * @private - */ - "_fnGridSetup": function () - { - var that = this; - var oOverflow = this._fnDTOverflow(); - var block; - - this.dom.body = this.s.dt.nTable; - this.dom.header = this.s.dt.nTHead.parentNode; - this.dom.header.parentNode.parentNode.style.position = "relative"; - - var nSWrapper = - $('
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    ')[0]; - var nLeft = nSWrapper.childNodes[0]; - var nRight = nSWrapper.childNodes[1]; - - this.dom.grid.dt.parentNode.insertBefore( nSWrapper, this.dom.grid.dt ); - nSWrapper.appendChild( this.dom.grid.dt ); - - this.dom.grid.wrapper = nSWrapper; - - if ( this.s.iLeftColumns > 0 ) - { - this.dom.grid.left.wrapper = nLeft; - this.dom.grid.left.head = nLeft.childNodes[0]; - this.dom.grid.left.body = nLeft.childNodes[1]; - this.dom.grid.left.liner = $('div.DTFC_LeftBodyLiner', nSWrapper)[0]; - - nSWrapper.appendChild( nLeft ); - } - - if ( this.s.iRightColumns > 0 ) - { - this.dom.grid.right.wrapper = nRight; - this.dom.grid.right.head = nRight.childNodes[0]; - this.dom.grid.right.body = nRight.childNodes[1]; - this.dom.grid.right.liner = $('div.DTFC_RightBodyLiner', nSWrapper)[0]; - - nRight.style.right = oOverflow.bar+"px"; - - block = $('div.DTFC_RightHeadBlocker', nSWrapper)[0]; - block.style.width = oOverflow.bar+"px"; - block.style.right = -oOverflow.bar+"px"; - this.dom.grid.right.headBlock = block; - - block = $('div.DTFC_RightFootBlocker', nSWrapper)[0]; - block.style.width = oOverflow.bar+"px"; - block.style.right = -oOverflow.bar+"px"; - this.dom.grid.right.footBlock = block; - - nSWrapper.appendChild( nRight ); - } - - if ( this.s.dt.nTFoot ) - { - this.dom.footer = this.s.dt.nTFoot.parentNode; - if ( this.s.iLeftColumns > 0 ) - { - this.dom.grid.left.foot = nLeft.childNodes[2]; - } - if ( this.s.iRightColumns > 0 ) - { - this.dom.grid.right.foot = nRight.childNodes[2]; - } - } - - // RTL support - swap the position of the left and right columns (#48) - if ( this.s.rtl ) { - $('div.DTFC_RightHeadBlocker', nSWrapper).css( { - left: -oOverflow.bar+'px', - right: '' - } ); - } - }, - - - /** - * Style and position the grid used for the FixedColumns layout - * @returns {void} - * @private - */ - "_fnGridLayout": function () - { - var that = this; - var oGrid = this.dom.grid; - var iWidth = $(oGrid.wrapper).width(); - var iBodyHeight = $(this.s.dt.nTable.parentNode).outerHeight(); - var iFullHeight = $(this.s.dt.nTable.parentNode.parentNode).outerHeight(); - var oOverflow = this._fnDTOverflow(); - var iLeftWidth = this.s.iLeftWidth; - var iRightWidth = this.s.iRightWidth; - var rtl = $(this.dom.body).css('direction') === 'rtl'; - var wrapper; - var scrollbarAdjust = function ( node, width ) { - if ( ! oOverflow.bar ) { - // If there is no scrollbar (Macs) we need to hide the auto scrollbar - node.style.width = (width+20)+"px"; - node.style.paddingRight = "20px"; - node.style.boxSizing = "border-box"; - } - else if ( that._firefoxScrollError() ) { - // See the above function for why this is required - if ( $(node).height() > 34 ) { - node.style.width = (width+oOverflow.bar)+"px"; - } - } - else { - // Otherwise just overflow by the scrollbar - node.style.width = (width+oOverflow.bar)+"px"; - } - }; - - // When x scrolling - don't paint the fixed columns over the x scrollbar - if ( oOverflow.x ) - { - iBodyHeight -= oOverflow.bar; - } - - oGrid.wrapper.style.height = iFullHeight+"px"; - - if ( this.s.iLeftColumns > 0 ) - { - wrapper = oGrid.left.wrapper; - wrapper.style.width = iLeftWidth+'px'; - wrapper.style.height = '1px'; - - // Swap the position of the left and right columns for rtl (#48) - // This is always up against the edge, scrollbar on the far side - if ( rtl ) { - wrapper.style.left = ''; - wrapper.style.right = 0; - } - else { - wrapper.style.left = 0; - wrapper.style.right = ''; - } - - oGrid.left.body.style.height = iBodyHeight+"px"; - if ( oGrid.left.foot ) { - oGrid.left.foot.style.top = (oOverflow.x ? oOverflow.bar : 0)+"px"; // shift footer for scrollbar - } - - scrollbarAdjust( oGrid.left.liner, iLeftWidth ); - oGrid.left.liner.style.height = iBodyHeight+"px"; - } - - if ( this.s.iRightColumns > 0 ) - { - wrapper = oGrid.right.wrapper; - wrapper.style.width = iRightWidth+'px'; - wrapper.style.height = '1px'; - - // Need to take account of the vertical scrollbar - if ( this.s.rtl ) { - wrapper.style.left = oOverflow.y ? oOverflow.bar+'px' : 0; - wrapper.style.right = ''; - } - else { - wrapper.style.left = ''; - wrapper.style.right = oOverflow.y ? oOverflow.bar+'px' : 0; - } - - oGrid.right.body.style.height = iBodyHeight+"px"; - if ( oGrid.right.foot ) { - oGrid.right.foot.style.top = (oOverflow.x ? oOverflow.bar : 0)+"px"; - } - - scrollbarAdjust( oGrid.right.liner, iRightWidth ); - oGrid.right.liner.style.height = iBodyHeight+"px"; - - oGrid.right.headBlock.style.display = oOverflow.y ? 'block' : 'none'; - oGrid.right.footBlock.style.display = oOverflow.y ? 'block' : 'none'; - } - }, - - - /** - * Get information about the DataTable's scrolling state - specifically if the table is scrolling - * on either the x or y axis, and also the scrollbar width. - * @returns {object} Information about the DataTables scrolling state with the properties: - * 'x', 'y' and 'bar' - * @private - */ - "_fnDTOverflow": function () - { - var nTable = this.s.dt.nTable; - var nTableScrollBody = nTable.parentNode; - var out = { - "x": false, - "y": false, - "bar": this.s.dt.oScroll.iBarWidth - }; - - if ( nTable.offsetWidth > nTableScrollBody.clientWidth ) - { - out.x = true; - } - - if ( nTable.offsetHeight > nTableScrollBody.clientHeight ) - { - out.y = true; - } - - return out; - }, - - - /** - * Clone and position the fixed columns - * @returns {void} - * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true) - * @private - */ - "_fnDraw": function ( bAll ) - { - this._fnGridLayout(); - this._fnCloneLeft( bAll ); - this._fnCloneRight( bAll ); - - /* Draw callback function */ - if ( this.s.fnDrawCallback !== null ) - { - this.s.fnDrawCallback.call( this, this.dom.clone.left, this.dom.clone.right ); - } - - /* Event triggering */ - $(this).trigger( 'draw.dtfc', { - "leftClone": this.dom.clone.left, - "rightClone": this.dom.clone.right - } ); - }, - - - /** - * Clone the right columns - * @returns {void} - * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true) - * @private - */ - "_fnCloneRight": function ( bAll ) - { - if ( this.s.iRightColumns <= 0 ) { - return; - } - - var that = this, - i, jq, - aiColumns = []; - - for ( i=this.s.iTableColumns-this.s.iRightColumns ; ithead', oClone.header); - jqCloneThead.empty(); - - /* Add the created cloned TR elements to the table */ - for ( i=0, iLen=aoCloneLayout.length ; ithead', oClone.header)[0] ); - - for ( i=0, iLen=aoCloneLayout.length ; itbody>tr', that.dom.body).css('height', 'auto'); - } - - if ( oClone.body !== null ) - { - $(oClone.body).remove(); - oClone.body = null; - } - - oClone.body = $(this.dom.body).clone(true)[0]; - oClone.body.className += " DTFC_Cloned"; - oClone.body.style.paddingBottom = dt.oScroll.iBarWidth+"px"; - oClone.body.style.marginBottom = (dt.oScroll.iBarWidth*2)+"px"; /* For IE */ - if ( oClone.body.getAttribute('id') !== null ) - { - oClone.body.removeAttribute('id'); - } - - $('>thead>tr', oClone.body).empty(); - $('>tfoot', oClone.body).remove(); - - var nBody = $('tbody', oClone.body)[0]; - $(nBody).empty(); - if ( dt.aiDisplay.length > 0 ) - { - /* Copy the DataTables' header elements to force the column width in exactly the - * same way that DataTables does it - have the header element, apply the width and - * colapse it down - */ - var nInnerThead = $('>thead>tr', oClone.body)[0]; - for ( iIndex=0 ; iIndextbody>tr', that.dom.body).each( function (z) { - var i = that.s.dt.oFeatures.bServerSide===false ? - that.s.dt.aiDisplay[ that.s.dt._iDisplayStart+z ] : z; - var aTds = that.s.dt.aoData[ i ].anCells || $(this).children('td, th'); - - var n = this.cloneNode(false); - n.removeAttribute('id'); - n.setAttribute( 'data-dt-row', i ); - - for ( iIndex=0 ; iIndex 0 ) - { - nClone = $( aTds[iColumn] ).clone(true, true)[0]; - nClone.setAttribute( 'data-dt-row', i ); - nClone.setAttribute( 'data-dt-column', iIndex ); - n.appendChild( nClone ); - } - } - nBody.appendChild( n ); - } ); - } - else - { - $('>tbody>tr', that.dom.body).each( function (z) { - nClone = this.cloneNode(true); - nClone.className += ' DTFC_NoData'; - $('td', nClone).html(''); - nBody.appendChild( nClone ); - } ); - } - - oClone.body.style.width = "100%"; - oClone.body.style.margin = "0"; - oClone.body.style.padding = "0"; - - // Interop with Scroller - need to use a height forcing element in the - // scrolling area in the same way that Scroller does in the body scroll. - if ( dt.oScroller !== undefined ) - { - var scrollerForcer = dt.oScroller.dom.force; - - if ( ! oGrid.forcer ) { - oGrid.forcer = scrollerForcer.cloneNode( true ); - oGrid.liner.appendChild( oGrid.forcer ); - } - else { - oGrid.forcer.style.height = scrollerForcer.style.height; - } - } - - oGrid.liner.appendChild( oClone.body ); - - this._fnEqualiseHeights( 'tbody', that.dom.body, oClone.body ); - - /* - * Footer - */ - if ( dt.nTFoot !== null ) - { - if ( bAll ) - { - if ( oClone.footer !== null ) - { - oClone.footer.parentNode.removeChild( oClone.footer ); - } - oClone.footer = $(this.dom.footer).clone(true, true)[0]; - oClone.footer.className += " DTFC_Cloned"; - oClone.footer.style.width = "100%"; - oGrid.foot.appendChild( oClone.footer ); - - /* Copy the footer just like we do for the header */ - aoCloneLayout = this._fnCopyLayout( dt.aoFooter, aiColumns, true ); - var jqCloneTfoot = $('>tfoot', oClone.footer); - jqCloneTfoot.empty(); - - for ( i=0, iLen=aoCloneLayout.length ; itfoot', oClone.footer)[0] ); - - for ( i=0, iLen=aoCloneLayout.length ; ithead', oClone.header)[0] ); - $(anUnique).each( function (i) { - iColumn = aiColumns[i]; - this.style.width = that.s.aiInnerWidths[iColumn]+"px"; - } ); - - if ( that.s.dt.nTFoot !== null ) - { - anUnique = dt.oApi._fnGetUniqueThs( dt, $('>tfoot', oClone.footer)[0] ); - $(anUnique).each( function (i) { - iColumn = aiColumns[i]; - this.style.width = that.s.aiInnerWidths[iColumn]+"px"; - } ); - } - }, - - - /** - * From a given table node (THEAD etc), get a list of TR direct child elements - * @param {Node} nIn Table element to search for TR elements (THEAD, TBODY or TFOOT element) - * @returns {Array} List of TR elements found - * @private - */ - "_fnGetTrNodes": function ( nIn ) - { - var aOut = []; - for ( var i=0, iLen=nIn.childNodes.length ; i'+nodeName+'>tr:eq(0)', original).children(':first'), - iBoxHack = jqBoxHack.outerHeight() - jqBoxHack.height(), - anOriginal = this._fnGetTrNodes( rootOriginal ), - anClone = this._fnGetTrNodes( rootClone ), - heights = []; - - for ( i=0, iLen=anClone.length ; i iHeightOriginal ? iHeightClone : iHeightOriginal; - - if ( this.s.sHeightMatch == 'semiauto' ) - { - anOriginal[i]._DTTC_iHeight = iHeight; - } - - heights.push( iHeight ); - } - - for ( i=0, iLen=anClone.length ; i') - .css( { - position: 'absolute', - top: 0, - left: 0, - height: 10, - width: 50, - overflow: 'scroll' - } ) - .appendTo( 'body' ); - - // Make sure this doesn't apply on Macs with 0 width scrollbars - _firefoxScroll = ( - test[0].clientWidth === test[0].offsetWidth && this._fnDTOverflow().bar !== 0 - ); - - test.remove(); - } - - return _firefoxScroll; - } -} ); - - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Statics - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/** - * FixedColumns default settings for initialisation - * @name FixedColumns.defaults - * @namespace - * @static - */ -FixedColumns.defaults = /** @lends FixedColumns.defaults */{ - /** - * Number of left hand columns to fix in position - * @type int - * @default 1 - * @static - * @example - * var = $('#example').dataTable( { - * "scrollX": "100%" - * } ); - * new $.fn.dataTable.fixedColumns( table, { - * "leftColumns": 2 - * } ); - */ - "iLeftColumns": 1, - - /** - * Number of right hand columns to fix in position - * @type int - * @default 0 - * @static - * @example - * var table = $('#example').dataTable( { - * "scrollX": "100%" - * } ); - * new $.fn.dataTable.fixedColumns( table, { - * "rightColumns": 1 - * } ); - */ - "iRightColumns": 0, - - /** - * Draw callback function which is called when FixedColumns has redrawn the fixed assets - * @type function(object, object):void - * @default null - * @static - * @example - * var table = $('#example').dataTable( { - * "scrollX": "100%" - * } ); - * new $.fn.dataTable.fixedColumns( table, { - * "drawCallback": function () { - * alert( "FixedColumns redraw" ); - * } - * } ); - */ - "fnDrawCallback": null, - - /** - * Height matching algorthim to use. This can be "none" which will result in no height - * matching being applied by FixedColumns (height matching could be forced by CSS in this - * case), "semiauto" whereby the height calculation will be performed once, and the result - * cached to be used again (fnRecalculateHeight can be used to force recalculation), or - * "auto" when height matching is performed on every draw (slowest but must accurate) - * @type string - * @default semiauto - * @static - * @example - * var table = $('#example').dataTable( { - * "scrollX": "100%" - * } ); - * new $.fn.dataTable.fixedColumns( table, { - * "heightMatch": "auto" - * } ); - */ - "sHeightMatch": "semiauto" -}; - - - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Constants - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/** - * FixedColumns version - * @name FixedColumns.version - * @type String - * @default See code - * @static - */ -FixedColumns.version = "3.2.2"; - - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * DataTables API integration - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -DataTable.Api.register( 'fixedColumns()', function () { - return this; -} ); - -DataTable.Api.register( 'fixedColumns().update()', function () { - return this.iterator( 'table', function ( ctx ) { - if ( ctx._oFixedColumns ) { - ctx._oFixedColumns.fnUpdate(); - } - } ); -} ); - -DataTable.Api.register( 'fixedColumns().relayout()', function () { - return this.iterator( 'table', function ( ctx ) { - if ( ctx._oFixedColumns ) { - ctx._oFixedColumns.fnRedrawLayout(); - } - } ); -} ); - -DataTable.Api.register( 'rows().recalcHeight()', function () { - return this.iterator( 'row', function ( ctx, idx ) { - if ( ctx._oFixedColumns ) { - ctx._oFixedColumns.fnRecalculateHeight( this.row(idx).node() ); - } - } ); -} ); - -DataTable.Api.register( 'fixedColumns().rowIndex()', function ( row ) { - row = $(row); - - return row.parents('.DTFC_Cloned').length ? - this.rows( { page: 'current' } ).indexes()[ row.index() ] : - this.row( row ).index(); -} ); - -DataTable.Api.register( 'fixedColumns().cellIndex()', function ( cell ) { - cell = $(cell); - - if ( cell.parents('.DTFC_Cloned').length ) { - var rowClonedIdx = cell.parent().index(); - var rowIdx = this.rows( { page: 'current' } ).indexes()[ rowClonedIdx ]; - var columnIdx; - - if ( cell.parents('.DTFC_LeftWrapper').length ) { - columnIdx = cell.index(); - } - else { - var columns = this.columns().flatten().length; - columnIdx = columns - this.context[0]._oFixedColumns.s.iRightColumns + cell.index(); - } - - return { - row: rowIdx, - column: this.column.index( 'toData', columnIdx ), - columnVisible: columnIdx - }; - } - else { - return this.cell( cell ).index(); - } -} ); - - - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Initialisation - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -// Attach a listener to the document which listens for DataTables initialisation -// events so we can automatically initialise -$(document).on( 'init.dt.fixedColumns', function (e, settings) { - if ( e.namespace !== 'dt' ) { - return; - } - - var init = settings.oInit.fixedColumns; - var defaults = DataTable.defaults.fixedColumns; - - if ( init || defaults ) { - var opts = $.extend( {}, init, defaults ); - - if ( init !== false ) { - new FixedColumns( settings, opts ); - } - } -} ); - - - -// Make FixedColumns accessible from the DataTables instance -$.fn.dataTable.FixedColumns = FixedColumns; -$.fn.DataTable.FixedColumns = FixedColumns; - -return FixedColumns; -})); diff --git a/app/static/DataTables/FixedColumns-3.2.2/js/dataTables.fixedColumns.min.js b/app/static/DataTables/FixedColumns-3.2.2/js/dataTables.fixedColumns.min.js deleted file mode 100644 index 6e3a593c9..000000000 --- a/app/static/DataTables/FixedColumns-3.2.2/js/dataTables.fixedColumns.min.js +++ /dev/null @@ -1,35 +0,0 @@ -/*! - FixedColumns 3.2.2 - ©2010-2016 SpryMedia Ltd - datatables.net/license -*/ -(function(d){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(q){return d(q,window,document)}):"object"===typeof exports?module.exports=function(q,r){q||(q=window);if(!r||!r.fn.dataTable)r=require("datatables.net")(q,r).$;return d(r,q,q.document)}:d(jQuery,window,document)})(function(d,q,r,t){var s=d.fn.dataTable,u,m=function(a,b){var c=this;if(this instanceof m){if(b===t||!0===b)b={};var e=d.fn.dataTable.camelToHungarian;e&&(e(m.defaults,m.defaults,!0),e(m.defaults, -b));e=(new d.fn.dataTable.Api(a)).settings()[0];this.s={dt:e,iTableColumns:e.aoColumns.length,aiOuterWidths:[],aiInnerWidths:[],rtl:"rtl"===d(e.nTable).css("direction")};this.dom={scroller:null,header:null,body:null,footer:null,grid:{wrapper:null,dt:null,left:{wrapper:null,head:null,body:null,foot:null},right:{wrapper:null,head:null,body:null,foot:null}},clone:{left:{header:null,body:null,footer:null},right:{header:null,body:null,footer:null}}};if(e._oFixedColumns)throw"FixedColumns already initialised on this table"; -e._oFixedColumns=this;e._bInitComplete?this._fnConstruct(b):e.oApi._fnCallbackReg(e,"aoInitComplete",function(){c._fnConstruct(b)},"FixedColumns")}else alert("FixedColumns warning: FixedColumns must be initialised with the 'new' keyword.")};d.extend(m.prototype,{fnUpdate:function(){this._fnDraw(!0)},fnRedrawLayout:function(){this._fnColCalc();this._fnGridLayout();this.fnUpdate()},fnRecalculateHeight:function(a){delete a._DTTC_iHeight;a.style.height="auto"},fnSetRowHeight:function(a,b){a.style.height= -b+"px"},fnGetPosition:function(a){var b=this.s.dt.oInstance;if(d(a).parents(".DTFC_Cloned").length){if("tr"===a.nodeName.toLowerCase())return a=d(a).index(),b.fnGetPosition(d("tr",this.s.dt.nTBody)[a]);var c=d(a).index(),a=d(a.parentNode).index();return[b.fnGetPosition(d("tr",this.s.dt.nTBody)[a]),c,b.oApi._fnVisibleToColumnIndex(this.s.dt,c)]}return b.fnGetPosition(a)},_fnConstruct:function(a){var b=this;if("function"!=typeof this.s.dt.oInstance.fnVersionCheck||!0!==this.s.dt.oInstance.fnVersionCheck("1.8.0"))alert("FixedColumns "+ -m.VERSION+" required DataTables 1.8.0 or later. Please upgrade your DataTables installation");else if(""===this.s.dt.oScroll.sX)this.s.dt.oInstance.oApi._fnLog(this.s.dt,1,"FixedColumns is not needed (no x-scrolling in DataTables enabled), so no action will be taken. Use 'FixedHeader' for column fixing when scrolling is not enabled");else{this.s=d.extend(!0,this.s,m.defaults,a);a=this.s.dt.oClasses;this.dom.grid.dt=d(this.s.dt.nTable).parents("div."+a.sScrollWrapper)[0];this.dom.scroller=d("div."+ -a.sScrollBody,this.dom.grid.dt)[0];this._fnColCalc();this._fnGridSetup();var c,e=!1;d(this.s.dt.nTableWrapper).on("mousedown.DTFC",function(){e=!0;d(r).one("mouseup",function(){e=!1})});d(this.dom.scroller).on("mouseover.DTFC touchstart.DTFC",function(){e||(c="main")}).on("scroll.DTFC",function(a){!c&&a.originalEvent&&(c="main");if("main"===c&&(0
    ')[0], -e=c.childNodes[0],f=c.childNodes[1];this.dom.grid.dt.parentNode.insertBefore(c,this.dom.grid.dt);c.appendChild(this.dom.grid.dt);this.dom.grid.wrapper=c;0b.clientWidth&&(c.x=!0);a.offsetHeight> -b.clientHeight&&(c.y=!0);return c},_fnDraw:function(a){this._fnGridLayout();this._fnCloneLeft(a);this._fnCloneRight(a);null!==this.s.fnDrawCallback&&this.s.fnDrawCallback.call(this,this.dom.clone.left,this.dom.clone.right);d(this).trigger("draw.dtfc",{leftClone:this.dom.clone.left,rightClone:this.dom.clone.right})},_fnCloneRight:function(a){if(!(0>=this.s.iRightColumns)){var b,c=[];for(b=this.s.iTableColumns-this.s.iRightColumns;b=this.s.iLeftColumns)){var b,c=[];for(b=0;bthead",a.header);j.empty();g=0;for(h=n.length;gthead",a.header)[0]);g=0;for(h=n.length;gtbody>tr",f.dom.body).css("height","auto");null!==a.body&&(d(a.body).remove(), -a.body=null);a.body=d(this.dom.body).clone(!0)[0];a.body.className+=" DTFC_Cloned";a.body.style.paddingBottom=k.oScroll.iBarWidth+"px";a.body.style.marginBottom=2*k.oScroll.iBarWidth+"px";null!==a.body.getAttribute("id")&&a.body.removeAttribute("id");d(">thead>tr",a.body).empty();d(">tfoot",a.body).remove();var q=d("tbody",a.body)[0];d(q).empty();if(0thead>tr",a.body)[0];for(p=0;ptbody>tr",f.dom.body).each(function(a){var a=f.s.dt.oFeatures.bServerSide===false?f.s.dt.aiDisplay[f.s.dt._iDisplayStart+a]:a,b=f.s.dt.aoData[a].anCells||d(this).children("td, th"),e=this.cloneNode(false);e.removeAttribute("id");e.setAttribute("data-dt-row",a);for(p=0;p0){o=d(b[l]).clone(true,true)[0];o.setAttribute("data-dt-row", -a);o.setAttribute("data-dt-column",p);e.appendChild(o)}}q.appendChild(e)})}else d(">tbody>tr",f.dom.body).each(function(){o=this.cloneNode(true);o.className=o.className+" DTFC_NoData";d("td",o).html("");q.appendChild(o)});a.body.style.width="100%";a.body.style.margin="0";a.body.style.padding="0";k.oScroller!==t&&(h=k.oScroller.dom.force,b.forcer?b.forcer.style.height=h.style.height:(b.forcer=h.cloneNode(!0),b.liner.appendChild(b.forcer)));b.liner.appendChild(a.body);this._fnEqualiseHeights("tbody", -f.dom.body,a.body);if(null!==k.nTFoot){if(e){null!==a.footer&&a.footer.parentNode.removeChild(a.footer);a.footer=d(this.dom.footer).clone(!0,!0)[0];a.footer.className+=" DTFC_Cloned";a.footer.style.width="100%";b.foot.appendChild(a.footer);n=this._fnCopyLayout(k.aoFooter,c,!0);b=d(">tfoot",a.footer);b.empty();g=0;for(h=n.length;gtfoot",a.footer)[0]);g=0;for(h=n.length;g< -h;g++){i=0;for(j=n[g].length;ithead",a.header)[0]);d(b).each(function(a){l=c[a];this.style.width=f.s.aiInnerWidths[l]+"px"});null!==f.s.dt.nTFoot&&(b=k.oApi._fnGetUniqueThs(k,d(">tfoot",a.footer)[0]),d(b).each(function(a){l=c[a];this.style.width=f.s.aiInnerWidths[l]+"px"}))},_fnGetTrNodes:function(a){for(var b=[],c=0,d=a.childNodes.length;c"+a+">tr:eq(0)",b).children(":first");a.outerHeight();a.height();for(var g=this._fnGetTrNodes(g),b=this._fnGetTrNodes(c),h=[],c=0,a=b.length;ce?f:e,"semiauto"==this.s.sHeightMatch&&(g[c]._DTTC_iHeight=e),h.push(e);c=0;for(a=b.length;c").css({position:"absolute",top:0,left:0,height:10,width:50,overflow:"scroll"}).appendTo("body");u=a[0].clientWidth===a[0].offsetWidth&&0!==this._fnDTOverflow().bar;a.remove()}return u}});m.defaults={iLeftColumns:1,iRightColumns:0,fnDrawCallback:null,sHeightMatch:"semiauto"};m.version="3.2.2";s.Api.register("fixedColumns()",function(){return this});s.Api.register("fixedColumns().update()",function(){return this.iterator("table", -function(a){a._oFixedColumns&&a._oFixedColumns.fnUpdate()})});s.Api.register("fixedColumns().relayout()",function(){return this.iterator("table",function(a){a._oFixedColumns&&a._oFixedColumns.fnRedrawLayout()})});s.Api.register("rows().recalcHeight()",function(){return this.iterator("row",function(a,b){a._oFixedColumns&&a._oFixedColumns.fnRecalculateHeight(this.row(b).node())})});s.Api.register("fixedColumns().rowIndex()",function(a){a=d(a);return a.parents(".DTFC_Cloned").length?this.rows({page:"current"}).indexes()[a.index()]: -this.row(a).index()});s.Api.register("fixedColumns().cellIndex()",function(a){a=d(a);if(a.parents(".DTFC_Cloned").length){var b=a.parent().index(),b=this.rows({page:"current"}).indexes()[b],a=a.parents(".DTFC_LeftWrapper").length?a.index():this.columns().flatten().length-this.context[0]._oFixedColumns.s.iRightColumns+a.index();return{row:b,column:this.column.index("toData",a),columnVisible:a}}return this.cell(a).index()});d(r).on("init.dt.fixedColumns",function(a,b){if("dt"===a.namespace){var c=b.oInit.fixedColumns, -e=s.defaults.fixedColumns;if(c||e)e=d.extend({},c,e),!1!==c&&new m(b,e)}});d.fn.dataTable.FixedColumns=m;return d.fn.DataTable.FixedColumns=m}); diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.bootstrap.css b/app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.bootstrap.css similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.bootstrap.css rename to app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.bootstrap.css diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.bootstrap.min.css b/app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.bootstrap.min.css similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.bootstrap.min.css rename to app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.bootstrap.min.css diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.bootstrap4.css b/app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.bootstrap4.css similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.bootstrap4.css rename to app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.bootstrap4.css diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.bootstrap4.min.css b/app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.bootstrap4.min.css similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.bootstrap4.min.css rename to app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.bootstrap4.min.css diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.bootstrap5.css b/app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.bootstrap5.css similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.bootstrap5.css rename to app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.bootstrap5.css diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.bootstrap5.min.css b/app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.bootstrap5.min.css similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.bootstrap5.min.css rename to app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.bootstrap5.min.css diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.bulma.css b/app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.bulma.css similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.bulma.css rename to app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.bulma.css diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.bulma.min.css b/app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.bulma.min.css similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.bulma.min.css rename to app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.bulma.min.css diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.dataTables.css b/app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.dataTables.css similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.dataTables.css rename to app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.dataTables.css diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.dataTables.min.css b/app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.dataTables.min.css similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.dataTables.min.css rename to app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.dataTables.min.css diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.foundation.css b/app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.foundation.css similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.foundation.css rename to app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.foundation.css diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.foundation.min.css b/app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.foundation.min.css similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.foundation.min.css rename to app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.foundation.min.css diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.jqueryui.css b/app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.jqueryui.css similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.jqueryui.css rename to app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.jqueryui.css diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.jqueryui.min.css b/app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.jqueryui.min.css similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.jqueryui.min.css rename to app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.jqueryui.min.css diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.semanticui.css b/app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.semanticui.css similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.semanticui.css rename to app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.semanticui.css diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.semanticui.min.css b/app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.semanticui.min.css similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/css/fixedColumns.semanticui.min.css rename to app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.semanticui.min.css diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/js/dataTables.fixedColumns.js b/app/static/DataTables/FixedColumns-4.0.1/js/dataTables.fixedColumns.js similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/js/dataTables.fixedColumns.js rename to app/static/DataTables/FixedColumns-4.0.1/js/dataTables.fixedColumns.js diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/js/dataTables.fixedColumns.min.js b/app/static/DataTables/FixedColumns-4.0.1/js/dataTables.fixedColumns.min.js similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/js/dataTables.fixedColumns.min.js rename to app/static/DataTables/FixedColumns-4.0.1/js/dataTables.fixedColumns.min.js diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.bootstrap.js b/app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.bootstrap.js similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.bootstrap.js rename to app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.bootstrap.js diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.bootstrap.min.js b/app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.bootstrap.min.js similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.bootstrap.min.js rename to app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.bootstrap.min.js diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.bootstrap4.js b/app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.bootstrap4.js similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.bootstrap4.js rename to app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.bootstrap4.js diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.bootstrap4.min.js b/app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.bootstrap4.min.js similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.bootstrap4.min.js rename to app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.bootstrap4.min.js diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.bootstrap5.js b/app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.bootstrap5.js similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.bootstrap5.js rename to app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.bootstrap5.js diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.bootstrap5.min.js b/app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.bootstrap5.min.js similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.bootstrap5.min.js rename to app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.bootstrap5.min.js diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.bulma.js b/app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.bulma.js similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.bulma.js rename to app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.bulma.js diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.bulma.min.js b/app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.bulma.min.js similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.bulma.min.js rename to app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.bulma.min.js diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.dataTables.js b/app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.dataTables.js similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.dataTables.js rename to app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.dataTables.js diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.dataTables.min.js b/app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.dataTables.min.js similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.dataTables.min.js rename to app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.dataTables.min.js diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.foundation.js b/app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.foundation.js similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.foundation.js rename to app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.foundation.js diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.foundation.min.js b/app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.foundation.min.js similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.foundation.min.js rename to app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.foundation.min.js diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.jqueryui.js b/app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.jqueryui.js similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.jqueryui.js rename to app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.jqueryui.js diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.jqueryui.min.js b/app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.jqueryui.min.js similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.jqueryui.min.js rename to app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.jqueryui.min.js diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.semanticui.js b/app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.semanticui.js similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.semanticui.js rename to app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.semanticui.js diff --git a/app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.semanticui.min.js b/app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.semanticui.min.js similarity index 100% rename from app/static/DataTables2022/FixedColumns-4.0.1/js/fixedColumns.semanticui.min.js rename to app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.semanticui.min.js diff --git a/app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.bootstrap.css b/app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.bootstrap.css deleted file mode 100644 index 98b09b07a..000000000 --- a/app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.bootstrap.css +++ /dev/null @@ -1,20 +0,0 @@ -table.dataTable.fixedHeader-floating, -table.dataTable.fixedHeader-locked { - background-color: white; - margin-top: 0 !important; - margin-bottom: 0 !important; -} - -table.dataTable.fixedHeader-floating { - position: fixed !important; -} - -table.dataTable.fixedHeader-locked { - position: absolute !important; -} - -@media print { - table.fixedHeader-floating { - display: none; - } -} diff --git a/app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.bootstrap.min.css b/app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.bootstrap.min.css deleted file mode 100644 index 68f816759..000000000 --- a/app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.bootstrap.min.css +++ /dev/null @@ -1 +0,0 @@ -table.dataTable.fixedHeader-floating,table.dataTable.fixedHeader-locked{background-color:white;margin-top:0 !important;margin-bottom:0 !important}table.dataTable.fixedHeader-floating{position:fixed !important}table.dataTable.fixedHeader-locked{position:absolute !important}@media print{table.fixedHeader-floating{display:none}} diff --git a/app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.dataTables.css b/app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.dataTables.css deleted file mode 100644 index 77509717e..000000000 --- a/app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.dataTables.css +++ /dev/null @@ -1,19 +0,0 @@ -table.fixedHeader-floating { - position: fixed !important; - background-color: white; -} - -table.fixedHeader-floating.no-footer { - border-bottom-width: 0; -} - -table.fixedHeader-locked { - position: absolute !important; - background-color: white; -} - -@media print { - table.fixedHeader-floating { - display: none; - } -} diff --git a/app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.dataTables.min.css b/app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.dataTables.min.css deleted file mode 100644 index 7113963e4..000000000 --- a/app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.dataTables.min.css +++ /dev/null @@ -1 +0,0 @@ -table.fixedHeader-floating{position:fixed !important;background-color:white}table.fixedHeader-floating.no-footer{border-bottom-width:0}table.fixedHeader-locked{position:absolute !important;background-color:white}@media print{table.fixedHeader-floating{display:none}} diff --git a/app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.foundation.css b/app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.foundation.css deleted file mode 100644 index 98b09b07a..000000000 --- a/app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.foundation.css +++ /dev/null @@ -1,20 +0,0 @@ -table.dataTable.fixedHeader-floating, -table.dataTable.fixedHeader-locked { - background-color: white; - margin-top: 0 !important; - margin-bottom: 0 !important; -} - -table.dataTable.fixedHeader-floating { - position: fixed !important; -} - -table.dataTable.fixedHeader-locked { - position: absolute !important; -} - -@media print { - table.fixedHeader-floating { - display: none; - } -} diff --git a/app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.foundation.min.css b/app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.foundation.min.css deleted file mode 100644 index 68f816759..000000000 --- a/app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.foundation.min.css +++ /dev/null @@ -1 +0,0 @@ -table.dataTable.fixedHeader-floating,table.dataTable.fixedHeader-locked{background-color:white;margin-top:0 !important;margin-bottom:0 !important}table.dataTable.fixedHeader-floating{position:fixed !important}table.dataTable.fixedHeader-locked{position:absolute !important}@media print{table.fixedHeader-floating{display:none}} diff --git a/app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.jqueryui.css b/app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.jqueryui.css deleted file mode 100644 index a453aa96d..000000000 --- a/app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.jqueryui.css +++ /dev/null @@ -1,15 +0,0 @@ -table.fixedHeader-floating { - position: fixed !important; - background-color: white; -} - -table.fixedHeader-locked { - position: absolute !important; - background-color: white; -} - -@media print { - table.fixedHeader-floating { - display: none; - } -} diff --git a/app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.jqueryui.min.css b/app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.jqueryui.min.css deleted file mode 100644 index c89d8145b..000000000 --- a/app/static/DataTables/FixedHeader-3.1.2/css/fixedHeader.jqueryui.min.css +++ /dev/null @@ -1 +0,0 @@ -table.fixedHeader-floating{position:fixed !important;background-color:white}table.fixedHeader-locked{position:absolute !important;background-color:white}@media print{table.fixedHeader-floating{display:none}} diff --git a/app/static/DataTables/FixedHeader-3.1.2/js/dataTables.fixedHeader.js b/app/static/DataTables/FixedHeader-3.1.2/js/dataTables.fixedHeader.js deleted file mode 100644 index 7c236da69..000000000 --- a/app/static/DataTables/FixedHeader-3.1.2/js/dataTables.fixedHeader.js +++ /dev/null @@ -1,672 +0,0 @@ -/*! FixedHeader 3.1.2 - * ©2009-2016 SpryMedia Ltd - datatables.net/license - */ - -/** - * @summary FixedHeader - * @description Fix a table's header or footer, so it is always visible while - * scrolling - * @version 3.1.2 - * @file dataTables.fixedHeader.js - * @author SpryMedia Ltd (www.sprymedia.co.uk) - * @contact www.sprymedia.co.uk/contact - * @copyright Copyright 2009-2016 SpryMedia Ltd. - * - * This source file is free software, available under the following license: - * MIT license - http://datatables.net/license/mit - * - * This source file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. - * - * For details please refer to: http://www.datatables.net - */ - -(function( factory ){ - if ( typeof define === 'function' && define.amd ) { - // AMD - define( ['jquery', 'datatables.net'], function ( $ ) { - return factory( $, window, document ); - } ); - } - else if ( typeof exports === 'object' ) { - // CommonJS - module.exports = function (root, $) { - if ( ! root ) { - root = window; - } - - if ( ! $ || ! $.fn.dataTable ) { - $ = require('datatables.net')(root, $).$; - } - - return factory( $, root, root.document ); - }; - } - else { - // Browser - factory( jQuery, window, document ); - } -}(function( $, window, document, undefined ) { -'use strict'; -var DataTable = $.fn.dataTable; - - -var _instCounter = 0; - -var FixedHeader = function ( dt, config ) { - // Sanity check - you just know it will happen - if ( ! (this instanceof FixedHeader) ) { - throw "FixedHeader must be initialised with the 'new' keyword."; - } - - // Allow a boolean true for defaults - if ( config === true ) { - config = {}; - } - - dt = new DataTable.Api( dt ); - - this.c = $.extend( true, {}, FixedHeader.defaults, config ); - - this.s = { - dt: dt, - position: { - theadTop: 0, - tbodyTop: 0, - tfootTop: 0, - tfootBottom: 0, - width: 0, - left: 0, - tfootHeight: 0, - theadHeight: 0, - windowHeight: $(window).height(), - visible: true - }, - headerMode: null, - footerMode: null, - autoWidth: dt.settings()[0].oFeatures.bAutoWidth, - namespace: '.dtfc'+(_instCounter++), - scrollLeft: { - header: -1, - footer: -1 - }, - enable: true - }; - - this.dom = { - floatingHeader: null, - thead: $(dt.table().header()), - tbody: $(dt.table().body()), - tfoot: $(dt.table().footer()), - header: { - host: null, - floating: null, - placeholder: null - }, - footer: { - host: null, - floating: null, - placeholder: null - } - }; - - this.dom.header.host = this.dom.thead.parent(); - this.dom.footer.host = this.dom.tfoot.parent(); - - var dtSettings = dt.settings()[0]; - if ( dtSettings._fixedHeader ) { - throw "FixedHeader already initialised on table "+dtSettings.nTable.id; - } - - dtSettings._fixedHeader = this; - - this._constructor(); -}; - - -/* - * Variable: FixedHeader - * Purpose: Prototype for FixedHeader - * Scope: global - */ -$.extend( FixedHeader.prototype, { - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * API methods - */ - - /** - * Enable / disable the fixed elements - * - * @param {boolean} enable `true` to enable, `false` to disable - */ - enable: function ( enable ) - { - this.s.enable = enable; - - if ( this.c.header ) { - this._modeChange( 'in-place', 'header', true ); - } - - if ( this.c.footer && this.dom.tfoot.length ) { - this._modeChange( 'in-place', 'footer', true ); - } - - this.update(); - }, - - /** - * Set header offset - * - * @param {int} new value for headerOffset - */ - headerOffset: function ( offset ) - { - if ( offset !== undefined ) { - this.c.headerOffset = offset; - this.update(); - } - - return this.c.headerOffset; - }, - - /** - * Set footer offset - * - * @param {int} new value for footerOffset - */ - footerOffset: function ( offset ) - { - if ( offset !== undefined ) { - this.c.footerOffset = offset; - this.update(); - } - - return this.c.footerOffset; - }, - - - /** - * Recalculate the position of the fixed elements and force them into place - */ - update: function () - { - this._positions(); - this._scroll( true ); - }, - - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Constructor - */ - - /** - * FixedHeader constructor - adding the required event listeners and - * simple initialisation - * - * @private - */ - _constructor: function () - { - var that = this; - var dt = this.s.dt; - - $(window) - .on( 'scroll'+this.s.namespace, function () { - that._scroll(); - } ) - .on( 'resize'+this.s.namespace, function () { - that.s.position.windowHeight = $(window).height(); - that.update(); - } ); - - var autoHeader = $('.fh-fixedHeader'); - if ( ! this.c.headerOffset && autoHeader.length ) { - this.c.headerOffset = autoHeader.outerHeight(); - } - - var autoFooter = $('.fh-fixedFooter'); - if ( ! this.c.footerOffset && autoFooter.length ) { - this.c.footerOffset = autoFooter.outerHeight(); - } - - dt.on( 'column-reorder.dt.dtfc column-visibility.dt.dtfc draw.dt.dtfc column-sizing.dt.dtfc', function () { - that.update(); - } ); - - dt.on( 'destroy.dtfc', function () { - dt.off( '.dtfc' ); - $(window).off( that.s.namespace ); - } ); - - this._positions(); - this._scroll(); - }, - - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Private methods - */ - - /** - * Clone a fixed item to act as a place holder for the original element - * which is moved into a clone of the table element, and moved around the - * document to give the fixed effect. - * - * @param {string} item 'header' or 'footer' - * @param {boolean} force Force the clone to happen, or allow automatic - * decision (reuse existing if available) - * @private - */ - _clone: function ( item, force ) - { - var dt = this.s.dt; - var itemDom = this.dom[ item ]; - var itemElement = item === 'header' ? - this.dom.thead : - this.dom.tfoot; - - if ( ! force && itemDom.floating ) { - // existing floating element - reuse it - itemDom.floating.removeClass( 'fixedHeader-floating fixedHeader-locked' ); - } - else { - if ( itemDom.floating ) { - itemDom.placeholder.remove(); - this._unsize( item ); - itemDom.floating.children().detach(); - itemDom.floating.remove(); - } - - itemDom.floating = $( dt.table().node().cloneNode( false ) ) - .css( 'table-layout', 'fixed' ) - .removeAttr( 'id' ) - .append( itemElement ) - .appendTo( 'body' ); - - // Insert a fake thead/tfoot into the DataTable to stop it jumping around - itemDom.placeholder = itemElement.clone( false ); - itemDom.host.prepend( itemDom.placeholder ); - - // Clone widths - this._matchWidths( itemDom.placeholder, itemDom.floating ); - } - }, - - /** - * Copy widths from the cells in one element to another. This is required - * for the footer as the footer in the main table takes its sizes from the - * header columns. That isn't present in the footer so to have it still - * align correctly, the sizes need to be copied over. It is also required - * for the header when auto width is not enabled - * - * @param {jQuery} from Copy widths from - * @param {jQuery} to Copy widths to - * @private - */ - _matchWidths: function ( from, to ) { - var get = function ( name ) { - return $(name, from) - .map( function () { - return $(this).width(); - } ).toArray(); - }; - - var set = function ( name, toWidths ) { - $(name, to).each( function ( i ) { - $(this).css( { - width: toWidths[i], - minWidth: toWidths[i] - } ); - } ); - }; - - var thWidths = get( 'th' ); - var tdWidths = get( 'td' ); - - set( 'th', thWidths ); - set( 'td', tdWidths ); - }, - - /** - * Remove assigned widths from the cells in an element. This is required - * when inserting the footer back into the main table so the size is defined - * by the header columns and also when auto width is disabled in the - * DataTable. - * - * @param {string} item The `header` or `footer` - * @private - */ - _unsize: function ( item ) { - var el = this.dom[ item ].floating; - - if ( el && (item === 'footer' || (item === 'header' && ! this.s.autoWidth)) ) { - $('th, td', el).css( { - width: '', - minWidth: '' - } ); - } - else if ( el && item === 'header' ) { - $('th, td', el).css( 'min-width', '' ); - } - }, - - /** - * Reposition the floating elements to take account of horizontal page - * scroll - * - * @param {string} item The `header` or `footer` - * @param {int} scrollLeft Document scrollLeft - * @private - */ - _horizontal: function ( item, scrollLeft ) - { - var itemDom = this.dom[ item ]; - var position = this.s.position; - var lastScrollLeft = this.s.scrollLeft; - - if ( itemDom.floating && lastScrollLeft[ item ] !== scrollLeft ) { - itemDom.floating.css( 'left', position.left - scrollLeft ); - - lastScrollLeft[ item ] = scrollLeft; - } - }, - - /** - * Change from one display mode to another. Each fixed item can be in one - * of: - * - * * `in-place` - In the main DataTable - * * `in` - Floating over the DataTable - * * `below` - (Header only) Fixed to the bottom of the table body - * * `above` - (Footer only) Fixed to the top of the table body - * - * @param {string} mode Mode that the item should be shown in - * @param {string} item 'header' or 'footer' - * @param {boolean} forceChange Force a redraw of the mode, even if already - * in that mode. - * @private - */ - _modeChange: function ( mode, item, forceChange ) - { - var dt = this.s.dt; - var itemDom = this.dom[ item ]; - var position = this.s.position; - - // Record focus. Browser's will cause input elements to loose focus if - // they are inserted else where in the doc - var tablePart = this.dom[ item==='footer' ? 'tfoot' : 'thead' ]; - var focus = $.contains( tablePart[0], document.activeElement ) ? - document.activeElement : - null; - - if ( mode === 'in-place' ) { - // Insert the header back into the table's real header - if ( itemDom.placeholder ) { - itemDom.placeholder.remove(); - itemDom.placeholder = null; - } - - this._unsize( item ); - - if ( item === 'header' ) { - itemDom.host.prepend( this.dom.thead ); - } - else { - itemDom.host.append( this.dom.tfoot ); - } - - if ( itemDom.floating ) { - itemDom.floating.remove(); - itemDom.floating = null; - } - } - else if ( mode === 'in' ) { - // Remove the header from the read header and insert into a fixed - // positioned floating table clone - this._clone( item, forceChange ); - - itemDom.floating - .addClass( 'fixedHeader-floating' ) - .css( item === 'header' ? 'top' : 'bottom', this.c[item+'Offset'] ) - .css( 'left', position.left+'px' ) - .css( 'width', position.width+'px' ); - - if ( item === 'footer' ) { - itemDom.floating.css( 'top', '' ); - } - } - else if ( mode === 'below' ) { // only used for the header - // Fix the position of the floating header at base of the table body - this._clone( item, forceChange ); - - itemDom.floating - .addClass( 'fixedHeader-locked' ) - .css( 'top', position.tfootTop - position.theadHeight ) - .css( 'left', position.left+'px' ) - .css( 'width', position.width+'px' ); - } - else if ( mode === 'above' ) { // only used for the footer - // Fix the position of the floating footer at top of the table body - this._clone( item, forceChange ); - - itemDom.floating - .addClass( 'fixedHeader-locked' ) - .css( 'top', position.tbodyTop ) - .css( 'left', position.left+'px' ) - .css( 'width', position.width+'px' ); - } - - // Restore focus if it was lost - if ( focus && focus !== document.activeElement ) { - focus.focus(); - } - - this.s.scrollLeft.header = -1; - this.s.scrollLeft.footer = -1; - this.s[item+'Mode'] = mode; - }, - - /** - * Cache the positional information that is required for the mode - * calculations that FixedHeader performs. - * - * @private - */ - _positions: function () - { - var dt = this.s.dt; - var table = dt.table(); - var position = this.s.position; - var dom = this.dom; - var tableNode = $(table.node()); - - // Need to use the header and footer that are in the main table, - // regardless of if they are clones, since they hold the positions we - // want to measure from - var thead = tableNode.children('thead'); - var tfoot = tableNode.children('tfoot'); - var tbody = dom.tbody; - - position.visible = tableNode.is(':visible'); - position.width = tableNode.outerWidth(); - position.left = tableNode.offset().left; - position.theadTop = thead.offset().top; - position.tbodyTop = tbody.offset().top; - position.theadHeight = position.tbodyTop - position.theadTop; - - if ( tfoot.length ) { - position.tfootTop = tfoot.offset().top; - position.tfootBottom = position.tfootTop + tfoot.outerHeight(); - position.tfootHeight = position.tfootBottom - position.tfootTop; - } - else { - position.tfootTop = position.tbodyTop + tbody.outerHeight(); - position.tfootBottom = position.tfootTop; - position.tfootHeight = position.tfootTop; - } - }, - - - /** - * Mode calculation - determine what mode the fixed items should be placed - * into. - * - * @param {boolean} forceChange Force a redraw of the mode, even if already - * in that mode. - * @private - */ - _scroll: function ( forceChange ) - { - var windowTop = $(document).scrollTop(); - var windowLeft = $(document).scrollLeft(); - var position = this.s.position; - var headerMode, footerMode; - - if ( ! this.s.enable ) { - return; - } - - if ( this.c.header ) { - if ( ! position.visible || windowTop <= position.theadTop - this.c.headerOffset ) { - headerMode = 'in-place'; - } - else if ( windowTop <= position.tfootTop - position.theadHeight - this.c.headerOffset ) { - headerMode = 'in'; - } - else { - headerMode = 'below'; - } - - if ( forceChange || headerMode !== this.s.headerMode ) { - this._modeChange( headerMode, 'header', forceChange ); - } - - this._horizontal( 'header', windowLeft ); - } - - if ( this.c.footer && this.dom.tfoot.length ) { - if ( ! position.visible || windowTop + position.windowHeight >= position.tfootBottom + this.c.footerOffset ) { - footerMode = 'in-place'; - } - else if ( position.windowHeight + windowTop > position.tbodyTop + position.tfootHeight + this.c.footerOffset ) { - footerMode = 'in'; - } - else { - footerMode = 'above'; - } - - if ( forceChange || footerMode !== this.s.footerMode ) { - this._modeChange( footerMode, 'footer', forceChange ); - } - - this._horizontal( 'footer', windowLeft ); - } - } -} ); - - -/** - * Version - * @type {String} - * @static - */ -FixedHeader.version = "3.1.2"; - -/** - * Defaults - * @type {Object} - * @static - */ -FixedHeader.defaults = { - header: true, - footer: false, - headerOffset: 0, - footerOffset: 0 -}; - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * DataTables interfaces - */ - -// Attach for constructor access -$.fn.dataTable.FixedHeader = FixedHeader; -$.fn.DataTable.FixedHeader = FixedHeader; - - -// DataTables creation - check if the FixedHeader option has been defined on the -// table and if so, initialise -$(document).on( 'init.dt.dtfh', function (e, settings, json) { - if ( e.namespace !== 'dt' ) { - return; - } - - var init = settings.oInit.fixedHeader; - var defaults = DataTable.defaults.fixedHeader; - - if ( (init || defaults) && ! settings._fixedHeader ) { - var opts = $.extend( {}, defaults, init ); - - if ( init !== false ) { - new FixedHeader( settings, opts ); - } - } -} ); - -// DataTables API methods -DataTable.Api.register( 'fixedHeader()', function () {} ); - -DataTable.Api.register( 'fixedHeader.adjust()', function () { - return this.iterator( 'table', function ( ctx ) { - var fh = ctx._fixedHeader; - - if ( fh ) { - fh.update(); - } - } ); -} ); - -DataTable.Api.register( 'fixedHeader.enable()', function ( flag ) { - return this.iterator( 'table', function ( ctx ) { - var fh = ctx._fixedHeader; - - if ( fh ) { - fh.enable( flag !== undefined ? flag : true ); - } - } ); -} ); - -DataTable.Api.register( 'fixedHeader.disable()', function ( ) { - return this.iterator( 'table', function ( ctx ) { - var fh = ctx._fixedHeader; - - if ( fh ) { - fh.enable( false ); - } - } ); -} ); - -$.each( ['header', 'footer'], function ( i, el ) { - DataTable.Api.register( 'fixedHeader.'+el+'Offset()', function ( offset ) { - var ctx = this.context; - - if ( offset === undefined ) { - return ctx.length && ctx[0]._fixedHeader ? - ctx[0]._fixedHeader[el +'Offset']() : - undefined; - } - - return this.iterator( 'table', function ( ctx ) { - var fh = ctx._fixedHeader; - - if ( fh ) { - fh[ el +'Offset' ]( offset ); - } - } ); - } ); -} ); - - -return FixedHeader; -})); diff --git a/app/static/DataTables/FixedHeader-3.1.2/js/dataTables.fixedHeader.min.js b/app/static/DataTables/FixedHeader-3.1.2/js/dataTables.fixedHeader.min.js deleted file mode 100644 index 80a8a4cba..000000000 --- a/app/static/DataTables/FixedHeader-3.1.2/js/dataTables.fixedHeader.min.js +++ /dev/null @@ -1,17 +0,0 @@ -/*! - FixedHeader 3.1.2 - ©2009-2016 SpryMedia Ltd - datatables.net/license -*/ -(function(d){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(g){return d(g,window,document)}):"object"===typeof exports?module.exports=function(g,h){g||(g=window);if(!h||!h.fn.dataTable)h=require("datatables.net")(g,h).$;return d(h,g,g.document)}:d(jQuery,window,document)})(function(d,g,h,k){var j=d.fn.dataTable,l=0,i=function(b,a){if(!(this instanceof i))throw"FixedHeader must be initialised with the 'new' keyword.";!0===a&&(a={});b=new j.Api(b);this.c=d.extend(!0, -{},i.defaults,a);this.s={dt:b,position:{theadTop:0,tbodyTop:0,tfootTop:0,tfootBottom:0,width:0,left:0,tfootHeight:0,theadHeight:0,windowHeight:d(g).height(),visible:!0},headerMode:null,footerMode:null,autoWidth:b.settings()[0].oFeatures.bAutoWidth,namespace:".dtfc"+l++,scrollLeft:{header:-1,footer:-1},enable:!0};this.dom={floatingHeader:null,thead:d(b.table().header()),tbody:d(b.table().body()),tfoot:d(b.table().footer()),header:{host:null,floating:null,placeholder:null},footer:{host:null,floating:null, -placeholder:null}};this.dom.header.host=this.dom.thead.parent();this.dom.footer.host=this.dom.tfoot.parent();var e=b.settings()[0];if(e._fixedHeader)throw"FixedHeader already initialised on table "+e.nTable.id;e._fixedHeader=this;this._constructor()};d.extend(i.prototype,{enable:function(b){this.s.enable=b;this.c.header&&this._modeChange("in-place","header",!0);this.c.footer&&this.dom.tfoot.length&&this._modeChange("in-place","footer",!0);this.update()},headerOffset:function(b){b!==k&&(this.c.headerOffset= -b,this.update());return this.c.headerOffset},footerOffset:function(b){b!==k&&(this.c.footerOffset=b,this.update());return this.c.footerOffset},update:function(){this._positions();this._scroll(!0)},_constructor:function(){var b=this,a=this.s.dt;d(g).on("scroll"+this.s.namespace,function(){b._scroll()}).on("resize"+this.s.namespace,function(){b.s.position.windowHeight=d(g).height();b.update()});var e=d(".fh-fixedHeader");!this.c.headerOffset&&e.length&&(this.c.headerOffset=e.outerHeight());e=d(".fh-fixedFooter"); -!this.c.footerOffset&&e.length&&(this.c.footerOffset=e.outerHeight());a.on("column-reorder.dt.dtfc column-visibility.dt.dtfc draw.dt.dtfc column-sizing.dt.dtfc",function(){b.update()});a.on("destroy.dtfc",function(){a.off(".dtfc");d(g).off(b.s.namespace)});this._positions();this._scroll()},_clone:function(b,a){var e=this.s.dt,c=this.dom[b],f="header"===b?this.dom.thead:this.dom.tfoot;!a&&c.floating?c.floating.removeClass("fixedHeader-floating fixedHeader-locked"):(c.floating&&(c.placeholder.remove(), -this._unsize(b),c.floating.children().detach(),c.floating.remove()),c.floating=d(e.table().node().cloneNode(!1)).css("table-layout","fixed").removeAttr("id").append(f).appendTo("body"),c.placeholder=f.clone(!1),c.host.prepend(c.placeholder),this._matchWidths(c.placeholder,c.floating))},_matchWidths:function(b,a){var e=function(a){return d(a,b).map(function(){return d(this).width()}).toArray()},c=function(b,c){d(b,a).each(function(a){d(this).css({width:c[a],minWidth:c[a]})})},f=e("th"),e=e("td");c("th", -f);c("td",e)},_unsize:function(b){var a=this.dom[b].floating;a&&("footer"===b||"header"===b&&!this.s.autoWidth)?d("th, td",a).css({width:"",minWidth:""}):a&&"header"===b&&d("th, td",a).css("min-width","")},_horizontal:function(b,a){var e=this.dom[b],c=this.s.position,d=this.s.scrollLeft;e.floating&&d[b]!==a&&(e.floating.css("left",c.left-a),d[b]=a)},_modeChange:function(b,a,e){var c=this.dom[a],f=this.s.position,g=d.contains(this.dom["footer"===a?"tfoot":"thead"][0],h.activeElement)?h.activeElement: -null;if("in-place"===b){if(c.placeholder&&(c.placeholder.remove(),c.placeholder=null),this._unsize(a),"header"===a?c.host.prepend(this.dom.thead):c.host.append(this.dom.tfoot),c.floating)c.floating.remove(),c.floating=null}else"in"===b?(this._clone(a,e),c.floating.addClass("fixedHeader-floating").css("header"===a?"top":"bottom",this.c[a+"Offset"]).css("left",f.left+"px").css("width",f.width+"px"),"footer"===a&&c.floating.css("top","")):"below"===b?(this._clone(a,e),c.floating.addClass("fixedHeader-locked").css("top", -f.tfootTop-f.theadHeight).css("left",f.left+"px").css("width",f.width+"px")):"above"===b&&(this._clone(a,e),c.floating.addClass("fixedHeader-locked").css("top",f.tbodyTop).css("left",f.left+"px").css("width",f.width+"px"));g&&g!==h.activeElement&&g.focus();this.s.scrollLeft.header=-1;this.s.scrollLeft.footer=-1;this.s[a+"Mode"]=b},_positions:function(){var b=this.s.dt.table(),a=this.s.position,e=this.dom,b=d(b.node()),c=b.children("thead"),f=b.children("tfoot"),e=e.tbody;a.visible=b.is(":visible"); -a.width=b.outerWidth();a.left=b.offset().left;a.theadTop=c.offset().top;a.tbodyTop=e.offset().top;a.theadHeight=a.tbodyTop-a.theadTop;f.length?(a.tfootTop=f.offset().top,a.tfootBottom=a.tfootTop+f.outerHeight(),a.tfootHeight=a.tfootBottom-a.tfootTop):(a.tfootTop=a.tbodyTop+e.outerHeight(),a.tfootBottom=a.tfootTop,a.tfootHeight=a.tfootTop)},_scroll:function(b){var a=d(h).scrollTop(),e=d(h).scrollLeft(),c=this.s.position,f;if(this.s.enable&&(this.c.header&&(f=!c.visible||a<=c.theadTop-this.c.headerOffset? -"in-place":a<=c.tfootTop-c.theadHeight-this.c.headerOffset?"in":"below",(b||f!==this.s.headerMode)&&this._modeChange(f,"header",b),this._horizontal("header",e)),this.c.footer&&this.dom.tfoot.length))a=!c.visible||a+c.windowHeight>=c.tfootBottom+this.c.footerOffset?"in-place":c.windowHeight+a>c.tbodyTop+c.tfootHeight+this.c.footerOffset?"in":"above",(b||a!==this.s.footerMode)&&this._modeChange(a,"footer",b),this._horizontal("footer",e)}});i.version="3.1.2";i.defaults={header:!0,footer:!1,headerOffset:0, -footerOffset:0};d.fn.dataTable.FixedHeader=i;d.fn.DataTable.FixedHeader=i;d(h).on("init.dt.dtfh",function(b,a){if("dt"===b.namespace){var e=a.oInit.fixedHeader,c=j.defaults.fixedHeader;if((e||c)&&!a._fixedHeader)c=d.extend({},c,e),!1!==e&&new i(a,c)}});j.Api.register("fixedHeader()",function(){});j.Api.register("fixedHeader.adjust()",function(){return this.iterator("table",function(b){(b=b._fixedHeader)&&b.update()})});j.Api.register("fixedHeader.enable()",function(b){return this.iterator("table", -function(a){(a=a._fixedHeader)&&a.enable(b!==k?b:!0)})});j.Api.register("fixedHeader.disable()",function(){return this.iterator("table",function(b){(b=b._fixedHeader)&&b.enable(!1)})});d.each(["header","footer"],function(b,a){j.Api.register("fixedHeader."+a+"Offset()",function(b){var c=this.context;return b===k?c.length&&c[0]._fixedHeader?c[0]._fixedHeader[a+"Offset"]():k:this.iterator("table",function(c){if(c=c._fixedHeader)c[a+"Offset"](b)})})});return i}); diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.bootstrap.css b/app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.bootstrap.css similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.bootstrap.css rename to app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.bootstrap.css diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.bootstrap.min.css b/app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.bootstrap.min.css similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.bootstrap.min.css rename to app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.bootstrap.min.css diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.bootstrap4.css b/app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.bootstrap4.css similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.bootstrap4.css rename to app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.bootstrap4.css diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.bootstrap4.min.css b/app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.bootstrap4.min.css similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.bootstrap4.min.css rename to app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.bootstrap4.min.css diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.bootstrap5.css b/app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.bootstrap5.css similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.bootstrap5.css rename to app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.bootstrap5.css diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.bootstrap5.min.css b/app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.bootstrap5.min.css similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.bootstrap5.min.css rename to app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.bootstrap5.min.css diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.bulma.css b/app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.bulma.css similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.bulma.css rename to app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.bulma.css diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.bulma.min.css b/app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.bulma.min.css similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.bulma.min.css rename to app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.bulma.min.css diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.dataTables.css b/app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.dataTables.css similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.dataTables.css rename to app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.dataTables.css diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.dataTables.min.css b/app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.dataTables.min.css similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.dataTables.min.css rename to app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.dataTables.min.css diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.foundation.css b/app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.foundation.css similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.foundation.css rename to app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.foundation.css diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.foundation.min.css b/app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.foundation.min.css similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.foundation.min.css rename to app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.foundation.min.css diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.jqueryui.css b/app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.jqueryui.css similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.jqueryui.css rename to app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.jqueryui.css diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.jqueryui.min.css b/app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.jqueryui.min.css similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.jqueryui.min.css rename to app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.jqueryui.min.css diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.semanticui.css b/app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.semanticui.css similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.semanticui.css rename to app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.semanticui.css diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.semanticui.min.css b/app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.semanticui.min.css similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/css/fixedHeader.semanticui.min.css rename to app/static/DataTables/FixedHeader-3.2.1/css/fixedHeader.semanticui.min.css diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/js/dataTables.fixedHeader.js b/app/static/DataTables/FixedHeader-3.2.1/js/dataTables.fixedHeader.js similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/js/dataTables.fixedHeader.js rename to app/static/DataTables/FixedHeader-3.2.1/js/dataTables.fixedHeader.js diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/js/dataTables.fixedHeader.min.js b/app/static/DataTables/FixedHeader-3.2.1/js/dataTables.fixedHeader.min.js similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/js/dataTables.fixedHeader.min.js rename to app/static/DataTables/FixedHeader-3.2.1/js/dataTables.fixedHeader.min.js diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.bootstrap.js b/app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.bootstrap.js similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.bootstrap.js rename to app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.bootstrap.js diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.bootstrap.min.js b/app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.bootstrap.min.js similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.bootstrap.min.js rename to app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.bootstrap.min.js diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.bootstrap4.js b/app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.bootstrap4.js similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.bootstrap4.js rename to app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.bootstrap4.js diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.bootstrap4.min.js b/app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.bootstrap4.min.js similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.bootstrap4.min.js rename to app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.bootstrap4.min.js diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.bootstrap5.js b/app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.bootstrap5.js similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.bootstrap5.js rename to app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.bootstrap5.js diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.bootstrap5.min.js b/app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.bootstrap5.min.js similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.bootstrap5.min.js rename to app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.bootstrap5.min.js diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.bulma.js b/app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.bulma.js similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.bulma.js rename to app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.bulma.js diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.bulma.min.js b/app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.bulma.min.js similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.bulma.min.js rename to app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.bulma.min.js diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.dataTables.js b/app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.dataTables.js similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.dataTables.js rename to app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.dataTables.js diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.dataTables.min.js b/app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.dataTables.min.js similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.dataTables.min.js rename to app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.dataTables.min.js diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.foundation.js b/app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.foundation.js similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.foundation.js rename to app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.foundation.js diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.foundation.min.js b/app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.foundation.min.js similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.foundation.min.js rename to app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.foundation.min.js diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.jqueryui.js b/app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.jqueryui.js similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.jqueryui.js rename to app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.jqueryui.js diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.jqueryui.min.js b/app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.jqueryui.min.js similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.jqueryui.min.js rename to app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.jqueryui.min.js diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.semanticui.js b/app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.semanticui.js similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.semanticui.js rename to app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.semanticui.js diff --git a/app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.semanticui.min.js b/app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.semanticui.min.js similarity index 100% rename from app/static/DataTables2022/FixedHeader-3.2.1/js/fixedHeader.semanticui.min.js rename to app/static/DataTables/FixedHeader-3.2.1/js/fixedHeader.semanticui.min.js diff --git a/app/static/DataTables/Responsive-2.1.1/css/responsive.bootstrap.css b/app/static/DataTables/Responsive-2.1.1/css/responsive.bootstrap.css deleted file mode 100644 index aa2fb3e0f..000000000 --- a/app/static/DataTables/Responsive-2.1.1/css/responsive.bootstrap.css +++ /dev/null @@ -1,181 +0,0 @@ -table.dataTable.dtr-inline.collapsed > tbody > tr > td.child, -table.dataTable.dtr-inline.collapsed > tbody > tr > th.child, -table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty { - cursor: default !important; -} -table.dataTable.dtr-inline.collapsed > tbody > tr > td.child:before, -table.dataTable.dtr-inline.collapsed > tbody > tr > th.child:before, -table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty:before { - display: none !important; -} -table.dataTable.dtr-inline.collapsed > tbody > tr > td:first-child, -table.dataTable.dtr-inline.collapsed > tbody > tr > th:first-child { - position: relative; - padding-left: 30px; - cursor: pointer; -} -table.dataTable.dtr-inline.collapsed > tbody > tr > td:first-child:before, -table.dataTable.dtr-inline.collapsed > tbody > tr > th:first-child:before { - top: 9px; - left: 4px; - height: 14px; - width: 14px; - display: block; - position: absolute; - color: white; - border: 2px solid white; - border-radius: 14px; - box-shadow: 0 0 3px #444; - box-sizing: content-box; - text-align: center; - font-family: 'Courier New', Courier, monospace; - line-height: 14px; - content: '+'; - background-color: #337ab7; -} -table.dataTable.dtr-inline.collapsed > tbody > tr.parent > td:first-child:before, -table.dataTable.dtr-inline.collapsed > tbody > tr.parent > th:first-child:before { - content: '-'; - background-color: #d33333; -} -table.dataTable.dtr-inline.collapsed > tbody > tr.child td:before { - display: none; -} -table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child, -table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child { - padding-left: 27px; -} -table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child:before, -table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child:before { - top: 5px; - left: 4px; - height: 14px; - width: 14px; - border-radius: 14px; - line-height: 14px; - text-indent: 3px; -} -table.dataTable.dtr-column > tbody > tr > td.control, -table.dataTable.dtr-column > tbody > tr > th.control { - position: relative; - cursor: pointer; -} -table.dataTable.dtr-column > tbody > tr > td.control:before, -table.dataTable.dtr-column > tbody > tr > th.control:before { - top: 50%; - left: 50%; - height: 16px; - width: 16px; - margin-top: -10px; - margin-left: -10px; - display: block; - position: absolute; - color: white; - border: 2px solid white; - border-radius: 14px; - box-shadow: 0 0 3px #444; - box-sizing: content-box; - text-align: center; - font-family: 'Courier New', Courier, monospace; - line-height: 14px; - content: '+'; - background-color: #337ab7; -} -table.dataTable.dtr-column > tbody > tr.parent td.control:before, -table.dataTable.dtr-column > tbody > tr.parent th.control:before { - content: '-'; - background-color: #d33333; -} -table.dataTable > tbody > tr.child { - padding: 0.5em 1em; -} -table.dataTable > tbody > tr.child:hover { - background: transparent !important; -} -table.dataTable > tbody > tr.child ul.dtr-details { - display: inline-block; - list-style-type: none; - margin: 0; - padding: 0; -} -table.dataTable > tbody > tr.child ul.dtr-details li { - border-bottom: 1px solid #efefef; - padding: 0.5em 0; -} -table.dataTable > tbody > tr.child ul.dtr-details li:first-child { - padding-top: 0; -} -table.dataTable > tbody > tr.child ul.dtr-details li:last-child { - border-bottom: none; -} -table.dataTable > tbody > tr.child span.dtr-title { - display: inline-block; - min-width: 75px; - font-weight: bold; -} - -div.dtr-modal { - position: fixed; - box-sizing: border-box; - top: 0; - left: 0; - height: 100%; - width: 100%; - z-index: 100; - padding: 10em 1em; -} -div.dtr-modal div.dtr-modal-display { - position: absolute; - top: 0; - left: 0; - bottom: 0; - right: 0; - width: 50%; - height: 50%; - overflow: auto; - margin: auto; - z-index: 102; - overflow: auto; - background-color: #f5f5f7; - border: 1px solid black; - border-radius: 0.5em; - box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6); -} -div.dtr-modal div.dtr-modal-content { - position: relative; - padding: 1em; -} -div.dtr-modal div.dtr-modal-close { - position: absolute; - top: 6px; - right: 6px; - width: 22px; - height: 22px; - border: 1px solid #eaeaea; - background-color: #f9f9f9; - text-align: center; - border-radius: 3px; - cursor: pointer; - z-index: 12; -} -div.dtr-modal div.dtr-modal-close:hover { - background-color: #eaeaea; -} -div.dtr-modal div.dtr-modal-background { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - z-index: 101; - background: rgba(0, 0, 0, 0.6); -} - -@media screen and (max-width: 767px) { - div.dtr-modal div.dtr-modal-display { - width: 95%; - } -} -div.dtr-bs-modal table.table tr:first-child td { - border-top: none; -} diff --git a/app/static/DataTables/Responsive-2.1.1/css/responsive.bootstrap.min.css b/app/static/DataTables/Responsive-2.1.1/css/responsive.bootstrap.min.css deleted file mode 100644 index b53db0e0f..000000000 --- a/app/static/DataTables/Responsive-2.1.1/css/responsive.bootstrap.min.css +++ /dev/null @@ -1 +0,0 @@ -table.dataTable.dtr-inline.collapsed>tbody>tr>td.child,table.dataTable.dtr-inline.collapsed>tbody>tr>th.child,table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty{cursor:default !important}table.dataTable.dtr-inline.collapsed>tbody>tr>td.child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>th.child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty:before{display:none !important}table.dataTable.dtr-inline.collapsed>tbody>tr>td:first-child,table.dataTable.dtr-inline.collapsed>tbody>tr>th:first-child{position:relative;padding-left:30px;cursor:pointer}table.dataTable.dtr-inline.collapsed>tbody>tr>td:first-child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>th:first-child:before{top:9px;left:4px;height:14px;width:14px;display:block;position:absolute;color:white;border:2px solid white;border-radius:14px;box-shadow:0 0 3px #444;box-sizing:content-box;text-align:center;font-family:'Courier New', Courier, monospace;line-height:14px;content:'+';background-color:#337ab7}table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td:first-child:before,table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th:first-child:before{content:'-';background-color:#d33333}table.dataTable.dtr-inline.collapsed>tbody>tr.child td:before{display:none}table.dataTable.dtr-inline.collapsed.compact>tbody>tr>td:first-child,table.dataTable.dtr-inline.collapsed.compact>tbody>tr>th:first-child{padding-left:27px}table.dataTable.dtr-inline.collapsed.compact>tbody>tr>td:first-child:before,table.dataTable.dtr-inline.collapsed.compact>tbody>tr>th:first-child:before{top:5px;left:4px;height:14px;width:14px;border-radius:14px;line-height:14px;text-indent:3px}table.dataTable.dtr-column>tbody>tr>td.control,table.dataTable.dtr-column>tbody>tr>th.control{position:relative;cursor:pointer}table.dataTable.dtr-column>tbody>tr>td.control:before,table.dataTable.dtr-column>tbody>tr>th.control:before{top:50%;left:50%;height:16px;width:16px;margin-top:-10px;margin-left:-10px;display:block;position:absolute;color:white;border:2px solid white;border-radius:14px;box-shadow:0 0 3px #444;box-sizing:content-box;text-align:center;font-family:'Courier New', Courier, monospace;line-height:14px;content:'+';background-color:#337ab7}table.dataTable.dtr-column>tbody>tr.parent td.control:before,table.dataTable.dtr-column>tbody>tr.parent th.control:before{content:'-';background-color:#d33333}table.dataTable>tbody>tr.child{padding:0.5em 1em}table.dataTable>tbody>tr.child:hover{background:transparent !important}table.dataTable>tbody>tr.child ul.dtr-details{display:inline-block;list-style-type:none;margin:0;padding:0}table.dataTable>tbody>tr.child ul.dtr-details li{border-bottom:1px solid #efefef;padding:0.5em 0}table.dataTable>tbody>tr.child ul.dtr-details li:first-child{padding-top:0}table.dataTable>tbody>tr.child ul.dtr-details li:last-child{border-bottom:none}table.dataTable>tbody>tr.child span.dtr-title{display:inline-block;min-width:75px;font-weight:bold}div.dtr-modal{position:fixed;box-sizing:border-box;top:0;left:0;height:100%;width:100%;z-index:100;padding:10em 1em}div.dtr-modal div.dtr-modal-display{position:absolute;top:0;left:0;bottom:0;right:0;width:50%;height:50%;overflow:auto;margin:auto;z-index:102;overflow:auto;background-color:#f5f5f7;border:1px solid black;border-radius:0.5em;box-shadow:0 12px 30px rgba(0,0,0,0.6)}div.dtr-modal div.dtr-modal-content{position:relative;padding:1em}div.dtr-modal div.dtr-modal-close{position:absolute;top:6px;right:6px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:12}div.dtr-modal div.dtr-modal-close:hover{background-color:#eaeaea}div.dtr-modal div.dtr-modal-background{position:fixed;top:0;left:0;right:0;bottom:0;z-index:101;background:rgba(0,0,0,0.6)}@media screen and (max-width: 767px){div.dtr-modal div.dtr-modal-display{width:95%}}div.dtr-bs-modal table.table tr:first-child td{border-top:none} diff --git a/app/static/DataTables/Responsive-2.1.1/css/responsive.dataTables.css b/app/static/DataTables/Responsive-2.1.1/css/responsive.dataTables.css deleted file mode 100644 index 72353d2af..000000000 --- a/app/static/DataTables/Responsive-2.1.1/css/responsive.dataTables.css +++ /dev/null @@ -1,178 +0,0 @@ -table.dataTable.dtr-inline.collapsed > tbody > tr > td.child, -table.dataTable.dtr-inline.collapsed > tbody > tr > th.child, -table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty { - cursor: default !important; -} -table.dataTable.dtr-inline.collapsed > tbody > tr > td.child:before, -table.dataTable.dtr-inline.collapsed > tbody > tr > th.child:before, -table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty:before { - display: none !important; -} -table.dataTable.dtr-inline.collapsed > tbody > tr > td:first-child, -table.dataTable.dtr-inline.collapsed > tbody > tr > th:first-child { - position: relative; - padding-left: 30px; - cursor: pointer; -} -table.dataTable.dtr-inline.collapsed > tbody > tr > td:first-child:before, -table.dataTable.dtr-inline.collapsed > tbody > tr > th:first-child:before { - top: 9px; - left: 4px; - height: 14px; - width: 14px; - display: block; - position: absolute; - color: white; - border: 2px solid white; - border-radius: 14px; - box-shadow: 0 0 3px #444; - box-sizing: content-box; - text-align: center; - font-family: 'Courier New', Courier, monospace; - line-height: 14px; - content: '+'; - background-color: #31b131; -} -table.dataTable.dtr-inline.collapsed > tbody > tr.parent > td:first-child:before, -table.dataTable.dtr-inline.collapsed > tbody > tr.parent > th:first-child:before { - content: '-'; - background-color: #d33333; -} -table.dataTable.dtr-inline.collapsed > tbody > tr.child td:before { - display: none; -} -table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child, -table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child { - padding-left: 27px; -} -table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child:before, -table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child:before { - top: 5px; - left: 4px; - height: 14px; - width: 14px; - border-radius: 14px; - line-height: 14px; - text-indent: 3px; -} -table.dataTable.dtr-column > tbody > tr > td.control, -table.dataTable.dtr-column > tbody > tr > th.control { - position: relative; - cursor: pointer; -} -table.dataTable.dtr-column > tbody > tr > td.control:before, -table.dataTable.dtr-column > tbody > tr > th.control:before { - top: 50%; - left: 50%; - height: 16px; - width: 16px; - margin-top: -10px; - margin-left: -10px; - display: block; - position: absolute; - color: white; - border: 2px solid white; - border-radius: 14px; - box-shadow: 0 0 3px #444; - box-sizing: content-box; - text-align: center; - font-family: 'Courier New', Courier, monospace; - line-height: 14px; - content: '+'; - background-color: #31b131; -} -table.dataTable.dtr-column > tbody > tr.parent td.control:before, -table.dataTable.dtr-column > tbody > tr.parent th.control:before { - content: '-'; - background-color: #d33333; -} -table.dataTable > tbody > tr.child { - padding: 0.5em 1em; -} -table.dataTable > tbody > tr.child:hover { - background: transparent !important; -} -table.dataTable > tbody > tr.child ul.dtr-details { - display: inline-block; - list-style-type: none; - margin: 0; - padding: 0; -} -table.dataTable > tbody > tr.child ul.dtr-details li { - border-bottom: 1px solid #efefef; - padding: 0.5em 0; -} -table.dataTable > tbody > tr.child ul.dtr-details li:first-child { - padding-top: 0; -} -table.dataTable > tbody > tr.child ul.dtr-details li:last-child { - border-bottom: none; -} -table.dataTable > tbody > tr.child span.dtr-title { - display: inline-block; - min-width: 75px; - font-weight: bold; -} - -div.dtr-modal { - position: fixed; - box-sizing: border-box; - top: 0; - left: 0; - height: 100%; - width: 100%; - z-index: 100; - padding: 10em 1em; -} -div.dtr-modal div.dtr-modal-display { - position: absolute; - top: 0; - left: 0; - bottom: 0; - right: 0; - width: 50%; - height: 50%; - overflow: auto; - margin: auto; - z-index: 102; - overflow: auto; - background-color: #f5f5f7; - border: 1px solid black; - border-radius: 0.5em; - box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6); -} -div.dtr-modal div.dtr-modal-content { - position: relative; - padding: 1em; -} -div.dtr-modal div.dtr-modal-close { - position: absolute; - top: 6px; - right: 6px; - width: 22px; - height: 22px; - border: 1px solid #eaeaea; - background-color: #f9f9f9; - text-align: center; - border-radius: 3px; - cursor: pointer; - z-index: 12; -} -div.dtr-modal div.dtr-modal-close:hover { - background-color: #eaeaea; -} -div.dtr-modal div.dtr-modal-background { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - z-index: 101; - background: rgba(0, 0, 0, 0.6); -} - -@media screen and (max-width: 767px) { - div.dtr-modal div.dtr-modal-display { - width: 95%; - } -} diff --git a/app/static/DataTables/Responsive-2.1.1/css/responsive.dataTables.min.css b/app/static/DataTables/Responsive-2.1.1/css/responsive.dataTables.min.css deleted file mode 100644 index db2f7d9c4..000000000 --- a/app/static/DataTables/Responsive-2.1.1/css/responsive.dataTables.min.css +++ /dev/null @@ -1 +0,0 @@ -table.dataTable.dtr-inline.collapsed>tbody>tr>td.child,table.dataTable.dtr-inline.collapsed>tbody>tr>th.child,table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty{cursor:default !important}table.dataTable.dtr-inline.collapsed>tbody>tr>td.child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>th.child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty:before{display:none !important}table.dataTable.dtr-inline.collapsed>tbody>tr>td:first-child,table.dataTable.dtr-inline.collapsed>tbody>tr>th:first-child{position:relative;padding-left:30px;cursor:pointer}table.dataTable.dtr-inline.collapsed>tbody>tr>td:first-child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>th:first-child:before{top:9px;left:4px;height:14px;width:14px;display:block;position:absolute;color:white;border:2px solid white;border-radius:14px;box-shadow:0 0 3px #444;box-sizing:content-box;text-align:center;font-family:'Courier New', Courier, monospace;line-height:14px;content:'+';background-color:#31b131}table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td:first-child:before,table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th:first-child:before{content:'-';background-color:#d33333}table.dataTable.dtr-inline.collapsed>tbody>tr.child td:before{display:none}table.dataTable.dtr-inline.collapsed.compact>tbody>tr>td:first-child,table.dataTable.dtr-inline.collapsed.compact>tbody>tr>th:first-child{padding-left:27px}table.dataTable.dtr-inline.collapsed.compact>tbody>tr>td:first-child:before,table.dataTable.dtr-inline.collapsed.compact>tbody>tr>th:first-child:before{top:5px;left:4px;height:14px;width:14px;border-radius:14px;line-height:14px;text-indent:3px}table.dataTable.dtr-column>tbody>tr>td.control,table.dataTable.dtr-column>tbody>tr>th.control{position:relative;cursor:pointer}table.dataTable.dtr-column>tbody>tr>td.control:before,table.dataTable.dtr-column>tbody>tr>th.control:before{top:50%;left:50%;height:16px;width:16px;margin-top:-10px;margin-left:-10px;display:block;position:absolute;color:white;border:2px solid white;border-radius:14px;box-shadow:0 0 3px #444;box-sizing:content-box;text-align:center;font-family:'Courier New', Courier, monospace;line-height:14px;content:'+';background-color:#31b131}table.dataTable.dtr-column>tbody>tr.parent td.control:before,table.dataTable.dtr-column>tbody>tr.parent th.control:before{content:'-';background-color:#d33333}table.dataTable>tbody>tr.child{padding:0.5em 1em}table.dataTable>tbody>tr.child:hover{background:transparent !important}table.dataTable>tbody>tr.child ul.dtr-details{display:inline-block;list-style-type:none;margin:0;padding:0}table.dataTable>tbody>tr.child ul.dtr-details li{border-bottom:1px solid #efefef;padding:0.5em 0}table.dataTable>tbody>tr.child ul.dtr-details li:first-child{padding-top:0}table.dataTable>tbody>tr.child ul.dtr-details li:last-child{border-bottom:none}table.dataTable>tbody>tr.child span.dtr-title{display:inline-block;min-width:75px;font-weight:bold}div.dtr-modal{position:fixed;box-sizing:border-box;top:0;left:0;height:100%;width:100%;z-index:100;padding:10em 1em}div.dtr-modal div.dtr-modal-display{position:absolute;top:0;left:0;bottom:0;right:0;width:50%;height:50%;overflow:auto;margin:auto;z-index:102;overflow:auto;background-color:#f5f5f7;border:1px solid black;border-radius:0.5em;box-shadow:0 12px 30px rgba(0,0,0,0.6)}div.dtr-modal div.dtr-modal-content{position:relative;padding:1em}div.dtr-modal div.dtr-modal-close{position:absolute;top:6px;right:6px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:12}div.dtr-modal div.dtr-modal-close:hover{background-color:#eaeaea}div.dtr-modal div.dtr-modal-background{position:fixed;top:0;left:0;right:0;bottom:0;z-index:101;background:rgba(0,0,0,0.6)}@media screen and (max-width: 767px){div.dtr-modal div.dtr-modal-display{width:95%}} diff --git a/app/static/DataTables/Responsive-2.1.1/css/responsive.foundation.css b/app/static/DataTables/Responsive-2.1.1/css/responsive.foundation.css deleted file mode 100644 index 9d7032803..000000000 --- a/app/static/DataTables/Responsive-2.1.1/css/responsive.foundation.css +++ /dev/null @@ -1,181 +0,0 @@ -table.dataTable.dtr-inline.collapsed > tbody > tr > td.child, -table.dataTable.dtr-inline.collapsed > tbody > tr > th.child, -table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty { - cursor: default !important; -} -table.dataTable.dtr-inline.collapsed > tbody > tr > td.child:before, -table.dataTable.dtr-inline.collapsed > tbody > tr > th.child:before, -table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty:before { - display: none !important; -} -table.dataTable.dtr-inline.collapsed > tbody > tr > td:first-child, -table.dataTable.dtr-inline.collapsed > tbody > tr > th:first-child { - position: relative; - padding-left: 30px; - cursor: pointer; -} -table.dataTable.dtr-inline.collapsed > tbody > tr > td:first-child:before, -table.dataTable.dtr-inline.collapsed > tbody > tr > th:first-child:before { - top: 9px; - left: 4px; - height: 14px; - width: 14px; - display: block; - position: absolute; - color: white; - border: 2px solid white; - border-radius: 14px; - box-shadow: 0 0 3px #444; - box-sizing: content-box; - text-align: center; - font-family: 'Courier New', Courier, monospace; - line-height: 14px; - content: '+'; - background-color: #008CBA; -} -table.dataTable.dtr-inline.collapsed > tbody > tr.parent > td:first-child:before, -table.dataTable.dtr-inline.collapsed > tbody > tr.parent > th:first-child:before { - content: '-'; - background-color: #d33333; -} -table.dataTable.dtr-inline.collapsed > tbody > tr.child td:before { - display: none; -} -table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child, -table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child { - padding-left: 27px; -} -table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child:before, -table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child:before { - top: 5px; - left: 4px; - height: 14px; - width: 14px; - border-radius: 14px; - line-height: 14px; - text-indent: 3px; -} -table.dataTable.dtr-column > tbody > tr > td.control, -table.dataTable.dtr-column > tbody > tr > th.control { - position: relative; - cursor: pointer; -} -table.dataTable.dtr-column > tbody > tr > td.control:before, -table.dataTable.dtr-column > tbody > tr > th.control:before { - top: 50%; - left: 50%; - height: 16px; - width: 16px; - margin-top: -10px; - margin-left: -10px; - display: block; - position: absolute; - color: white; - border: 2px solid white; - border-radius: 14px; - box-shadow: 0 0 3px #444; - box-sizing: content-box; - text-align: center; - font-family: 'Courier New', Courier, monospace; - line-height: 14px; - content: '+'; - background-color: #008CBA; -} -table.dataTable.dtr-column > tbody > tr.parent td.control:before, -table.dataTable.dtr-column > tbody > tr.parent th.control:before { - content: '-'; - background-color: #d33333; -} -table.dataTable > tbody > tr.child { - padding: 0.5em 1em; -} -table.dataTable > tbody > tr.child:hover { - background: transparent !important; -} -table.dataTable > tbody > tr.child ul.dtr-details { - display: inline-block; - list-style-type: none; - margin: 0; - padding: 0; -} -table.dataTable > tbody > tr.child ul.dtr-details li { - border-bottom: 1px solid #efefef; - padding: 0.5em 0; -} -table.dataTable > tbody > tr.child ul.dtr-details li:first-child { - padding-top: 0; -} -table.dataTable > tbody > tr.child ul.dtr-details li:last-child { - border-bottom: none; -} -table.dataTable > tbody > tr.child span.dtr-title { - display: inline-block; - min-width: 75px; - font-weight: bold; -} - -div.dtr-modal { - position: fixed; - box-sizing: border-box; - top: 0; - left: 0; - height: 100%; - width: 100%; - z-index: 100; - padding: 10em 1em; -} -div.dtr-modal div.dtr-modal-display { - position: absolute; - top: 0; - left: 0; - bottom: 0; - right: 0; - width: 50%; - height: 50%; - overflow: auto; - margin: auto; - z-index: 102; - overflow: auto; - background-color: #f5f5f7; - border: 1px solid black; - border-radius: 0.5em; - box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6); -} -div.dtr-modal div.dtr-modal-content { - position: relative; - padding: 1em; -} -div.dtr-modal div.dtr-modal-close { - position: absolute; - top: 6px; - right: 6px; - width: 22px; - height: 22px; - border: 1px solid #eaeaea; - background-color: #f9f9f9; - text-align: center; - border-radius: 3px; - cursor: pointer; - z-index: 12; -} -div.dtr-modal div.dtr-modal-close:hover { - background-color: #eaeaea; -} -div.dtr-modal div.dtr-modal-background { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - z-index: 101; - background: rgba(0, 0, 0, 0.6); -} - -@media screen and (max-width: 767px) { - div.dtr-modal div.dtr-modal-display { - width: 95%; - } -} -table.dataTable > tbody > tr.child ul { - font-size: 1em; -} diff --git a/app/static/DataTables/Responsive-2.1.1/css/responsive.foundation.min.css b/app/static/DataTables/Responsive-2.1.1/css/responsive.foundation.min.css deleted file mode 100644 index e8842be3c..000000000 --- a/app/static/DataTables/Responsive-2.1.1/css/responsive.foundation.min.css +++ /dev/null @@ -1 +0,0 @@ -table.dataTable.dtr-inline.collapsed>tbody>tr>td.child,table.dataTable.dtr-inline.collapsed>tbody>tr>th.child,table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty{cursor:default !important}table.dataTable.dtr-inline.collapsed>tbody>tr>td.child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>th.child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty:before{display:none !important}table.dataTable.dtr-inline.collapsed>tbody>tr>td:first-child,table.dataTable.dtr-inline.collapsed>tbody>tr>th:first-child{position:relative;padding-left:30px;cursor:pointer}table.dataTable.dtr-inline.collapsed>tbody>tr>td:first-child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>th:first-child:before{top:9px;left:4px;height:14px;width:14px;display:block;position:absolute;color:white;border:2px solid white;border-radius:14px;box-shadow:0 0 3px #444;box-sizing:content-box;text-align:center;font-family:'Courier New', Courier, monospace;line-height:14px;content:'+';background-color:#008CBA}table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td:first-child:before,table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th:first-child:before{content:'-';background-color:#d33333}table.dataTable.dtr-inline.collapsed>tbody>tr.child td:before{display:none}table.dataTable.dtr-inline.collapsed.compact>tbody>tr>td:first-child,table.dataTable.dtr-inline.collapsed.compact>tbody>tr>th:first-child{padding-left:27px}table.dataTable.dtr-inline.collapsed.compact>tbody>tr>td:first-child:before,table.dataTable.dtr-inline.collapsed.compact>tbody>tr>th:first-child:before{top:5px;left:4px;height:14px;width:14px;border-radius:14px;line-height:14px;text-indent:3px}table.dataTable.dtr-column>tbody>tr>td.control,table.dataTable.dtr-column>tbody>tr>th.control{position:relative;cursor:pointer}table.dataTable.dtr-column>tbody>tr>td.control:before,table.dataTable.dtr-column>tbody>tr>th.control:before{top:50%;left:50%;height:16px;width:16px;margin-top:-10px;margin-left:-10px;display:block;position:absolute;color:white;border:2px solid white;border-radius:14px;box-shadow:0 0 3px #444;box-sizing:content-box;text-align:center;font-family:'Courier New', Courier, monospace;line-height:14px;content:'+';background-color:#008CBA}table.dataTable.dtr-column>tbody>tr.parent td.control:before,table.dataTable.dtr-column>tbody>tr.parent th.control:before{content:'-';background-color:#d33333}table.dataTable>tbody>tr.child{padding:0.5em 1em}table.dataTable>tbody>tr.child:hover{background:transparent !important}table.dataTable>tbody>tr.child ul.dtr-details{display:inline-block;list-style-type:none;margin:0;padding:0}table.dataTable>tbody>tr.child ul.dtr-details li{border-bottom:1px solid #efefef;padding:0.5em 0}table.dataTable>tbody>tr.child ul.dtr-details li:first-child{padding-top:0}table.dataTable>tbody>tr.child ul.dtr-details li:last-child{border-bottom:none}table.dataTable>tbody>tr.child span.dtr-title{display:inline-block;min-width:75px;font-weight:bold}div.dtr-modal{position:fixed;box-sizing:border-box;top:0;left:0;height:100%;width:100%;z-index:100;padding:10em 1em}div.dtr-modal div.dtr-modal-display{position:absolute;top:0;left:0;bottom:0;right:0;width:50%;height:50%;overflow:auto;margin:auto;z-index:102;overflow:auto;background-color:#f5f5f7;border:1px solid black;border-radius:0.5em;box-shadow:0 12px 30px rgba(0,0,0,0.6)}div.dtr-modal div.dtr-modal-content{position:relative;padding:1em}div.dtr-modal div.dtr-modal-close{position:absolute;top:6px;right:6px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:12}div.dtr-modal div.dtr-modal-close:hover{background-color:#eaeaea}div.dtr-modal div.dtr-modal-background{position:fixed;top:0;left:0;right:0;bottom:0;z-index:101;background:rgba(0,0,0,0.6)}@media screen and (max-width: 767px){div.dtr-modal div.dtr-modal-display{width:95%}}table.dataTable>tbody>tr.child ul{font-size:1em} diff --git a/app/static/DataTables/Responsive-2.1.1/css/responsive.jqueryui.css b/app/static/DataTables/Responsive-2.1.1/css/responsive.jqueryui.css deleted file mode 100644 index 72353d2af..000000000 --- a/app/static/DataTables/Responsive-2.1.1/css/responsive.jqueryui.css +++ /dev/null @@ -1,178 +0,0 @@ -table.dataTable.dtr-inline.collapsed > tbody > tr > td.child, -table.dataTable.dtr-inline.collapsed > tbody > tr > th.child, -table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty { - cursor: default !important; -} -table.dataTable.dtr-inline.collapsed > tbody > tr > td.child:before, -table.dataTable.dtr-inline.collapsed > tbody > tr > th.child:before, -table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty:before { - display: none !important; -} -table.dataTable.dtr-inline.collapsed > tbody > tr > td:first-child, -table.dataTable.dtr-inline.collapsed > tbody > tr > th:first-child { - position: relative; - padding-left: 30px; - cursor: pointer; -} -table.dataTable.dtr-inline.collapsed > tbody > tr > td:first-child:before, -table.dataTable.dtr-inline.collapsed > tbody > tr > th:first-child:before { - top: 9px; - left: 4px; - height: 14px; - width: 14px; - display: block; - position: absolute; - color: white; - border: 2px solid white; - border-radius: 14px; - box-shadow: 0 0 3px #444; - box-sizing: content-box; - text-align: center; - font-family: 'Courier New', Courier, monospace; - line-height: 14px; - content: '+'; - background-color: #31b131; -} -table.dataTable.dtr-inline.collapsed > tbody > tr.parent > td:first-child:before, -table.dataTable.dtr-inline.collapsed > tbody > tr.parent > th:first-child:before { - content: '-'; - background-color: #d33333; -} -table.dataTable.dtr-inline.collapsed > tbody > tr.child td:before { - display: none; -} -table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child, -table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child { - padding-left: 27px; -} -table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child:before, -table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child:before { - top: 5px; - left: 4px; - height: 14px; - width: 14px; - border-radius: 14px; - line-height: 14px; - text-indent: 3px; -} -table.dataTable.dtr-column > tbody > tr > td.control, -table.dataTable.dtr-column > tbody > tr > th.control { - position: relative; - cursor: pointer; -} -table.dataTable.dtr-column > tbody > tr > td.control:before, -table.dataTable.dtr-column > tbody > tr > th.control:before { - top: 50%; - left: 50%; - height: 16px; - width: 16px; - margin-top: -10px; - margin-left: -10px; - display: block; - position: absolute; - color: white; - border: 2px solid white; - border-radius: 14px; - box-shadow: 0 0 3px #444; - box-sizing: content-box; - text-align: center; - font-family: 'Courier New', Courier, monospace; - line-height: 14px; - content: '+'; - background-color: #31b131; -} -table.dataTable.dtr-column > tbody > tr.parent td.control:before, -table.dataTable.dtr-column > tbody > tr.parent th.control:before { - content: '-'; - background-color: #d33333; -} -table.dataTable > tbody > tr.child { - padding: 0.5em 1em; -} -table.dataTable > tbody > tr.child:hover { - background: transparent !important; -} -table.dataTable > tbody > tr.child ul.dtr-details { - display: inline-block; - list-style-type: none; - margin: 0; - padding: 0; -} -table.dataTable > tbody > tr.child ul.dtr-details li { - border-bottom: 1px solid #efefef; - padding: 0.5em 0; -} -table.dataTable > tbody > tr.child ul.dtr-details li:first-child { - padding-top: 0; -} -table.dataTable > tbody > tr.child ul.dtr-details li:last-child { - border-bottom: none; -} -table.dataTable > tbody > tr.child span.dtr-title { - display: inline-block; - min-width: 75px; - font-weight: bold; -} - -div.dtr-modal { - position: fixed; - box-sizing: border-box; - top: 0; - left: 0; - height: 100%; - width: 100%; - z-index: 100; - padding: 10em 1em; -} -div.dtr-modal div.dtr-modal-display { - position: absolute; - top: 0; - left: 0; - bottom: 0; - right: 0; - width: 50%; - height: 50%; - overflow: auto; - margin: auto; - z-index: 102; - overflow: auto; - background-color: #f5f5f7; - border: 1px solid black; - border-radius: 0.5em; - box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6); -} -div.dtr-modal div.dtr-modal-content { - position: relative; - padding: 1em; -} -div.dtr-modal div.dtr-modal-close { - position: absolute; - top: 6px; - right: 6px; - width: 22px; - height: 22px; - border: 1px solid #eaeaea; - background-color: #f9f9f9; - text-align: center; - border-radius: 3px; - cursor: pointer; - z-index: 12; -} -div.dtr-modal div.dtr-modal-close:hover { - background-color: #eaeaea; -} -div.dtr-modal div.dtr-modal-background { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - z-index: 101; - background: rgba(0, 0, 0, 0.6); -} - -@media screen and (max-width: 767px) { - div.dtr-modal div.dtr-modal-display { - width: 95%; - } -} diff --git a/app/static/DataTables/Responsive-2.1.1/css/responsive.jqueryui.min.css b/app/static/DataTables/Responsive-2.1.1/css/responsive.jqueryui.min.css deleted file mode 100644 index db2f7d9c4..000000000 --- a/app/static/DataTables/Responsive-2.1.1/css/responsive.jqueryui.min.css +++ /dev/null @@ -1 +0,0 @@ -table.dataTable.dtr-inline.collapsed>tbody>tr>td.child,table.dataTable.dtr-inline.collapsed>tbody>tr>th.child,table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty{cursor:default !important}table.dataTable.dtr-inline.collapsed>tbody>tr>td.child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>th.child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty:before{display:none !important}table.dataTable.dtr-inline.collapsed>tbody>tr>td:first-child,table.dataTable.dtr-inline.collapsed>tbody>tr>th:first-child{position:relative;padding-left:30px;cursor:pointer}table.dataTable.dtr-inline.collapsed>tbody>tr>td:first-child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>th:first-child:before{top:9px;left:4px;height:14px;width:14px;display:block;position:absolute;color:white;border:2px solid white;border-radius:14px;box-shadow:0 0 3px #444;box-sizing:content-box;text-align:center;font-family:'Courier New', Courier, monospace;line-height:14px;content:'+';background-color:#31b131}table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td:first-child:before,table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th:first-child:before{content:'-';background-color:#d33333}table.dataTable.dtr-inline.collapsed>tbody>tr.child td:before{display:none}table.dataTable.dtr-inline.collapsed.compact>tbody>tr>td:first-child,table.dataTable.dtr-inline.collapsed.compact>tbody>tr>th:first-child{padding-left:27px}table.dataTable.dtr-inline.collapsed.compact>tbody>tr>td:first-child:before,table.dataTable.dtr-inline.collapsed.compact>tbody>tr>th:first-child:before{top:5px;left:4px;height:14px;width:14px;border-radius:14px;line-height:14px;text-indent:3px}table.dataTable.dtr-column>tbody>tr>td.control,table.dataTable.dtr-column>tbody>tr>th.control{position:relative;cursor:pointer}table.dataTable.dtr-column>tbody>tr>td.control:before,table.dataTable.dtr-column>tbody>tr>th.control:before{top:50%;left:50%;height:16px;width:16px;margin-top:-10px;margin-left:-10px;display:block;position:absolute;color:white;border:2px solid white;border-radius:14px;box-shadow:0 0 3px #444;box-sizing:content-box;text-align:center;font-family:'Courier New', Courier, monospace;line-height:14px;content:'+';background-color:#31b131}table.dataTable.dtr-column>tbody>tr.parent td.control:before,table.dataTable.dtr-column>tbody>tr.parent th.control:before{content:'-';background-color:#d33333}table.dataTable>tbody>tr.child{padding:0.5em 1em}table.dataTable>tbody>tr.child:hover{background:transparent !important}table.dataTable>tbody>tr.child ul.dtr-details{display:inline-block;list-style-type:none;margin:0;padding:0}table.dataTable>tbody>tr.child ul.dtr-details li{border-bottom:1px solid #efefef;padding:0.5em 0}table.dataTable>tbody>tr.child ul.dtr-details li:first-child{padding-top:0}table.dataTable>tbody>tr.child ul.dtr-details li:last-child{border-bottom:none}table.dataTable>tbody>tr.child span.dtr-title{display:inline-block;min-width:75px;font-weight:bold}div.dtr-modal{position:fixed;box-sizing:border-box;top:0;left:0;height:100%;width:100%;z-index:100;padding:10em 1em}div.dtr-modal div.dtr-modal-display{position:absolute;top:0;left:0;bottom:0;right:0;width:50%;height:50%;overflow:auto;margin:auto;z-index:102;overflow:auto;background-color:#f5f5f7;border:1px solid black;border-radius:0.5em;box-shadow:0 12px 30px rgba(0,0,0,0.6)}div.dtr-modal div.dtr-modal-content{position:relative;padding:1em}div.dtr-modal div.dtr-modal-close{position:absolute;top:6px;right:6px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:12}div.dtr-modal div.dtr-modal-close:hover{background-color:#eaeaea}div.dtr-modal div.dtr-modal-background{position:fixed;top:0;left:0;right:0;bottom:0;z-index:101;background:rgba(0,0,0,0.6)}@media screen and (max-width: 767px){div.dtr-modal div.dtr-modal-display{width:95%}} diff --git a/app/static/DataTables/Responsive-2.1.1/js/dataTables.responsive.js b/app/static/DataTables/Responsive-2.1.1/js/dataTables.responsive.js deleted file mode 100644 index a1bd5b668..000000000 --- a/app/static/DataTables/Responsive-2.1.1/js/dataTables.responsive.js +++ /dev/null @@ -1,1255 +0,0 @@ -/*! Responsive 2.1.1 - * 2014-2016 SpryMedia Ltd - datatables.net/license - */ - -/** - * @summary Responsive - * @description Responsive tables plug-in for DataTables - * @version 2.1.1 - * @file dataTables.responsive.js - * @author SpryMedia Ltd (www.sprymedia.co.uk) - * @contact www.sprymedia.co.uk/contact - * @copyright Copyright 2014-2016 SpryMedia Ltd. - * - * This source file is free software, available under the following license: - * MIT license - http://datatables.net/license/mit - * - * This source file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. - * - * For details please refer to: http://www.datatables.net - */ -(function( factory ){ - if ( typeof define === 'function' && define.amd ) { - // AMD - define( ['jquery', 'datatables.net'], function ( $ ) { - return factory( $, window, document ); - } ); - } - else if ( typeof exports === 'object' ) { - // CommonJS - module.exports = function (root, $) { - if ( ! root ) { - root = window; - } - - if ( ! $ || ! $.fn.dataTable ) { - $ = require('datatables.net')(root, $).$; - } - - return factory( $, root, root.document ); - }; - } - else { - // Browser - factory( jQuery, window, document ); - } -}(function( $, window, document, undefined ) { -'use strict'; -var DataTable = $.fn.dataTable; - - -/** - * Responsive is a plug-in for the DataTables library that makes use of - * DataTables' ability to change the visibility of columns, changing the - * visibility of columns so the displayed columns fit into the table container. - * The end result is that complex tables will be dynamically adjusted to fit - * into the viewport, be it on a desktop, tablet or mobile browser. - * - * Responsive for DataTables has two modes of operation, which can used - * individually or combined: - * - * * Class name based control - columns assigned class names that match the - * breakpoint logic can be shown / hidden as required for each breakpoint. - * * Automatic control - columns are automatically hidden when there is no - * room left to display them. Columns removed from the right. - * - * In additional to column visibility control, Responsive also has built into - * options to use DataTables' child row display to show / hide the information - * from the table that has been hidden. There are also two modes of operation - * for this child row display: - * - * * Inline - when the control element that the user can use to show / hide - * child rows is displayed inside the first column of the table. - * * Column - where a whole column is dedicated to be the show / hide control. - * - * Initialisation of Responsive is performed by: - * - * * Adding the class `responsive` or `dt-responsive` to the table. In this case - * Responsive will automatically be initialised with the default configuration - * options when the DataTable is created. - * * Using the `responsive` option in the DataTables configuration options. This - * can also be used to specify the configuration options, or simply set to - * `true` to use the defaults. - * - * @class - * @param {object} settings DataTables settings object for the host table - * @param {object} [opts] Configuration options - * @requires jQuery 1.7+ - * @requires DataTables 1.10.3+ - * - * @example - * $('#example').DataTable( { - * responsive: true - * } ); - * } ); - */ -var Responsive = function ( settings, opts ) { - // Sanity check that we are using DataTables 1.10 or newer - if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.3' ) ) { - throw 'DataTables Responsive requires DataTables 1.10.3 or newer'; - } - - this.s = { - dt: new DataTable.Api( settings ), - columns: [], - current: [] - }; - - // Check if responsive has already been initialised on this table - if ( this.s.dt.settings()[0].responsive ) { - return; - } - - // details is an object, but for simplicity the user can give it as a string - // or a boolean - if ( opts && typeof opts.details === 'string' ) { - opts.details = { type: opts.details }; - } - else if ( opts && opts.details === false ) { - opts.details = { type: false }; - } - else if ( opts && opts.details === true ) { - opts.details = { type: 'inline' }; - } - - this.c = $.extend( true, {}, Responsive.defaults, DataTable.defaults.responsive, opts ); - settings.responsive = this; - this._constructor(); -}; - -$.extend( Responsive.prototype, { - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Constructor - */ - - /** - * Initialise the Responsive instance - * - * @private - */ - _constructor: function () - { - var that = this; - var dt = this.s.dt; - var dtPrivateSettings = dt.settings()[0]; - var oldWindowWidth = $(window).width(); - - dt.settings()[0]._responsive = this; - - // Use DataTables' throttle function to avoid processor thrashing on - // resize - $(window).on( 'resize.dtr orientationchange.dtr', DataTable.util.throttle( function () { - // iOS has a bug whereby resize can fire when only scrolling - // See: http://stackoverflow.com/questions/8898412 - var width = $(window).width(); - - if ( width !== oldWindowWidth ) { - that._resize(); - oldWindowWidth = width; - } - } ) ); - - // DataTables doesn't currently trigger an event when a row is added, so - // we need to hook into its private API to enforce the hidden rows when - // new data is added - dtPrivateSettings.oApi._fnCallbackReg( dtPrivateSettings, 'aoRowCreatedCallback', function (tr, data, idx) { - if ( $.inArray( false, that.s.current ) !== -1 ) { - $('>td, >th', tr).each( function ( i ) { - var idx = dt.column.index( 'toData', i ); - - if ( that.s.current[idx] === false ) { - $(this).css('display', 'none'); - } - } ); - } - } ); - - // Destroy event handler - dt.on( 'destroy.dtr', function () { - dt.off( '.dtr' ); - $( dt.table().body() ).off( '.dtr' ); - $(window).off( 'resize.dtr orientationchange.dtr' ); - - // Restore the columns that we've hidden - $.each( that.s.current, function ( i, val ) { - if ( val === false ) { - that._setColumnVis( i, true ); - } - } ); - } ); - - // Reorder the breakpoints array here in case they have been added out - // of order - this.c.breakpoints.sort( function (a, b) { - return a.width < b.width ? 1 : - a.width > b.width ? -1 : 0; - } ); - - this._classLogic(); - this._resizeAuto(); - - // Details handler - var details = this.c.details; - - if ( details.type !== false ) { - that._detailsInit(); - - // DataTables will trigger this event on every column it shows and - // hides individually - dt.on( 'column-visibility.dtr', function (e, ctx, col, vis) { - that._classLogic(); - that._resizeAuto(); - that._resize(); - } ); - - // Redraw the details box on each draw which will happen if the data - // has changed. This is used until DataTables implements a native - // `updated` event for rows - dt.on( 'draw.dtr', function () { - that._redrawChildren(); - } ); - - $(dt.table().node()).addClass( 'dtr-'+details.type ); - } - - dt.on( 'column-reorder.dtr', function (e, settings, details) { - that._classLogic(); - that._resizeAuto(); - that._resize(); - } ); - - // Change in column sizes means we need to calc - dt.on( 'column-sizing.dtr', function () { - that._resizeAuto(); - that._resize(); - }); - - // On Ajax reload we want to reopen any child rows which are displayed - // by responsive - dt.on( 'preXhr.dtr', function () { - var rowIds = []; - dt.rows().every( function () { - if ( this.child.isShown() ) { - rowIds.push( this.id(true) ); - } - } ); - - dt.one( 'draw.dtr', function () { - dt.rows( rowIds ).every( function () { - that._detailsDisplay( this, false ); - } ); - } ); - }); - - dt.on( 'init.dtr', function (e, settings, details) { - that._resizeAuto(); - that._resize(); - - // If columns were hidden, then DataTables needs to adjust the - // column sizing - if ( $.inArray( false, that.s.current ) ) { - dt.columns.adjust(); - } - } ); - - // First pass - draw the table for the current viewport size - this._resize(); - }, - - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Private methods - */ - - /** - * Calculate the visibility for the columns in a table for a given - * breakpoint. The result is pre-determined based on the class logic if - * class names are used to control all columns, but the width of the table - * is also used if there are columns which are to be automatically shown - * and hidden. - * - * @param {string} breakpoint Breakpoint name to use for the calculation - * @return {array} Array of boolean values initiating the visibility of each - * column. - * @private - */ - _columnsVisiblity: function ( breakpoint ) - { - var dt = this.s.dt; - var columns = this.s.columns; - var i, ien; - - // Create an array that defines the column ordering based first on the - // column's priority, and secondly the column index. This allows the - // columns to be removed from the right if the priority matches - var order = columns - .map( function ( col, idx ) { - return { - columnIdx: idx, - priority: col.priority - }; - } ) - .sort( function ( a, b ) { - if ( a.priority !== b.priority ) { - return a.priority - b.priority; - } - return a.columnIdx - b.columnIdx; - } ); - - // Class logic - determine which columns are in this breakpoint based - // on the classes. If no class control (i.e. `auto`) then `-` is used - // to indicate this to the rest of the function - var display = $.map( columns, function ( col ) { - return col.auto && col.minWidth === null ? - false : - col.auto === true ? - '-' : - $.inArray( breakpoint, col.includeIn ) !== -1; - } ); - - // Auto column control - first pass: how much width is taken by the - // ones that must be included from the non-auto columns - var requiredWidth = 0; - for ( i=0, ien=display.length ; i
    ') - .append( headerCells ) - .appendTo( clonedHeader ); - - // In the inline case extra padding is applied to the first column to - // give space for the show / hide icon. We need to use this in the - // calculation - if ( this.c.details.type === 'inline' ) { - $(clonedTable).addClass( 'dtr-inline collapsed' ); - } - - // It is unsafe to insert elements with the same name into the DOM - // multiple times. For example, cloning and inserting a checked radio - // clears the chcecked state of the original radio. - $( clonedTable ).find( '[name]' ).removeAttr( 'name' ); - - var inserted = $('
    ') - .css( { - width: 1, - height: 1, - overflow: 'hidden' - } ) - .append( clonedTable ); - - inserted.insertBefore( dt.table().node() ); - - // The cloned header now contains the smallest that each column can be - headerCells.each( function (i) { - var idx = dt.column.index( 'fromVisible', i ); - columns[ idx ].minWidth = this.offsetWidth || 0; - } ); - - inserted.remove(); - }, - - /** - * Set a column's visibility. - * - * We don't use DataTables' column visibility controls in order to ensure - * that column visibility can Responsive can no-exist. Since only IE8+ is - * supported (and all evergreen browsers of course) the control of the - * display attribute works well. - * - * @param {integer} col Column index - * @param {boolean} showHide Show or hide (true or false) - * @private - */ - _setColumnVis: function ( col, showHide ) - { - var dt = this.s.dt; - var display = showHide ? '' : 'none'; // empty string will remove the attr - - $( dt.column( col ).header() ).css( 'display', display ); - $( dt.column( col ).footer() ).css( 'display', display ); - dt.column( col ).nodes().to$().css( 'display', display ); - }, - - - /** - * Update the cell tab indexes for keyboard accessibility. This is called on - * every table draw - that is potentially inefficient, but also the least - * complex option given that column visibility can change on the fly. Its a - * shame user-focus was removed from CSS 3 UI, as it would have solved this - * issue with a single CSS statement. - * - * @private - */ - _tabIndexes: function () - { - var dt = this.s.dt; - var cells = dt.cells( { page: 'current' } ).nodes().to$(); - var ctx = dt.settings()[0]; - var target = this.c.details.target; - - cells.filter( '[data-dtr-keyboard]' ).removeData( '[data-dtr-keyboard]' ); - - var selector = typeof target === 'number' ? - ':eq('+target+')' : - target; - - // This is a bit of a hack - we need to limit the selected nodes to just - // those of this table - if ( selector === 'td:first-child, th:first-child' ) { - selector = '>td:first-child, >th:first-child'; - } - - $( selector, dt.rows( { page: 'current' } ).nodes() ) - .attr( 'tabIndex', ctx.iTabIndex ) - .data( 'dtr-keyboard', 1 ); - } -} ); - - -/** - * List of default breakpoints. Each item in the array is an object with two - * properties: - * - * * `name` - the breakpoint name. - * * `width` - the breakpoint width - * - * @name Responsive.breakpoints - * @static - */ -Responsive.breakpoints = [ - { name: 'desktop', width: Infinity }, - { name: 'tablet-l', width: 1024 }, - { name: 'tablet-p', width: 768 }, - { name: 'mobile-l', width: 480 }, - { name: 'mobile-p', width: 320 } -]; - - -/** - * Display methods - functions which define how the hidden data should be shown - * in the table. - * - * @namespace - * @name Responsive.defaults - * @static - */ -Responsive.display = { - childRow: function ( row, update, render ) { - if ( update ) { - if ( $(row.node()).hasClass('parent') ) { - row.child( render(), 'child' ).show(); - - return true; - } - } - else { - if ( ! row.child.isShown() ) { - row.child( render(), 'child' ).show(); - $( row.node() ).addClass( 'parent' ); - - return true; - } - else { - row.child( false ); - $( row.node() ).removeClass( 'parent' ); - - return false; - } - } - }, - - childRowImmediate: function ( row, update, render ) { - if ( (! update && row.child.isShown()) || ! row.responsive.hasHidden() ) { - // User interaction and the row is show, or nothing to show - row.child( false ); - $( row.node() ).removeClass( 'parent' ); - - return false; - } - else { - // Display - row.child( render(), 'child' ).show(); - $( row.node() ).addClass( 'parent' ); - - return true; - } - }, - - // This is a wrapper so the modal options for Bootstrap and jQuery UI can - // have options passed into them. This specific one doesn't need to be a - // function but it is for consistency in the `modal` name - modal: function ( options ) { - return function ( row, update, render ) { - if ( ! update ) { - // Show a modal - var close = function () { - modal.remove(); // will tidy events for us - $(document).off( 'keypress.dtr' ); - }; - - var modal = $('
    ') - .append( $('
    ') - .append( $('
    ') - .append( render() ) - ) - .append( $('
    ×
    ' ) - .click( function () { - close(); - } ) - ) - ) - .append( $('
    ') - .click( function () { - close(); - } ) - ) - .appendTo( 'body' ); - - $(document).on( 'keyup.dtr', function (e) { - if ( e.keyCode === 27 ) { - e.stopPropagation(); - - close(); - } - } ); - } - else { - $('div.dtr-modal-content') - .empty() - .append( render() ); - } - - if ( options && options.header ) { - $('div.dtr-modal-content').prepend( - '

    '+options.header( row )+'

    ' - ); - } - }; - } -}; - - -/** - * Display methods - functions which define how the hidden data should be shown - * in the table. - * - * @namespace - * @name Responsive.defaults - * @static - */ -Responsive.renderer = { - listHidden: function () { - return function ( api, rowIdx, columns ) { - var data = $.map( columns, function ( col ) { - return col.hidden ? - '
  • '+ - ''+ - col.title+ - ' '+ - ''+ - col.data+ - ''+ - '
  • ' : - ''; - } ).join(''); - - return data ? - $('
      ').append( data ) : - false; - } - }, - - tableAll: function ( options ) { - options = $.extend( { - tableClass: '' - }, options ); - - return function ( api, rowIdx, columns ) { - var data = $.map( columns, function ( col ) { - return '
    '+ - ' '+ - ''+ - ''; - } ).join(''); - - return $('
    ",{valign:"top",colSpan:ba(a),"class":a.oClasses.sRowEmpty}).html(c))[0];s(a,"aoHeaderCallback","header",[h(a.nTHead).children("tr")[0],Ma(a),g,n,i]);s(a,"aoFooterCallback","footer",[h(a.nTFoot).children("tr")[0],Ma(a),g,n,i]);d=h(a.nTBody);d.children().detach();d.append(h(b));s(a,"aoDrawCallback","draw",[a]);a.bSorted=!1;a.bFiltered=!1;a.bDrawing=!1}}function T(a,b){var c=a.oFeatures,d=c.bFilter; -c.bSort&&ob(a);d?ga(a,a.oPreviousSearch):a.aiDisplay=a.aiDisplayMaster.slice();!0!==b&&(a._iDisplayStart=0);a._drawHold=b;O(a);a._drawHold=!1}function pb(a){var b=a.oClasses,c=h(a.nTable),c=h("
    ").insertBefore(c),d=a.oFeatures,e=h("
    ",{id:a.sTableId+"_wrapper","class":b.sWrapper+(a.nTFoot?"":" "+b.sNoFooter)});a.nHolding=c[0];a.nTableWrapper=e[0];a.nTableReinsertBefore=a.nTable.nextSibling;for(var f=a.sDom.split(""),g,j,i,n,l,q,k=0;k")[0]; -n=f[k+1];if("'"==n||'"'==n){l="";for(q=2;f[k+q]!=n;)l+=f[k+q],q++;"H"==l?l=b.sJUIHeader:"F"==l&&(l=b.sJUIFooter);-1!=l.indexOf(".")?(n=l.split("."),i.id=n[0].substr(1,n[0].length-1),i.className=n[1]):"#"==l.charAt(0)?i.id=l.substr(1,l.length-1):i.className=l;k+=q}e.append(i);e=h(i)}else if(">"==j)e=e.parent();else if("l"==j&&d.bPaginate&&d.bLengthChange)g=qb(a);else if("f"==j&&d.bFilter)g=rb(a);else if("r"==j&&d.bProcessing)g=sb(a);else if("t"==j)g=tb(a);else if("i"==j&&d.bInfo)g=ub(a);else if("p"== -j&&d.bPaginate)g=vb(a);else if(0!==m.ext.feature.length){i=m.ext.feature;q=0;for(n=i.length;q',j=d.sSearch,j=j.match(/_INPUT_/)?j.replace("_INPUT_",g):j+g,b=h("
    ",{id:!f.f?c+"_filter":null,"class":b.sFilter}).append(h("
    ").addClass(b.sLength);a.aanFeatures.l||(i[0].id=c+"_length");i.children().append(a.oLanguage.sLengthMenu.replace("_MENU_",e[0].outerHTML));h("select",i).val(a._iDisplayLength).on("change.DT",function(){Ta(a,h(this).val());O(a)});h(a.nTable).on("length.dt.DT",function(b,c,d){a===c&&h("select",i).val(d)});return i[0]}function vb(a){var b=a.sPaginationType,c=m.ext.pager[b],d="function"===typeof c,e=function(a){O(a)},b=h("
    ").addClass(a.oClasses.sPaging+ -b)[0],f=a.aanFeatures;d||c.fnInit(a,b,e);f.p||(b.id=a.sTableId+"_paginate",a.aoDrawCallback.push({fn:function(a){if(d){var b=a._iDisplayStart,i=a._iDisplayLength,h=a.fnRecordsDisplay(),l=-1===i,b=l?0:Math.ceil(b/i),i=l?1:Math.ceil(h/i),h=c(b,i),k,l=0;for(k=f.p.length;lf&& -(d=0)):"first"==b?d=0:"previous"==b?(d=0<=e?d-e:0,0>d&&(d=0)):"next"==b?d+e",{id:!a.aanFeatures.r?a.sTableId+"_processing":null,"class":a.oClasses.sProcessing}).html(a.oLanguage.sProcessing).insertBefore(a.nTable)[0]}function C(a,b){a.oFeatures.bProcessing&&h(a.aanFeatures.r).css("display",b?"block":"none"); -s(a,null,"processing",[a,b])}function tb(a){var b=h(a.nTable);b.attr("role","grid");var c=a.oScroll;if(""===c.sX&&""===c.sY)return a.nTable;var d=c.sX,e=c.sY,f=a.oClasses,g=b.children("caption"),j=g.length?g[0]._captionSide:null,i=h(b[0].cloneNode(!1)),n=h(b[0].cloneNode(!1)),l=b.children("tfoot");l.length||(l=null);i=h("
    ",{"class":f.sScrollWrapper}).append(h("
    ",{"class":f.sScrollHead}).css({overflow:"hidden",position:"relative",border:0,width:d?!d?null:v(d):"100%"}).append(h("
    ", -{"class":f.sScrollHeadInner}).css({"box-sizing":"content-box",width:c.sXInner||"100%"}).append(i.removeAttr("id").css("margin-left",0).append("top"===j?g:null).append(b.children("thead"))))).append(h("
    ",{"class":f.sScrollBody}).css({position:"relative",overflow:"auto",width:!d?null:v(d)}).append(b));l&&i.append(h("
    ",{"class":f.sScrollFoot}).css({overflow:"hidden",border:0,width:d?!d?null:v(d):"100%"}).append(h("
    ",{"class":f.sScrollFootInner}).append(n.removeAttr("id").css("margin-left", -0).append("bottom"===j?g:null).append(b.children("tfoot")))));var b=i.children(),k=b[0],f=b[1],r=l?b[2]:null;if(d)h(f).on("scroll.DT",function(){var a=this.scrollLeft;k.scrollLeft=a;l&&(r.scrollLeft=a)});h(f).css(e&&c.bCollapse?"max-height":"height",e);a.nScrollHead=k;a.nScrollBody=f;a.nScrollFoot=r;a.aoDrawCallback.push({fn:ma,sName:"scrolling"});return i[0]}function ma(a){var b=a.oScroll,c=b.sX,d=b.sXInner,e=b.sY,b=b.iBarWidth,f=h(a.nScrollHead),g=f[0].style,j=f.children("div"),i=j[0].style,n=j.children("table"), -j=a.nScrollBody,l=h(j),q=j.style,r=h(a.nScrollFoot).children("div"),m=r.children("table"),p=h(a.nTHead),o=h(a.nTable),t=o[0],s=t.style,u=a.nTFoot?h(a.nTFoot):null,x=a.oBrowser,U=x.bScrollOversize,ac=D(a.aoColumns,"nTh"),P,L,Q,w,Wa=[],y=[],z=[],A=[],B,C=function(a){a=a.style;a.paddingTop="0";a.paddingBottom="0";a.borderTopWidth="0";a.borderBottomWidth="0";a.height=0};L=j.scrollHeight>j.clientHeight;if(a.scrollBarVis!==L&&a.scrollBarVis!==k)a.scrollBarVis=L,Z(a);else{a.scrollBarVis=L;o.children("thead, tfoot").remove(); -u&&(Q=u.clone().prependTo(o),P=u.find("tr"),Q=Q.find("tr"));w=p.clone().prependTo(o);p=p.find("tr");L=w.find("tr");w.find("th, td").removeAttr("tabindex");c||(q.width="100%",f[0].style.width="100%");h.each(ta(a,w),function(b,c){B=$(a,b);c.style.width=a.aoColumns[B].sWidth});u&&I(function(a){a.style.width=""},Q);f=o.outerWidth();if(""===c){s.width="100%";if(U&&(o.find("tbody").height()>j.offsetHeight||"scroll"==l.css("overflow-y")))s.width=v(o.outerWidth()-b);f=o.outerWidth()}else""!==d&&(s.width= -v(d),f=o.outerWidth());I(C,L);I(function(a){z.push(a.innerHTML);Wa.push(v(h(a).css("width")))},L);I(function(a,b){if(h.inArray(a,ac)!==-1)a.style.width=Wa[b]},p);h(L).height(0);u&&(I(C,Q),I(function(a){A.push(a.innerHTML);y.push(v(h(a).css("width")))},Q),I(function(a,b){a.style.width=y[b]},P),h(Q).height(0));I(function(a,b){a.innerHTML='
    '+z[b]+"
    ";a.style.width=Wa[b]},L);u&&I(function(a,b){a.innerHTML='
    '+ -A[b]+"
    ";a.style.width=y[b]},Q);if(o.outerWidth()j.offsetHeight||"scroll"==l.css("overflow-y")?f+b:f;if(U&&(j.scrollHeight>j.offsetHeight||"scroll"==l.css("overflow-y")))s.width=v(P-b);(""===c||""!==d)&&K(a,1,"Possible column misalignment",6)}else P="100%";q.width=v(P);g.width=v(P);u&&(a.nScrollFoot.style.width=v(P));!e&&U&&(q.height=v(t.offsetHeight+b));c=o.outerWidth();n[0].style.width=v(c);i.width=v(c);d=o.height()>j.clientHeight||"scroll"==l.css("overflow-y");e="padding"+ -(x.bScrollbarLeft?"Left":"Right");i[e]=d?b+"px":"0px";u&&(m[0].style.width=v(c),r[0].style.width=v(c),r[0].style[e]=d?b+"px":"0px");o.children("colgroup").insertBefore(o.children("thead"));l.scroll();if((a.bSorted||a.bFiltered)&&!a._drawHold)j.scrollTop=0}}function I(a,b,c){for(var d=0,e=0,f=b.length,g,j;e").appendTo(j.find("tbody")); -j.find("thead, tfoot").remove();j.append(h(a.nTHead).clone()).append(h(a.nTFoot).clone());j.find("tfoot th, tfoot td").css("width","");n=ta(a,j.find("thead")[0]);for(m=0;m").css({width:p.sWidthOrig,margin:0,padding:0,border:0,height:1}));if(a.aoData.length)for(m=0;m").css(f||e?{position:"absolute",top:0,left:0,height:1,right:0,overflow:"hidden"}:{}).append(j).appendTo(k);f&&g?j.width(g):f?(j.css("width","auto"),j.removeAttr("width"),j.width()").css("width",v(a)).appendTo(b||H.body),d=c[0].offsetWidth;c.remove();return d}function Hb(a,b){var c=Ib(a,b);if(0>c)return null;var d=a.aoData[c];return!d.nTr?h("
    ").html(B(a,c,b,"display"))[0]:d.anCells[b]}function Ib(a,b){for(var c,d=-1,e=-1,f=0,g=a.aoData.length;fd&&(d=c.length,e=f);return e}function v(a){return null===a?"0px":"number"==typeof a?0>a?"0px":a+"px":a.match(/\d$/)?a+"px":a}function W(a){var b,c,d=[],e=a.aoColumns,f,g,j,i;b=a.aaSortingFixed;c=h.isPlainObject(b);var n=[];f=function(a){a.length&&!h.isArray(a[0])?n.push(a):h.merge(n,a)};h.isArray(b)&&f(b);c&&b.pre&&f(b.pre);f(a.aaSorting);c&&b.post&&f(b.post);for(a=0;ae?1:0,0!==c)return"asc"===j.dir?c:-c;c=d[a];e=d[b];return ce?1:0}):i.sort(function(a,b){var c,g,j,i,k=h.length,m=f[a]._aSortData,p=f[b]._aSortData;for(j=0;jg?1:0})}a.bSorted=!0}function Kb(a){for(var b,c,d=a.aoColumns,e=W(a),a=a.oLanguage.oAria,f=0,g=d.length;f/g, -"");var i=c.nTh;i.removeAttribute("aria-sort");c.bSortable&&(0e?e+1:3));e=0;for(f=d.length;ee?e+1:3))}a.aLastSort=d}function Jb(a,b){var c=a.aoColumns[b],d=m.ext.order[c.sSortDataType],e;d&&(e=d.call(a.oInstance,a,b,aa(a,b)));for(var f,g=m.ext.type.order[c.sType+"-pre"],j=0,i=a.aoData.length;j=f.length?[0,c[1]]:c)}));b.search!== -k&&h.extend(a.oPreviousSearch,Db(b.search));if(b.columns){d=0;for(e=b.columns.length;d=c&&(b=c-d);b-=b%d;if(-1===d||0>b)b=0;a._iDisplayStart=b}function Pa(a,b){var c=a.renderer,d=m.ext.renderer[b];return h.isPlainObject(c)&&c[b]?d[c[b]]||d._:"string"===typeof c?d[c]||d._:d._}function y(a){return a.oFeatures.bServerSide?"ssp":a.ajax||a.sAjaxSource?"ajax":"dom"}function ia(a,b){var c=[],c=Nb.numbers_length,d=Math.floor(c/2);b<=c?c=X(0,b):a<=d?(c=X(0, -c-2),c.push("ellipsis"),c.push(b-1)):(a>=b-1-d?c=X(b-(c-2),b):(c=X(a-d+2,a+d-1),c.push("ellipsis"),c.push(b-1)),c.splice(0,0,"ellipsis"),c.splice(0,0,0));c.DT_el="span";return c}function fb(a){h.each({num:function(b){return Ba(b,a)},"num-fmt":function(b){return Ba(b,a,Za)},"html-num":function(b){return Ba(b,a,Ca)},"html-num-fmt":function(b){return Ba(b,a,Ca,Za)}},function(b,c){x.type.order[b+a+"-pre"]=c;b.match(/^html\-/)&&(x.type.search[b+a]=x.type.search.html)})}function Ob(a){return function(){var b= -[Aa(this[m.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return m.ext.internal[a].apply(this,b)}}var m=function(a){this.$=function(a,b){return this.api(!0).$(a,b)};this._=function(a,b){return this.api(!0).rows(a,b).data()};this.api=function(a){return a?new t(Aa(this[x.iApiIndex])):new t(this)};this.fnAddData=function(a,b){var c=this.api(!0),d=h.isArray(a)&&(h.isArray(a[0])||h.isPlainObject(a[0]))?c.rows.add(a):c.row.add(a);(b===k||b)&&c.draw();return d.flatten().toArray()};this.fnAdjustColumnSizing= -function(a){var b=this.api(!0).columns.adjust(),c=b.settings()[0],d=c.oScroll;a===k||a?b.draw(!1):(""!==d.sX||""!==d.sY)&&ma(c)};this.fnClearTable=function(a){var b=this.api(!0).clear();(a===k||a)&&b.draw()};this.fnClose=function(a){this.api(!0).row(a).child.hide()};this.fnDeleteRow=function(a,b,c){var d=this.api(!0),a=d.rows(a),e=a.settings()[0],h=e.aoData[a[0][0]];a.remove();b&&b.call(this,e,h);(c===k||c)&&d.draw();return h};this.fnDestroy=function(a){this.api(!0).destroy(a)};this.fnDraw=function(a){this.api(!0).draw(a)}; -this.fnFilter=function(a,b,c,d,e,h){e=this.api(!0);null===b||b===k?e.search(a,c,d,h):e.column(b).search(a,c,d,h);e.draw()};this.fnGetData=function(a,b){var c=this.api(!0);if(a!==k){var d=a.nodeName?a.nodeName.toLowerCase():"";return b!==k||"td"==d||"th"==d?c.cell(a,b).data():c.row(a).data()||null}return c.data().toArray()};this.fnGetNodes=function(a){var b=this.api(!0);return a!==k?b.row(a).node():b.rows().nodes().flatten().toArray()};this.fnGetPosition=function(a){var b=this.api(!0),c=a.nodeName.toUpperCase(); -return"TR"==c?b.row(a).index():"TD"==c||"TH"==c?(a=b.cell(a).index(),[a.row,a.columnVisible,a.column]):null};this.fnIsOpen=function(a){return this.api(!0).row(a).child.isShown()};this.fnOpen=function(a,b,c){return this.api(!0).row(a).child(b,c).show().child()[0]};this.fnPageChange=function(a,b){var c=this.api(!0).page(a);(b===k||b)&&c.draw(!1)};this.fnSetColumnVis=function(a,b,c){a=this.api(!0).column(a).visible(b);(c===k||c)&&a.columns.adjust().draw()};this.fnSettings=function(){return Aa(this[x.iApiIndex])}; -this.fnSort=function(a){this.api(!0).order(a).draw()};this.fnSortListener=function(a,b,c){this.api(!0).order.listener(a,b,c)};this.fnUpdate=function(a,b,c,d,e){var h=this.api(!0);c===k||null===c?h.row(b).data(a):h.cell(b,c).data(a);(e===k||e)&&h.columns.adjust();(d===k||d)&&h.draw();return 0};this.fnVersionCheck=x.fnVersionCheck;var b=this,c=a===k,d=this.length;c&&(a={});this.oApi=this.internal=x.internal;for(var e in m.ext.internal)e&&(this[e]=Ob(e));this.each(function(){var e={},g=1t<"F"ip>'),o.renderer)?h.isPlainObject(o.renderer)&& -!o.renderer.header&&(o.renderer.header="jqueryui"):o.renderer="jqueryui":h.extend(u,m.ext.classes,g.oClasses);q.addClass(u.sTable);o.iInitDisplayStart===k&&(o.iInitDisplayStart=g.iDisplayStart,o._iDisplayStart=g.iDisplayStart);null!==g.iDeferLoading&&(o.bDeferLoading=!0,e=h.isArray(g.iDeferLoading),o._iRecordsDisplay=e?g.iDeferLoading[0]:g.iDeferLoading,o._iRecordsTotal=e?g.iDeferLoading[1]:g.iDeferLoading);var v=o.oLanguage;h.extend(!0,v,g.oLanguage);v.sUrl&&(h.ajax({dataType:"json",url:v.sUrl,success:function(a){Fa(a); -J(l.oLanguage,a);h.extend(true,v,a);ha(o)},error:function(){ha(o)}}),n=!0);null===g.asStripeClasses&&(o.asStripeClasses=[u.sStripeOdd,u.sStripeEven]);var e=o.asStripeClasses,x=q.children("tbody").find("tr").eq(0);-1!==h.inArray(!0,h.map(e,function(a){return x.hasClass(a)}))&&(h("tbody tr",this).removeClass(e.join(" ")),o.asDestroyStripes=e.slice());e=[];r=this.getElementsByTagName("thead");0!==r.length&&(ea(o.aoHeader,r[0]),e=ta(o));if(null===g.aoColumns){r=[];j=0;for(i=e.length;j").appendTo(q)); -o.nTHead=b[0];b=q.children("tbody");b.length===0&&(b=h("
    '+col.title+':'+''+col.data+'
    ').append( data ); - } - } -}; - -/** - * Responsive default settings for initialisation - * - * @namespace - * @name Responsive.defaults - * @static - */ -Responsive.defaults = { - /** - * List of breakpoints for the instance. Note that this means that each - * instance can have its own breakpoints. Additionally, the breakpoints - * cannot be changed once an instance has been creased. - * - * @type {Array} - * @default Takes the value of `Responsive.breakpoints` - */ - breakpoints: Responsive.breakpoints, - - /** - * Enable / disable auto hiding calculations. It can help to increase - * performance slightly if you disable this option, but all columns would - * need to have breakpoint classes assigned to them - * - * @type {Boolean} - * @default `true` - */ - auto: true, - - /** - * Details control. If given as a string value, the `type` property of the - * default object is set to that value, and the defaults used for the rest - * of the object - this is for ease of implementation. - * - * The object consists of the following properties: - * - * * `display` - A function that is used to show and hide the hidden details - * * `renderer` - function that is called for display of the child row data. - * The default function will show the data from the hidden columns - * * `target` - Used as the selector for what objects to attach the child - * open / close to - * * `type` - `false` to disable the details display, `inline` or `column` - * for the two control types - * - * @type {Object|string} - */ - details: { - display: Responsive.display.childRow, - - renderer: Responsive.renderer.listHidden(), - - target: 0, - - type: 'inline' - }, - - /** - * Orthogonal data request option. This is used to define the data type - * requested when Responsive gets the data to show in the child row. - * - * @type {String} - */ - orthogonal: 'display' -}; - - -/* - * API - */ -var Api = $.fn.dataTable.Api; - -// Doesn't do anything - work around for a bug in DT... Not documented -Api.register( 'responsive()', function () { - return this; -} ); - -Api.register( 'responsive.index()', function ( li ) { - li = $(li); - - return { - column: li.data('dtr-index'), - row: li.parent().data('dtr-index') - }; -} ); - -Api.register( 'responsive.rebuild()', function () { - return this.iterator( 'table', function ( ctx ) { - if ( ctx._responsive ) { - ctx._responsive._classLogic(); - } - } ); -} ); - -Api.register( 'responsive.recalc()', function () { - return this.iterator( 'table', function ( ctx ) { - if ( ctx._responsive ) { - ctx._responsive._resizeAuto(); - ctx._responsive._resize(); - } - } ); -} ); - -Api.register( 'responsive.hasHidden()', function () { - var ctx = this.context[0]; - - return ctx._responsive ? - $.inArray( false, ctx._responsive.s.current ) !== -1 : - false; -} ); - - -/** - * Version information - * - * @name Responsive.version - * @static - */ -Responsive.version = '2.1.1'; - - -$.fn.dataTable.Responsive = Responsive; -$.fn.DataTable.Responsive = Responsive; - -// Attach a listener to the document which listens for DataTables initialisation -// events so we can automatically initialise -$(document).on( 'preInit.dt.dtr', function (e, settings, json) { - if ( e.namespace !== 'dt' ) { - return; - } - - if ( $(settings.nTable).hasClass( 'responsive' ) || - $(settings.nTable).hasClass( 'dt-responsive' ) || - settings.oInit.responsive || - DataTable.defaults.responsive - ) { - var init = settings.oInit.responsive; - - if ( init !== false ) { - new Responsive( settings, $.isPlainObject( init ) ? init : {} ); - } - } -} ); - - -return Responsive; -})); diff --git a/app/static/DataTables/Responsive-2.1.1/js/dataTables.responsive.min.js b/app/static/DataTables/Responsive-2.1.1/js/dataTables.responsive.min.js deleted file mode 100644 index 2bbfabbbb..000000000 --- a/app/static/DataTables/Responsive-2.1.1/js/dataTables.responsive.min.js +++ /dev/null @@ -1,26 +0,0 @@ -/*! - Responsive 2.1.1 - 2014-2016 SpryMedia Ltd - datatables.net/license -*/ -(function(c){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(l){return c(l,window,document)}):"object"===typeof exports?module.exports=function(l,k){l||(l=window);if(!k||!k.fn.dataTable)k=require("datatables.net")(l,k).$;return c(k,l,l.document)}:c(jQuery,window,document)})(function(c,l,k,p){var m=c.fn.dataTable,j=function(b,a){if(!m.versionCheck||!m.versionCheck("1.10.3"))throw"DataTables Responsive requires DataTables 1.10.3 or newer";this.s={dt:new m.Api(b),columns:[], -current:[]};this.s.dt.settings()[0].responsive||(a&&"string"===typeof a.details?a.details={type:a.details}:a&&!1===a.details?a.details={type:!1}:a&&!0===a.details&&(a.details={type:"inline"}),this.c=c.extend(!0,{},j.defaults,m.defaults.responsive,a),b.responsive=this,this._constructor())};c.extend(j.prototype,{_constructor:function(){var b=this,a=this.s.dt,d=a.settings()[0],e=c(l).width();a.settings()[0]._responsive=this;c(l).on("resize.dtr orientationchange.dtr",m.util.throttle(function(){var a= -c(l).width();a!==e&&(b._resize(),e=a)}));d.oApi._fnCallbackReg(d,"aoRowCreatedCallback",function(e){-1!==c.inArray(!1,b.s.current)&&c(">td, >th",e).each(function(e){e=a.column.index("toData",e);!1===b.s.current[e]&&c(this).css("display","none")})});a.on("destroy.dtr",function(){a.off(".dtr");c(a.table().body()).off(".dtr");c(l).off("resize.dtr orientationchange.dtr");c.each(b.s.current,function(a,e){!1===e&&b._setColumnVis(a,!0)})});this.c.breakpoints.sort(function(a,b){return a.width -b.width?-1:0});this._classLogic();this._resizeAuto();d=this.c.details;!1!==d.type&&(b._detailsInit(),a.on("column-visibility.dtr",function(){b._classLogic();b._resizeAuto();b._resize()}),a.on("draw.dtr",function(){b._redrawChildren()}),c(a.table().node()).addClass("dtr-"+d.type));a.on("column-reorder.dtr",function(){b._classLogic();b._resizeAuto();b._resize()});a.on("column-sizing.dtr",function(){b._resizeAuto();b._resize()});a.on("preXhr.dtr",function(){var e=[];a.rows().every(function(){this.child.isShown()&& -e.push(this.id(true))});a.one("draw.dtr",function(){a.rows(e).every(function(){b._detailsDisplay(this,false)})})});a.on("init.dtr",function(){b._resizeAuto();b._resize();c.inArray(false,b.s.current)&&a.columns.adjust()});this._resize()},_columnsVisiblity:function(b){var a=this.s.dt,d=this.s.columns,e,f,g=d.map(function(a,b){return{columnIdx:b,priority:a.priority}}).sort(function(a,b){return a.priority!==b.priority?a.priority-b.priority:a.columnIdx-b.columnIdx}),h=c.map(d,function(a){return a.auto&& -null===a.minWidth?!1:!0===a.auto?"-":-1!==c.inArray(b,a.includeIn)}),n=0;e=0;for(f=h.length;ea-d[i].minWidth?(n=!0,h[i]=!1):h[i]=!0,a-=d[i].minWidth)}g=!1;e=0;for(f=d.length;e=g&&f(c,a[d].name)}else{if("not-"===i){d=0;for(i=a.length;d").append(h).appendTo(f)}c("").append(g).appendTo(e);"inline"===this.c.details.type&&c(d).addClass("dtr-inline collapsed");c(d).find("[name]").removeAttr("name");d=c("
    ").css({width:1,height:1,overflow:"hidden"}).append(d);d.insertBefore(b.table().node());g.each(function(c){c=b.column.index("fromVisible",c);a[c].minWidth=this.offsetWidth||0});d.remove()}},_setColumnVis:function(b, -a){var d=this.s.dt,e=a?"":"none";c(d.column(b).header()).css("display",e);c(d.column(b).footer()).css("display",e);d.column(b).nodes().to$().css("display",e)},_tabIndexes:function(){var b=this.s.dt,a=b.cells({page:"current"}).nodes().to$(),d=b.settings()[0],e=this.c.details.target;a.filter("[data-dtr-keyboard]").removeData("[data-dtr-keyboard]");a="number"===typeof e?":eq("+e+")":e;"td:first-child, th:first-child"===a&&(a=">td:first-child, >th:first-child");c(a,b.rows({page:"current"}).nodes()).attr("tabIndex", -d.iTabIndex).data("dtr-keyboard",1)}});j.breakpoints=[{name:"desktop",width:Infinity},{name:"tablet-l",width:1024},{name:"tablet-p",width:768},{name:"mobile-l",width:480},{name:"mobile-p",width:320}];j.display={childRow:function(b,a,d){if(a){if(c(b.node()).hasClass("parent"))return b.child(d(),"child").show(),!0}else{if(b.child.isShown())return b.child(!1),c(b.node()).removeClass("parent"),!1;b.child(d(),"child").show();c(b.node()).addClass("parent");return!0}},childRowImmediate:function(b,a,d){if(!a&& -b.child.isShown()||!b.responsive.hasHidden())return b.child(!1),c(b.node()).removeClass("parent"),!1;b.child(d(),"child").show();c(b.node()).addClass("parent");return!0},modal:function(b){return function(a,d,e){if(d)c("div.dtr-modal-content").empty().append(e());else{var f=function(){g.remove();c(k).off("keypress.dtr")},g=c('
    ').append(c('
    ').append(c('
    ').append(e())).append(c('
    ×
    ').click(function(){f()}))).append(c('
    ').click(function(){f()})).appendTo("body"); -c(k).on("keyup.dtr",function(a){27===a.keyCode&&(a.stopPropagation(),f())})}b&&b.header&&c("div.dtr-modal-content").prepend("

    "+b.header(a)+"

    ")}}};j.renderer={listHidden:function(){return function(b,a,d){return(b=c.map(d,function(a){return a.hidden?'
  • '+a.title+' '+a.data+"
  • ":""}).join(""))?c('
      ').append(b): -!1}},tableAll:function(b){b=c.extend({tableClass:""},b);return function(a,d,e){a=c.map(e,function(a){return'
    "}).join("");return c('
    '+a.title+": "+a.data+"
    ').append(a)}}};j.defaults={breakpoints:j.breakpoints,auto:!0,details:{display:j.display.childRow,renderer:j.renderer.listHidden(),target:0,type:"inline"},orthogonal:"display"};var o=c.fn.dataTable.Api; -o.register("responsive()",function(){return this});o.register("responsive.index()",function(b){b=c(b);return{column:b.data("dtr-index"),row:b.parent().data("dtr-index")}});o.register("responsive.rebuild()",function(){return this.iterator("table",function(b){b._responsive&&b._responsive._classLogic()})});o.register("responsive.recalc()",function(){return this.iterator("table",function(b){b._responsive&&(b._responsive._resizeAuto(),b._responsive._resize())})});o.register("responsive.hasHidden()",function(){var b= -this.context[0];return b._responsive?-1!==c.inArray(!1,b._responsive.s.current):!1});j.version="2.1.1";c.fn.dataTable.Responsive=j;c.fn.DataTable.Responsive=j;c(k).on("preInit.dt.dtr",function(b,a){if("dt"===b.namespace&&(c(a.nTable).hasClass("responsive")||c(a.nTable).hasClass("dt-responsive")||a.oInit.responsive||m.defaults.responsive)){var d=a.oInit.responsive;!1!==d&&new j(a,c.isPlainObject(d)?d:{})}});return j}); diff --git a/app/static/DataTables/Responsive-2.1.1/js/responsive.bootstrap.min.js b/app/static/DataTables/Responsive-2.1.1/js/responsive.bootstrap.min.js deleted file mode 100644 index e77a6da5e..000000000 --- a/app/static/DataTables/Responsive-2.1.1/js/responsive.bootstrap.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/*! - Bootstrap integration for DataTables' Responsive - ©2015-2016 SpryMedia Ltd - datatables.net/license -*/ -(function(c){"function"===typeof define&&define.amd?define(["jquery","datatables.net-bs","datatables.net-responsive"],function(a){return c(a,window,document)}):"object"===typeof exports?module.exports=function(a,b){a||(a=window);if(!b||!b.fn.dataTable)b=require("datatables.net-bs")(a,b).$;b.fn.dataTable.Responsive||require("datatables.net-responsive")(a,b);return c(b,a,a.document)}:c(jQuery,window,document)})(function(c){var a=c.fn.dataTable,b=a.Responsive.display,g=b.modal,e=c('').appendTo($this); + tbody = $('').insertAfter(thead); } oSettings.nTBody = tbody[0]; @@ -1334,10 +1322,11 @@ }; /* Must be done after everything which can be overridden by the state saving! */ + _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' ); + if ( oInit.bStateSave ) { features.bStateSave = true; - _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' ); _fnLoadState( oSettings, oInit, loadedInit ); } else { @@ -1372,7 +1361,7 @@ var _api_registerPlural; // DataTable.Api.registerPlural var _re_dic = {}; - var _re_new_lines = /[\r\n]/g; + var _re_new_lines = /[\r\n\u2028]/g; var _re_html = /<.*?>/g; // This is not strict ISO8601 - Date.parse() is quite lax, although @@ -1391,8 +1380,10 @@ // - fr - Swiss Franc // - kr - Swedish krona, Norwegian krone and Danish krone // - \u2009 is thin space and \u202F is narrow no-break space, both used in many + // - Ƀ - Bitcoin + // - Ξ - Ethereum // standards as thousands separators. - var _re_formatted_numeric = /[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi; + var _re_formatted_numeric = /['\u00A0,$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi; var _empty = function ( d ) { @@ -1620,6 +1611,52 @@ return out; }; + // Surprisingly this is faster than [].concat.apply + // https://jsperf.com/flatten-an-array-loop-vs-reduce/2 + var _flatten = function (out, val) { + if (Array.isArray(val)) { + for (var i=0 ; i').addClass( k ); + var created = $('').addClass( k ); $('td', created) .addClass( k ) .html( r ) @@ -8230,6 +8418,8 @@ row._detailsShow = undefined; row._details = undefined; + $( row.nTr ).removeClass( 'dt-hasChild' ); + _fnSaveState( ctx[0] ); } } }; @@ -8246,12 +8436,17 @@ if ( show ) { row._details.insertAfter( row.nTr ); + $( row.nTr ).addClass( 'dt-hasChild' ); } else { row._details.detach(); + $( row.nTr ).removeClass( 'dt-hasChild' ); } + _fnCallbackFire( ctx[0], null, 'childRow', [ show, api.row( api[0] ) ] ) + __details_events( ctx[0] ); + _fnSaveState( ctx[0] ); } } }; @@ -8558,10 +8753,6 @@ // Common actions col.bVisible = vis; - _fnDrawHead( settings, settings.aoHeader ); - _fnDrawHead( settings, settings.aoFooter ); - - _fnSaveState( settings ); }; @@ -8625,6 +8816,7 @@ } ); _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) { + var that = this; var ret = this.iterator( 'column', function ( settings, column ) { if ( vis === undefined ) { return settings.aoColumns[ column ].bVisible; @@ -8634,14 +8826,28 @@ // Group the column visibility changes if ( vis !== undefined ) { - // Second loop once the first is done for events - this.iterator( 'column', function ( settings, column ) { - _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] ); - } ); + this.iterator( 'table', function ( settings ) { + // Redraw the header after changes + _fnDrawHead( settings, settings.aoHeader ); + _fnDrawHead( settings, settings.aoFooter ); + + // Update colspan for no records display. Child rows and extensions will use their own + // listeners to do this - only need to update the empty table item here + if ( ! settings.aiDisplay.length ) { + $(settings.nTBody).find('td[colspan]').attr('colspan', _fnVisbleColumns(settings)); + } + + _fnSaveState( settings ); - if ( calc === undefined || calc ) { - this.columns.adjust(); - } + // Second loop once the first is done for events + that.iterator( 'column', function ( settings, column ) { + _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] ); + } ); + + if ( calc === undefined || calc ) { + that.columns.adjust(); + } + }); } return ret; @@ -8678,14 +8884,12 @@ return _selector_first( this.columns( selector, opts ) ); } ); - - var __cell_selector = function ( settings, selector, opts ) { var data = settings.aoData; var rows = _selector_row_indexes( settings, opts ); var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) ); - var allCells = $( [].concat.apply([], cells) ); + var allCells = $(_flatten( [], cells )); var row; var columns = settings.aoColumns.length; var a, i, ien, j, o, host; @@ -8726,7 +8930,10 @@ // Selector - index if ( $.isPlainObject( s ) ) { - return [s]; + // Valid cell index and its in the array of selectable rows + return s.column !== undefined && s.row !== undefined && $.inArray( s.row, rows ) !== -1 ? + [s] : + []; } // Selector - jQuery filtered cells @@ -8789,13 +8996,20 @@ } ); } - // Row + column selector - var columns = this.columns( columnSelector, opts ); - var rows = this.rows( rowSelector, opts ); - var a, i, ien, j, jen; + // The default built in options need to apply to row and columns + var internalOpts = opts ? { + page: opts.page, + order: opts.order, + search: opts.search + } : {}; - var cells = this.iterator( 'table', function ( settings, idx ) { - a = []; + // Row + column selector + var columns = this.columns( columnSelector, internalOpts ); + var rows = this.rows( rowSelector, internalOpts ); + var i, ien, j, jen; + + var cellsNoOpts = this.iterator( 'table', function ( settings, idx ) { + var a = []; for ( i=0, ien=rows[idx].length ; i' ) .appendTo( container ); attach( inner, button ); } else { btnDisplay = null; - btnClass = ''; + btnClass = button; + tabIndex = settings.iTabIndex; switch ( button ) { case 'ellipsis': @@ -14614,30 +14749,42 @@ case 'first': btnDisplay = lang.sFirst; - btnClass = button + (page > 0 ? - '' : ' '+classes.sPageButtonDisabled); + + if ( page === 0 ) { + tabIndex = -1; + btnClass += ' ' + disabledClass; + } break; case 'previous': btnDisplay = lang.sPrevious; - btnClass = button + (page > 0 ? - '' : ' '+classes.sPageButtonDisabled); + + if ( page === 0 ) { + tabIndex = -1; + btnClass += ' ' + disabledClass; + } break; case 'next': btnDisplay = lang.sNext; - btnClass = button + (page < pages-1 ? - '' : ' '+classes.sPageButtonDisabled); + + if ( pages === 0 || page === pages-1 ) { + tabIndex = -1; + btnClass += ' ' + disabledClass; + } break; case 'last': btnDisplay = lang.sLast; - btnClass = button + (page < pages-1 ? - '' : ' '+classes.sPageButtonDisabled); + + if ( pages === 0 || page === pages-1 ) { + tabIndex = -1; + btnClass += ' ' + disabledClass; + } break; default: - btnDisplay = button + 1; + btnDisplay = settings.fnFormatNumber( button + 1 ); btnClass = page === button ? classes.sPageButtonActive : ''; break; @@ -14649,7 +14796,7 @@ 'aria-controls': settings.sTableId, 'aria-label': aria[ button ], 'data-dt-idx': counter, - 'tabindex': settings.iTabIndex, + 'tabindex': tabIndex, 'id': idx === 0 && typeof button === 'string' ? settings.sTableId +'_'+ button : null @@ -14684,7 +14831,7 @@ attach( $(host).empty(), buttons ); if ( activeEl !== undefined ) { - $(host).find( '[data-dt-idx='+activeEl+']' ).focus(); + $(host).find( '[data-dt-idx='+activeEl+']' ).trigger('focus'); } } } @@ -14846,7 +14993,8 @@ $.extend( _ext.type.order, { // Dates "date-pre": function ( d ) { - return Date.parse( d ) || -Infinity; + var ts = Date.parse( d ); + return isNaN(ts) ? -Infinity : ts; }, // html @@ -14904,7 +15052,6 @@ cell .removeClass( - column.sSortingClass +' '+ classes.sSortAsc +' '+ classes.sSortDesc ) @@ -14968,8 +15115,16 @@ */ var __htmlEscapeEntities = function ( d ) { + if (Array.isArray(d)) { + d = d.join(','); + } + return typeof d === 'string' ? - d.replace(//g, '>').replace(/"/g, '"') : + d + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') : d; }; @@ -15025,6 +15180,11 @@ decimal+(d - intPart).toFixed( precision ).substring( 2 ): ''; + // If zero, then can't have a negative prefix + if (intPart === 0 && parseFloat(floatPart) === 0) { + negative = ''; + } + return negative + (prefix||'') + intPart.toString().replace( /\B(?=(\d{3})+(?!\d))/g, thousands @@ -15037,7 +15197,8 @@ text: function () { return { - display: __htmlEscapeEntities + display: __htmlEscapeEntities, + filter: __htmlEscapeEntities }; } }; @@ -15152,6 +15313,7 @@ _fnSortData: _fnSortData, _fnSaveState: _fnSaveState, _fnLoadState: _fnLoadState, + _fnImplementState: _fnImplementState, _fnSettingsFromNode: _fnSettingsFromNode, _fnLog: _fnLog, _fnMap: _fnMap, @@ -15162,6 +15324,7 @@ _fnRenderer: _fnRenderer, _fnDataSource: _fnDataSource, _fnRowAttributes: _fnRowAttributes, + _fnExtend: _fnExtend, _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant // in 1.10, so this dead-end function is // added to prevent errors @@ -15190,195 +15353,14 @@ $.fn.DataTable[ prop ] = val; } ); - - // Information about events fired by DataTables - for documentation. - /** - * Draw event, fired whenever the table is redrawn on the page, at the same - * point as fnDrawCallback. This may be useful for binding events or - * performing calculations when the table is altered at all. - * @name DataTable#draw.dt - * @event - * @param {event} e jQuery event object - * @param {object} o DataTables settings object {@link DataTable.models.oSettings} - */ - - /** - * Search event, fired when the searching applied to the table (using the - * built-in global search, or column filters) is altered. - * @name DataTable#search.dt - * @event - * @param {event} e jQuery event object - * @param {object} o DataTables settings object {@link DataTable.models.oSettings} - */ - - /** - * Page change event, fired when the paging of the table is altered. - * @name DataTable#page.dt - * @event - * @param {event} e jQuery event object - * @param {object} o DataTables settings object {@link DataTable.models.oSettings} - */ - - /** - * Order event, fired when the ordering applied to the table is altered. - * @name DataTable#order.dt - * @event - * @param {event} e jQuery event object - * @param {object} o DataTables settings object {@link DataTable.models.oSettings} - */ - - /** - * DataTables initialisation complete event, fired when the table is fully - * drawn, including Ajax data loaded, if Ajax data is required. - * @name DataTable#init.dt - * @event - * @param {event} e jQuery event object - * @param {object} oSettings DataTables settings object - * @param {object} json The JSON object request from the server - only - * present if client-side Ajax sourced data is used - */ - - /** - * State save event, fired when the table has changed state a new state save - * is required. This event allows modification of the state saving object - * prior to actually doing the save, including addition or other state - * properties (for plug-ins) or modification of a DataTables core property. - * @name DataTable#stateSaveParams.dt - * @event - * @param {event} e jQuery event object - * @param {object} oSettings DataTables settings object - * @param {object} json The state information to be saved - */ - - /** - * State load event, fired when the table is loading state from the stored - * data, but prior to the settings object being modified by the saved state - * - allowing modification of the saved state is required or loading of - * state for a plug-in. - * @name DataTable#stateLoadParams.dt - * @event - * @param {event} e jQuery event object - * @param {object} oSettings DataTables settings object - * @param {object} json The saved state information - */ - - /** - * State loaded event, fired when state has been loaded from stored data and - * the settings object has been modified by the loaded data. - * @name DataTable#stateLoaded.dt - * @event - * @param {event} e jQuery event object - * @param {object} oSettings DataTables settings object - * @param {object} json The saved state information - */ - - /** - * Processing event, fired when DataTables is doing some kind of processing - * (be it, order, searcg or anything else). It can be used to indicate to - * the end user that there is something happening, or that something has - * finished. - * @name DataTable#processing.dt - * @event - * @param {event} e jQuery event object - * @param {object} oSettings DataTables settings object - * @param {boolean} bShow Flag for if DataTables is doing processing or not - */ - - /** - * Ajax (XHR) event, fired whenever an Ajax request is completed from a - * request to made to the server for new data. This event is called before - * DataTables processed the returned data, so it can also be used to pre- - * process the data returned from the server, if needed. - * - * Note that this trigger is called in `fnServerData`, if you override - * `fnServerData` and which to use this event, you need to trigger it in you - * success function. - * @name DataTable#xhr.dt - * @event - * @param {event} e jQuery event object - * @param {object} o DataTables settings object {@link DataTable.models.oSettings} - * @param {object} json JSON returned from the server - * - * @example - * // Use a custom property returned from the server in another DOM element - * $('#table').dataTable().on('xhr.dt', function (e, settings, json) { - * $('#status').html( json.status ); - * } ); - * - * @example - * // Pre-process the data returned from the server - * $('#table').dataTable().on('xhr.dt', function (e, settings, json) { - * for ( var i=0, ien=json.aaData.length ; i= iCols ) - { - this.oApi._fnLog( oSettings, 1, "ColReorder 'from' index is out of bounds: "+iFrom ); - return; - } - - if ( iTo < 0 || iTo >= iCols ) - { - this.oApi._fnLog( oSettings, 1, "ColReorder 'to' index is out of bounds: "+iTo ); - return; - } - - /* - * Calculate the new column array index, so we have a mapping between the old and new - */ - var aiMapping = []; - for ( i=0, iLen=iCols ; i this.s.fixed-1 && i < iLen - this.s.fixedRight ) - { - this._fnMouseListener( i, this.s.dt.aoColumns[i].nTh ); - } - - /* Mark the original column order for later reference */ - this.s.dt.aoColumns[i]._ColReorder_iOrigCol = i; - } - - /* State saving */ - this.s.dt.oApi._fnCallbackReg( this.s.dt, 'aoStateSaveParams', function (oS, oData) { - that._fnStateSave.call( that, oData ); - }, "ColReorder_State" ); - - /* An initial column order has been specified */ - var aiOrder = null; - if ( this.s.init.aiOrder ) - { - aiOrder = this.s.init.aiOrder.slice(); - } - - /* State loading, overrides the column order given */ - if ( this.s.dt.oLoadedState && typeof this.s.dt.oLoadedState.ColReorder != 'undefined' && - this.s.dt.oLoadedState.ColReorder.length == this.s.dt.aoColumns.length ) - { - aiOrder = this.s.dt.oLoadedState.ColReorder; - } - - /* If we have an order to apply - do so */ - if ( aiOrder ) - { - /* We might be called during or after the DataTables initialisation. If before, then we need - * to wait until the draw is done, if after, then do what we need to do right away - */ - if ( !that.s.dt._bInitComplete ) - { - var bDone = false; - $(table).on( 'draw.dt.colReorder', function () { - if ( !that.s.dt._bInitComplete && !bDone ) - { - bDone = true; - var resort = fnInvertKeyValues( aiOrder ); - that._fnOrderColumns.call( that, resort ); - } - } ); - } - else - { - var resort = fnInvertKeyValues( aiOrder ); - that._fnOrderColumns.call( that, resort ); - } - } - else { - this._fnSetColumnIndexes(); - } - - // Destroy clean up - $(table).on( 'destroy.dt.colReorder', function () { - $(table).off( 'destroy.dt.colReorder draw.dt.colReorder' ); - $(that.s.dt.nTHead).find( '*' ).off( '.ColReorder' ); - - $.each( that.s.dt.aoColumns, function (i, column) { - $(column.nTh).removeAttr('data-column-index'); - } ); - - that.s.dt._colReorder = null; - that.s = null; - } ); - }, - - - /** - * Set the column order from an array - * @method _fnOrderColumns - * @param array a An array of integers which dictate the column order that should be applied - * @returns void - * @private - */ - "_fnOrderColumns": function ( a ) - { - var changed = false; - - if ( a.length != this.s.dt.aoColumns.length ) - { - this.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, "ColReorder - array reorder does not "+ - "match known number of columns. Skipping." ); - return; - } - - for ( var i=0, iLen=a.length ; i') - .addClass( 'DTCR_pointer' ) - .css( { - position: 'absolute', - top: scrolling ? - $('div.dataTables_scroll', this.s.dt.nTableWrapper).offset().top : - $(this.s.dt.nTable).offset().top, - height : scrolling ? - $('div.dataTables_scroll', this.s.dt.nTableWrapper).height() : - $(this.s.dt.nTable).height() - } ) - .appendTo( 'body' ); - }, - - - /** - * Add a data attribute to the column headers, so we know the index of - * the row to be reordered. This allows fast detection of the index, and - * for this plug-in to work with FixedHeader which clones the nodes. - * @private - */ - "_fnSetColumnIndexes": function () - { - $.each( this.s.dt.aoColumns, function (i, column) { - $(column.nTh).attr('data-column-index', i); - } ); - }, - - - /** - * Get cursor position regardless of mouse or touch input - * @param {Event} e jQuery Event - * @param {string} prop Property to get - * @return {number} Value - */ - _fnCursorPosition: function ( e, prop ) { - if ( e.type.indexOf('touch') !== -1 ) { - return e.originalEvent.touches[0][ prop ]; - } - return e[ prop ]; - } -} ); - - - - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Static parameters - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -/** - * ColReorder default settings for initialisation - * @namespace - * @static - */ -ColReorder.defaults = { - /** - * Predefined ordering for the columns that will be applied automatically - * on initialisation. If not specified then the order that the columns are - * found to be in the HTML is the order used. - * @type array - * @default null - * @static - */ - aiOrder: null, - - /** - * Redraw the table's column ordering as the end user draws the column - * (`true`) or wait until the mouse is released (`false` - default). Note - * that this will perform a redraw on each reordering, which involves an - * Ajax request each time if you are using server-side processing in - * DataTables. - * @type boolean - * @default false - * @static - */ - bRealtime: true, - - /** - * Indicate how many columns should be fixed in position (counting from the - * left). This will typically be 1 if used, but can be as high as you like. - * @type int - * @default 0 - * @static - */ - iFixedColumnsLeft: 0, - - /** - * As `iFixedColumnsRight` but counting from the right. - * @type int - * @default 0 - * @static - */ - iFixedColumnsRight: 0, - - /** - * Callback function that is fired when columns are reordered. The `column- - * reorder` event is preferred over this callback - * @type function():void - * @default null - * @static - */ - fnReorderCallback: null -}; - - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Constants - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/** - * ColReorder version - * @constant version - * @type String - * @default As code - */ -ColReorder.version = "1.3.3"; - - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * DataTables interfaces - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -// Expose -$.fn.dataTable.ColReorder = ColReorder; -$.fn.DataTable.ColReorder = ColReorder; - - -// Register a new feature with DataTables -if ( typeof $.fn.dataTable == "function" && - typeof $.fn.dataTableExt.fnVersionCheck == "function" && - $.fn.dataTableExt.fnVersionCheck('1.10.8') ) -{ - $.fn.dataTableExt.aoFeatures.push( { - "fnInit": function( settings ) { - var table = settings.oInstance; - - if ( ! settings._colReorder ) { - var dtInit = settings.oInit; - var opts = dtInit.colReorder || dtInit.oColReorder || {}; - - new ColReorder( settings, opts ); - } - else { - table.oApi._fnLog( settings, 1, "ColReorder attempted to initialise twice. Ignoring second" ); - } - - return null; /* No node for DataTables to insert */ - }, - "cFeature": "R", - "sFeature": "ColReorder" - } ); -} -else { - alert( "Warning: ColReorder requires DataTables 1.10.8 or greater - www.datatables.net/download"); -} - - -// Attach a listener to the document which listens for DataTables initialisation -// events so we can automatically initialise -$(document).on( 'preInit.dt.colReorder', function (e, settings) { - if ( e.namespace !== 'dt' ) { - return; - } - - var init = settings.oInit.colReorder; - var defaults = DataTable.defaults.colReorder; - - if ( init || defaults ) { - var opts = $.extend( {}, init, defaults ); - - if ( init !== false ) { - new ColReorder( settings, opts ); - } - } -} ); - - -// API augmentation -$.fn.dataTable.Api.register( 'colReorder.reset()', function () { - return this.iterator( 'table', function ( ctx ) { - ctx._colReorder.fnReset(); - } ); -} ); - -$.fn.dataTable.Api.register( 'colReorder.order()', function ( set, original ) { - if ( set ) { - return this.iterator( 'table', function ( ctx ) { - ctx._colReorder.fnOrder( set, original ); - } ); - } - - return this.context.length ? - this.context[0]._colReorder.fnOrder() : - null; -} ); - -$.fn.dataTable.Api.register( 'colReorder.transpose()', function ( idx, dir ) { - return this.context.length && this.context[0]._colReorder ? - this.context[0]._colReorder.fnTranspose( idx, dir ) : - idx; -} ); - - -return ColReorder; })); -/*! FixedColumns 3.2.2 - * ©2010-2016 SpryMedia Ltd - datatables.net/license +/*! FixedColumns 4.0.1 + * 2019-2021 SpryMedia Ltd - datatables.net/license */ - -/** - * @summary FixedColumns - * @description Freeze columns in place on a scrolling DataTable - * @version 3.2.2 - * @file dataTables.fixedColumns.js - * @author SpryMedia Ltd (www.sprymedia.co.uk) - * @contact www.sprymedia.co.uk/contact - * @copyright Copyright 2010-2016 SpryMedia Ltd. - * - * This source file is free software, available under the following license: - * MIT license - http://datatables.net/license/mit - * - * This source file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. - * - * For details please refer to: http://www.datatables.net - */ -(function( factory ){ - if ( typeof define === 'function' && define.amd ) { - // AMD - define( ['jquery', 'datatables.net'], function ( $ ) { - return factory( $, window, document ); - } ); - } - else if ( typeof exports === 'object' ) { - // CommonJS - module.exports = function (root, $) { - if ( ! root ) { - root = window; - } - - if ( ! $ || ! $.fn.dataTable ) { - $ = require('datatables.net')(root, $).$; - } - - return factory( $, root, root.document ); - }; - } - else { - // Browser - factory( jQuery, window, document ); - } -}(function( $, window, document, undefined ) { -'use strict'; -var DataTable = $.fn.dataTable; -var _firefoxScroll; - -/** - * When making use of DataTables' x-axis scrolling feature, you may wish to - * fix the left most column in place. This plug-in for DataTables provides - * exactly this option (note for non-scrolling tables, please use the - * FixedHeader plug-in, which can fix headers, footers and columns). Key - * features include: - * - * * Freezes the left or right most columns to the side of the table - * * Option to freeze two or more columns - * * Full integration with DataTables' scrolling options - * * Speed - FixedColumns is fast in its operation - * - * @class - * @constructor - * @global - * @param {object} dt DataTables instance. With DataTables 1.10 this can also - * be a jQuery collection, a jQuery selector, DataTables API instance or - * settings object. - * @param {object} [init={}] Configuration object for FixedColumns. Options are - * defined by {@link FixedColumns.defaults} - * - * @requires jQuery 1.7+ - * @requires DataTables 1.8.0+ - * - * @example - * var table = $('#example').dataTable( { - * "scrollX": "100%" - * } ); - * new $.fn.dataTable.fixedColumns( table ); - */ -var FixedColumns = function ( dt, init ) { - var that = this; - - /* Sanity check - you just know it will happen */ - if ( ! ( this instanceof FixedColumns ) ) { - alert( "FixedColumns warning: FixedColumns must be initialised with the 'new' keyword." ); - return; - } - - if ( init === undefined || init === true ) { - init = {}; - } - - // Use the DataTables Hungarian notation mapping method, if it exists to - // provide forwards compatibility for camel case variables - var camelToHungarian = $.fn.dataTable.camelToHungarian; - if ( camelToHungarian ) { - camelToHungarian( FixedColumns.defaults, FixedColumns.defaults, true ); - camelToHungarian( FixedColumns.defaults, init ); - } - - // v1.10 allows the settings object to be got form a number of sources - var dtSettings = new $.fn.dataTable.Api( dt ).settings()[0]; - - /** - * Settings object which contains customisable information for FixedColumns instance - * @namespace - * @extends FixedColumns.defaults - * @private - */ - this.s = { - /** - * DataTables settings objects - * @type object - * @default Obtained from DataTables instance - */ - "dt": dtSettings, - - /** - * Number of columns in the DataTable - stored for quick access - * @type int - * @default Obtained from DataTables instance - */ - "iTableColumns": dtSettings.aoColumns.length, - - /** - * Original outer widths of the columns as rendered by DataTables - used to calculate - * the FixedColumns grid bounding box - * @type array. - * @default [] - */ - "aiOuterWidths": [], - - /** - * Original inner widths of the columns as rendered by DataTables - used to apply widths - * to the columns - * @type array. - * @default [] - */ - "aiInnerWidths": [], - - - /** - * Is the document layout right-to-left - * @type boolean - */ - rtl: $(dtSettings.nTable).css('direction') === 'rtl' - }; - - - /** - * DOM elements used by the class instance - * @namespace - * @private - * - */ - this.dom = { - /** - * DataTables scrolling element - * @type node - * @default null - */ - "scroller": null, - - /** - * DataTables header table - * @type node - * @default null - */ - "header": null, - - /** - * DataTables body table - * @type node - * @default null - */ - "body": null, - - /** - * DataTables footer table - * @type node - * @default null - */ - "footer": null, - - /** - * Display grid elements - * @namespace - */ - "grid": { - /** - * Grid wrapper. This is the container element for the 3x3 grid - * @type node - * @default null - */ - "wrapper": null, - - /** - * DataTables scrolling element. This element is the DataTables - * component in the display grid (making up the main table - i.e. - * not the fixed columns). - * @type node - * @default null - */ - "dt": null, - - /** - * Left fixed column grid components - * @namespace - */ - "left": { - "wrapper": null, - "head": null, - "body": null, - "foot": null - }, - - /** - * Right fixed column grid components - * @namespace - */ - "right": { - "wrapper": null, - "head": null, - "body": null, - "foot": null - } - }, - - /** - * Cloned table nodes - * @namespace - */ - "clone": { - /** - * Left column cloned table nodes - * @namespace - */ - "left": { - /** - * Cloned header table - * @type node - * @default null - */ - "header": null, - - /** - * Cloned body table - * @type node - * @default null - */ - "body": null, - - /** - * Cloned footer table - * @type node - * @default null - */ - "footer": null - }, - - /** - * Right column cloned table nodes - * @namespace - */ - "right": { - /** - * Cloned header table - * @type node - * @default null - */ - "header": null, - - /** - * Cloned body table - * @type node - * @default null - */ - "body": null, - - /** - * Cloned footer table - * @type node - * @default null - */ - "footer": null - } - } - }; - - if ( dtSettings._oFixedColumns ) { - throw 'FixedColumns already initialised on this table'; - } - - /* Attach the instance to the DataTables instance so it can be accessed easily */ - dtSettings._oFixedColumns = this; - - /* Let's do it */ - if ( ! dtSettings._bInitComplete ) - { - dtSettings.oApi._fnCallbackReg( dtSettings, 'aoInitComplete', function () { - that._fnConstruct( init ); - }, 'FixedColumns' ); - } - else - { - this._fnConstruct( init ); - } -}; - - - -$.extend( FixedColumns.prototype , { - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Public methods - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - /** - * Update the fixed columns - including headers and footers. Note that FixedColumns will - * automatically update the display whenever the host DataTable redraws. - * @returns {void} - * @example - * var table = $('#example').dataTable( { - * "scrollX": "100%" - * } ); - * var fc = new $.fn.dataTable.fixedColumns( table ); - * - * // at some later point when the table has been manipulated.... - * fc.fnUpdate(); - */ - "fnUpdate": function () - { - this._fnDraw( true ); - }, - - - /** - * Recalculate the resizes of the 3x3 grid that FixedColumns uses for display of the table. - * This is useful if you update the width of the table container. Note that FixedColumns will - * perform this function automatically when the window.resize event is fired. - * @returns {void} - * @example - * var table = $('#example').dataTable( { - * "scrollX": "100%" - * } ); - * var fc = new $.fn.dataTable.fixedColumns( table ); - * - * // Resize the table container and then have FixedColumns adjust its layout.... - * $('#content').width( 1200 ); - * fc.fnRedrawLayout(); - */ - "fnRedrawLayout": function () - { - this._fnColCalc(); - this._fnGridLayout(); - this.fnUpdate(); - }, - - - /** - * Mark a row such that it's height should be recalculated when using 'semiauto' row - * height matching. This function will have no effect when 'none' or 'auto' row height - * matching is used. - * @param {Node} nTr TR element that should have it's height recalculated - * @returns {void} - * @example - * var table = $('#example').dataTable( { - * "scrollX": "100%" - * } ); - * var fc = new $.fn.dataTable.fixedColumns( table ); - * - * // manipulate the table - mark the row as needing an update then update the table - * // this allows the redraw performed by DataTables fnUpdate to recalculate the row - * // height - * fc.fnRecalculateHeight(); - * table.fnUpdate( $('#example tbody tr:eq(0)')[0], ["insert date", 1, 2, 3 ... ]); - */ - "fnRecalculateHeight": function ( nTr ) - { - delete nTr._DTTC_iHeight; - nTr.style.height = 'auto'; - }, - - - /** - * Set the height of a given row - provides cross browser compatibility - * @param {Node} nTarget TR element that should have it's height recalculated - * @param {int} iHeight Height in pixels to set - * @returns {void} - * @example - * var table = $('#example').dataTable( { - * "scrollX": "100%" - * } ); - * var fc = new $.fn.dataTable.fixedColumns( table ); - * - * // You may want to do this after manipulating a row in the fixed column - * fc.fnSetRowHeight( $('#example tbody tr:eq(0)')[0], 50 ); - */ - "fnSetRowHeight": function ( nTarget, iHeight ) - { - nTarget.style.height = iHeight+"px"; - }, - - - /** - * Get data index information about a row or cell in the table body. - * This function is functionally identical to fnGetPosition in DataTables, - * taking the same parameter (TH, TD or TR node) and returning exactly the - * the same information (data index information). THe difference between - * the two is that this method takes into account the fixed columns in the - * table, so you can pass in nodes from the master table, or the cloned - * tables and get the index position for the data in the main table. - * @param {node} node TR, TH or TD element to get the information about - * @returns {int} If nNode is given as a TR, then a single index is - * returned, or if given as a cell, an array of [row index, column index - * (visible), column index (all)] is given. - */ - "fnGetPosition": function ( node ) - { - var idx; - var inst = this.s.dt.oInstance; - - if ( ! $(node).parents('.DTFC_Cloned').length ) - { - // Not in a cloned table - return inst.fnGetPosition( node ); - } - else - { - // Its in the cloned table, so need to look up position - if ( node.nodeName.toLowerCase() === 'tr' ) { - idx = $(node).index(); - return inst.fnGetPosition( $('tr', this.s.dt.nTBody)[ idx ] ); - } - else - { - var colIdx = $(node).index(); - idx = $(node.parentNode).index(); - var row = inst.fnGetPosition( $('tr', this.s.dt.nTBody)[ idx ] ); - - return [ - row, - colIdx, - inst.oApi._fnVisibleToColumnIndex( this.s.dt, colIdx ) - ]; - } - } - }, - - - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Private methods (they are of course public in JS, but recommended as private) - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - /** - * Initialisation for FixedColumns - * @param {Object} oInit User settings for initialisation - * @returns {void} - * @private - */ - "_fnConstruct": function ( oInit ) - { - var i, iLen, iWidth, - that = this; - - /* Sanity checking */ - if ( typeof this.s.dt.oInstance.fnVersionCheck != 'function' || - this.s.dt.oInstance.fnVersionCheck( '1.8.0' ) !== true ) - { - alert( "FixedColumns "+FixedColumns.VERSION+" required DataTables 1.8.0 or later. "+ - "Please upgrade your DataTables installation" ); - return; - } - - if ( this.s.dt.oScroll.sX === "" ) - { - this.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, "FixedColumns is not needed (no "+ - "x-scrolling in DataTables enabled), so no action will be taken. Use 'FixedHeader' for "+ - "column fixing when scrolling is not enabled" ); - return; - } - - /* Apply the settings from the user / defaults */ - this.s = $.extend( true, this.s, FixedColumns.defaults, oInit ); - - /* Set up the DOM as we need it and cache nodes */ - var classes = this.s.dt.oClasses; - this.dom.grid.dt = $(this.s.dt.nTable).parents('div.'+classes.sScrollWrapper)[0]; - this.dom.scroller = $('div.'+classes.sScrollBody, this.dom.grid.dt )[0]; - - /* Set up the DOM that we want for the fixed column layout grid */ - this._fnColCalc(); - this._fnGridSetup(); - - /* Event handlers */ - var mouseController; - var mouseDown = false; - - // When the mouse is down (drag scroll) the mouse controller cannot - // change, as the browser keeps the original element as the scrolling one - $(this.s.dt.nTableWrapper).on( 'mousedown.DTFC', function () { - mouseDown = true; - - $(document).one( 'mouseup', function () { - mouseDown = false; - } ); - } ); - - // When the body is scrolled - scroll the left and right columns - $(this.dom.scroller) - .on( 'mouseover.DTFC touchstart.DTFC', function () { - if ( ! mouseDown ) { - mouseController = 'main'; - } - } ) - .on( 'scroll.DTFC', function (e) { - if ( ! mouseController && e.originalEvent ) { - mouseController = 'main'; - } - - if ( mouseController === 'main' ) { - if ( that.s.iLeftColumns > 0 ) { - that.dom.grid.left.liner.scrollTop = that.dom.scroller.scrollTop; - } - if ( that.s.iRightColumns > 0 ) { - that.dom.grid.right.liner.scrollTop = that.dom.scroller.scrollTop; - } - } - } ); - - var wheelType = 'onwheel' in document.createElement('div') ? - 'wheel.DTFC' : - 'mousewheel.DTFC'; - - if ( that.s.iLeftColumns > 0 ) { - // When scrolling the left column, scroll the body and right column - $(that.dom.grid.left.liner) - .on( 'mouseover.DTFC touchstart.DTFC', function () { - if ( ! mouseDown ) { - mouseController = 'left'; - } - } ) - .on( 'scroll.DTFC', function ( e ) { - if ( ! mouseController && e.originalEvent ) { - mouseController = 'left'; - } - - if ( mouseController === 'left' ) { - that.dom.scroller.scrollTop = that.dom.grid.left.liner.scrollTop; - if ( that.s.iRightColumns > 0 ) { - that.dom.grid.right.liner.scrollTop = that.dom.grid.left.liner.scrollTop; - } - } - } ) - .on( wheelType, function(e) { - // Pass horizontal scrolling through - var xDelta = e.type === 'wheel' ? - -e.originalEvent.deltaX : - e.originalEvent.wheelDeltaX; - that.dom.scroller.scrollLeft -= xDelta; - } ); - } - - if ( that.s.iRightColumns > 0 ) { - // When scrolling the right column, scroll the body and the left column - $(that.dom.grid.right.liner) - .on( 'mouseover.DTFC touchstart.DTFC', function () { - if ( ! mouseDown ) { - mouseController = 'right'; - } - } ) - .on( 'scroll.DTFC', function ( e ) { - if ( ! mouseController && e.originalEvent ) { - mouseController = 'right'; - } - - if ( mouseController === 'right' ) { - that.dom.scroller.scrollTop = that.dom.grid.right.liner.scrollTop; - if ( that.s.iLeftColumns > 0 ) { - that.dom.grid.left.liner.scrollTop = that.dom.grid.right.liner.scrollTop; - } - } - } ) - .on( wheelType, function(e) { - // Pass horizontal scrolling through - var xDelta = e.type === 'wheel' ? - -e.originalEvent.deltaX : - e.originalEvent.wheelDeltaX; - that.dom.scroller.scrollLeft -= xDelta; - } ); - } - - $(window).on( 'resize.DTFC', function () { - that._fnGridLayout.call( that ); - } ); - - var bFirstDraw = true; - var jqTable = $(this.s.dt.nTable); - - jqTable - .on( 'draw.dt.DTFC', function () { - that._fnColCalc(); - that._fnDraw.call( that, bFirstDraw ); - bFirstDraw = false; - } ) - .on( 'column-sizing.dt.DTFC', function () { - that._fnColCalc(); - that._fnGridLayout( that ); - } ) - .on( 'column-visibility.dt.DTFC', function ( e, settings, column, vis, recalc ) { - if ( recalc === undefined || recalc ) { - that._fnColCalc(); - that._fnGridLayout( that ); - that._fnDraw( true ); - } - } ) - .on( 'select.dt.DTFC deselect.dt.DTFC', function ( e, dt, type, indexes ) { - if ( e.namespace === 'dt' ) { - that._fnDraw( false ); - } - } ) - .on( 'destroy.dt.DTFC', function () { - jqTable.off( '.DTFC' ); - - $(that.dom.scroller).off( '.DTFC' ); - $(window).off( '.DTFC' ); - $(that.s.dt.nTableWrapper).off( '.DTFC' ); - - $(that.dom.grid.left.liner).off( '.DTFC '+wheelType ); - $(that.dom.grid.left.wrapper).remove(); - - $(that.dom.grid.right.liner).off( '.DTFC '+wheelType ); - $(that.dom.grid.right.wrapper).remove(); - } ); - - /* Get things right to start with - note that due to adjusting the columns, there must be - * another redraw of the main table. It doesn't need to be a full redraw however. - */ - this._fnGridLayout(); - this.s.dt.oInstance.fnDraw(false); - }, - - - /** - * Calculate the column widths for the grid layout - * @returns {void} - * @private - */ - "_fnColCalc": function () - { - var that = this; - var iLeftWidth = 0; - var iRightWidth = 0; - - this.s.aiInnerWidths = []; - this.s.aiOuterWidths = []; - - $.each( this.s.dt.aoColumns, function (i, col) { - var th = $(col.nTh); - var border; - - if ( ! th.filter(':visible').length ) { - that.s.aiInnerWidths.push( 0 ); - that.s.aiOuterWidths.push( 0 ); - } - else - { - // Inner width is used to assign widths to cells - // Outer width is used to calculate the container - var iWidth = th.outerWidth(); - - // When working with the left most-cell, need to add on the - // table's border to the outerWidth, since we need to take - // account of it, but it isn't in any cell - if ( that.s.aiOuterWidths.length === 0 ) { - border = $(that.s.dt.nTable).css('border-left-width'); - iWidth += typeof border === 'string' ? 1 : parseInt( border, 10 ); - } - - // Likewise with the final column on the right - if ( that.s.aiOuterWidths.length === that.s.dt.aoColumns.length-1 ) { - border = $(that.s.dt.nTable).css('border-right-width'); - iWidth += typeof border === 'string' ? 1 : parseInt( border, 10 ); - } - - that.s.aiOuterWidths.push( iWidth ); - that.s.aiInnerWidths.push( th.width() ); - - if ( i < that.s.iLeftColumns ) - { - iLeftWidth += iWidth; - } - - if ( that.s.iTableColumns-that.s.iRightColumns <= i ) - { - iRightWidth += iWidth; - } - } - } ); - - this.s.iLeftWidth = iLeftWidth; - this.s.iRightWidth = iRightWidth; - }, - - - /** - * Set up the DOM for the fixed column. The way the layout works is to create a 1x3 grid - * for the left column, the DataTable (for which we just reuse the scrolling element DataTable - * puts into the DOM) and the right column. In each of he two fixed column elements there is a - * grouping wrapper element and then a head, body and footer wrapper. In each of these we then - * place the cloned header, body or footer tables. This effectively gives as 3x3 grid structure. - * @returns {void} - * @private - */ - "_fnGridSetup": function () - { - var that = this; - var oOverflow = this._fnDTOverflow(); - var block; - - this.dom.body = this.s.dt.nTable; - this.dom.header = this.s.dt.nTHead.parentNode; - this.dom.header.parentNode.parentNode.style.position = "relative"; - - var nSWrapper = - $('
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    ')[0]; - var nLeft = nSWrapper.childNodes[0]; - var nRight = nSWrapper.childNodes[1]; - - this.dom.grid.dt.parentNode.insertBefore( nSWrapper, this.dom.grid.dt ); - nSWrapper.appendChild( this.dom.grid.dt ); - - this.dom.grid.wrapper = nSWrapper; - - if ( this.s.iLeftColumns > 0 ) - { - this.dom.grid.left.wrapper = nLeft; - this.dom.grid.left.head = nLeft.childNodes[0]; - this.dom.grid.left.body = nLeft.childNodes[1]; - this.dom.grid.left.liner = $('div.DTFC_LeftBodyLiner', nSWrapper)[0]; - - nSWrapper.appendChild( nLeft ); - } - - if ( this.s.iRightColumns > 0 ) - { - this.dom.grid.right.wrapper = nRight; - this.dom.grid.right.head = nRight.childNodes[0]; - this.dom.grid.right.body = nRight.childNodes[1]; - this.dom.grid.right.liner = $('div.DTFC_RightBodyLiner', nSWrapper)[0]; - - nRight.style.right = oOverflow.bar+"px"; - - block = $('div.DTFC_RightHeadBlocker', nSWrapper)[0]; - block.style.width = oOverflow.bar+"px"; - block.style.right = -oOverflow.bar+"px"; - this.dom.grid.right.headBlock = block; - - block = $('div.DTFC_RightFootBlocker', nSWrapper)[0]; - block.style.width = oOverflow.bar+"px"; - block.style.right = -oOverflow.bar+"px"; - this.dom.grid.right.footBlock = block; - - nSWrapper.appendChild( nRight ); - } - - if ( this.s.dt.nTFoot ) - { - this.dom.footer = this.s.dt.nTFoot.parentNode; - if ( this.s.iLeftColumns > 0 ) - { - this.dom.grid.left.foot = nLeft.childNodes[2]; - } - if ( this.s.iRightColumns > 0 ) - { - this.dom.grid.right.foot = nRight.childNodes[2]; - } - } - - // RTL support - swap the position of the left and right columns (#48) - if ( this.s.rtl ) { - $('div.DTFC_RightHeadBlocker', nSWrapper).css( { - left: -oOverflow.bar+'px', - right: '' - } ); - } - }, - - - /** - * Style and position the grid used for the FixedColumns layout - * @returns {void} - * @private - */ - "_fnGridLayout": function () - { - var that = this; - var oGrid = this.dom.grid; - var iWidth = $(oGrid.wrapper).width(); - var iBodyHeight = $(this.s.dt.nTable.parentNode).outerHeight(); - var iFullHeight = $(this.s.dt.nTable.parentNode.parentNode).outerHeight(); - var oOverflow = this._fnDTOverflow(); - var iLeftWidth = this.s.iLeftWidth; - var iRightWidth = this.s.iRightWidth; - var rtl = $(this.dom.body).css('direction') === 'rtl'; - var wrapper; - var scrollbarAdjust = function ( node, width ) { - if ( ! oOverflow.bar ) { - // If there is no scrollbar (Macs) we need to hide the auto scrollbar - node.style.width = (width+20)+"px"; - node.style.paddingRight = "20px"; - node.style.boxSizing = "border-box"; - } - else if ( that._firefoxScrollError() ) { - // See the above function for why this is required - if ( $(node).height() > 34 ) { - node.style.width = (width+oOverflow.bar)+"px"; - } - } - else { - // Otherwise just overflow by the scrollbar - node.style.width = (width+oOverflow.bar)+"px"; - } - }; - - // When x scrolling - don't paint the fixed columns over the x scrollbar - if ( oOverflow.x ) - { - iBodyHeight -= oOverflow.bar; - } - - oGrid.wrapper.style.height = iFullHeight+"px"; - - if ( this.s.iLeftColumns > 0 ) - { - wrapper = oGrid.left.wrapper; - wrapper.style.width = iLeftWidth+'px'; - wrapper.style.height = '1px'; - - // Swap the position of the left and right columns for rtl (#48) - // This is always up against the edge, scrollbar on the far side - if ( rtl ) { - wrapper.style.left = ''; - wrapper.style.right = 0; - } - else { - wrapper.style.left = 0; - wrapper.style.right = ''; - } - - oGrid.left.body.style.height = iBodyHeight+"px"; - if ( oGrid.left.foot ) { - oGrid.left.foot.style.top = (oOverflow.x ? oOverflow.bar : 0)+"px"; // shift footer for scrollbar - } - - scrollbarAdjust( oGrid.left.liner, iLeftWidth ); - oGrid.left.liner.style.height = iBodyHeight+"px"; - } - - if ( this.s.iRightColumns > 0 ) - { - wrapper = oGrid.right.wrapper; - wrapper.style.width = iRightWidth+'px'; - wrapper.style.height = '1px'; - - // Need to take account of the vertical scrollbar - if ( this.s.rtl ) { - wrapper.style.left = oOverflow.y ? oOverflow.bar+'px' : 0; - wrapper.style.right = ''; - } - else { - wrapper.style.left = ''; - wrapper.style.right = oOverflow.y ? oOverflow.bar+'px' : 0; - } - - oGrid.right.body.style.height = iBodyHeight+"px"; - if ( oGrid.right.foot ) { - oGrid.right.foot.style.top = (oOverflow.x ? oOverflow.bar : 0)+"px"; - } - - scrollbarAdjust( oGrid.right.liner, iRightWidth ); - oGrid.right.liner.style.height = iBodyHeight+"px"; - - oGrid.right.headBlock.style.display = oOverflow.y ? 'block' : 'none'; - oGrid.right.footBlock.style.display = oOverflow.y ? 'block' : 'none'; - } - }, - - - /** - * Get information about the DataTable's scrolling state - specifically if the table is scrolling - * on either the x or y axis, and also the scrollbar width. - * @returns {object} Information about the DataTables scrolling state with the properties: - * 'x', 'y' and 'bar' - * @private - */ - "_fnDTOverflow": function () - { - var nTable = this.s.dt.nTable; - var nTableScrollBody = nTable.parentNode; - var out = { - "x": false, - "y": false, - "bar": this.s.dt.oScroll.iBarWidth - }; - - if ( nTable.offsetWidth > nTableScrollBody.clientWidth ) - { - out.x = true; - } - - if ( nTable.offsetHeight > nTableScrollBody.clientHeight ) - { - out.y = true; - } - - return out; - }, - - - /** - * Clone and position the fixed columns - * @returns {void} - * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true) - * @private - */ - "_fnDraw": function ( bAll ) - { - this._fnGridLayout(); - this._fnCloneLeft( bAll ); - this._fnCloneRight( bAll ); - - /* Draw callback function */ - if ( this.s.fnDrawCallback !== null ) - { - this.s.fnDrawCallback.call( this, this.dom.clone.left, this.dom.clone.right ); - } - - /* Event triggering */ - $(this).trigger( 'draw.dtfc', { - "leftClone": this.dom.clone.left, - "rightClone": this.dom.clone.right - } ); - }, - - - /** - * Clone the right columns - * @returns {void} - * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true) - * @private - */ - "_fnCloneRight": function ( bAll ) - { - if ( this.s.iRightColumns <= 0 ) { - return; - } - - var that = this, - i, jq, - aiColumns = []; - - for ( i=this.s.iTableColumns-this.s.iRightColumns ; ithead', oClone.header); - jqCloneThead.empty(); - - /* Add the created cloned TR elements to the table */ - for ( i=0, iLen=aoCloneLayout.length ; ithead', oClone.header)[0] ); - - for ( i=0, iLen=aoCloneLayout.length ; itbody>tr', that.dom.body).css('height', 'auto'); - } - - if ( oClone.body !== null ) - { - $(oClone.body).remove(); - oClone.body = null; - } - - oClone.body = $(this.dom.body).clone(true)[0]; - oClone.body.className += " DTFC_Cloned"; - oClone.body.style.paddingBottom = dt.oScroll.iBarWidth+"px"; - oClone.body.style.marginBottom = (dt.oScroll.iBarWidth*2)+"px"; /* For IE */ - if ( oClone.body.getAttribute('id') !== null ) - { - oClone.body.removeAttribute('id'); - } - - $('>thead>tr', oClone.body).empty(); - $('>tfoot', oClone.body).remove(); - - var nBody = $('tbody', oClone.body)[0]; - $(nBody).empty(); - if ( dt.aiDisplay.length > 0 ) - { - /* Copy the DataTables' header elements to force the column width in exactly the - * same way that DataTables does it - have the header element, apply the width and - * colapse it down - */ - var nInnerThead = $('>thead>tr', oClone.body)[0]; - for ( iIndex=0 ; iIndextbody>tr', that.dom.body).each( function (z) { - var i = that.s.dt.oFeatures.bServerSide===false ? - that.s.dt.aiDisplay[ that.s.dt._iDisplayStart+z ] : z; - var aTds = that.s.dt.aoData[ i ].anCells || $(this).children('td, th'); - - var n = this.cloneNode(false); - n.removeAttribute('id'); - n.setAttribute( 'data-dt-row', i ); - - for ( iIndex=0 ; iIndex 0 ) - { - nClone = $( aTds[iColumn] ).clone(true, true)[0]; - nClone.setAttribute( 'data-dt-row', i ); - nClone.setAttribute( 'data-dt-column', iIndex ); - n.appendChild( nClone ); - } - } - nBody.appendChild( n ); - } ); - } - else - { - $('>tbody>tr', that.dom.body).each( function (z) { - nClone = this.cloneNode(true); - nClone.className += ' DTFC_NoData'; - $('td', nClone).html(''); - nBody.appendChild( nClone ); - } ); - } - - oClone.body.style.width = "100%"; - oClone.body.style.margin = "0"; - oClone.body.style.padding = "0"; - - // Interop with Scroller - need to use a height forcing element in the - // scrolling area in the same way that Scroller does in the body scroll. - if ( dt.oScroller !== undefined ) - { - var scrollerForcer = dt.oScroller.dom.force; - - if ( ! oGrid.forcer ) { - oGrid.forcer = scrollerForcer.cloneNode( true ); - oGrid.liner.appendChild( oGrid.forcer ); - } - else { - oGrid.forcer.style.height = scrollerForcer.style.height; - } - } - - oGrid.liner.appendChild( oClone.body ); - - this._fnEqualiseHeights( 'tbody', that.dom.body, oClone.body ); - - /* - * Footer - */ - if ( dt.nTFoot !== null ) - { - if ( bAll ) - { - if ( oClone.footer !== null ) - { - oClone.footer.parentNode.removeChild( oClone.footer ); - } - oClone.footer = $(this.dom.footer).clone(true, true)[0]; - oClone.footer.className += " DTFC_Cloned"; - oClone.footer.style.width = "100%"; - oGrid.foot.appendChild( oClone.footer ); - - /* Copy the footer just like we do for the header */ - aoCloneLayout = this._fnCopyLayout( dt.aoFooter, aiColumns, true ); - var jqCloneTfoot = $('>tfoot', oClone.footer); - jqCloneTfoot.empty(); - - for ( i=0, iLen=aoCloneLayout.length ; itfoot', oClone.footer)[0] ); - - for ( i=0, iLen=aoCloneLayout.length ; ithead', oClone.header)[0] ); - $(anUnique).each( function (i) { - iColumn = aiColumns[i]; - this.style.width = that.s.aiInnerWidths[iColumn]+"px"; - } ); - - if ( that.s.dt.nTFoot !== null ) - { - anUnique = dt.oApi._fnGetUniqueThs( dt, $('>tfoot', oClone.footer)[0] ); - $(anUnique).each( function (i) { - iColumn = aiColumns[i]; - this.style.width = that.s.aiInnerWidths[iColumn]+"px"; - } ); - } - }, - - - /** - * From a given table node (THEAD etc), get a list of TR direct child elements - * @param {Node} nIn Table element to search for TR elements (THEAD, TBODY or TFOOT element) - * @returns {Array} List of TR elements found - * @private - */ - "_fnGetTrNodes": function ( nIn ) - { - var aOut = []; - for ( var i=0, iLen=nIn.childNodes.length ; i'+nodeName+'>tr:eq(0)', original).children(':first'), - iBoxHack = jqBoxHack.outerHeight() - jqBoxHack.height(), - anOriginal = this._fnGetTrNodes( rootOriginal ), - anClone = this._fnGetTrNodes( rootClone ), - heights = []; - - for ( i=0, iLen=anClone.length ; i iHeightOriginal ? iHeightClone : iHeightOriginal; - - if ( this.s.sHeightMatch == 'semiauto' ) - { - anOriginal[i]._DTTC_iHeight = iHeight; - } - - heights.push( iHeight ); - } - - for ( i=0, iLen=anClone.length ; i') - .css( { - position: 'absolute', - top: 0, - left: 0, - height: 10, - width: 50, - overflow: 'scroll' - } ) - .appendTo( 'body' ); - - // Make sure this doesn't apply on Macs with 0 width scrollbars - _firefoxScroll = ( - test[0].clientWidth === test[0].offsetWidth && this._fnDTOverflow().bar !== 0 - ); - - test.remove(); - } - - return _firefoxScroll; - } -} ); - - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Statics - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/** - * FixedColumns default settings for initialisation - * @name FixedColumns.defaults - * @namespace - * @static - */ -FixedColumns.defaults = /** @lends FixedColumns.defaults */{ - /** - * Number of left hand columns to fix in position - * @type int - * @default 1 - * @static - * @example - * var = $('#example').dataTable( { - * "scrollX": "100%" - * } ); - * new $.fn.dataTable.fixedColumns( table, { - * "leftColumns": 2 - * } ); - */ - "iLeftColumns": 1, - - /** - * Number of right hand columns to fix in position - * @type int - * @default 0 - * @static - * @example - * var table = $('#example').dataTable( { - * "scrollX": "100%" - * } ); - * new $.fn.dataTable.fixedColumns( table, { - * "rightColumns": 1 - * } ); - */ - "iRightColumns": 0, - - /** - * Draw callback function which is called when FixedColumns has redrawn the fixed assets - * @type function(object, object):void - * @default null - * @static - * @example - * var table = $('#example').dataTable( { - * "scrollX": "100%" - * } ); - * new $.fn.dataTable.fixedColumns( table, { - * "drawCallback": function () { - * alert( "FixedColumns redraw" ); - * } - * } ); - */ - "fnDrawCallback": null, - - /** - * Height matching algorthim to use. This can be "none" which will result in no height - * matching being applied by FixedColumns (height matching could be forced by CSS in this - * case), "semiauto" whereby the height calculation will be performed once, and the result - * cached to be used again (fnRecalculateHeight can be used to force recalculation), or - * "auto" when height matching is performed on every draw (slowest but must accurate) - * @type string - * @default semiauto - * @static - * @example - * var table = $('#example').dataTable( { - * "scrollX": "100%" - * } ); - * new $.fn.dataTable.fixedColumns( table, { - * "heightMatch": "auto" - * } ); - */ - "sHeightMatch": "semiauto" -}; - - - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Constants - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/** - * FixedColumns version - * @name FixedColumns.version - * @type String - * @default See code - * @static - */ -FixedColumns.version = "3.2.2"; - - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * DataTables API integration - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -DataTable.Api.register( 'fixedColumns()', function () { - return this; -} ); - -DataTable.Api.register( 'fixedColumns().update()', function () { - return this.iterator( 'table', function ( ctx ) { - if ( ctx._oFixedColumns ) { - ctx._oFixedColumns.fnUpdate(); - } - } ); -} ); - -DataTable.Api.register( 'fixedColumns().relayout()', function () { - return this.iterator( 'table', function ( ctx ) { - if ( ctx._oFixedColumns ) { - ctx._oFixedColumns.fnRedrawLayout(); - } - } ); -} ); - -DataTable.Api.register( 'rows().recalcHeight()', function () { - return this.iterator( 'row', function ( ctx, idx ) { - if ( ctx._oFixedColumns ) { - ctx._oFixedColumns.fnRecalculateHeight( this.row(idx).node() ); - } - } ); -} ); - -DataTable.Api.register( 'fixedColumns().rowIndex()', function ( row ) { - row = $(row); - - return row.parents('.DTFC_Cloned').length ? - this.rows( { page: 'current' } ).indexes()[ row.index() ] : - this.row( row ).index(); -} ); - -DataTable.Api.register( 'fixedColumns().cellIndex()', function ( cell ) { - cell = $(cell); - - if ( cell.parents('.DTFC_Cloned').length ) { - var rowClonedIdx = cell.parent().index(); - var rowIdx = this.rows( { page: 'current' } ).indexes()[ rowClonedIdx ]; - var columnIdx; - - if ( cell.parents('.DTFC_LeftWrapper').length ) { - columnIdx = cell.index(); - } - else { - var columns = this.columns().flatten().length; - columnIdx = columns - this.context[0]._oFixedColumns.s.iRightColumns + cell.index(); - } - - return { - row: rowIdx, - column: this.column.index( 'toData', columnIdx ), - columnVisible: columnIdx - }; - } - else { - return this.cell( cell ).index(); - } -} ); - - - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Initialisation - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -// Attach a listener to the document which listens for DataTables initialisation -// events so we can automatically initialise -$(document).on( 'init.dt.fixedColumns', function (e, settings) { - if ( e.namespace !== 'dt' ) { - return; - } - - var init = settings.oInit.fixedColumns; - var defaults = DataTable.defaults.fixedColumns; - - if ( init || defaults ) { - var opts = $.extend( {}, init, defaults ); - - if ( init !== false ) { - new FixedColumns( settings, opts ); - } - } -} ); - - - -// Make FixedColumns accessible from the DataTables instance -$.fn.dataTable.FixedColumns = FixedColumns; -$.fn.DataTable.FixedColumns = FixedColumns; - -return FixedColumns; -})); - - -/*! FixedHeader 3.1.2 - * ©2009-2016 SpryMedia Ltd - datatables.net/license +(function () { + 'use strict'; + + var $; + var dataTable; + function setJQuery(jq) { + $ = jq; + dataTable = $.fn.dataTable; + } + var FixedColumns = /** @class */ (function () { + function FixedColumns(settings, opts) { + var _this = this; + // Check that the required version of DataTables is included + if (!dataTable || !dataTable.versionCheck || !dataTable.versionCheck('1.10.0')) { + throw new Error('StateRestore requires DataTables 1.10 or newer'); + } + var table = new dataTable.Api(settings); + this.classes = $.extend(true, {}, FixedColumns.classes); + // Get options from user + this.c = $.extend(true, {}, FixedColumns.defaults, opts); + // Backwards compatibility for deprecated leftColumns + if (opts.left === undefined && this.c.leftColumns !== undefined) { + this.c.left = this.c.leftColumns; + } + // Backwards compatibility for deprecated rightColumns + if (opts.right === undefined && this.c.rightColumns !== undefined) { + this.c.right = this.c.rightColumns; + } + this.s = { + barWidth: 0, + dt: table, + rtl: $(table.table().node()).css('direction') === 'rtl' + }; + // Common CSS for all blockers + var blockerCSS = { + 'background-color': 'white', + 'bottom': '0px', + 'display': 'block', + 'position': 'absolute', + 'width': this.s.barWidth + 1 + 'px' + }; + this.dom = { + leftBottomBlocker: $('
    ') + .css(blockerCSS) + .css('left', 0) + .addClass(this.classes.leftBottomBlocker), + leftTopBlocker: $('
    ') + .css(blockerCSS) + .css({ + left: 0, + top: 0 + }) + .addClass(this.classes.leftTopBlocker), + rightBottomBlocker: $('
    ') + .css(blockerCSS) + .css('right', 0) + .addClass(this.classes.rightBottomBlocker), + rightTopBlocker: $('
    ') + .css(blockerCSS) + .css({ + right: 0, + top: 0 + }) + .addClass(this.classes.rightTopBlocker) + }; + if (this.s.dt.settings()[0]._bInitComplete) { + // Fixed Columns Initialisation + this._addStyles(); + this._setKeyTableListener(); + } + else { + table.one('preInit.dt', function () { + // Fixed Columns Initialisation + _this._addStyles(); + _this._setKeyTableListener(); + }); + } + // Make class available through dt object + table.settings()[0]._fixedColumns = this; + return this; + } + /** + * Getter/Setter for the `fixedColumns.left` property + * + * @param newVal Optional. If present this will be the new value for the number of left fixed columns + * @returns The number of left fixed columns + */ + FixedColumns.prototype.left = function (newVal) { + // If the value is to change + if (newVal !== undefined) { + // Set the new values and redraw the columns + this.c.left = newVal; + this._addStyles(); + } + return this.c.left; + }; + /** + * Getter/Setter for the `fixedColumns.left` property + * + * @param newVal Optional. If present this will be the new value for the number of right fixed columns + * @returns The number of right fixed columns + */ + FixedColumns.prototype.right = function (newVal) { + // If the value is to change + if (newVal !== undefined) { + // Set the new values and redraw the columns + this.c.right = newVal; + this._addStyles(); + } + return this.c.right; + }; + /** + * Iterates over the columns, fixing the appropriate ones to the left and right + */ + FixedColumns.prototype._addStyles = function () { + // Set the bar width if vertical scrolling is enabled + if (this.s.dt.settings()[0].oScroll.sY) { + var scroll_1 = $(this.s.dt.table().node()).closest('div.dataTables_scrollBody')[0]; + var barWidth = this.s.dt.settings()[0].oBrowser.barWidth; + if (scroll_1.offsetWidth - scroll_1.clientWidth >= barWidth) { + this.s.barWidth = barWidth; + } + else { + this.s.barWidth = 0; + } + this.dom.rightTopBlocker.css('width', this.s.barWidth + 1); + this.dom.leftTopBlocker.css('width', this.s.barWidth + 1); + this.dom.rightBottomBlocker.css('width', this.s.barWidth + 1); + this.dom.leftBottomBlocker.css('width', this.s.barWidth + 1); + } + var parentDiv = null; + // Get the header and it's height + var header = this.s.dt.column(0).header(); + var headerHeight = null; + if (header !== null) { + header = $(header); + headerHeight = header.outerHeight() + 1; + parentDiv = $(header.closest('div.dataTables_scroll')).css('position', 'relative'); + } + // Get the footer and it's height + var footer = this.s.dt.column(0).footer(); + var footerHeight = null; + if (footer !== null) { + footer = $(footer); + footerHeight = footer.outerHeight(); + // Only attempt to retrieve the parentDiv if it has not been retrieved already + if (parentDiv === null) { + parentDiv = $(footer.closest('div.dataTables_scroll')).css('position', 'relative'); + } + } + // Get the number of columns in the table - this is used often so better to only make 1 api call + var numCols = this.s.dt.columns().data().toArray().length; + // Tracker for the number of pixels should be left to the left of the table + var distLeft = 0; + // Sometimes the headers have slightly different widths so need to track them individually + var headLeft = 0; + // Get all of the row elements in the table + var rows = $(this.s.dt.table().node()).children('tbody').children('tr'); + var invisibles = 0; + // When working from right to left we need to know how many are invisible before a point, + // without including those that are invisible after + var prevInvisible = new Map(); + // Iterate over all of the columns + for (var i = 0; i < numCols; i++) { + var column = this.s.dt.column(i); + // Set the map for the previous column + if (i > 0) { + prevInvisible.set(i - 1, invisibles); + } + if (!column.visible()) { + invisibles++; + continue; + } + // Get the columns header and footer element + var colHeader = $(column.header()); + var colFooter = $(column.footer()); + // If i is less than the value of left then this column should be fixed left + if (i - invisibles < this.c.left) { + $(this.s.dt.table().node()).addClass(this.classes.tableFixedLeft); + parentDiv.addClass(this.classes.tableFixedLeft); + // Add the width of the previous node - only if we are on atleast the second column + if (i - invisibles > 0) { + var prevIdx = i; + // Simply using the number of hidden columns doesn't work here, + // if the first is hidden then this would be thrown off + while (prevIdx + 1 < numCols) { + var prevCol = this.s.dt.column(prevIdx - 1, { page: 'current' }); + if (prevCol.visible()) { + distLeft += $(prevCol.nodes()[0]).outerWidth(); + headLeft += prevCol.header() ? + $(prevCol.header()).outerWidth() : + prevCol.footer() ? + $(prevCol.header()).outerWidth() : + 0; + break; + } + prevIdx--; + } + } + // Iterate over all of the rows, fixing the cell to the left + for (var _i = 0, rows_1 = rows; _i < rows_1.length; _i++) { + var row = rows_1[_i]; + $($(row).children()[i - invisibles]) + .css(this._getCellCSS(false, distLeft, 'left')) + .addClass(this.classes.fixedLeft); + } + // Add the css for the header and the footer + colHeader + .css(this._getCellCSS(true, headLeft, 'left')) + .addClass(this.classes.fixedLeft); + colFooter + .css(this._getCellCSS(true, headLeft, 'left')) + .addClass(this.classes.fixedLeft); + } + else { + // Iteriate through all of the rows, making sure they aren't currently trying to fix left + for (var _a = 0, rows_2 = rows; _a < rows_2.length; _a++) { + var row = rows_2[_a]; + var cell = $($(row).children()[i - invisibles]); + // If the cell is trying to fix to the left, remove the class and the css + if (cell.hasClass(this.classes.fixedLeft)) { + cell + .css(this._clearCellCSS('left')) + .removeClass(this.classes.fixedLeft); + } + } + // Make sure the header for this column isn't fixed left + if (colHeader.hasClass(this.classes.fixedLeft)) { + colHeader + .css(this._clearCellCSS('left')) + .removeClass(this.classes.fixedLeft); + } + // Make sure the footer for this column isn't fixed left + if (colFooter.hasClass(this.classes.fixedLeft)) { + colFooter + .css(this._clearCellCSS('left')) + .removeClass(this.classes.fixedLeft); + } + } + } + // If there is a header with the index class and reading rtl then add left top blocker + if (header !== null && !header.hasClass('index')) { + if (this.s.rtl) { + this.dom.leftTopBlocker.outerHeight(headerHeight); + parentDiv.append(this.dom.leftTopBlocker); + } + else { + this.dom.rightTopBlocker.outerHeight(headerHeight); + parentDiv.append(this.dom.rightTopBlocker); + } + } + // If there is a footer with the index class and reading rtl then add left bottom blocker + if (footer !== null && !footer.hasClass('index')) { + if (this.s.rtl) { + this.dom.leftBottomBlocker.outerHeight(footerHeight); + parentDiv.append(this.dom.leftBottomBlocker); + } + else { + this.dom.rightBottomBlocker.outerHeight(footerHeight); + parentDiv.append(this.dom.rightBottomBlocker); + } + } + var distRight = 0; + var headRight = 0; + // Counter for the number of invisible columns so far + var rightInvisibles = 0; + for (var i = numCols - 1; i >= 0; i--) { + var column = this.s.dt.column(i); + // If a column is invisible just skip it + if (!column.visible()) { + rightInvisibles++; + continue; + } + // Get the columns header and footer element + var colHeader = $(column.header()); + var colFooter = $(column.footer()); + // Get the number of visible columns that came before this one + var prev = prevInvisible.get(i); + if (prev === undefined) { + // If it wasn't set then it was the last column so just use the final value + prev = invisibles; + } + if (i + rightInvisibles >= numCols - this.c.right) { + $(this.s.dt.table().node()).addClass(this.classes.tableFixedRight); + parentDiv.addClass(this.classes.tableFixedRight); + // Add the widht of the previous node, only if we are on atleast the second column + if (i + 1 + rightInvisibles < numCols) { + var prevIdx = i; + // Simply using the number of hidden columns doesn't work here, + // if the first is hidden then this would be thrown off + while (prevIdx + 1 < numCols) { + var prevCol = this.s.dt.column(prevIdx + 1, { page: 'current' }); + if (prevCol.visible()) { + distRight += $(prevCol.nodes()[0]).outerWidth(); + headRight += prevCol.header() ? + $(prevCol.header()).outerWidth() : + prevCol.footer() ? + $(prevCol.header()).outerWidth() : + 0; + break; + } + prevIdx++; + } + } + // Iterate over all of the rows, fixing the cell to the right + for (var _b = 0, rows_3 = rows; _b < rows_3.length; _b++) { + var row = rows_3[_b]; + $($(row).children()[i - prev]) + .css(this._getCellCSS(false, distRight, 'right')) + .addClass(this.classes.fixedRight); + } + // Add the css for the header and the footer + colHeader + .css(this._getCellCSS(true, headRight, 'right')) + .addClass(this.classes.fixedRight); + colFooter + .css(this._getCellCSS(true, headRight, 'right')) + .addClass(this.classes.fixedRight); + } + else { + // Iteriate through all of the rows, making sure they aren't currently trying to fix right + for (var _c = 0, rows_4 = rows; _c < rows_4.length; _c++) { + var row = rows_4[_c]; + var cell = $($(row).children()[i - prev]); + // If the cell is trying to fix to the right, remove the class and the css + if (cell.hasClass(this.classes.fixedRight)) { + cell + .css(this._clearCellCSS('right')) + .removeClass(this.classes.fixedRight); + } + } + // Make sure the header for this column isn't fixed right + if (colHeader.hasClass(this.classes.fixedRight)) { + colHeader + .css(this._clearCellCSS('right')) + .removeClass(this.classes.fixedRight); + } + // Make sure the footer for this column isn't fixed right + if (colFooter.hasClass(this.classes.fixedRight)) { + colFooter + .css(this._clearCellCSS('right')) + .removeClass(this.classes.fixedRight); + } + } + } + // If there is a header with the index class and reading rtl then add right top blocker + if (header) { + if (!this.s.rtl) { + this.dom.rightTopBlocker.outerHeight(headerHeight); + parentDiv.append(this.dom.rightTopBlocker); + } + else { + this.dom.leftTopBlocker.outerHeight(headerHeight); + parentDiv.append(this.dom.leftTopBlocker); + } + } + // If there is a footer with the index class and reading rtl then add right bottom blocker + if (footer) { + if (!this.s.rtl) { + this.dom.rightBottomBlocker.outerHeight(footerHeight); + parentDiv.append(this.dom.rightBottomBlocker); + } + else { + this.dom.leftBottomBlocker.outerHeight(footerHeight); + parentDiv.append(this.dom.leftBottomBlocker); + } + } + }; + /** + * Gets the correct CSS for the cell, header or footer based on options provided + * + * @param header Whether this cell is a header or a footer + * @param dist The distance that the cell should be moved away from the edge + * @param lr Indicator of fixing to the left or the right + * @returns An object containing the correct css + */ + FixedColumns.prototype._getCellCSS = function (header, dist, lr) { + if (lr === 'left') { + return !this.s.rtl ? + { + left: dist + 'px', + position: 'sticky' + } : + { + position: 'sticky', + right: dist + (header ? this.s.barWidth : 0) + 'px' + }; + } + else { + return !this.s.rtl ? + { + position: 'sticky', + right: dist + (header ? this.s.barWidth : 0) + 'px' + } : + { + left: dist + 'px', + position: 'sticky' + }; + } + }; + /** + * Gets the css that is required to clear the fixing to a side + * + * @param lr Indicator of fixing to the left or the right + * @returns An object containing the correct css + */ + FixedColumns.prototype._clearCellCSS = function (lr) { + if (lr === 'left') { + return !this.s.rtl ? + { + left: '', + position: '' + } : + { + position: '', + right: '' + }; + } + else { + return !this.s.rtl ? + { + position: '', + right: '' + } : + { + left: '', + position: '' + }; + } + }; + FixedColumns.prototype._setKeyTableListener = function () { + var _this = this; + this.s.dt.on('key-focus', function (e, dt, cell) { + var cellPos = $(cell.node()).offset(); + var scroll = $($(_this.s.dt.table().node()).closest('div.dataTables_scrollBody')); + // If there are fixed columns to the left + if (_this.c.left > 0) { + // Get the rightmost left fixed column header, it's position and it's width + var rightMost = $(_this.s.dt.column(_this.c.left - 1).header()); + var rightMostPos = rightMost.offset(); + var rightMostWidth = rightMost.outerWidth(); + // If the current highlighted cell is left of the rightmost cell on the screen + if (cellPos.left < rightMostPos.left + rightMostWidth) { + // Scroll it into view + var currScroll = scroll.scrollLeft(); + scroll.scrollLeft(currScroll - (rightMostPos.left + rightMostWidth - cellPos.left)); + } + } + // If there are fixed columns to the right + if (_this.c.right > 0) { + // Get the number of columns and the width of the cell as doing right side calc + var numCols = _this.s.dt.columns().data().toArray().length; + var cellWidth = $(cell.node()).outerWidth(); + // Get the leftmost right fixed column header and it's position + var leftMost = $(_this.s.dt.column(numCols - _this.c.right).header()); + var leftMostPos = leftMost.offset(); + // If the current highlighted cell is right of the leftmost cell on the screen + if (cellPos.left + cellWidth > leftMostPos.left) { + // Scroll it into view + var currScroll = scroll.scrollLeft(); + scroll.scrollLeft(currScroll - (leftMostPos.left - (cellPos.left + cellWidth))); + } + } + }); + // Whenever a draw occurs there is potential for the data to have changed and therefore also the column widths + // Therefore it is necessary to recalculate the values for the fixed columns + this.s.dt.on('draw', function () { + _this._addStyles(); + }); + this.s.dt.on('column-reorder', function () { + _this._addStyles(); + }); + this.s.dt.on('column-visibility', function () { + setTimeout(function () { + _this._addStyles(); + }, 50); + }); + }; + FixedColumns.version = '4.0.1'; + FixedColumns.classes = { + fixedLeft: 'dtfc-fixed-left', + fixedRight: 'dtfc-fixed-right', + leftBottomBlocker: 'dtfc-left-bottom-blocker', + leftTopBlocker: 'dtfc-left-top-blocker', + rightBottomBlocker: 'dtfc-right-bottom-blocker', + rightTopBlocker: 'dtfc-right-top-blocker', + tableFixedLeft: 'dtfc-has-left', + tableFixedRight: 'dtfc-has-right' + }; + FixedColumns.defaults = { + i18n: { + button: 'FixedColumns' + }, + left: 1, + right: 0 + }; + return FixedColumns; + }()); + + /*! FixedColumns 4.0.1 + * 2019-2021 SpryMedia Ltd - datatables.net/license + */ + // DataTables extensions common UMD. Note that this allows for AMD, CommonJS + // (with window and jQuery being allowed as parameters to the returned + // function) or just default browser loading. + (function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD + define(['jquery', 'datatables.net'], function ($) { + return factory($, window, document); + }); + } + else if (typeof exports === 'object') { + // CommonJS + module.exports = function (root, $) { + if (!root) { + root = window; + } + if (!$ || !$.fn.dataTable) { + // eslint-disable-next-line @typescript-eslint/no-var-requires + $ = require('datatables.net')(root, $).$; + } + return factory($, root, root.document); + }; + } + else { + // Browser - assume jQuery has already been loaded + factory(window.jQuery, window, document); + } + }(function ($, window, document) { + setJQuery($); + var dataTable = $.fn.dataTable; + $.fn.dataTable.FixedColumns = FixedColumns; + $.fn.DataTable.FixedColumns = FixedColumns; + var apiRegister = $.fn.dataTable.Api.register; + apiRegister('fixedColumns()', function () { + return this; + }); + apiRegister('fixedColumns().left()', function (newVal) { + var ctx = this.context[0]; + if (newVal !== undefined) { + ctx._fixedColumns.left(newVal); + return this; + } + else { + return ctx._fixedColumns.left(); + } + }); + apiRegister('fixedColumns().right()', function (newVal) { + var ctx = this.context[0]; + if (newVal !== undefined) { + ctx._fixedColumns.right(newVal); + return this; + } + else { + return ctx._fixedColumns.right(); + } + }); + $.fn.dataTable.ext.buttons.fixedColumns = { + action: function (e, dt, node, config) { + if ($(node).attr('active')) { + $(node).removeAttr('active').removeClass('active'); + dt.fixedColumns().left(0); + dt.fixedColumns().right(0); + } + else { + $(node).attr('active', true).addClass('active'); + dt.fixedColumns().left(config.config.left); + dt.fixedColumns().right(config.config.right); + } + }, + config: { + left: 1, + right: 0 + }, + init: function (dt, node, config) { + if (dt.settings()[0]._fixedColumns === undefined) { + _init(dt.settings(), config); + } + $(node).attr('active', true).addClass('active'); + dt.button(node).text(config.text || dt.i18n('buttons.fixedColumns', dt.settings()[0]._fixedColumns.c.i18n.button)); + }, + text: null + }; + function _init(settings, options) { + if (options === void 0) { options = null; } + var api = new dataTable.Api(settings); + var opts = options + ? options + : api.init().fixedColumns || dataTable.defaults.fixedColumns; + var fixedColumns = new FixedColumns(api, opts); + return fixedColumns; + } + // Attach a listener to the document which listens for DataTables initialisation + // events so we can automatically initialise + $(document).on('init.dt.dtfc', function (e, settings) { + if (e.namespace !== 'dt') { + return; + } + if (settings.oInit.fixedColumns || + dataTable.defaults.fixedColumns) { + if (!settings._fixedColumns) { + _init(settings, null); + } + } + }); + })); + +}()); + + +/*! FixedHeader 3.2.1 + * ©2009-2021 SpryMedia Ltd - datatables.net/license */ /** * @summary FixedHeader * @description Fix a table's header or footer, so it is always visible while * scrolling - * @version 3.1.2 + * @version 3.2.1 * @file dataTables.fixedHeader.js * @author SpryMedia Ltd (www.sprymedia.co.uk) * @contact www.sprymedia.co.uk/contact - * @copyright Copyright 2009-2016 SpryMedia Ltd. + * @copyright Copyright 2009-2021 SpryMedia Ltd. * * This source file is free software, available under the following license: * MIT license - http://datatables.net/license/mit @@ -18441,11 +16114,13 @@ var FixedHeader = function ( dt, config ) { header: { host: null, floating: null, + floatingParent: $('
    '), placeholder: null }, footer: { host: null, floating: null, + floatingParent: $('
    '), placeholder: null } }; @@ -18473,15 +16148,13 @@ $.extend( FixedHeader.prototype, { /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * API methods */ - + /** - * Enable / disable the fixed elements - * - * @param {boolean} enable `true` to enable, `false` to disable + * Kill off FH and any events */ - enable: function ( enable ) - { - this.s.enable = enable; + destroy: function () { + this.s.dt.off( '.dtfc' ); + $(window).off( this.s.namespace ); if ( this.c.header ) { this._modeChange( 'in-place', 'header', true ); @@ -18490,8 +16163,29 @@ $.extend( FixedHeader.prototype, { if ( this.c.footer && this.dom.tfoot.length ) { this._modeChange( 'in-place', 'footer', true ); } + }, - this.update(); + /** + * Enable / disable the fixed elements + * + * @param {boolean} enable `true` to enable, `false` to disable + */ + enable: function ( enable, update ) + { + this.s.enable = enable; + + if ( update || update === undefined ) { + this._positions(); + this._scroll( true ); + } + }, + + /** + * Get enabled status + */ + enabled: function () + { + return this.s.enable; }, /** @@ -18528,10 +16222,25 @@ $.extend( FixedHeader.prototype, { /** * Recalculate the position of the fixed elements and force them into place */ - update: function () + update: function (force) { + var table = this.s.dt.table().node(); + + if ( $(table).is(':visible') ) { + this.enable( true, false ); + } + else { + this.enable( false, false ); + } + + // Don't update if header is not in the document atm (due to + // async events) + if ($(table).children('thead').length === 0) { + return; + } + this._positions(); - this._scroll( true ); + this._scroll( force !== undefined ? force : true ); }, @@ -18554,10 +16263,10 @@ $.extend( FixedHeader.prototype, { .on( 'scroll'+this.s.namespace, function () { that._scroll(); } ) - .on( 'resize'+this.s.namespace, function () { + .on( 'resize'+this.s.namespace, DataTable.util.throttle( function () { that.s.position.windowHeight = $(window).height(); that.update(); - } ); + }, 50 ) ); var autoHeader = $('.fh-fixedHeader'); if ( ! this.c.headerOffset && autoHeader.length ) { @@ -18569,13 +16278,17 @@ $.extend( FixedHeader.prototype, { this.c.footerOffset = autoFooter.outerHeight(); } - dt.on( 'column-reorder.dt.dtfc column-visibility.dt.dtfc draw.dt.dtfc column-sizing.dt.dtfc', function () { - that.update(); - } ); + dt + .on( 'column-reorder.dt.dtfc column-visibility.dt.dtfc column-sizing.dt.dtfc responsive-display.dt.dtfc', function (e, ctx) { + that.update(); + } ) + .on( 'draw.dt.dtfc', function (e, ctx) { + // For updates from our own table, don't reclone, but for all others, do + that.update(ctx === dt.settings()[0] ? false : true); + } ); dt.on( 'destroy.dtfc', function () { - dt.off( '.dtfc' ); - $(window).off( that.s.namespace ); + that.destroy(); } ); this._positions(); @@ -18605,26 +16318,80 @@ $.extend( FixedHeader.prototype, { this.dom.thead : this.dom.tfoot; + // If footer and scrolling is enabled then we don't clone + // Instead the table's height is decreased accordingly - see `_scroll()` + if (item === 'footer' && this._scrollEnabled()) { + return; + } + if ( ! force && itemDom.floating ) { // existing floating element - reuse it itemDom.floating.removeClass( 'fixedHeader-floating fixedHeader-locked' ); } else { if ( itemDom.floating ) { - itemDom.placeholder.remove(); + if(itemDom.placeholder !== null) { + itemDom.placeholder.remove(); + } this._unsize( item ); itemDom.floating.children().detach(); itemDom.floating.remove(); } + var tableNode = $(dt.table().node()); + var scrollBody = $(tableNode.parent()); + var scrollEnabled = this._scrollEnabled(); + itemDom.floating = $( dt.table().node().cloneNode( false ) ) - .css( 'table-layout', 'fixed' ) + .attr( 'aria-hidden', 'true' ) + .css({ + 'table-layout': 'fixed', + top: 0, + left: 0 + }) .removeAttr( 'id' ) - .append( itemElement ) + .append( itemElement ); + + itemDom.floatingParent + .css({ + width: scrollBody.width(), + overflow: 'hidden', + height: 'fit-content', + position: 'fixed', + left: scrollEnabled ? tableNode.offset().left + scrollBody.scrollLeft() : 0 + }) + .css( + item === 'header' ? + { + top: this.c.headerOffset, + bottom: '' + } : + { + top: '', + bottom: this.c.footerOffset + } + ) + .addClass(item === 'footer' ? 'dtfh-floatingparentfoot' : 'dtfh-floatingparenthead') + .append(itemDom.floating) .appendTo( 'body' ); + this._stickyPosition(itemDom.floating, '-'); + + var scrollLeftUpdate = () => { + var scrollLeft = scrollBody.scrollLeft() + this.s.scrollLeft = {footer: scrollLeft, header: scrollLeft}; + itemDom.floatingParent.scrollLeft(this.s.scrollLeft.header); + } + + scrollLeftUpdate(); + scrollBody.scroll(scrollLeftUpdate) + // Insert a fake thead/tfoot into the DataTable to stop it jumping around itemDom.placeholder = itemElement.clone( false ); + itemDom.placeholder + .find( '*[id]' ) + .removeAttr( 'id' ); + itemDom.host.prepend( itemDom.placeholder ); // Clone widths @@ -18632,6 +16399,35 @@ $.extend( FixedHeader.prototype, { } }, + /** + * This method sets the sticky position of the header elements to match fixed columns + * @param {JQuery} el + * @param {string} sign + */ + _stickyPosition(el, sign) { + if (this._scrollEnabled()) { + var that = this + var rtl = $(that.s.dt.table().node()).css('direction') === 'rtl'; + + el.find('th').each(function() { + // Find out if fixed header has previously set this column + if ($(this).css('position') === 'sticky') { + var right = $(this).css('right'); + var left = $(this).css('left'); + if (right !== 'auto' && !rtl) { + // New position either adds or dismisses the barWidth + var potential = +right.replace(/px/g, '') + (sign === '-' ? -1 : 1) * that.s.dt.settings()[0].oBrowser.barWidth; + $(this).css('right', potential > 0 ? potential : 0); + } + else if(left !== 'auto' && rtl) { + var potential = +left.replace(/px/g, '') + (sign === '-' ? -1 : 1) * that.s.dt.settings()[0].oBrowser.barWidth; + $(this).css('left', potential > 0 ? potential : 0); + } + } + }); + } + }, + /** * Copy widths from the cells in one element to another. This is required * for the footer as the footer in the main table takes its sizes from the @@ -18647,7 +16443,7 @@ $.extend( FixedHeader.prototype, { var get = function ( name ) { return $(name, from) .map( function () { - return $(this).width(); + return $(this).css('width').replace(/[^\d\.]/g, '') * 1; } ).toArray(); }; @@ -18705,7 +16501,12 @@ $.extend( FixedHeader.prototype, { var lastScrollLeft = this.s.scrollLeft; if ( itemDom.floating && lastScrollLeft[ item ] !== scrollLeft ) { - itemDom.floating.css( 'left', position.left - scrollLeft ); + // If scrolling is enabled we need to match the floating header to the body + if (this._scrollEnabled()) { + var newScrollLeft = $($(this.s.dt.table().node()).parent()).scrollLeft() + itemDom.floating.scrollLeft(newScrollLeft); + itemDom.floatingParent.scrollLeft(newScrollLeft); + } lastScrollLeft[ item ] = scrollLeft; } @@ -18732,12 +16533,36 @@ $.extend( FixedHeader.prototype, { var itemDom = this.dom[ item ]; var position = this.s.position; + // Just determine if scroll is enabled once + var scrollEnabled = this._scrollEnabled(); + + // If footer and scrolling is enabled then we don't clone + // Instead the table's height is decreased accordingly - see `_scroll()` + if (item === 'footer' && scrollEnabled) { + return; + } + + // It isn't trivial to add a !important css attribute... + var importantWidth = function (w) { + itemDom.floating.attr('style', function(i,s) { + return (s || '') + 'width: '+w+'px !important;'; + }); + + // If not scrolling also have to update the floatingParent + if (!scrollEnabled) { + itemDom.floatingParent.attr('style', function(i,s) { + return (s || '') + 'width: '+w+'px !important;'; + }); + } + }; + // Record focus. Browser's will cause input elements to loose focus if // they are inserted else where in the doc var tablePart = this.dom[ item==='footer' ? 'tfoot' : 'thead' ]; var focus = $.contains( tablePart[0], document.activeElement ) ? document.activeElement : null; + var scrollBody = $($(this.s.dt.table().node()).parent()); if ( mode === 'in-place' ) { // Insert the header back into the table's real header @@ -18749,27 +16574,64 @@ $.extend( FixedHeader.prototype, { this._unsize( item ); if ( item === 'header' ) { - itemDom.host.prepend( this.dom.thead ); + itemDom.host.prepend( tablePart ); } else { - itemDom.host.append( this.dom.tfoot ); + itemDom.host.append( tablePart ); } if ( itemDom.floating ) { itemDom.floating.remove(); itemDom.floating = null; + this._stickyPosition(itemDom.host, '+'); } + + if ( itemDom.floatingParent ) { + itemDom.floatingParent.remove(); + } + + $($(itemDom.host.parent()).parent()).scrollLeft(scrollBody.scrollLeft()) } else if ( mode === 'in' ) { // Remove the header from the read header and insert into a fixed // positioned floating table clone this._clone( item, forceChange ); - itemDom.floating - .addClass( 'fixedHeader-floating' ) - .css( item === 'header' ? 'top' : 'bottom', this.c[item+'Offset'] ) - .css( 'left', position.left+'px' ) - .css( 'width', position.width+'px' ); + // Get useful position values + var scrollOffset = scrollBody.offset(); + var windowTop = $(document).scrollTop(); + var windowHeight = $(window).height(); + var windowBottom = windowTop + windowHeight; + var bodyTop = scrollEnabled ? scrollOffset.top : position.tbodyTop; + var bodyBottom = scrollEnabled ? scrollOffset.top + scrollBody.outerHeight() : position.tfootTop + + // Calculate the amount that the footer or header needs to be shuffled + var shuffle = item === 'footer' ? + // footer and top of body isn't on screen + bodyTop > windowBottom ? + // Yes - push the footer below + position.tfootHeight : + // No - bottom set to the gap between the top of the body and the bottom of the window + bodyTop + position.tfootHeight - windowBottom : + // Otherwise must be a header so get the difference from the bottom of the + // desired floating header and the bottom of the table body + windowTop + this.c.headerOffset + position.theadHeight - bodyBottom + + // Set the top or bottom based off of the offset and the shuffle value + var prop = item === 'header' ? 'top' : 'bottom'; + var val = this.c[item+'Offset'] - (shuffle > 0 ? shuffle : 0); + + itemDom.floating.addClass( 'fixedHeader-floating' ); + itemDom.floatingParent + .css(prop, val) + .css( { + 'left': position.left, + 'height': item === 'header' ? position.theadHeight : position.tfootHeight, + 'z-index': 2 + }) + .append(itemDom.floating); + + importantWidth(position.width); if ( item === 'footer' ) { itemDom.floating.css( 'top', '' ); @@ -18779,26 +16641,34 @@ $.extend( FixedHeader.prototype, { // Fix the position of the floating header at base of the table body this._clone( item, forceChange ); - itemDom.floating - .addClass( 'fixedHeader-locked' ) - .css( 'top', position.tfootTop - position.theadHeight ) - .css( 'left', position.left+'px' ) - .css( 'width', position.width+'px' ); + itemDom.floating.addClass( 'fixedHeader-locked' ); + itemDom.floatingParent.css({ + position: 'absolute', + top: position.tfootTop - position.theadHeight, + left: position.left+'px' + }); + + importantWidth(position.width); } else if ( mode === 'above' ) { // only used for the footer // Fix the position of the floating footer at top of the table body this._clone( item, forceChange ); - itemDom.floating - .addClass( 'fixedHeader-locked' ) - .css( 'top', position.tbodyTop ) - .css( 'left', position.left+'px' ) - .css( 'width', position.width+'px' ); + itemDom.floating.addClass( 'fixedHeader-locked' ); + itemDom.floatingParent.css({ + position: 'absolute', + top: position.tbodyTop, + left: position.left+'px' + }); + + importantWidth(position.width); } // Restore focus if it was lost if ( focus && focus !== document.activeElement ) { - focus.focus(); + setTimeout( function () { + focus.focus(); + }, 10 ); } this.s.scrollLeft.header = -1; @@ -18819,25 +16689,29 @@ $.extend( FixedHeader.prototype, { var position = this.s.position; var dom = this.dom; var tableNode = $(table.node()); + var scrollEnabled = this._scrollEnabled(); // Need to use the header and footer that are in the main table, // regardless of if they are clones, since they hold the positions we // want to measure from - var thead = tableNode.children('thead'); - var tfoot = tableNode.children('tfoot'); + var thead = $(dt.table().header()); + var tfoot = $(dt.table().footer()); var tbody = dom.tbody; + var scrollBody = tableNode.parent(); position.visible = tableNode.is(':visible'); position.width = tableNode.outerWidth(); position.left = tableNode.offset().left; position.theadTop = thead.offset().top; - position.tbodyTop = tbody.offset().top; - position.theadHeight = position.tbodyTop - position.theadTop; + position.tbodyTop = scrollEnabled ? scrollBody.offset().top : tbody.offset().top; + position.tbodyHeight = scrollEnabled ? scrollBody.outerHeight() : tbody.outerHeight(); + position.theadHeight = thead.outerHeight(); + position.theadBottom = position.theadTop + position.theadHeight; if ( tfoot.length ) { - position.tfootTop = tfoot.offset().top; + position.tfootTop = position.tbodyTop + position.tbodyHeight; //tfoot.offset().top; position.tfootBottom = position.tfootTop + tfoot.outerHeight(); - position.tfootHeight = position.tfootBottom - position.tfootTop; + position.tfootHeight = tfoot.outerHeight(); } else { position.tfootTop = position.tbodyTop + tbody.outerHeight(); @@ -18857,22 +16731,64 @@ $.extend( FixedHeader.prototype, { */ _scroll: function ( forceChange ) { - var windowTop = $(document).scrollTop(); + // ScrollBody details + var scrollEnabled = this._scrollEnabled(); + var scrollBody = $(this.s.dt.table().node()).parent(); + var scrollOffset = scrollBody.offset(); + var scrollHeight = scrollBody.outerHeight(); + + // Window details var windowLeft = $(document).scrollLeft(); + var windowTop = $(document).scrollTop(); + var windowHeight = $(window).height(); + var windowBottom = windowHeight + windowTop + + var position = this.s.position; var headerMode, footerMode; - if ( ! this.s.enable ) { - return; - } + // Body Details + var bodyTop = (scrollEnabled ? scrollOffset.top : position.tbodyTop); + var bodyLeft = (scrollEnabled ? scrollOffset.left : position.left); + var bodyBottom = (scrollEnabled ? scrollOffset.top + scrollHeight : position.tfootTop); + var bodyWidth = (scrollEnabled ? scrollBody.outerWidth() : position.tbodyWidth); + + var windowBottom = windowTop + windowHeight; if ( this.c.header ) { - if ( ! position.visible || windowTop <= position.theadTop - this.c.headerOffset ) { + if ( ! this.s.enable ) { headerMode = 'in-place'; } - else if ( windowTop <= position.tfootTop - position.theadHeight - this.c.headerOffset ) { - headerMode = 'in'; + // The header is in it's normal place if the body top is lower than + // the scroll of the window plus the headerOffset and the height of the header + else if ( ! position.visible || windowTop + this.c.headerOffset + position.theadHeight <= bodyTop) { + headerMode = 'in-place'; } + // The header should be floated if + else if ( + // The scrolling plus the header offset plus the height of the header is lower than the top of the body + windowTop + this.c.headerOffset + position.theadHeight > bodyTop && + // And the scrolling at the top plus the header offset is above the bottom of the body + windowTop + this.c.headerOffset < bodyBottom + ) { + headerMode = 'in'; + var scrollBody = $($(this.s.dt.table().node()).parent()); + + // Further to the above, If the scrolling plus the header offset plus the header height is lower + // than the bottom of the table a shuffle is required so have to force the calculation + if(windowTop + this.c.headerOffset + position.theadHeight > bodyBottom || this.dom.header.floatingParent === undefined){ + forceChange = true; + } + else { + this.dom.header.floatingParent + .css({ + 'top': this.c.headerOffset, + 'position': 'fixed' + }) + .append(this.dom.header.floating); + } + } + // Anything else and the view is below the table else { headerMode = 'below'; } @@ -18884,23 +16800,136 @@ $.extend( FixedHeader.prototype, { this._horizontal( 'header', windowLeft ); } + var header = { + offset: {top: 0, left: 0}, + height: 0 + } + var footer = { + offset: {top: 0, left: 0}, + height: 0 + } + if ( this.c.footer && this.dom.tfoot.length ) { - if ( ! position.visible || windowTop + position.windowHeight >= position.tfootBottom + this.c.footerOffset ) { + if ( ! this.s.enable ) { footerMode = 'in-place'; } - else if ( position.windowHeight + windowTop > position.tbodyTop + position.tfootHeight + this.c.footerOffset ) { + else if ( ! position.visible || position.tfootBottom + this.c.footerOffset <= windowBottom ) { + footerMode = 'in-place'; + } + else if ( + bodyBottom + position.tfootHeight + this.c.footerOffset > windowBottom && + bodyTop + this.c.footerOffset < windowBottom + ) { footerMode = 'in'; + forceChange = true; } else { footerMode = 'above'; } - + if ( forceChange || footerMode !== this.s.footerMode ) { this._modeChange( footerMode, 'footer', forceChange ); } this._horizontal( 'footer', windowLeft ); + + var getOffsetHeight = (el) => { + return { + offset: el.offset(), + height: el.outerHeight() + } + } + + header = this.dom.header.floating ? getOffsetHeight(this.dom.header.floating) : getOffsetHeight(this.dom.thead); + footer = this.dom.footer.floating ? getOffsetHeight(this.dom.footer.floating) : getOffsetHeight(this.dom.tfoot); + + // If scrolling is enabled and the footer is off the screen + if (scrollEnabled && footer.offset.top > windowTop){// && footer.offset.top >= windowBottom) { + // Calculate the gap between the top of the scrollBody and the top of the window + var overlap = windowTop - scrollOffset.top; + // The new height is the bottom of the window + var newHeight = windowBottom + + // If the gap between the top of the scrollbody and the window is more than + // the height of the header then the top of the table is still visible so add that gap + // Doing this has effectively calculated the height from the top of the table to the bottom of the current page + (overlap > -header.height ? overlap : 0) - + // Take from that + ( + // The top of the header plus + header.offset.top + + // The header height if the standard header is present + (overlap < -header.height ? header.height : 0) + + // And the height of the footer + footer.height + ) + + // Don't want a negative height + if (newHeight < 0) { + newHeight = 0; + } + + // At the end of the above calculation the space between the header (top of the page if floating) + // and the point just above the footer should be the new value for the height of the table. + scrollBody.outerHeight(newHeight); + + // Need some rounding here as sometimes very small decimal places are encountered + // If the actual height is bigger or equal to the height we just applied then the footer is "Floating" + if(Math.round(scrollBody.outerHeight()) >= Math.round(newHeight)) { + $(this.dom.tfoot.parent()).addClass("fixedHeader-floating"); + } + // Otherwise max-width has kicked in so it is not floating + else { + $(this.dom.tfoot.parent()).removeClass("fixedHeader-floating"); + } + } } + + if(this.dom.header.floating){ + this.dom.header.floatingParent.css('left', bodyLeft-windowLeft); + } + if(this.dom.footer.floating){ + this.dom.footer.floatingParent.css('left', bodyLeft-windowLeft); + } + + // If fixed columns is being used on this table then the blockers need to be copied across + // Cloning these is cleaner than creating as our own as it will keep consistency with fixedColumns automatically + // ASSUMING that the class remains the same + if (this.s.dt.settings()[0]._fixedColumns !== undefined) { + var adjustBlocker = (side, end, el) => { + if (el === undefined) { + let blocker = $('div.dtfc-'+side+'-'+end+'-blocker'); + el = blocker.length === 0 ? + null : + blocker.clone().appendTo('body').css('z-index', 1); + } + if(el !== null) { + el.css({ + top: end === 'top' ? header.offset.top : footer.offset.top, + left: side === 'right' ? bodyLeft + bodyWidth - el.width() : bodyLeft + }); + } + + return el; + } + + // Adjust all blockers + this.dom.header.rightBlocker = adjustBlocker('right', 'top', this.dom.header.rightBlocker); + this.dom.header.leftBlocker = adjustBlocker('left', 'top', this.dom.header.leftBlocker); + this.dom.footer.rightBlocker = adjustBlocker('right', 'bottom', this.dom.footer.rightBlocker); + this.dom.footer.leftBlocker = adjustBlocker('left', 'bottom', this.dom.footer.leftBlocker); + } + }, + + /** + * Function to check if scrolling is enabled on the table or not + * @returns Boolean value indicating if scrolling on the table is enabled or not + */ + _scrollEnabled: function() { + var oScroll = this.s.dt.settings()[0].oScroll; + if(oScroll.sY !== "" || oScroll.sX !== "") { + return true; + } + return false } } ); @@ -18910,7 +16939,7 @@ $.extend( FixedHeader.prototype, { * @type {String} * @static */ -FixedHeader.version = "3.1.2"; +FixedHeader.version = "3.2.1"; /** * Defaults @@ -18970,17 +16999,30 @@ DataTable.Api.register( 'fixedHeader.enable()', function ( flag ) { return this.iterator( 'table', function ( ctx ) { var fh = ctx._fixedHeader; - if ( fh ) { - fh.enable( flag !== undefined ? flag : true ); + flag = ( flag !== undefined ? flag : true ); + if ( fh && flag !== fh.enabled() ) { + fh.enable( flag ); } } ); } ); +DataTable.Api.register( 'fixedHeader.enabled()', function () { + if ( this.context.length ) { + var fh = this.context[0]._fixedHeader; + + if ( fh ) { + return fh.enabled(); + } + } + + return false; +} ); + DataTable.Api.register( 'fixedHeader.disable()', function ( ) { return this.iterator( 'table', function ( ctx ) { var fh = ctx._fixedHeader; - if ( fh ) { + if ( fh && fh.enabled() ) { fh.enable( false ); } } ); @@ -19011,18 +17053,18 @@ return FixedHeader; })); -/*! Responsive 2.1.1 - * 2014-2016 SpryMedia Ltd - datatables.net/license +/*! Responsive 2.2.9 + * 2014-2021 SpryMedia Ltd - datatables.net/license */ /** * @summary Responsive * @description Responsive tables plug-in for DataTables - * @version 2.1.1 + * @version 2.2.9 * @file dataTables.responsive.js * @author SpryMedia Ltd (www.sprymedia.co.uk) * @contact www.sprymedia.co.uk/contact - * @copyright Copyright 2014-2016 SpryMedia Ltd. + * @copyright Copyright 2014-2021 SpryMedia Ltd. * * This source file is free software, available under the following license: * MIT license - http://datatables.net/license/mit @@ -19110,8 +17152,8 @@ var DataTable = $.fn.dataTable; */ var Responsive = function ( settings, opts ) { // Sanity check that we are using DataTables 1.10 or newer - if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.3' ) ) { - throw 'DataTables Responsive requires DataTables 1.10.3 or newer'; + if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.10' ) ) { + throw 'DataTables Responsive requires DataTables 1.10.10 or newer'; } this.s = { @@ -19157,7 +17199,7 @@ $.extend( Responsive.prototype, { var that = this; var dt = this.s.dt; var dtPrivateSettings = dt.settings()[0]; - var oldWindowWidth = $(window).width(); + var oldWindowWidth = $(window).innerWidth(); dt.settings()[0]._responsive = this; @@ -19166,7 +17208,7 @@ $.extend( Responsive.prototype, { $(window).on( 'resize.dtr orientationchange.dtr', DataTable.util.throttle( function () { // iOS has a bug whereby resize can fire when only scrolling // See: http://stackoverflow.com/questions/8898412 - var width = $(window).width(); + var width = $(window).innerWidth(); if ( width !== oldWindowWidth ) { that._resize(); @@ -19194,6 +17236,7 @@ $.extend( Responsive.prototype, { dt.off( '.dtr' ); $( dt.table().body() ).off( '.dtr' ); $(window).off( 'resize.dtr orientationchange.dtr' ); + dt.cells('.dtr-control').nodes().to$().removeClass('dtr-control'); // Restore the columns that we've hidden $.each( that.s.current, function ( i, val ) { @@ -19221,10 +17264,21 @@ $.extend( Responsive.prototype, { // DataTables will trigger this event on every column it shows and // hides individually - dt.on( 'column-visibility.dtr', function (e, ctx, col, vis) { - that._classLogic(); - that._resizeAuto(); - that._resize(); + dt.on( 'column-visibility.dtr', function () { + // Use a small debounce to allow multiple columns to be set together + if ( that._timer ) { + clearTimeout( that._timer ); + } + + that._timer = setTimeout( function () { + that._timer = null; + + that._classLogic(); + that._resizeAuto(); + that._resize(true); + + that._redrawChildren(); + }, 100 ); } ); // Redraw the details box on each draw which will happen if the data @@ -19240,7 +17294,7 @@ $.extend( Responsive.prototype, { dt.on( 'column-reorder.dtr', function (e, settings, details) { that._classLogic(); that._resizeAuto(); - that._resize(); + that._resize(true); } ); // Change in column sizes means we need to calc @@ -19260,22 +17314,33 @@ $.extend( Responsive.prototype, { } ); dt.one( 'draw.dtr', function () { + that._resizeAuto(); + that._resize(); + dt.rows( rowIds ).every( function () { that._detailsDisplay( this, false ); } ); } ); }); - dt.on( 'init.dtr', function (e, settings, details) { - that._resizeAuto(); - that._resize(); + dt + .on( 'draw.dtr', function () { + that._controlClass(); + }) + .on( 'init.dtr', function (e, settings, details) { + if ( e.namespace !== 'dt' ) { + return; + } - // If columns were hidden, then DataTables needs to adjust the - // column sizing - if ( $.inArray( false, that.s.current ) ) { - dt.columns.adjust(); - } - } ); + that._resizeAuto(); + that._resize(); + + // If columns were hidden, then DataTables needs to adjust the + // column sizing + if ( $.inArray( false, that.s.current ) ) { + dt.columns.adjust(); + } + } ); // First pass - draw the table for the current viewport size this._resize(); @@ -19324,7 +17389,10 @@ $.extend( Responsive.prototype, { // Class logic - determine which columns are in this breakpoint based // on the classes. If no class control (i.e. `auto`) then `-` is used // to indicate this to the rest of the function - var display = $.map( columns, function ( col ) { + var display = $.map( columns, function ( col, i ) { + if ( dt.column(i).visible() === false ) { + return 'not-visible'; + } return col.auto && col.minWidth === null ? false : col.auto === true ? @@ -19392,7 +17460,7 @@ $.extend( Responsive.prototype, { var showControl = false; for ( i=0, ien=columns.length ; i
    '+ + var klass = col.className ? + 'class="'+ col.className +'"' : + ''; + + return ''+ ' '+ ''+ ''; @@ -20226,10 +18479,18 @@ Api.register( 'responsive.hasHidden()', function () { var ctx = this.context[0]; return ctx._responsive ? - $.inArray( false, ctx._responsive.s.current ) !== -1 : + $.inArray( false, ctx._responsive._responsiveOnlyHidden() ) !== -1 : false; } ); +Api.registerPlural( 'columns().responsiveHidden()', 'column().responsiveHidden()', function () { + return this.iterator( 'column', function ( settings, column ) { + return settings._responsive ? + settings._responsive._responsiveOnlyHidden()[ column ] : + false; + }, 1 ); +} ); + /** * Version information @@ -20237,7 +18498,7 @@ Api.register( 'responsive.hasHidden()', function () { * @name Responsive.version * @static */ -Responsive.version = '2.1.1'; +Responsive.version = '2.2.9'; $.fn.dataTable.Responsive = Responsive; @@ -20268,3 +18529,3879 @@ return Responsive; })); +/*! DataTables styling wrapper for Responsive + * ©2018 SpryMedia Ltd - datatables.net/license + */ + +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net-dt', 'datatables.net-responsive'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + module.exports = function (root, $) { + if ( ! root ) { + root = window; + } + + if ( ! $ || ! $.fn.dataTable ) { + $ = require('datatables.net-dt')(root, $).$; + } + + if ( ! $.fn.dataTable.Responsive ) { + require('datatables.net-responsive')(root, $); + } + + return factory( $, root, root.document ); + }; + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { + +return $.fn.dataTable; + +})); + +/*! SearchBuilder 1.3.1 + * ©SpryMedia Ltd - datatables.net/license/mit + */ +(function () { + 'use strict'; + + var $$2; + var dataTable$2; + // eslint-disable-next-line no-extra-parens + var moment = window.moment; + // eslint-disable-next-line no-extra-parens + var luxon = window.luxon; + /** + * Sets the value of jQuery for use in the file + * + * @param jq the instance of jQuery to be set + */ + function setJQuery$2(jq) { + $$2 = jq; + dataTable$2 = jq.fn.dataTable; + } + /** + * The Criteria class is used within SearchBuilder to represent a search criteria + */ + var Criteria = /** @class */ (function () { + function Criteria(table, opts, topGroup, index, depth) { + var _this = this; + if (index === void 0) { index = 0; } + if (depth === void 0) { depth = 1; } + // Check that the required version of DataTables is included + if (!dataTable$2 || !dataTable$2.versionCheck || !dataTable$2.versionCheck('1.10.0')) { + throw new Error('SearchPane requires DataTables 1.10 or newer'); + } + this.classes = $$2.extend(true, {}, Criteria.classes); + // Get options from user and any extra conditions/column types defined by plug-ins + this.c = $$2.extend(true, {}, Criteria.defaults, $$2.fn.dataTable.ext.searchBuilder, opts); + var i18n = this.c.i18n; + this.s = { + condition: undefined, + conditions: {}, + data: undefined, + dataIdx: -1, + dataPoints: [], + dateFormat: false, + depth: depth, + dt: table, + filled: false, + index: index, + origData: undefined, + topGroup: topGroup, + type: '', + value: [] + }; + this.dom = { + buttons: $$2('
    ') + .addClass(this.classes.buttonContainer), + condition: $$2('') + .addClass(this.classes.data) + .addClass(this.classes.dropDown) + .addClass(this.classes.italic), + dataTitle: $$2('
    ").appendTo(q));o.nTBody=b[0];b=q.children("tfoot");if(b.length===0&&a.length>0&&(o.oScroll.sX!==""||o.oScroll.sY!==""))b=h("").appendTo(q);if(b.length===0||b.children().length===0)q.addClass(u.sNoFooter);else if(b.length>0){o.nTFoot=b[0];ea(o.aoFooter,o.nTFoot)}if(g.aaData)for(j=0;j/g,cc=/^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/,dc=RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\|\\$|\\^|\\-)","g"),Za=/[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi,M=function(a){return!a||!0===a||"-"===a?!0:!1},Qb=function(a){var b=parseInt(a,10);return!isNaN(b)&& -isFinite(a)?b:null},Rb=function(a,b){$a[b]||($a[b]=RegExp(Sa(b),"g"));return"string"===typeof a&&"."!==b?a.replace(/\./g,"").replace($a[b],"."):a},ab=function(a,b,c){var d="string"===typeof a;if(M(a))return!0;b&&d&&(a=Rb(a,b));c&&d&&(a=a.replace(Za,""));return!isNaN(parseFloat(a))&&isFinite(a)},Sb=function(a,b,c){return M(a)?!0:!(M(a)||"string"===typeof a)?null:ab(a.replace(Ca,""),b,c)?!0:null},D=function(a,b,c){var d=[],e=0,f=a.length;if(c!==k)for(;ea.length)){b=a.slice().sort();for(var c=b[0],d=1,e=b.length;d")[0],$b=xa.textContent!==k,bc= -/<.*?>/g,Qa=m.util.throttle,Ub=[],w=Array.prototype,ec=function(a){var b,c,d=m.settings,e=h.map(d,function(a){return a.nTable});if(a){if(a.nTable&&a.oApi)return[a];if(a.nodeName&&"table"===a.nodeName.toLowerCase())return b=h.inArray(a,e),-1!==b?[d[b]]:null;if(a&&"function"===typeof a.settings)return a.settings().toArray();"string"===typeof a?c=h(a):a instanceof h&&(c=a)}else return[];if(c)return c.map(function(){b=h.inArray(this,e);return-1!==b?d[b]:null}).toArray()};t=function(a,b){if(!(this instanceof -t))return new t(a,b);var c=[],d=function(a){(a=ec(a))&&(c=c.concat(a))};if(h.isArray(a))for(var e=0,f=a.length;ea?new t(b[a],this[a]):null},filter:function(a){var b=[];if(w.filter)b=w.filter.call(this,a,this);else for(var c=0,d=this.length;c").addClass(b),h("td",c).addClass(b).html(a)[0].colSpan=ba(d),e.push(c[0]))};f(a,b);c._details&&c._details.detach();c._details=h(e);c._detailsShow&&c._details.insertAfter(c.nTr)}return this});p(["row().child.show()","row().child().show()"],function(){Wb(this,!0);return this});p(["row().child.hide()","row().child().hide()"],function(){Wb(this,!1); -return this});p(["row().child.remove()","row().child().remove()"],function(){eb(this);return this});p("row().child.isShown()",function(){var a=this.context;return a.length&&this.length?a[0].aoData[this[0]]._detailsShow||!1:!1});var fc=/^([^:]+):(name|visIdx|visible)$/,Xb=function(a,b,c,d,e){for(var c=[],d=0,f=e.length;d=0?b:g.length+b];if(typeof a==="function"){var e=Da(c,f);return h.map(g,function(b,f){return a(f,Xb(c,f,0,0,e),i[f])?f:null})}var k=typeof a==="string"?a.match(fc):"";if(k)switch(k[2]){case "visIdx":case "visible":b=parseInt(k[1],10);if(b<0){var m=h.map(g,function(a,b){return a.bVisible?b:null});return[m[m.length+b]]}return[$(c,b)];case "name":return h.map(j,function(a,b){return a=== -k[1]?b:null});default:return[]}if(a.nodeName&&a._DT_CellIndex)return[a._DT_CellIndex.column];b=h(i).filter(a).map(function(){return h.inArray(this,i)}).toArray();if(b.length||!a.nodeName)return b;b=h(a).closest("*[data-dt-column]");return b.length?[b.data("dt-column")]:[]},c,f)},1);c.selector.cols=a;c.selector.opts=b;return c});u("columns().header()","column().header()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTh},1)});u("columns().footer()","column().footer()", -function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTf},1)});u("columns().data()","column().data()",function(){return this.iterator("column-rows",Xb,1)});u("columns().dataSrc()","column().dataSrc()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].mData},1)});u("columns().cache()","column().cache()",function(a){return this.iterator("column-rows",function(b,c,d,e,f){return ja(b.aoData,f,"search"===a?"_aFilterData":"_aSortData",c)},1)});u("columns().nodes()", -"column().nodes()",function(){return this.iterator("column-rows",function(a,b,c,d,e){return ja(a.aoData,e,"anCells",b)},1)});u("columns().visible()","column().visible()",function(a,b){var c=this.iterator("column",function(b,c){if(a===k)return b.aoColumns[c].bVisible;var f=b.aoColumns,g=f[c],j=b.aoData,i,n,l;if(a!==k&&g.bVisible!==a){if(a){var m=h.inArray(!0,D(f,"bVisible"),c+1);i=0;for(n=j.length;id;return!0};m.isDataTable=m.fnIsDataTable=function(a){var b=h(a).get(0),c=!1;if(a instanceof m.Api)return!0;h.each(m.settings,function(a,e){var f=e.nScrollHead?h("table",e.nScrollHead)[0]:null,g=e.nScrollFoot?h("table",e.nScrollFoot)[0]:null;if(e.nTable===b||f===b||g===b)c=!0});return c};m.tables=m.fnTables=function(a){var b=!1;h.isPlainObject(a)&&(b=a.api,a=a.visible);var c=h.map(m.settings, -function(b){if(!a||a&&h(b.nTable).is(":visible"))return b.nTable});return b?new t(c):c};m.camelToHungarian=J;p("$()",function(a,b){var c=this.rows(b).nodes(),c=h(c);return h([].concat(c.filter(a).toArray(),c.find(a).toArray()))});h.each(["on","one","off"],function(a,b){p(b+"()",function(){var a=Array.prototype.slice.call(arguments);a[0]=h.map(a[0].split(/\s/),function(a){return!a.match(/\.dt\b/)?a+".dt":a}).join(" ");var d=h(this.tables().nodes());d[b].apply(d,a);return this})});p("clear()",function(){return this.iterator("table", -function(a){pa(a)})});p("settings()",function(){return new t(this.context,this.context)});p("init()",function(){var a=this.context;return a.length?a[0].oInit:null});p("data()",function(){return this.iterator("table",function(a){return D(a.aoData,"_aData")}).flatten()});p("destroy()",function(a){a=a||!1;return this.iterator("table",function(b){var c=b.nTableWrapper.parentNode,d=b.oClasses,e=b.nTable,f=b.nTBody,g=b.nTHead,j=b.nTFoot,i=h(e),f=h(f),k=h(b.nTableWrapper),l=h.map(b.aoData,function(a){return a.nTr}), -p;b.bDestroying=!0;s(b,"aoDestroyCallback","destroy",[b]);a||(new t(b)).columns().visible(!0);k.off(".DT").find(":not(tbody *)").off(".DT");h(E).off(".DT-"+b.sInstance);e!=g.parentNode&&(i.children("thead").detach(),i.append(g));j&&e!=j.parentNode&&(i.children("tfoot").detach(),i.append(j));b.aaSorting=[];b.aaSortingFixed=[];ya(b);h(l).removeClass(b.asStripeClasses.join(" "));h("th, td",g).removeClass(d.sSortable+" "+d.sSortableAsc+" "+d.sSortableDesc+" "+d.sSortableNone);b.bJUI&&(h("th span."+d.sSortIcon+ -", td span."+d.sSortIcon,g).detach(),h("th, td",g).each(function(){var a=h("div."+d.sSortJUIWrapper,this);h(this).append(a.contents());a.detach()}));f.children().detach();f.append(l);g=a?"remove":"detach";i[g]();k[g]();!a&&c&&(c.insertBefore(e,b.nTableReinsertBefore),i.css("width",b.sDestroyWidth).removeClass(d.sTable),(p=b.asDestroyStripes.length)&&f.children().each(function(a){h(this).addClass(b.asDestroyStripes[a%p])}));c=h.inArray(b,m.settings);-1!==c&&m.settings.splice(c,1)})});h.each(["column", -"row","cell"],function(a,b){p(b+"s().every()",function(a){var d=this.selector.opts,e=this;return this.iterator(b,function(f,g,h,i,m){a.call(e[b](g,"cell"===b?h:d,"cell"===b?d:k),g,h,i,m)})})});p("i18n()",function(a,b,c){var d=this.context[0],a=R(a)(d.oLanguage);a===k&&(a=b);c!==k&&h.isPlainObject(a)&&(a=a[c]!==k?a[c]:a._);return a.replace("%d",c)});m.version="1.10.15";m.settings=[];m.models={};m.models.oSearch={bCaseInsensitive:!0,sSearch:"",bRegex:!1,bSmart:!0};m.models.oRow={nTr:null,anCells:null, -_aData:[],_aSortData:null,_aFilterData:null,_sFilterRow:null,_sRowStripe:"",src:null,idx:-1};m.models.oColumn={idx:null,aDataSort:null,asSorting:null,bSearchable:null,bSortable:null,bVisible:null,_sManualType:null,_bAttrSrc:!1,fnCreatedCell:null,fnGetData:null,fnSetData:null,mData:null,mRender:null,nTh:null,nTf:null,sClass:null,sContentPadding:null,sDefaultContent:null,sName:null,sSortDataType:"std",sSortingClass:null,sSortingClassJUI:null,sTitle:null,sType:null,sWidth:null,sWidthOrig:null};m.defaults= -{aaData:null,aaSorting:[[0,"asc"]],aaSortingFixed:[],ajax:null,aLengthMenu:[10,25,50,100],aoColumns:null,aoColumnDefs:null,aoSearchCols:[],asStripeClasses:null,bAutoWidth:!0,bDeferRender:!1,bDestroy:!1,bFilter:!0,bInfo:!0,bJQueryUI:!1,bLengthChange:!0,bPaginate:!0,bProcessing:!1,bRetrieve:!1,bScrollCollapse:!1,bServerSide:!1,bSort:!0,bSortMulti:!0,bSortCellsTop:!1,bSortClasses:!0,bStateSave:!1,fnCreatedRow:null,fnDrawCallback:null,fnFooterCallback:null,fnFormatNumber:function(a){return a.toString().replace(/\B(?=(\d{3})+(?!\d))/g, -this.oLanguage.sThousands)},fnHeaderCallback:null,fnInfoCallback:null,fnInitComplete:null,fnPreDrawCallback:null,fnRowCallback:null,fnServerData:null,fnServerParams:null,fnStateLoadCallback:function(a){try{return JSON.parse((-1===a.iStateDuration?sessionStorage:localStorage).getItem("DataTables_"+a.sInstance+"_"+location.pathname))}catch(b){}},fnStateLoadParams:null,fnStateLoaded:null,fnStateSaveCallback:function(a,b){try{(-1===a.iStateDuration?sessionStorage:localStorage).setItem("DataTables_"+a.sInstance+ -"_"+location.pathname,JSON.stringify(b))}catch(c){}},fnStateSaveParams:null,iStateDuration:7200,iDeferLoading:null,iDisplayLength:10,iDisplayStart:0,iTabIndex:0,oClasses:{},oLanguage:{oAria:{sSortAscending:": activate to sort column ascending",sSortDescending:": activate to sort column descending"},oPaginate:{sFirst:"First",sLast:"Last",sNext:"Next",sPrevious:"Previous"},sEmptyTable:"No data available in table",sInfo:"Showing _START_ to _END_ of _TOTAL_ entries",sInfoEmpty:"Showing 0 to 0 of 0 entries", -sInfoFiltered:"(filtered from _MAX_ total entries)",sInfoPostFix:"",sDecimal:"",sThousands:",",sLengthMenu:"Show _MENU_ entries",sLoadingRecords:"Loading...",sProcessing:"Processing...",sSearch:"Search:",sSearchPlaceholder:"",sUrl:"",sZeroRecords:"No matching records found"},oSearch:h.extend({},m.models.oSearch),sAjaxDataProp:"data",sAjaxSource:null,sDom:"lfrtip",searchDelay:null,sPaginationType:"simple_numbers",sScrollX:"",sScrollXInner:"",sScrollY:"",sServerMethod:"GET",renderer:null,rowId:"DT_RowId"}; -Y(m.defaults);m.defaults.column={aDataSort:null,iDataSort:-1,asSorting:["asc","desc"],bSearchable:!0,bSortable:!0,bVisible:!0,fnCreatedCell:null,mData:null,mRender:null,sCellType:"td",sClass:"",sContentPadding:"",sDefaultContent:null,sName:"",sSortDataType:"std",sTitle:null,sType:null,sWidth:null};Y(m.defaults.column);m.models.oSettings={oFeatures:{bAutoWidth:null,bDeferRender:null,bFilter:null,bInfo:null,bLengthChange:null,bPaginate:null,bProcessing:null,bServerSide:null,bSort:null,bSortMulti:null, -bSortClasses:null,bStateSave:null},oScroll:{bCollapse:null,iBarWidth:0,sX:null,sXInner:null,sY:null},oLanguage:{fnInfoCallback:null},oBrowser:{bScrollOversize:!1,bScrollbarLeft:!1,bBounding:!1,barWidth:0},ajax:null,aanFeatures:[],aoData:[],aiDisplay:[],aiDisplayMaster:[],aIds:{},aoColumns:[],aoHeader:[],aoFooter:[],oPreviousSearch:{},aoPreSearchCols:[],aaSorting:null,aaSortingFixed:[],asStripeClasses:null,asDestroyStripes:[],sDestroyWidth:0,aoRowCallback:[],aoHeaderCallback:[],aoFooterCallback:[], -aoDrawCallback:[],aoRowCreatedCallback:[],aoPreDrawCallback:[],aoInitComplete:[],aoStateSaveParams:[],aoStateLoadParams:[],aoStateLoaded:[],sTableId:"",nTable:null,nTHead:null,nTFoot:null,nTBody:null,nTableWrapper:null,bDeferLoading:!1,bInitialised:!1,aoOpenRows:[],sDom:null,searchDelay:null,sPaginationType:"two_button",iStateDuration:0,aoStateSave:[],aoStateLoad:[],oSavedState:null,oLoadedState:null,sAjaxSource:null,sAjaxDataProp:null,bAjaxDataGet:!0,jqXHR:null,json:k,oAjaxData:k,fnServerData:null, -aoServerParams:[],sServerMethod:null,fnFormatNumber:null,aLengthMenu:null,iDraw:0,bDrawing:!1,iDrawError:-1,_iDisplayLength:10,_iDisplayStart:0,_iRecordsTotal:0,_iRecordsDisplay:0,bJUI:null,oClasses:{},bFiltered:!1,bSorted:!1,bSortCellsTop:null,oInit:null,aoDestroyCallback:[],fnRecordsTotal:function(){return"ssp"==y(this)?1*this._iRecordsTotal:this.aiDisplayMaster.length},fnRecordsDisplay:function(){return"ssp"==y(this)?1*this._iRecordsDisplay:this.aiDisplay.length},fnDisplayEnd:function(){var a= -this._iDisplayLength,b=this._iDisplayStart,c=b+a,d=this.aiDisplay.length,e=this.oFeatures,f=e.bPaginate;return e.bServerSide?!1===f||-1===a?b+d:Math.min(b+a,this._iRecordsDisplay):!f||c>d||-1===a?d:c},oInstance:null,sInstance:null,iTabIndex:0,nScrollHead:null,nScrollFoot:null,aLastSort:[],oPlugins:{},rowIdFn:null,rowId:null};m.ext=x={buttons:{},classes:{},build:"dt/dt-1.10.15/cr-1.3.3/fc-3.2.2/fh-3.1.2/r-2.1.1",errMode:"alert",feature:[],search:[],selector:{cell:[],column:[],row:[]},internal:{},legacy:{ajax:null},pager:{},renderer:{pageButton:{}, -header:{}},order:{},type:{detect:[],search:{},order:{}},_unique:0,fnVersionCheck:m.fnVersionCheck,iApiIndex:0,oJUIClasses:{},sVersion:m.version};h.extend(x,{afnFiltering:x.search,aTypes:x.type.detect,ofnSearch:x.type.search,oSort:x.type.order,afnSortData:x.order,aoFeatures:x.feature,oApi:x.internal,oStdClasses:x.classes,oPagination:x.pager});h.extend(m.ext.classes,{sTable:"dataTable",sNoFooter:"no-footer",sPageButton:"paginate_button",sPageButtonActive:"current",sPageButtonDisabled:"disabled",sStripeOdd:"odd", -sStripeEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_asc_disabled",sSortableDesc:"sorting_desc_disabled",sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sFilterInput:"",sLengthSelect:"",sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead", -sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sHeaderTH:"",sFooterTH:"",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:"",sSortJUIWrapper:"",sSortIcon:"",sJUIHeader:"",sJUIFooter:""});var Ea="",Ea="",G=Ea+"ui-state-default",ka=Ea+"css_right ui-icon ui-icon-",Yb=Ea+"fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix";h.extend(m.ext.oJUIClasses, -m.ext.classes,{sPageButton:"fg-button ui-button "+G,sPageButtonActive:"ui-state-disabled",sPageButtonDisabled:"ui-state-disabled",sPaging:"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi ui-buttonset-multi paging_",sSortAsc:G+" sorting_asc",sSortDesc:G+" sorting_desc",sSortable:G+" sorting",sSortableAsc:G+" sorting_asc_disabled",sSortableDesc:G+" sorting_desc_disabled",sSortableNone:G+" sorting_disabled",sSortJUIAsc:ka+"triangle-1-n",sSortJUIDesc:ka+"triangle-1-s",sSortJUI:ka+"carat-2-n-s", -sSortJUIAscAllowed:ka+"carat-1-n",sSortJUIDescAllowed:ka+"carat-1-s",sSortJUIWrapper:"DataTables_sort_wrapper",sSortIcon:"DataTables_sort_icon",sScrollHead:"dataTables_scrollHead "+G,sScrollFoot:"dataTables_scrollFoot "+G,sHeaderTH:G,sFooterTH:G,sJUIHeader:Yb+" ui-corner-tl ui-corner-tr",sJUIFooter:Yb+" ui-corner-bl ui-corner-br"});var Nb=m.ext.pager;h.extend(Nb,{simple:function(){return["previous","next"]},full:function(){return["first","previous","next","last"]},numbers:function(a,b){return[ia(a, -b)]},simple_numbers:function(a,b){return["previous",ia(a,b),"next"]},full_numbers:function(a,b){return["first","previous",ia(a,b),"next","last"]},first_last_numbers:function(a,b){return["first",ia(a,b),"last"]},_numbers:ia,numbers_length:7});h.extend(!0,m.ext.renderer,{pageButton:{_:function(a,b,c,d,e,f){var g=a.oClasses,j=a.oLanguage.oPaginate,i=a.oLanguage.oAria.paginate||{},m,l,p=0,r=function(b,d){var k,t,u,s,v=function(b){Va(a,b.data.action,true)};k=0;for(t=d.length;k").appendTo(b);r(u,s)}else{m=null;l="";switch(s){case "ellipsis":b.append('');break;case "first":m=j.sFirst;l=s+(e>0?"":" "+g.sPageButtonDisabled);break;case "previous":m=j.sPrevious;l=s+(e>0?"":" "+g.sPageButtonDisabled);break;case "next":m=j.sNext;l=s+(e",{"class":g.sPageButton+ -" "+l,"aria-controls":a.sTableId,"aria-label":i[s],"data-dt-idx":p,tabindex:a.iTabIndex,id:c===0&&typeof s==="string"?a.sTableId+"_"+s:null}).html(m).appendTo(b);Ya(u,{action:s},v);p++}}}},t;try{t=h(b).find(H.activeElement).data("dt-idx")}catch(u){}r(h(b).empty(),d);t!==k&&h(b).find("[data-dt-idx="+t+"]").focus()}}});h.extend(m.ext.type.detect,[function(a,b){var c=b.oLanguage.sDecimal;return ab(a,c)?"num"+c:null},function(a){if(a&&!(a instanceof Date)&&!cc.test(a))return null;var b=Date.parse(a); -return null!==b&&!isNaN(b)||M(a)?"date":null},function(a,b){var c=b.oLanguage.sDecimal;return ab(a,c,!0)?"num-fmt"+c:null},function(a,b){var c=b.oLanguage.sDecimal;return Sb(a,c)?"html-num"+c:null},function(a,b){var c=b.oLanguage.sDecimal;return Sb(a,c,!0)?"html-num-fmt"+c:null},function(a){return M(a)||"string"===typeof a&&-1!==a.indexOf("<")?"html":null}]);h.extend(m.ext.type.search,{html:function(a){return M(a)?a:"string"===typeof a?a.replace(Pb," ").replace(Ca,""):""},string:function(a){return M(a)? -a:"string"===typeof a?a.replace(Pb," "):a}});var Ba=function(a,b,c,d){if(0!==a&&(!a||"-"===a))return-Infinity;b&&(a=Rb(a,b));a.replace&&(c&&(a=a.replace(c,"")),d&&(a=a.replace(d,"")));return 1*a};h.extend(x.type.order,{"date-pre":function(a){return Date.parse(a)||-Infinity},"html-pre":function(a){return M(a)?"":a.replace?a.replace(/<.*?>/g,"").toLowerCase():a+""},"string-pre":function(a){return M(a)?"":"string"===typeof a?a.toLowerCase():!a.toString?"":a.toString()},"string-asc":function(a,b){return a< -b?-1:a>b?1:0},"string-desc":function(a,b){return ab?-1:0}});fb("");h.extend(!0,m.ext.renderer,{header:{_:function(a,b,c,d){h(a.nTable).on("order.dt.DT",function(e,f,g,h){if(a===f){e=c.idx;b.removeClass(c.sSortingClass+" "+d.sSortAsc+" "+d.sSortDesc).addClass(h[e]=="asc"?d.sSortAsc:h[e]=="desc"?d.sSortDesc:c.sSortingClass)}})},jqueryui:function(a,b,c,d){h("
    ").addClass(d.sSortJUIWrapper).append(b.contents()).append(h("").addClass(d.sSortIcon+" "+c.sSortingClassJUI)).appendTo(b); -h(a.nTable).on("order.dt.DT",function(e,f,g,h){if(a===f){e=c.idx;b.removeClass(d.sSortAsc+" "+d.sSortDesc).addClass(h[e]=="asc"?d.sSortAsc:h[e]=="desc"?d.sSortDesc:c.sSortingClass);b.find("span."+d.sSortIcon).removeClass(d.sSortJUIAsc+" "+d.sSortJUIDesc+" "+d.sSortJUI+" "+d.sSortJUIAscAllowed+" "+d.sSortJUIDescAllowed).addClass(h[e]=="asc"?d.sSortJUIAsc:h[e]=="desc"?d.sSortJUIDesc:c.sSortingClassJUI)}})}}});var Zb=function(a){return"string"===typeof a?a.replace(//g,">").replace(/"/g, -"""):a};m.render={number:function(a,b,c,d,e){return{display:function(f){if("number"!==typeof f&&"string"!==typeof f)return f;var g=0>f?"-":"",h=parseFloat(f);if(isNaN(h))return Zb(f);h=h.toFixed(c);f=Math.abs(h);h=parseInt(f,10);f=c?b+(f-h).toFixed(c).substring(2):"";return g+(d||"")+h.toString().replace(/\B(?=(\d{3})+(?!\d))/g,a)+f+(e||"")}}},text:function(){return{display:Zb}}};h.extend(m.ext.internal,{_fnExternApiFunc:Ob,_fnBuildAjax:ua,_fnAjaxUpdate:nb,_fnAjaxParameters:wb,_fnAjaxUpdateDraw:xb, -_fnAjaxDataSrc:va,_fnAddColumn:Ga,_fnColumnOptions:la,_fnAdjustColumnSizing:Z,_fnVisibleToColumnIndex:$,_fnColumnIndexToVisible:aa,_fnVisbleColumns:ba,_fnGetColumns:na,_fnColumnTypes:Ia,_fnApplyColumnDefs:kb,_fnHungarianMap:Y,_fnCamelToHungarian:J,_fnLanguageCompat:Fa,_fnBrowserDetect:ib,_fnAddData:N,_fnAddTr:oa,_fnNodeToDataIndex:function(a,b){return b._DT_RowIndex!==k?b._DT_RowIndex:null},_fnNodeToColumnIndex:function(a,b,c){return h.inArray(c,a.aoData[b].anCells)},_fnGetCellData:B,_fnSetCellData:lb, -_fnSplitObjNotation:La,_fnGetObjectDataFn:R,_fnSetObjectDataFn:S,_fnGetDataMaster:Ma,_fnClearTable:pa,_fnDeleteIndex:qa,_fnInvalidate:da,_fnGetRowElements:Ka,_fnCreateTr:Ja,_fnBuildHead:mb,_fnDrawHead:fa,_fnDraw:O,_fnReDraw:T,_fnAddOptionsHtml:pb,_fnDetectHeader:ea,_fnGetUniqueThs:ta,_fnFeatureHtmlFilter:rb,_fnFilterComplete:ga,_fnFilterCustom:Ab,_fnFilterColumn:zb,_fnFilter:yb,_fnFilterCreateSearch:Ra,_fnEscapeRegex:Sa,_fnFilterData:Bb,_fnFeatureHtmlInfo:ub,_fnUpdateInfo:Eb,_fnInfoMacros:Fb,_fnInitialise:ha, -_fnInitComplete:wa,_fnLengthChange:Ta,_fnFeatureHtmlLength:qb,_fnFeatureHtmlPaginate:vb,_fnPageChange:Va,_fnFeatureHtmlProcessing:sb,_fnProcessingDisplay:C,_fnFeatureHtmlTable:tb,_fnScrollDraw:ma,_fnApplyToChildren:I,_fnCalculateColumnWidths:Ha,_fnThrottle:Qa,_fnConvertToWidth:Gb,_fnGetWidestNode:Hb,_fnGetMaxLenString:Ib,_fnStringToCss:v,_fnSortFlatten:W,_fnSort:ob,_fnSortAria:Kb,_fnSortListener:Xa,_fnSortAttachListener:Oa,_fnSortingClasses:ya,_fnSortData:Jb,_fnSaveState:za,_fnLoadState:Lb,_fnSettingsFromNode:Aa, -_fnLog:K,_fnMap:F,_fnBindAction:Ya,_fnCallbackReg:z,_fnCallbackFire:s,_fnLengthOverflow:Ua,_fnRenderer:Pa,_fnDataSource:y,_fnRowAttributes:Na,_fnCalculateEnd:function(){}});h.fn.dataTable=m;m.$=h;h.fn.dataTableSettings=m.settings;h.fn.dataTableExt=m.ext;h.fn.DataTable=function(a){return h(this).dataTable(a).api()};h.each(m,function(a,b){h.fn.DataTable[a]=b});return h.fn.dataTable}); +var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.findInternal=function(l,z,A){l instanceof String&&(l=String(l));for(var q=l.length,E=0;E").css({position:"fixed",top:0,left:-1*l(z).scrollLeft(),height:1, +width:1,overflow:"hidden"}).append(l("
    ").css({position:"absolute",top:1,left:1,width:100,overflow:"scroll"}).append(l("
    ").css({width:"100%",height:10}))).appendTo("body"),d=c.children(),e=d.children();b.barWidth=d[0].offsetWidth-d[0].clientWidth;b.bScrollOversize=100===e[0].offsetWidth&&100!==d[0].clientWidth;b.bScrollbarLeft=1!==Math.round(e.offset().left);b.bBounding=c[0].getBoundingClientRect().width?!0:!1;c.remove()}l.extend(a.oBrowser,u.__browser);a.oScroll.iBarWidth=u.__browser.barWidth} +function Cb(a,b,c,d,e,h){var f=!1;if(c!==q){var g=c;f=!0}for(;d!==e;)a.hasOwnProperty(d)&&(g=f?b(g,a[d],d,a):a[d],f=!0,d+=h);return g}function Ya(a,b){var c=u.defaults.column,d=a.aoColumns.length;c=l.extend({},u.models.oColumn,c,{nTh:b?b:A.createElement("th"),sTitle:c.sTitle?c.sTitle:b?b.innerHTML:"",aDataSort:c.aDataSort?c.aDataSort:[d],mData:c.mData?c.mData:d,idx:d});a.aoColumns.push(c);c=a.aoPreSearchCols;c[d]=l.extend({},u.models.oSearch,c[d]);Ga(a,d,l(b).data())}function Ga(a,b,c){b=a.aoColumns[b]; +var d=a.oClasses,e=l(b.nTh);if(!b.sWidthOrig){b.sWidthOrig=e.attr("width")||null;var h=(e.attr("style")||"").match(/width:\s*(\d+[pxem%]+)/);h&&(b.sWidthOrig=h[1])}c!==q&&null!==c&&(Ab(c),P(u.defaults.column,c,!0),c.mDataProp===q||c.mData||(c.mData=c.mDataProp),c.sType&&(b._sManualType=c.sType),c.className&&!c.sClass&&(c.sClass=c.className),c.sClass&&e.addClass(c.sClass),l.extend(b,c),X(b,c,"sWidth","sWidthOrig"),c.iDataSort!==q&&(b.aDataSort=[c.iDataSort]),X(b,c,"aDataSort"));var f=b.mData,g=na(f), +k=b.mRender?na(b.mRender):null;c=function(m){return"string"===typeof m&&-1!==m.indexOf("@")};b._bAttrSrc=l.isPlainObject(f)&&(c(f.sort)||c(f.type)||c(f.filter));b._setter=null;b.fnGetData=function(m,n,p){var t=g(m,n,q,p);return k&&n?k(t,n,m,p):t};b.fnSetData=function(m,n,p){return ha(f)(m,n,p)};"number"!==typeof f&&(a._rowReadObject=!0);a.oFeatures.bSort||(b.bSortable=!1,e.addClass(d.sSortableNone));a=-1!==l.inArray("asc",b.asSorting);c=-1!==l.inArray("desc",b.asSorting);b.bSortable&&(a||c)?a&&!c? +(b.sSortingClass=d.sSortableAsc,b.sSortingClassJUI=d.sSortJUIAscAllowed):!a&&c?(b.sSortingClass=d.sSortableDesc,b.sSortingClassJUI=d.sSortJUIDescAllowed):(b.sSortingClass=d.sSortable,b.sSortingClassJUI=d.sSortJUI):(b.sSortingClass=d.sSortableNone,b.sSortingClassJUI="")}function ta(a){if(!1!==a.oFeatures.bAutoWidth){var b=a.aoColumns;Za(a);for(var c=0,d=b.length;cm[n])d(g.length+m[n],k);else if("string"===typeof m[n]){var p=0;for(f=g.length;pb&&a[e]--; -1!=d&&c===q&&a.splice(d,1)}function wa(a,b,c,d){var e=a.aoData[b],h,f=function(k,m){for(;k.childNodes.length;)k.removeChild(k.firstChild);k.innerHTML=T(a,b,m,"display")};if("dom"!==c&&(c&&"auto"!==c||"dom"!==e.src)){var g=e.anCells;if(g)if(d!==q)f(g[d],d);else for(c=0,h=g.length;c").appendTo(d));var k=0;for(b=g.length;k=a.fnRecordsDisplay()?0:d,a.iInitDisplayStart=-1);c=F(a,"aoPreDrawCallback","preDraw",[a]);if(-1!==l.inArray(!1,c))V(a,!1);else{c=[];var e=0;d=a.asStripeClasses;var h=d.length,f=a.oLanguage,g="ssp"==Q(a),k=a.aiDisplay,m=a._iDisplayStart,n=a.fnDisplayEnd();a.bDrawing=!0;if(a.bDeferLoading)a.bDeferLoading=!1,a.iDraw++,V(a,!1);else if(!g)a.iDraw++;else if(!a.bDestroying&&!b){Gb(a);return}if(0!==k.length)for(b=g?a.aoData.length:n,f=g?0:m;f",{"class":h?d[0]:""}).append(l("
    ").insertAfter(H));r.nTBody=ea[0];H=t.children("tfoot");0===H.length&&0").appendTo(t));0===H.length||0===H.children().length?t.addClass(C.sNoFooter):0/g,uc=/^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/,vc=/(\/|\.|\*|\+|\?|\||\(|\)|\[|\]|\{|\}|\\|\$|\^|\-)/g,rb=/['\u00A0,$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi,Z=function(a){return a&&!0!==a&&"-"!==a?!1:!0},hc= +function(a){var b=parseInt(a,10);return!isNaN(b)&&isFinite(a)?b:null},ic=function(a,b){sb[b]||(sb[b]=new RegExp(jb(b),"g"));return"string"===typeof a&&"."!==b?a.replace(/\./g,"").replace(sb[b],"."):a},tb=function(a,b,c){var d="string"===typeof a;if(Z(a))return!0;b&&d&&(a=ic(a,b));c&&d&&(a=a.replace(rb,""));return!isNaN(parseFloat(a))&&isFinite(a)},jc=function(a,b,c){return Z(a)?!0:Z(a)||"string"===typeof a?tb(a.replace(Va,""),b,c)?!0:null:null},U=function(a,b,c){var d=[],e=0,h=a.length;if(c!==q)for(;e< +h;e++)a[e]&&a[e][b]&&d.push(a[e][b][c]);else for(;ea.length)){var b=a.slice().sort();for(var c=b[0],d=1,e=b.length;d< +e;d++){if(b[d]===c){b=!1;break a}c=b[d]}}b=!0}if(b)return a.slice();b=[];e=a.length;var h,f=0;d=0;a:for(;d")[0],sc=Qa.textContent!==q,tc=/<.*?>/g,hb=u.util.throttle,nc=[],N=Array.prototype,wc=function(a){var b,c=u.settings,d=l.map(c,function(h,f){return h.nTable});if(a){if(a.nTable&&a.oApi)return[a];if(a.nodeName&&"table"===a.nodeName.toLowerCase()){var e= +l.inArray(a,d);return-1!==e?[c[e]]:null}if(a&&"function"===typeof a.settings)return a.settings().toArray();"string"===typeof a?b=l(a):a instanceof l&&(b=a)}else return[];if(b)return b.map(function(h){e=l.inArray(this,d);return-1!==e?c[e]:null}).toArray()};var B=function(a,b){if(!(this instanceof B))return new B(a,b);var c=[],d=function(f){(f=wc(f))&&c.push.apply(c,f)};if(Array.isArray(a))for(var e=0,h=a.length;ea?new B(b[a],this[a]):null},filter:function(a){var b=[];if(N.filter)b=N.filter.call(this,a,this);else for(var c=0,d=this.length;c").addClass(g),l("td",k).addClass(g).html(f)[0].colSpan=oa(a),e.push(k[0]))};h(c,d);b._details&&b._details.detach();b._details=l(e);b._detailsShow&&b._details.insertAfter(b.nTr)},xb=function(a,b){var c=a.context;c.length&&(a=c[0].aoData[b!==q?b:a[0]])&&a._details&&(a._details.remove(),a._detailsShow=q,a._details= +q,l(a.nTr).removeClass("dt-hasChild"),qa(c[0]))},qc=function(a,b){var c=a.context;if(c.length&&a.length){var d=c[0].aoData[a[0]];d._details&&((d._detailsShow=b)?(d._details.insertAfter(d.nTr),l(d.nTr).addClass("dt-hasChild")):(d._details.detach(),l(d.nTr).removeClass("dt-hasChild")),F(c[0],null,"childRow",[b,a.row(a[0])]),zc(c[0]),qa(c[0]))}},zc=function(a){var b=new B(a),c=a.aoData;b.off("draw.dt.DT_details column-visibility.dt.DT_details destroy.dt.DT_details");0g){var n=l.map(d,function(p,t){return p.bVisible?t:null});return[n[n.length+g]]}return[ua(a,g)];case "name":return l.map(e,function(p,t){return p===m[1]?t:null});default:return[]}if(f.nodeName&&f._DT_CellIndex)return[f._DT_CellIndex.column];g=l(h).filter(f).map(function(){return l.inArray(this,h)}).toArray();if(g.length||!f.nodeName)return g;g=l(f).closest("*[data-dt-column]");return g.length?[g.data("dt-column")]:[]},a,c)};y("columns()",function(a,b){a===q?a="":l.isPlainObject(a)&&(b=a, +a="");b=vb(b);var c=this.iterator("table",function(d){return Bc(d,a,b)},1);c.selector.cols=a;c.selector.opts=b;return c});J("columns().header()","column().header()",function(a,b){return this.iterator("column",function(c,d){return c.aoColumns[d].nTh},1)});J("columns().footer()","column().footer()",function(a,b){return this.iterator("column",function(c,d){return c.aoColumns[d].nTf},1)});J("columns().data()","column().data()",function(){return this.iterator("column-rows",rc,1)});J("columns().dataSrc()", +"column().dataSrc()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].mData},1)});J("columns().cache()","column().cache()",function(a){return this.iterator("column-rows",function(b,c,d,e,h){return Ea(b.aoData,h,"search"===a?"_aFilterData":"_aSortData",c)},1)});J("columns().nodes()","column().nodes()",function(){return this.iterator("column-rows",function(a,b,c,d,e){return Ea(a.aoData,e,"anCells",b)},1)});J("columns().visible()","column().visible()",function(a,b){var c= +this,d=this.iterator("column",function(e,h){if(a===q)return e.aoColumns[h].bVisible;var f=e.aoColumns,g=f[h],k=e.aoData,m;if(a!==q&&g.bVisible!==a){if(a){var n=l.inArray(!0,U(f,"bVisible"),h+1);f=0;for(m=k.length;fd;return!0};u.isDataTable=u.fnIsDataTable=function(a){var b=l(a).get(0),c=!1;if(a instanceof u.Api)return!0;l.each(u.settings,function(d,e){d=e.nScrollHead?l("table",e.nScrollHead)[0]:null;var h=e.nScrollFoot?l("table",e.nScrollFoot)[0]:null;if(e.nTable===b||d===b||h===b)c=!0});return c};u.tables=u.fnTables=function(a){var b= +!1;l.isPlainObject(a)&&(b=a.api,a=a.visible);var c=l.map(u.settings,function(d){if(!a||a&&l(d.nTable).is(":visible"))return d.nTable});return b?new B(c):c};u.camelToHungarian=P;y("$()",function(a,b){b=this.rows(b).nodes();b=l(b);return l([].concat(b.filter(a).toArray(),b.find(a).toArray()))});l.each(["on","one","off"],function(a,b){y(b+"()",function(){var c=Array.prototype.slice.call(arguments);c[0]=l.map(c[0].split(/\s/),function(e){return e.match(/\.dt\b/)?e:e+".dt"}).join(" ");var d=l(this.tables().nodes()); +d[b].apply(d,c);return this})});y("clear()",function(){return this.iterator("table",function(a){Ka(a)})});y("settings()",function(){return new B(this.context,this.context)});y("init()",function(){var a=this.context;return a.length?a[0].oInit:null});y("data()",function(){return this.iterator("table",function(a){return U(a.aoData,"_aData")}).flatten()});y("destroy()",function(a){a=a||!1;return this.iterator("table",function(b){var c=b.nTableWrapper.parentNode,d=b.oClasses,e=b.nTable,h=b.nTBody,f=b.nTHead, +g=b.nTFoot,k=l(e);h=l(h);var m=l(b.nTableWrapper),n=l.map(b.aoData,function(t){return t.nTr}),p;b.bDestroying=!0;F(b,"aoDestroyCallback","destroy",[b]);a||(new B(b)).columns().visible(!0);m.off(".DT").find(":not(tbody *)").off(".DT");l(z).off(".DT-"+b.sInstance);e!=f.parentNode&&(k.children("thead").detach(),k.append(f));g&&e!=g.parentNode&&(k.children("tfoot").detach(),k.append(g));b.aaSorting=[];b.aaSortingFixed=[];Sa(b);l(n).removeClass(b.asStripeClasses.join(" "));l("th, td",f).removeClass(d.sSortable+ +" "+d.sSortableAsc+" "+d.sSortableDesc+" "+d.sSortableNone);h.children().detach();h.append(n);f=a?"remove":"detach";k[f]();m[f]();!a&&c&&(c.insertBefore(e,b.nTableReinsertBefore),k.css("width",b.sDestroyWidth).removeClass(d.sTable),(p=b.asDestroyStripes.length)&&h.children().each(function(t){l(this).addClass(b.asDestroyStripes[t%p])}));c=l.inArray(b,u.settings);-1!==c&&u.settings.splice(c,1)})});l.each(["column","row","cell"],function(a,b){y(b+"s().every()",function(c){var d=this.selector.opts,e= +this;return this.iterator(b,function(h,f,g,k,m){c.call(e[b](f,"cell"===b?g:d,"cell"===b?d:q),f,g,k,m)})})});y("i18n()",function(a,b,c){var d=this.context[0];a=na(a)(d.oLanguage);a===q&&(a=b);c!==q&&l.isPlainObject(a)&&(a=a[c]!==q?a[c]:a._);return a.replace("%d",c)});u.version="1.11.4";u.settings=[];u.models={};u.models.oSearch={bCaseInsensitive:!0,sSearch:"",bRegex:!1,bSmart:!0,"return":!1};u.models.oRow={nTr:null,anCells:null,_aData:[],_aSortData:null,_aFilterData:null,_sFilterRow:null,_sRowStripe:"", +src:null,idx:-1};u.models.oColumn={idx:null,aDataSort:null,asSorting:null,bSearchable:null,bSortable:null,bVisible:null,_sManualType:null,_bAttrSrc:!1,fnCreatedCell:null,fnGetData:null,fnSetData:null,mData:null,mRender:null,nTh:null,nTf:null,sClass:null,sContentPadding:null,sDefaultContent:null,sName:null,sSortDataType:"std",sSortingClass:null,sSortingClassJUI:null,sTitle:null,sType:null,sWidth:null,sWidthOrig:null};u.defaults={aaData:null,aaSorting:[[0,"asc"]],aaSortingFixed:[],ajax:null,aLengthMenu:[10, +25,50,100],aoColumns:null,aoColumnDefs:null,aoSearchCols:[],asStripeClasses:null,bAutoWidth:!0,bDeferRender:!1,bDestroy:!1,bFilter:!0,bInfo:!0,bLengthChange:!0,bPaginate:!0,bProcessing:!1,bRetrieve:!1,bScrollCollapse:!1,bServerSide:!1,bSort:!0,bSortMulti:!0,bSortCellsTop:!1,bSortClasses:!0,bStateSave:!1,fnCreatedRow:null,fnDrawCallback:null,fnFooterCallback:null,fnFormatNumber:function(a){return a.toString().replace(/\B(?=(\d{3})+(?!\d))/g,this.oLanguage.sThousands)},fnHeaderCallback:null,fnInfoCallback:null, +fnInitComplete:null,fnPreDrawCallback:null,fnRowCallback:null,fnServerData:null,fnServerParams:null,fnStateLoadCallback:function(a){try{return JSON.parse((-1===a.iStateDuration?sessionStorage:localStorage).getItem("DataTables_"+a.sInstance+"_"+location.pathname))}catch(b){return{}}},fnStateLoadParams:null,fnStateLoaded:null,fnStateSaveCallback:function(a,b){try{(-1===a.iStateDuration?sessionStorage:localStorage).setItem("DataTables_"+a.sInstance+"_"+location.pathname,JSON.stringify(b))}catch(c){}}, +fnStateSaveParams:null,iStateDuration:7200,iDeferLoading:null,iDisplayLength:10,iDisplayStart:0,iTabIndex:0,oClasses:{},oLanguage:{oAria:{sSortAscending:": activate to sort column ascending",sSortDescending:": activate to sort column descending"},oPaginate:{sFirst:"First",sLast:"Last",sNext:"Next",sPrevious:"Previous"},sEmptyTable:"No data available in table",sInfo:"Showing _START_ to _END_ of _TOTAL_ entries",sInfoEmpty:"Showing 0 to 0 of 0 entries",sInfoFiltered:"(filtered from _MAX_ total entries)", +sInfoPostFix:"",sDecimal:"",sThousands:",",sLengthMenu:"Show _MENU_ entries",sLoadingRecords:"Loading...",sProcessing:"Processing...",sSearch:"Search:",sSearchPlaceholder:"",sUrl:"",sZeroRecords:"No matching records found"},oSearch:l.extend({},u.models.oSearch),sAjaxDataProp:"data",sAjaxSource:null,sDom:"lfrtip",searchDelay:null,sPaginationType:"simple_numbers",sScrollX:"",sScrollXInner:"",sScrollY:"",sServerMethod:"GET",renderer:null,rowId:"DT_RowId"};E(u.defaults);u.defaults.column={aDataSort:null, +iDataSort:-1,asSorting:["asc","desc"],bSearchable:!0,bSortable:!0,bVisible:!0,fnCreatedCell:null,mData:null,mRender:null,sCellType:"td",sClass:"",sContentPadding:"",sDefaultContent:null,sName:"",sSortDataType:"std",sTitle:null,sType:null,sWidth:null};E(u.defaults.column);u.models.oSettings={oFeatures:{bAutoWidth:null,bDeferRender:null,bFilter:null,bInfo:null,bLengthChange:null,bPaginate:null,bProcessing:null,bServerSide:null,bSort:null,bSortMulti:null,bSortClasses:null,bStateSave:null},oScroll:{bCollapse:null, +iBarWidth:0,sX:null,sXInner:null,sY:null},oLanguage:{fnInfoCallback:null},oBrowser:{bScrollOversize:!1,bScrollbarLeft:!1,bBounding:!1,barWidth:0},ajax:null,aanFeatures:[],aoData:[],aiDisplay:[],aiDisplayMaster:[],aIds:{},aoColumns:[],aoHeader:[],aoFooter:[],oPreviousSearch:{},aoPreSearchCols:[],aaSorting:null,aaSortingFixed:[],asStripeClasses:null,asDestroyStripes:[],sDestroyWidth:0,aoRowCallback:[],aoHeaderCallback:[],aoFooterCallback:[],aoDrawCallback:[],aoRowCreatedCallback:[],aoPreDrawCallback:[], +aoInitComplete:[],aoStateSaveParams:[],aoStateLoadParams:[],aoStateLoaded:[],sTableId:"",nTable:null,nTHead:null,nTFoot:null,nTBody:null,nTableWrapper:null,bDeferLoading:!1,bInitialised:!1,aoOpenRows:[],sDom:null,searchDelay:null,sPaginationType:"two_button",iStateDuration:0,aoStateSave:[],aoStateLoad:[],oSavedState:null,oLoadedState:null,sAjaxSource:null,sAjaxDataProp:null,jqXHR:null,json:q,oAjaxData:q,fnServerData:null,aoServerParams:[],sServerMethod:null,fnFormatNumber:null,aLengthMenu:null,iDraw:0, +bDrawing:!1,iDrawError:-1,_iDisplayLength:10,_iDisplayStart:0,_iRecordsTotal:0,_iRecordsDisplay:0,oClasses:{},bFiltered:!1,bSorted:!1,bSortCellsTop:null,oInit:null,aoDestroyCallback:[],fnRecordsTotal:function(){return"ssp"==Q(this)?1*this._iRecordsTotal:this.aiDisplayMaster.length},fnRecordsDisplay:function(){return"ssp"==Q(this)?1*this._iRecordsDisplay:this.aiDisplay.length},fnDisplayEnd:function(){var a=this._iDisplayLength,b=this._iDisplayStart,c=b+a,d=this.aiDisplay.length,e=this.oFeatures,h= +e.bPaginate;return e.bServerSide?!1===h||-1===a?b+d:Math.min(b+a,this._iRecordsDisplay):!h||c>d||-1===a?d:c},oInstance:null,sInstance:null,iTabIndex:0,nScrollHead:null,nScrollFoot:null,aLastSort:[],oPlugins:{},rowIdFn:null,rowId:null};u.ext=M={buttons:{},classes:{},build:"dt/dt-1.11.4/fc-4.0.1/fh-3.2.1/r-2.2.9/sb-1.3.1",errMode:"alert",feature:[],search:[],selector:{cell:[],column:[],row:[]},internal:{},legacy:{ajax:null},pager:{},renderer:{pageButton:{},header:{}},order:{},type:{detect:[],search:{},order:{}},_unique:0,fnVersionCheck:u.fnVersionCheck, +iApiIndex:0,oJUIClasses:{},sVersion:u.version};l.extend(M,{afnFiltering:M.search,aTypes:M.type.detect,ofnSearch:M.type.search,oSort:M.type.order,afnSortData:M.order,aoFeatures:M.feature,oApi:M.internal,oStdClasses:M.classes,oPagination:M.pager});l.extend(u.ext.classes,{sTable:"dataTable",sNoFooter:"no-footer",sPageButton:"paginate_button",sPageButtonActive:"current",sPageButtonDisabled:"disabled",sStripeOdd:"odd",sStripeEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter", +sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_desc_disabled",sSortableDesc:"sorting_asc_disabled",sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sFilterInput:"",sLengthSelect:"",sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead",sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody", +sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sHeaderTH:"",sFooterTH:"",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:"",sSortJUIWrapper:"",sSortIcon:"",sJUIHeader:"",sJUIFooter:""});var ec=u.ext.pager;l.extend(ec,{simple:function(a,b){return["previous","next"]},full:function(a,b){return["first","previous","next","last"]},numbers:function(a,b){return[Da(a,b)]},simple_numbers:function(a,b){return["previous",Da(a,b),"next"]}, +full_numbers:function(a,b){return["first","previous",Da(a,b),"next","last"]},first_last_numbers:function(a,b){return["first",Da(a,b),"last"]},_numbers:Da,numbers_length:7});l.extend(!0,u.ext.renderer,{pageButton:{_:function(a,b,c,d,e,h){var f=a.oClasses,g=a.oLanguage.oPaginate,k=a.oLanguage.oAria.paginate||{},m,n,p=0,t=function(x,w){var r,C=f.sPageButtonDisabled,G=function(I){Ra(a,I.data.action,!0)};var aa=0;for(r=w.length;aa").appendTo(x); +t(O,L)}else{m=null;n=L;O=a.iTabIndex;switch(L){case "ellipsis":x.append('');break;case "first":m=g.sFirst;0===e&&(O=-1,n+=" "+C);break;case "previous":m=g.sPrevious;0===e&&(O=-1,n+=" "+C);break;case "next":m=g.sNext;if(0===h||e===h-1)O=-1,n+=" "+C;break;case "last":m=g.sLast;if(0===h||e===h-1)O=-1,n+=" "+C;break;default:m=a.fnFormatNumber(L+1),n=e===L?f.sPageButtonActive:""}null!==m&&(O=l("",{"class":f.sPageButton+" "+n,"aria-controls":a.sTableId,"aria-label":k[L], +"data-dt-idx":p,tabindex:O,id:0===c&&"string"===typeof L?a.sTableId+"_"+L:null}).html(m).appendTo(x),ob(O,{action:L},G),p++)}}};try{var v=l(b).find(A.activeElement).data("dt-idx")}catch(x){}t(l(b).empty(),d);v!==q&&l(b).find("[data-dt-idx="+v+"]").trigger("focus")}}});l.extend(u.ext.type.detect,[function(a,b){b=b.oLanguage.sDecimal;return tb(a,b)?"num"+b:null},function(a,b){if(a&&!(a instanceof Date)&&!uc.test(a))return null;b=Date.parse(a);return null!==b&&!isNaN(b)||Z(a)?"date":null},function(a, +b){b=b.oLanguage.sDecimal;return tb(a,b,!0)?"num-fmt"+b:null},function(a,b){b=b.oLanguage.sDecimal;return jc(a,b)?"html-num"+b:null},function(a,b){b=b.oLanguage.sDecimal;return jc(a,b,!0)?"html-num-fmt"+b:null},function(a,b){return Z(a)||"string"===typeof a&&-1!==a.indexOf("<")?"html":null}]);l.extend(u.ext.type.search,{html:function(a){return Z(a)?a:"string"===typeof a?a.replace(gc," ").replace(Va,""):""},string:function(a){return Z(a)?a:"string"===typeof a?a.replace(gc," "):a}});var Ua=function(a, +b,c,d){if(0!==a&&(!a||"-"===a))return-Infinity;b&&(a=ic(a,b));a.replace&&(c&&(a=a.replace(c,"")),d&&(a=a.replace(d,"")));return 1*a};l.extend(M.type.order,{"date-pre":function(a){a=Date.parse(a);return isNaN(a)?-Infinity:a},"html-pre":function(a){return Z(a)?"":a.replace?a.replace(/<.*?>/g,"").toLowerCase():a+""},"string-pre":function(a){return Z(a)?"":"string"===typeof a?a.toLowerCase():a.toString?a.toString():""},"string-asc":function(a,b){return ab?1:0},"string-desc":function(a,b){return a< +b?1:a>b?-1:0}});Xa("");l.extend(!0,u.ext.renderer,{header:{_:function(a,b,c,d){l(a.nTable).on("order.dt.DT",function(e,h,f,g){a===h&&(e=c.idx,b.removeClass(d.sSortAsc+" "+d.sSortDesc).addClass("asc"==g[e]?d.sSortAsc:"desc"==g[e]?d.sSortDesc:c.sSortingClass))})},jqueryui:function(a,b,c,d){l("
    ").addClass(d.sSortJUIWrapper).append(b.contents()).append(l("").addClass(d.sSortIcon+" "+c.sSortingClassJUI)).appendTo(b);l(a.nTable).on("order.dt.DT",function(e,h,f,g){a===h&&(e=c.idx,b.removeClass(d.sSortAsc+ +" "+d.sSortDesc).addClass("asc"==g[e]?d.sSortAsc:"desc"==g[e]?d.sSortDesc:c.sSortingClass),b.find("span."+d.sSortIcon).removeClass(d.sSortJUIAsc+" "+d.sSortJUIDesc+" "+d.sSortJUI+" "+d.sSortJUIAscAllowed+" "+d.sSortJUIDescAllowed).addClass("asc"==g[e]?d.sSortJUIAsc:"desc"==g[e]?d.sSortJUIDesc:c.sSortingClassJUI))})}}});var yb=function(a){Array.isArray(a)&&(a=a.join(","));return"string"===typeof a?a.replace(/&/g,"&").replace(//g,">").replace(/"/g,"""):a};u.render= +{number:function(a,b,c,d,e){return{display:function(h){if("number"!==typeof h&&"string"!==typeof h)return h;var f=0>h?"-":"",g=parseFloat(h);if(isNaN(g))return yb(h);g=g.toFixed(c);h=Math.abs(g);g=parseInt(h,10);h=c?b+(h-g).toFixed(c).substring(2):"";0===g&&0===parseFloat(h)&&(f="");return f+(d||"")+g.toString().replace(/\B(?=(\d{3})+(?!\d))/g,a)+h+(e||"")}}},text:function(){return{display:yb,filter:yb}}};l.extend(u.ext.internal,{_fnExternApiFunc:fc,_fnBuildAjax:Oa,_fnAjaxUpdate:Gb,_fnAjaxParameters:Pb, +_fnAjaxUpdateDraw:Qb,_fnAjaxDataSrc:Aa,_fnAddColumn:Ya,_fnColumnOptions:Ga,_fnAdjustColumnSizing:ta,_fnVisibleToColumnIndex:ua,_fnColumnIndexToVisible:va,_fnVisbleColumns:oa,_fnGetColumns:Ia,_fnColumnTypes:$a,_fnApplyColumnDefs:Db,_fnHungarianMap:E,_fnCamelToHungarian:P,_fnLanguageCompat:ma,_fnBrowserDetect:Bb,_fnAddData:ia,_fnAddTr:Ja,_fnNodeToDataIndex:function(a,b){return b._DT_RowIndex!==q?b._DT_RowIndex:null},_fnNodeToColumnIndex:function(a,b,c){return l.inArray(c,a.aoData[b].anCells)},_fnGetCellData:T, +_fnSetCellData:Eb,_fnSplitObjNotation:cb,_fnGetObjectDataFn:na,_fnSetObjectDataFn:ha,_fnGetDataMaster:db,_fnClearTable:Ka,_fnDeleteIndex:La,_fnInvalidate:wa,_fnGetRowElements:bb,_fnCreateTr:ab,_fnBuildHead:Fb,_fnDrawHead:ya,_fnDraw:ja,_fnReDraw:ka,_fnAddOptionsHtml:Ib,_fnDetectHeader:xa,_fnGetUniqueThs:Na,_fnFeatureHtmlFilter:Kb,_fnFilterComplete:za,_fnFilterCustom:Tb,_fnFilterColumn:Sb,_fnFilter:Rb,_fnFilterCreateSearch:ib,_fnEscapeRegex:jb,_fnFilterData:Ub,_fnFeatureHtmlInfo:Nb,_fnUpdateInfo:Xb, +_fnInfoMacros:Yb,_fnInitialise:Ba,_fnInitComplete:Pa,_fnLengthChange:kb,_fnFeatureHtmlLength:Jb,_fnFeatureHtmlPaginate:Ob,_fnPageChange:Ra,_fnFeatureHtmlProcessing:Lb,_fnProcessingDisplay:V,_fnFeatureHtmlTable:Mb,_fnScrollDraw:Ha,_fnApplyToChildren:ca,_fnCalculateColumnWidths:Za,_fnThrottle:hb,_fnConvertToWidth:Zb,_fnGetWidestNode:$b,_fnGetMaxLenString:ac,_fnStringToCss:K,_fnSortFlatten:pa,_fnSort:Hb,_fnSortAria:cc,_fnSortListener:nb,_fnSortAttachListener:fb,_fnSortingClasses:Sa,_fnSortData:bc,_fnSaveState:qa, +_fnLoadState:dc,_fnImplementState:pb,_fnSettingsFromNode:Ta,_fnLog:da,_fnMap:X,_fnBindAction:ob,_fnCallbackReg:R,_fnCallbackFire:F,_fnLengthOverflow:lb,_fnRenderer:gb,_fnDataSource:Q,_fnRowAttributes:eb,_fnExtend:qb,_fnCalculateEnd:function(){}});l.fn.dataTable=u;u.$=l;l.fn.dataTableSettings=u.settings;l.fn.dataTableExt=u.ext;l.fn.DataTable=function(a){return l(this).dataTable(a).api()};l.each(u,function(a,b){l.fn.DataTable[a]=b});return u}); /*! - ColReorder 1.3.3 - ©2010-2015 SpryMedia Ltd - datatables.net/license + DataTables styling integration + ©2018 SpryMedia Ltd - datatables.net/license */ -(function(f){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(o){return f(o,window,document)}):"object"===typeof exports?module.exports=function(o,l){o||(o=window);if(!l||!l.fn.dataTable)l=require("datatables.net")(o,l).$;return f(l,o,o.document)}:f(jQuery,window,document)})(function(f,o,l,r){function q(a){for(var b=[],d=0,e=a.length;db||b>=l)this.oApi._fnLog(a,1,"ColReorder 'from' index is out of bounds: "+b);else if(0>d||d>=l)this.oApi._fnLog(a,1,"ColReorder 'to' index is out of bounds: "+ -d);else{j=[];c=0;for(h=l;cthis.s.fixed-1&&eMath.pow(Math.pow(this._fnCursorPosition(a,"pageX")-this.s.mouse.startX,2)+Math.pow(this._fnCursorPosition(a,"pageY")-this.s.mouse.startY,2),0.5))return;this._fnCreateDragNode()}this.dom.drag.css({left:this._fnCursorPosition(a, -"pageX")-this.s.mouse.offsetX,top:this._fnCursorPosition(a,"pageY")-this.s.mouse.offsetY});for(var b=!1,d=this.s.mouse.toIndex,e=1,f=this.s.aoTargets.length;e
    ").addClass("DTCR_pointer").css({position:"absolute",top:a?f("div.dataTables_scroll",this.s.dt.nTableWrapper).offset().top:f(this.s.dt.nTable).offset().top,height:a?f("div.dataTables_scroll",this.s.dt.nTableWrapper).height():f(this.s.dt.nTable).height()}).appendTo("body")},_fnSetColumnIndexes:function(){f.each(this.s.dt.aoColumns,function(a,b){f(b.nTh).attr("data-column-index",a)})},_fnCursorPosition:function(a, -b){return-1!==a.type.indexOf("touch")?a.originalEvent.touches[0][b]:a[b]}});i.defaults={aiOrder:null,bRealtime:!0,iFixedColumnsLeft:0,iFixedColumnsRight:0,fnReorderCallback:null};i.version="1.3.3";f.fn.dataTable.ColReorder=i;f.fn.DataTable.ColReorder=i;"function"==typeof f.fn.dataTable&&"function"==typeof f.fn.dataTableExt.fnVersionCheck&&f.fn.dataTableExt.fnVersionCheck("1.10.8")?f.fn.dataTableExt.aoFeatures.push({fnInit:function(a){var b=a.oInstance;a._colReorder?b.oApi._fnLog(a,1,"ColReorder attempted to initialise twice. Ignoring second"): -(b=a.oInit,new i(a,b.colReorder||b.oColReorder||{}));return null},cFeature:"R",sFeature:"ColReorder"}):alert("Warning: ColReorder requires DataTables 1.10.8 or greater - www.datatables.net/download");f(l).on("preInit.dt.colReorder",function(a,b){if("dt"===a.namespace){var d=b.oInit.colReorder,e=t.defaults.colReorder;if(d||e)e=f.extend({},d,e),!1!==d&&new i(b,e)}});f.fn.dataTable.Api.register("colReorder.reset()",function(){return this.iterator("table",function(a){a._colReorder.fnReset()})});f.fn.dataTable.Api.register("colReorder.order()", -function(a,b){return a?this.iterator("table",function(d){d._colReorder.fnOrder(a,b)}):this.context.length?this.context[0]._colReorder.fnOrder():null});f.fn.dataTable.Api.register("colReorder.transpose()",function(a,b){return this.context.length&&this.context[0]._colReorder?this.context[0]._colReorder.fnTranspose(a,b):a});return i}); +(function(c){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(a){return c(a,window,document)}):"object"===typeof exports?module.exports=function(a,b){a||(a=window);b&&b.fn.dataTable||(b=require("datatables.net")(a,b).$);return c(b,a,a.document)}:c(jQuery,window,document)})(function(c,a,b,d){return c.fn.dataTable}); /*! - FixedColumns 3.2.2 - ©2010-2016 SpryMedia Ltd - datatables.net/license + FixedColumns 4.0.1 + 2019-2021 SpryMedia Ltd - datatables.net/license */ -(function(d){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(q){return d(q,window,document)}):"object"===typeof exports?module.exports=function(q,r){q||(q=window);if(!r||!r.fn.dataTable)r=require("datatables.net")(q,r).$;return d(r,q,q.document)}:d(jQuery,window,document)})(function(d,q,r,t){var s=d.fn.dataTable,u,m=function(a,b){var c=this;if(this instanceof m){if(b===t||!0===b)b={};var e=d.fn.dataTable.camelToHungarian;e&&(e(m.defaults,m.defaults,!0),e(m.defaults, -b));e=(new d.fn.dataTable.Api(a)).settings()[0];this.s={dt:e,iTableColumns:e.aoColumns.length,aiOuterWidths:[],aiInnerWidths:[],rtl:"rtl"===d(e.nTable).css("direction")};this.dom={scroller:null,header:null,body:null,footer:null,grid:{wrapper:null,dt:null,left:{wrapper:null,head:null,body:null,foot:null},right:{wrapper:null,head:null,body:null,foot:null}},clone:{left:{header:null,body:null,footer:null},right:{header:null,body:null,footer:null}}};if(e._oFixedColumns)throw"FixedColumns already initialised on this table"; -e._oFixedColumns=this;e._bInitComplete?this._fnConstruct(b):e.oApi._fnCallbackReg(e,"aoInitComplete",function(){c._fnConstruct(b)},"FixedColumns")}else alert("FixedColumns warning: FixedColumns must be initialised with the 'new' keyword.")};d.extend(m.prototype,{fnUpdate:function(){this._fnDraw(!0)},fnRedrawLayout:function(){this._fnColCalc();this._fnGridLayout();this.fnUpdate()},fnRecalculateHeight:function(a){delete a._DTTC_iHeight;a.style.height="auto"},fnSetRowHeight:function(a,b){a.style.height= -b+"px"},fnGetPosition:function(a){var b=this.s.dt.oInstance;if(d(a).parents(".DTFC_Cloned").length){if("tr"===a.nodeName.toLowerCase())return a=d(a).index(),b.fnGetPosition(d("tr",this.s.dt.nTBody)[a]);var c=d(a).index(),a=d(a.parentNode).index();return[b.fnGetPosition(d("tr",this.s.dt.nTBody)[a]),c,b.oApi._fnVisibleToColumnIndex(this.s.dt,c)]}return b.fnGetPosition(a)},_fnConstruct:function(a){var b=this;if("function"!=typeof this.s.dt.oInstance.fnVersionCheck||!0!==this.s.dt.oInstance.fnVersionCheck("1.8.0"))alert("FixedColumns "+ -m.VERSION+" required DataTables 1.8.0 or later. Please upgrade your DataTables installation");else if(""===this.s.dt.oScroll.sX)this.s.dt.oInstance.oApi._fnLog(this.s.dt,1,"FixedColumns is not needed (no x-scrolling in DataTables enabled), so no action will be taken. Use 'FixedHeader' for column fixing when scrolling is not enabled");else{this.s=d.extend(!0,this.s,m.defaults,a);a=this.s.dt.oClasses;this.dom.grid.dt=d(this.s.dt.nTable).parents("div."+a.sScrollWrapper)[0];this.dom.scroller=d("div."+ -a.sScrollBody,this.dom.grid.dt)[0];this._fnColCalc();this._fnGridSetup();var c,e=!1;d(this.s.dt.nTableWrapper).on("mousedown.DTFC",function(){e=!0;d(r).one("mouseup",function(){e=!1})});d(this.dom.scroller).on("mouseover.DTFC touchstart.DTFC",function(){e||(c="main")}).on("scroll.DTFC",function(a){!c&&a.originalEvent&&(c="main");if("main"===c&&(0
    ')[0], -e=c.childNodes[0],f=c.childNodes[1];this.dom.grid.dt.parentNode.insertBefore(c,this.dom.grid.dt);c.appendChild(this.dom.grid.dt);this.dom.grid.wrapper=c;0b.clientWidth&&(c.x=!0);a.offsetHeight> -b.clientHeight&&(c.y=!0);return c},_fnDraw:function(a){this._fnGridLayout();this._fnCloneLeft(a);this._fnCloneRight(a);null!==this.s.fnDrawCallback&&this.s.fnDrawCallback.call(this,this.dom.clone.left,this.dom.clone.right);d(this).trigger("draw.dtfc",{leftClone:this.dom.clone.left,rightClone:this.dom.clone.right})},_fnCloneRight:function(a){if(!(0>=this.s.iRightColumns)){var b,c=[];for(b=this.s.iTableColumns-this.s.iRightColumns;b=this.s.iLeftColumns)){var b,c=[];for(b=0;bthead",a.header);j.empty();g=0;for(h=n.length;gthead",a.header)[0]);g=0;for(h=n.length;gtbody>tr",f.dom.body).css("height","auto");null!==a.body&&(d(a.body).remove(), -a.body=null);a.body=d(this.dom.body).clone(!0)[0];a.body.className+=" DTFC_Cloned";a.body.style.paddingBottom=k.oScroll.iBarWidth+"px";a.body.style.marginBottom=2*k.oScroll.iBarWidth+"px";null!==a.body.getAttribute("id")&&a.body.removeAttribute("id");d(">thead>tr",a.body).empty();d(">tfoot",a.body).remove();var q=d("tbody",a.body)[0];d(q).empty();if(0thead>tr",a.body)[0];for(p=0;ptbody>tr",f.dom.body).each(function(a){var a=f.s.dt.oFeatures.bServerSide===false?f.s.dt.aiDisplay[f.s.dt._iDisplayStart+a]:a,b=f.s.dt.aoData[a].anCells||d(this).children("td, th"),e=this.cloneNode(false);e.removeAttribute("id");e.setAttribute("data-dt-row",a);for(p=0;p0){o=d(b[l]).clone(true,true)[0];o.setAttribute("data-dt-row", -a);o.setAttribute("data-dt-column",p);e.appendChild(o)}}q.appendChild(e)})}else d(">tbody>tr",f.dom.body).each(function(){o=this.cloneNode(true);o.className=o.className+" DTFC_NoData";d("td",o).html("");q.appendChild(o)});a.body.style.width="100%";a.body.style.margin="0";a.body.style.padding="0";k.oScroller!==t&&(h=k.oScroller.dom.force,b.forcer?b.forcer.style.height=h.style.height:(b.forcer=h.cloneNode(!0),b.liner.appendChild(b.forcer)));b.liner.appendChild(a.body);this._fnEqualiseHeights("tbody", -f.dom.body,a.body);if(null!==k.nTFoot){if(e){null!==a.footer&&a.footer.parentNode.removeChild(a.footer);a.footer=d(this.dom.footer).clone(!0,!0)[0];a.footer.className+=" DTFC_Cloned";a.footer.style.width="100%";b.foot.appendChild(a.footer);n=this._fnCopyLayout(k.aoFooter,c,!0);b=d(">tfoot",a.footer);b.empty();g=0;for(h=n.length;gtfoot",a.footer)[0]);g=0;for(h=n.length;g< -h;g++){i=0;for(j=n[g].length;ithead",a.header)[0]);d(b).each(function(a){l=c[a];this.style.width=f.s.aiInnerWidths[l]+"px"});null!==f.s.dt.nTFoot&&(b=k.oApi._fnGetUniqueThs(k,d(">tfoot",a.footer)[0]),d(b).each(function(a){l=c[a];this.style.width=f.s.aiInnerWidths[l]+"px"}))},_fnGetTrNodes:function(a){for(var b=[],c=0,d=a.childNodes.length;c"+a+">tr:eq(0)",b).children(":first");a.outerHeight();a.height();for(var g=this._fnGetTrNodes(g),b=this._fnGetTrNodes(c),h=[],c=0,a=b.length;ce?f:e,"semiauto"==this.s.sHeightMatch&&(g[c]._DTTC_iHeight=e),h.push(e);c=0;for(a=b.length;c").css({position:"absolute",top:0,left:0,height:10,width:50,overflow:"scroll"}).appendTo("body");u=a[0].clientWidth===a[0].offsetWidth&&0!==this._fnDTOverflow().bar;a.remove()}return u}});m.defaults={iLeftColumns:1,iRightColumns:0,fnDrawCallback:null,sHeightMatch:"semiauto"};m.version="3.2.2";s.Api.register("fixedColumns()",function(){return this});s.Api.register("fixedColumns().update()",function(){return this.iterator("table", -function(a){a._oFixedColumns&&a._oFixedColumns.fnUpdate()})});s.Api.register("fixedColumns().relayout()",function(){return this.iterator("table",function(a){a._oFixedColumns&&a._oFixedColumns.fnRedrawLayout()})});s.Api.register("rows().recalcHeight()",function(){return this.iterator("row",function(a,b){a._oFixedColumns&&a._oFixedColumns.fnRecalculateHeight(this.row(b).node())})});s.Api.register("fixedColumns().rowIndex()",function(a){a=d(a);return a.parents(".DTFC_Cloned").length?this.rows({page:"current"}).indexes()[a.index()]: -this.row(a).index()});s.Api.register("fixedColumns().cellIndex()",function(a){a=d(a);if(a.parents(".DTFC_Cloned").length){var b=a.parent().index(),b=this.rows({page:"current"}).indexes()[b],a=a.parents(".DTFC_LeftWrapper").length?a.index():this.columns().flatten().length-this.context[0]._oFixedColumns.s.iRightColumns+a.index();return{row:b,column:this.column.index("toData",a),columnVisible:a}}return this.cell(a).index()});d(r).on("init.dt.fixedColumns",function(a,b){if("dt"===a.namespace){var c=b.oInit.fixedColumns, -e=s.defaults.fixedColumns;if(c||e)e=d.extend({},c,e),!1!==c&&new m(b,e)}});d.fn.dataTable.FixedColumns=m;return d.fn.DataTable.FixedColumns=m}); +var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.getGlobal=function(a){a=["object"==typeof globalThis&&globalThis,a,"object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global];for(var g=0;g").css(h).css("left",0).addClass(this.classes.leftBottomBlocker),leftTopBlocker:a("
    ").css(h).css({left:0,top:0}).addClass(this.classes.leftTopBlocker),rightBottomBlocker:a("
    ").css(h).css("right",0).addClass(this.classes.rightBottomBlocker),rightTopBlocker:a("
    ").css(h).css({right:0,top:0}).addClass(this.classes.rightTopBlocker)};if(this.s.dt.settings()[0]._bInitComplete)this._addStyles(), +this._setKeyTableListener();else d.one("preInit.dt",function(){m._addStyles();m._setKeyTableListener()});d.settings()[0]._fixedColumns=this;return this}e.prototype.left=function(d){void 0!==d&&(this.c.left=d,this._addStyles());return this.c.left};e.prototype.right=function(d){void 0!==d&&(this.c.right=d,this._addStyles());return this.c.right};e.prototype._addStyles=function(){if(this.s.dt.settings()[0].oScroll.sY){var d=a(this.s.dt.table().node()).closest("div.dataTables_scrollBody")[0],h=this.s.dt.settings()[0].oBrowser.barWidth; +this.s.barWidth=d.offsetWidth-d.clientWidth>=h?h:0;this.dom.rightTopBlocker.css("width",this.s.barWidth+1);this.dom.leftTopBlocker.css("width",this.s.barWidth+1);this.dom.rightBottomBlocker.css("width",this.s.barWidth+1);this.dom.leftBottomBlocker.css("width",this.s.barWidth+1)}d=null;h=this.s.dt.column(0).header();var m=null;null!==h&&(h=a(h),m=h.outerHeight()+1,d=a(h.closest("div.dataTables_scroll")).css("position","relative"));var n=this.s.dt.column(0).footer(),c=null;null!==n&&(n=a(n),c=n.outerHeight(), +null===d&&(d=a(n.closest("div.dataTables_scroll")).css("position","relative")));for(var b=this.s.dt.columns().data().toArray().length,f=0,l=0,u=a(this.s.dt.table().node()).children("tbody").children("tr"),x=0,A=new Map,r=0;r=b-this.c.right){a(this.s.dt.table().node()).addClass(this.classes.tableFixedRight);d.addClass(this.classes.tableFixedRight);if(r+1+vb.left&&(c=m.scrollLeft(),m.scrollLeft(c-(b.left-(h.left+n)))))});this.s.dt.on("draw",function(){d._addStyles()});this.s.dt.on("column-reorder",function(){d._addStyles()});this.s.dt.on("column-visibility",function(){setTimeout(function(){d._addStyles()},50)})};e.version="4.0.1";e.classes={fixedLeft:"dtfc-fixed-left",fixedRight:"dtfc-fixed-right",leftBottomBlocker:"dtfc-left-bottom-blocker",leftTopBlocker:"dtfc-left-top-blocker",rightBottomBlocker:"dtfc-right-bottom-blocker",rightTopBlocker:"dtfc-right-top-blocker", +tableFixedLeft:"dtfc-has-left",tableFixedRight:"dtfc-has-right"};e.defaults={i18n:{button:"FixedColumns"},left:1,right:0};return e}();(function(e){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(d){return e(d,window,document)}):"object"===typeof exports?module.exports=function(d,h){d||(d=window);h&&h.fn.dataTable||(h=require("datatables.net")(d,h).$);return e(h,d,d.document)}:e(window.jQuery,window,document)})(function(e,d,h){function m(c,b){void 0===b&&(b=null); +c=new n.Api(c);b=b?b:c.init().fixedColumns||n.defaults.fixedColumns;return new k(c,b)}a=e;g=a.fn.dataTable;var n=e.fn.dataTable;e.fn.dataTable.FixedColumns=k;e.fn.DataTable.FixedColumns=k;d=e.fn.dataTable.Api.register;d("fixedColumns()",function(){return this});d("fixedColumns().left()",function(c){var b=this.context[0];return void 0!==c?(b._fixedColumns.left(c),this):b._fixedColumns.left()});d("fixedColumns().right()",function(c){var b=this.context[0];return void 0!==c?(b._fixedColumns.right(c), +this):b._fixedColumns.right()});e.fn.dataTable.ext.buttons.fixedColumns={action:function(c,b,f,l){e(f).attr("active")?(e(f).removeAttr("active").removeClass("active"),b.fixedColumns().left(0),b.fixedColumns().right(0)):(e(f).attr("active",!0).addClass("active"),b.fixedColumns().left(l.config.left),b.fixedColumns().right(l.config.right))},config:{left:1,right:0},init:function(c,b,f){void 0===c.settings()[0]._fixedColumns&&m(c.settings(),f);e(b).attr("active",!0).addClass("active");c.button(b).text(f.text|| +c.i18n("buttons.fixedColumns",c.settings()[0]._fixedColumns.c.i18n.button))},text:null};e(h).on("init.dt.dtfc",function(c,b){"dt"===c.namespace&&(b.oInit.fixedColumns||n.defaults.fixedColumns)&&(b._fixedColumns||m(b,null))})})})(); /*! - FixedHeader 3.1.2 - ©2009-2016 SpryMedia Ltd - datatables.net/license + Copyright 2009-2021 SpryMedia Ltd. + + This source file is free software, available under the following license: + MIT license - http://datatables.net/license/mit + + This source file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. + + For details please refer to: http://www.datatables.net + FixedHeader 3.2.1 + ©2009-2021 SpryMedia Ltd - datatables.net/license */ -(function(d){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(g){return d(g,window,document)}):"object"===typeof exports?module.exports=function(g,h){g||(g=window);if(!h||!h.fn.dataTable)h=require("datatables.net")(g,h).$;return d(h,g,g.document)}:d(jQuery,window,document)})(function(d,g,h,k){var j=d.fn.dataTable,l=0,i=function(b,a){if(!(this instanceof i))throw"FixedHeader must be initialised with the 'new' keyword.";!0===a&&(a={});b=new j.Api(b);this.c=d.extend(!0, -{},i.defaults,a);this.s={dt:b,position:{theadTop:0,tbodyTop:0,tfootTop:0,tfootBottom:0,width:0,left:0,tfootHeight:0,theadHeight:0,windowHeight:d(g).height(),visible:!0},headerMode:null,footerMode:null,autoWidth:b.settings()[0].oFeatures.bAutoWidth,namespace:".dtfc"+l++,scrollLeft:{header:-1,footer:-1},enable:!0};this.dom={floatingHeader:null,thead:d(b.table().header()),tbody:d(b.table().body()),tfoot:d(b.table().footer()),header:{host:null,floating:null,placeholder:null},footer:{host:null,floating:null, -placeholder:null}};this.dom.header.host=this.dom.thead.parent();this.dom.footer.host=this.dom.tfoot.parent();var e=b.settings()[0];if(e._fixedHeader)throw"FixedHeader already initialised on table "+e.nTable.id;e._fixedHeader=this;this._constructor()};d.extend(i.prototype,{enable:function(b){this.s.enable=b;this.c.header&&this._modeChange("in-place","header",!0);this.c.footer&&this.dom.tfoot.length&&this._modeChange("in-place","footer",!0);this.update()},headerOffset:function(b){b!==k&&(this.c.headerOffset= -b,this.update());return this.c.headerOffset},footerOffset:function(b){b!==k&&(this.c.footerOffset=b,this.update());return this.c.footerOffset},update:function(){this._positions();this._scroll(!0)},_constructor:function(){var b=this,a=this.s.dt;d(g).on("scroll"+this.s.namespace,function(){b._scroll()}).on("resize"+this.s.namespace,function(){b.s.position.windowHeight=d(g).height();b.update()});var e=d(".fh-fixedHeader");!this.c.headerOffset&&e.length&&(this.c.headerOffset=e.outerHeight());e=d(".fh-fixedFooter"); -!this.c.footerOffset&&e.length&&(this.c.footerOffset=e.outerHeight());a.on("column-reorder.dt.dtfc column-visibility.dt.dtfc draw.dt.dtfc column-sizing.dt.dtfc",function(){b.update()});a.on("destroy.dtfc",function(){a.off(".dtfc");d(g).off(b.s.namespace)});this._positions();this._scroll()},_clone:function(b,a){var e=this.s.dt,c=this.dom[b],f="header"===b?this.dom.thead:this.dom.tfoot;!a&&c.floating?c.floating.removeClass("fixedHeader-floating fixedHeader-locked"):(c.floating&&(c.placeholder.remove(), -this._unsize(b),c.floating.children().detach(),c.floating.remove()),c.floating=d(e.table().node().cloneNode(!1)).css("table-layout","fixed").removeAttr("id").append(f).appendTo("body"),c.placeholder=f.clone(!1),c.host.prepend(c.placeholder),this._matchWidths(c.placeholder,c.floating))},_matchWidths:function(b,a){var e=function(a){return d(a,b).map(function(){return d(this).width()}).toArray()},c=function(b,c){d(b,a).each(function(a){d(this).css({width:c[a],minWidth:c[a]})})},f=e("th"),e=e("td");c("th", -f);c("td",e)},_unsize:function(b){var a=this.dom[b].floating;a&&("footer"===b||"header"===b&&!this.s.autoWidth)?d("th, td",a).css({width:"",minWidth:""}):a&&"header"===b&&d("th, td",a).css("min-width","")},_horizontal:function(b,a){var e=this.dom[b],c=this.s.position,d=this.s.scrollLeft;e.floating&&d[b]!==a&&(e.floating.css("left",c.left-a),d[b]=a)},_modeChange:function(b,a,e){var c=this.dom[a],f=this.s.position,g=d.contains(this.dom["footer"===a?"tfoot":"thead"][0],h.activeElement)?h.activeElement: -null;if("in-place"===b){if(c.placeholder&&(c.placeholder.remove(),c.placeholder=null),this._unsize(a),"header"===a?c.host.prepend(this.dom.thead):c.host.append(this.dom.tfoot),c.floating)c.floating.remove(),c.floating=null}else"in"===b?(this._clone(a,e),c.floating.addClass("fixedHeader-floating").css("header"===a?"top":"bottom",this.c[a+"Offset"]).css("left",f.left+"px").css("width",f.width+"px"),"footer"===a&&c.floating.css("top","")):"below"===b?(this._clone(a,e),c.floating.addClass("fixedHeader-locked").css("top", -f.tfootTop-f.theadHeight).css("left",f.left+"px").css("width",f.width+"px")):"above"===b&&(this._clone(a,e),c.floating.addClass("fixedHeader-locked").css("top",f.tbodyTop).css("left",f.left+"px").css("width",f.width+"px"));g&&g!==h.activeElement&&g.focus();this.s.scrollLeft.header=-1;this.s.scrollLeft.footer=-1;this.s[a+"Mode"]=b},_positions:function(){var b=this.s.dt.table(),a=this.s.position,e=this.dom,b=d(b.node()),c=b.children("thead"),f=b.children("tfoot"),e=e.tbody;a.visible=b.is(":visible"); -a.width=b.outerWidth();a.left=b.offset().left;a.theadTop=c.offset().top;a.tbodyTop=e.offset().top;a.theadHeight=a.tbodyTop-a.theadTop;f.length?(a.tfootTop=f.offset().top,a.tfootBottom=a.tfootTop+f.outerHeight(),a.tfootHeight=a.tfootBottom-a.tfootTop):(a.tfootTop=a.tbodyTop+e.outerHeight(),a.tfootBottom=a.tfootTop,a.tfootHeight=a.tfootTop)},_scroll:function(b){var a=d(h).scrollTop(),e=d(h).scrollLeft(),c=this.s.position,f;if(this.s.enable&&(this.c.header&&(f=!c.visible||a<=c.theadTop-this.c.headerOffset? -"in-place":a<=c.tfootTop-c.theadHeight-this.c.headerOffset?"in":"below",(b||f!==this.s.headerMode)&&this._modeChange(f,"header",b),this._horizontal("header",e)),this.c.footer&&this.dom.tfoot.length))a=!c.visible||a+c.windowHeight>=c.tfootBottom+this.c.footerOffset?"in-place":c.windowHeight+a>c.tbodyTop+c.tfootHeight+this.c.footerOffset?"in":"above",(b||a!==this.s.footerMode)&&this._modeChange(a,"footer",b),this._horizontal("footer",e)}});i.version="3.1.2";i.defaults={header:!0,footer:!1,headerOffset:0, -footerOffset:0};d.fn.dataTable.FixedHeader=i;d.fn.DataTable.FixedHeader=i;d(h).on("init.dt.dtfh",function(b,a){if("dt"===b.namespace){var e=a.oInit.fixedHeader,c=j.defaults.fixedHeader;if((e||c)&&!a._fixedHeader)c=d.extend({},c,e),!1!==e&&new i(a,c)}});j.Api.register("fixedHeader()",function(){});j.Api.register("fixedHeader.adjust()",function(){return this.iterator("table",function(b){(b=b._fixedHeader)&&b.update()})});j.Api.register("fixedHeader.enable()",function(b){return this.iterator("table", -function(a){(a=a._fixedHeader)&&a.enable(b!==k?b:!0)})});j.Api.register("fixedHeader.disable()",function(){return this.iterator("table",function(b){(b=b._fixedHeader)&&b.enable(!1)})});d.each(["header","footer"],function(b,a){j.Api.register("fixedHeader."+a+"Offset()",function(b){var c=this.context;return b===k?c.length&&c[0]._fixedHeader?c[0]._fixedHeader[a+"Offset"]():k:this.iterator("table",function(c){if(c=c._fixedHeader)c[a+"Offset"](b)})})});return i}); +var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.findInternal=function(b,g,h){b instanceof String&&(b=String(b));for(var l=b.length,k=0;k'), +placeholder:null},footer:{host:null,floating:null,floatingParent:b('
    '),placeholder:null}};this.dom.header.host=this.dom.thead.parent();this.dom.footer.host=this.dom.tfoot.parent();a=a.settings()[0];if(a._fixedHeader)throw"FixedHeader already initialised on table "+a.nTable.id;a._fixedHeader=this;this._constructor()};b.extend(t.prototype,{destroy:function(){this.s.dt.off(".dtfc");b(g).off(this.s.namespace);this.c.header&&this._modeChange("in-place","header",!0);this.c.footer&& +this.dom.tfoot.length&&this._modeChange("in-place","footer",!0)},enable:function(a,c){this.s.enable=a;if(c||c===l)this._positions(),this._scroll(!0)},enabled:function(){return this.s.enable},headerOffset:function(a){a!==l&&(this.c.headerOffset=a,this.update());return this.c.headerOffset},footerOffset:function(a){a!==l&&(this.c.footerOffset=a,this.update());return this.c.footerOffset},update:function(a){var c=this.s.dt.table().node();b(c).is(":visible")?this.enable(!0,!1):this.enable(!1,!1);0!==b(c).children("thead").length&& +(this._positions(),this._scroll(a!==l?a:!0))},_constructor:function(){var a=this,c=this.s.dt;b(g).on("scroll"+this.s.namespace,function(){a._scroll()}).on("resize"+this.s.namespace,k.util.throttle(function(){a.s.position.windowHeight=b(g).height();a.update()},50));var d=b(".fh-fixedHeader");!this.c.headerOffset&&d.length&&(this.c.headerOffset=d.outerHeight());d=b(".fh-fixedFooter");!this.c.footerOffset&&d.length&&(this.c.footerOffset=d.outerHeight());c.on("column-reorder.dt.dtfc column-visibility.dt.dtfc column-sizing.dt.dtfc responsive-display.dt.dtfc", +function(f,e){a.update()}).on("draw.dt.dtfc",function(f,e){a.update(e===c.settings()[0]?!1:!0)});c.on("destroy.dtfc",function(){a.destroy()});this._positions();this._scroll()},_clone:function(a,c){var d=this,f=this.s.dt,e=this.dom[a],p="header"===a?this.dom.thead:this.dom.tfoot;if("footer"!==a||!this._scrollEnabled())if(!c&&e.floating)e.floating.removeClass("fixedHeader-floating fixedHeader-locked");else{e.floating&&(null!==e.placeholder&&e.placeholder.remove(),this._unsize(a),e.floating.children().detach(), +e.floating.remove());c=b(f.table().node());var n=b(c.parent()),q=this._scrollEnabled();e.floating=b(f.table().node().cloneNode(!1)).attr("aria-hidden","true").css({"table-layout":"fixed",top:0,left:0}).removeAttr("id").append(p);e.floatingParent.css({width:n.width(),overflow:"hidden",height:"fit-content",position:"fixed",left:q?c.offset().left+n.scrollLeft():0}).css("header"===a?{top:this.c.headerOffset,bottom:""}:{top:"",bottom:this.c.footerOffset}).addClass("footer"===a?"dtfh-floatingparentfoot": +"dtfh-floatingparenthead").append(e.floating).appendTo("body");this._stickyPosition(e.floating,"-");a=function(){var r=n.scrollLeft();d.s.scrollLeft={footer:r,header:r};e.floatingParent.scrollLeft(d.s.scrollLeft.header)};a();n.scroll(a);e.placeholder=p.clone(!1);e.placeholder.find("*[id]").removeAttr("id");e.host.prepend(e.placeholder);this._matchWidths(e.placeholder,e.floating)}},_stickyPosition:function(a,c){if(this._scrollEnabled()){var d=this,f="rtl"===b(d.s.dt.table().node()).css("direction"); +a.find("th").each(function(){if("sticky"===b(this).css("position")){var e=b(this).css("right"),p=b(this).css("left");"auto"===e||f?"auto"!==p&&f&&(e=+p.replace(/px/g,"")+("-"===c?-1:1)*d.s.dt.settings()[0].oBrowser.barWidth,b(this).css("left",0y?e.tfootHeight:z+e.tfootHeight-y:d+ +this.c.headerOffset+e.theadHeight-m;m="header"===c?"top":"bottom";d=this.c[c+"Offset"]-(0y&&n+this.c.headerOffsete||this.dom.header.floatingParent===l?a=!0:this.dom.header.floatingParent.css({top:this.c.headerOffset, +position:"fixed"}).append(this.dom.header.floating)):q="below":q="in-place",(a||q!==this.s.headerMode)&&this._modeChange(q,"header",a),this._horizontal("header",p));var w={offset:{top:0,left:0},height:0},x={offset:{top:0,left:0},height:0};this.c.footer&&this.dom.tfoot.length&&(this.s.enable?!m.visible||m.tfootBottom+this.c.footerOffset<=r?m="in-place":e+m.tfootHeight+this.c.footerOffset>r&&y+this.c.footerOffsetn&&(c=n-f.top,r=r+(c>-w.height?c:0)-(w.offset.top+(c<-w.height?w.height:0)+x.height),0>r&&(r=0),d.outerHeight(r),Math.round(d.outerHeight())>=Math.round(r)?b(this.dom.tfoot.parent()).addClass("fixedHeader-floating"):b(this.dom.tfoot.parent()).removeClass("fixedHeader-floating"))); +this.dom.header.floating&&this.dom.header.floatingParent.css("left",z-p);this.dom.footer.floating&&this.dom.footer.floatingParent.css("left",z-p);this.s.dt.settings()[0]._fixedColumns!==l&&(d=function(A,C,u){u===l&&(u=b("div.dtfc-"+A+"-"+C+"-blocker"),u=0===u.length?null:u.clone().appendTo("body").css("z-index",1));null!==u&&u.css({top:"top"===C?w.offset.top:x.offset.top,left:"right"===A?z+B-u.width():z});return u},this.dom.header.rightBlocker=d("right","top",this.dom.header.rightBlocker),this.dom.header.leftBlocker= +d("left","top",this.dom.header.leftBlocker),this.dom.footer.rightBlocker=d("right","bottom",this.dom.footer.rightBlocker),this.dom.footer.leftBlocker=d("left","bottom",this.dom.footer.leftBlocker))},_scrollEnabled:function(){var a=this.s.dt.settings()[0].oScroll;return""!==a.sY||""!==a.sX?!0:!1}});t.version="3.2.1";t.defaults={header:!0,footer:!1,headerOffset:0,footerOffset:0};b.fn.dataTable.FixedHeader=t;b.fn.DataTable.FixedHeader=t;b(h).on("init.dt.dtfh",function(a,c,d){"dt"===a.namespace&&(a=c.oInit.fixedHeader, +d=k.defaults.fixedHeader,!a&&!d||c._fixedHeader||(d=b.extend({},d,a),!1!==a&&new t(c,d)))});k.Api.register("fixedHeader()",function(){});k.Api.register("fixedHeader.adjust()",function(){return this.iterator("table",function(a){(a=a._fixedHeader)&&a.update()})});k.Api.register("fixedHeader.enable()",function(a){return this.iterator("table",function(c){c=c._fixedHeader;a=a!==l?a:!0;c&&a!==c.enabled()&&c.enable(a)})});k.Api.register("fixedHeader.enabled()",function(){if(this.context.length){var a=this.context[0]._fixedHeader; +if(a)return a.enabled()}return!1});k.Api.register("fixedHeader.disable()",function(){return this.iterator("table",function(a){(a=a._fixedHeader)&&a.enabled()&&a.enable(!1)})});b.each(["header","footer"],function(a,c){k.Api.register("fixedHeader."+c+"Offset()",function(d){var f=this.context;return d===l?f.length&&f[0]._fixedHeader?f[0]._fixedHeader[c+"Offset"]():l:this.iterator("table",function(e){if(e=e._fixedHeader)e[c+"Offset"](d)})})});return t}); /*! - Responsive 2.1.1 - 2014-2016 SpryMedia Ltd - datatables.net/license + Copyright 2014-2021 SpryMedia Ltd. + + This source file is free software, available under the following license: + MIT license - http://datatables.net/license/mit + + This source file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. + + For details please refer to: http://www.datatables.net + Responsive 2.2.9 + 2014-2021 SpryMedia Ltd - datatables.net/license */ -(function(c){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(l){return c(l,window,document)}):"object"===typeof exports?module.exports=function(l,k){l||(l=window);if(!k||!k.fn.dataTable)k=require("datatables.net")(l,k).$;return c(k,l,l.document)}:c(jQuery,window,document)})(function(c,l,k,p){var m=c.fn.dataTable,j=function(b,a){if(!m.versionCheck||!m.versionCheck("1.10.3"))throw"DataTables Responsive requires DataTables 1.10.3 or newer";this.s={dt:new m.Api(b),columns:[], -current:[]};this.s.dt.settings()[0].responsive||(a&&"string"===typeof a.details?a.details={type:a.details}:a&&!1===a.details?a.details={type:!1}:a&&!0===a.details&&(a.details={type:"inline"}),this.c=c.extend(!0,{},j.defaults,m.defaults.responsive,a),b.responsive=this,this._constructor())};c.extend(j.prototype,{_constructor:function(){var b=this,a=this.s.dt,d=a.settings()[0],e=c(l).width();a.settings()[0]._responsive=this;c(l).on("resize.dtr orientationchange.dtr",m.util.throttle(function(){var a= -c(l).width();a!==e&&(b._resize(),e=a)}));d.oApi._fnCallbackReg(d,"aoRowCreatedCallback",function(e){-1!==c.inArray(!1,b.s.current)&&c(">td, >th",e).each(function(e){e=a.column.index("toData",e);!1===b.s.current[e]&&c(this).css("display","none")})});a.on("destroy.dtr",function(){a.off(".dtr");c(a.table().body()).off(".dtr");c(l).off("resize.dtr orientationchange.dtr");c.each(b.s.current,function(a,e){!1===e&&b._setColumnVis(a,!0)})});this.c.breakpoints.sort(function(a,b){return a.width -b.width?-1:0});this._classLogic();this._resizeAuto();d=this.c.details;!1!==d.type&&(b._detailsInit(),a.on("column-visibility.dtr",function(){b._classLogic();b._resizeAuto();b._resize()}),a.on("draw.dtr",function(){b._redrawChildren()}),c(a.table().node()).addClass("dtr-"+d.type));a.on("column-reorder.dtr",function(){b._classLogic();b._resizeAuto();b._resize()});a.on("column-sizing.dtr",function(){b._resizeAuto();b._resize()});a.on("preXhr.dtr",function(){var e=[];a.rows().every(function(){this.child.isShown()&& -e.push(this.id(true))});a.one("draw.dtr",function(){a.rows(e).every(function(){b._detailsDisplay(this,false)})})});a.on("init.dtr",function(){b._resizeAuto();b._resize();c.inArray(false,b.s.current)&&a.columns.adjust()});this._resize()},_columnsVisiblity:function(b){var a=this.s.dt,d=this.s.columns,e,f,g=d.map(function(a,b){return{columnIdx:b,priority:a.priority}}).sort(function(a,b){return a.priority!==b.priority?a.priority-b.priority:a.columnIdx-b.columnIdx}),h=c.map(d,function(a){return a.auto&& -null===a.minWidth?!1:!0===a.auto?"-":-1!==c.inArray(b,a.includeIn)}),n=0;e=0;for(f=h.length;ea-d[i].minWidth?(n=!0,h[i]=!1):h[i]=!0,a-=d[i].minWidth)}g=!1;e=0;for(f=d.length;e=g&&f(c,a[d].name)}else{if("not-"===i){d=0;for(i=a.length;d").append(h).appendTo(f)}c("
    ").append(g).appendTo(e);"inline"===this.c.details.type&&c(d).addClass("dtr-inline collapsed");c(d).find("[name]").removeAttr("name");d=c("
    ").css({width:1,height:1,overflow:"hidden"}).append(d);d.insertBefore(b.table().node());g.each(function(c){c=b.column.index("fromVisible",c);a[c].minWidth=this.offsetWidth||0});d.remove()}},_setColumnVis:function(b, -a){var d=this.s.dt,e=a?"":"none";c(d.column(b).header()).css("display",e);c(d.column(b).footer()).css("display",e);d.column(b).nodes().to$().css("display",e)},_tabIndexes:function(){var b=this.s.dt,a=b.cells({page:"current"}).nodes().to$(),d=b.settings()[0],e=this.c.details.target;a.filter("[data-dtr-keyboard]").removeData("[data-dtr-keyboard]");a="number"===typeof e?":eq("+e+")":e;"td:first-child, th:first-child"===a&&(a=">td:first-child, >th:first-child");c(a,b.rows({page:"current"}).nodes()).attr("tabIndex", -d.iTabIndex).data("dtr-keyboard",1)}});j.breakpoints=[{name:"desktop",width:Infinity},{name:"tablet-l",width:1024},{name:"tablet-p",width:768},{name:"mobile-l",width:480},{name:"mobile-p",width:320}];j.display={childRow:function(b,a,d){if(a){if(c(b.node()).hasClass("parent"))return b.child(d(),"child").show(),!0}else{if(b.child.isShown())return b.child(!1),c(b.node()).removeClass("parent"),!1;b.child(d(),"child").show();c(b.node()).addClass("parent");return!0}},childRowImmediate:function(b,a,d){if(!a&& -b.child.isShown()||!b.responsive.hasHidden())return b.child(!1),c(b.node()).removeClass("parent"),!1;b.child(d(),"child").show();c(b.node()).addClass("parent");return!0},modal:function(b){return function(a,d,e){if(d)c("div.dtr-modal-content").empty().append(e());else{var f=function(){g.remove();c(k).off("keypress.dtr")},g=c('
    ').append(c('
    ').append(c('
    ').append(e())).append(c('
    ×
    ').click(function(){f()}))).append(c('
    ').click(function(){f()})).appendTo("body"); -c(k).on("keyup.dtr",function(a){27===a.keyCode&&(a.stopPropagation(),f())})}b&&b.header&&c("div.dtr-modal-content").prepend("

    "+b.header(a)+"

    ")}}};j.renderer={listHidden:function(){return function(b,a,d){return(b=c.map(d,function(a){return a.hidden?'
  • '+a.title+' '+a.data+"
  • ":""}).join(""))?c('
      ').append(b): -!1}},tableAll:function(b){b=c.extend({tableClass:""},b);return function(a,d,e){a=c.map(e,function(a){return'
    "}).join("");return c('
    '+col.title+':'+''+col.data+'
    ",{valign:"top",colSpan:ba(a),"class":a.oClasses.sRowEmpty}).html(c))[0];s(a,"aoHeaderCallback","header",[h(a.nTHead).children("tr")[0],Ma(a),g,n,i]);s(a,"aoFooterCallback","footer",[h(a.nTFoot).children("tr")[0],Ma(a),g,n,i]);d=h(a.nTBody);d.children().detach();d.append(h(b));s(a,"aoDrawCallback","draw",[a]);a.bSorted=!1;a.bFiltered=!1;a.bDrawing=!1}}function T(a,b){var c=a.oFeatures,d=c.bFilter; -c.bSort&&ob(a);d?ga(a,a.oPreviousSearch):a.aiDisplay=a.aiDisplayMaster.slice();!0!==b&&(a._iDisplayStart=0);a._drawHold=b;O(a);a._drawHold=!1}function pb(a){var b=a.oClasses,c=h(a.nTable),c=h("
    ").insertBefore(c),d=a.oFeatures,e=h("
    ",{id:a.sTableId+"_wrapper","class":b.sWrapper+(a.nTFoot?"":" "+b.sNoFooter)});a.nHolding=c[0];a.nTableWrapper=e[0];a.nTableReinsertBefore=a.nTable.nextSibling;for(var f=a.sDom.split(""),g,j,i,n,l,q,k=0;k")[0]; -n=f[k+1];if("'"==n||'"'==n){l="";for(q=2;f[k+q]!=n;)l+=f[k+q],q++;"H"==l?l=b.sJUIHeader:"F"==l&&(l=b.sJUIFooter);-1!=l.indexOf(".")?(n=l.split("."),i.id=n[0].substr(1,n[0].length-1),i.className=n[1]):"#"==l.charAt(0)?i.id=l.substr(1,l.length-1):i.className=l;k+=q}e.append(i);e=h(i)}else if(">"==j)e=e.parent();else if("l"==j&&d.bPaginate&&d.bLengthChange)g=qb(a);else if("f"==j&&d.bFilter)g=rb(a);else if("r"==j&&d.bProcessing)g=sb(a);else if("t"==j)g=tb(a);else if("i"==j&&d.bInfo)g=ub(a);else if("p"== -j&&d.bPaginate)g=vb(a);else if(0!==m.ext.feature.length){i=m.ext.feature;q=0;for(n=i.length;q',j=d.sSearch,j=j.match(/_INPUT_/)?j.replace("_INPUT_",g):j+g,b=h("
    ",{id:!f.f?c+"_filter":null,"class":b.sFilter}).append(h("
    ").addClass(b.sLength);a.aanFeatures.l||(i[0].id=c+"_length");i.children().append(a.oLanguage.sLengthMenu.replace("_MENU_",e[0].outerHTML));h("select",i).val(a._iDisplayLength).on("change.DT",function(){Ta(a,h(this).val());O(a)});h(a.nTable).on("length.dt.DT",function(b,c,d){a===c&&h("select",i).val(d)});return i[0]}function vb(a){var b=a.sPaginationType,c=m.ext.pager[b],d="function"===typeof c,e=function(a){O(a)},b=h("
    ").addClass(a.oClasses.sPaging+ -b)[0],f=a.aanFeatures;d||c.fnInit(a,b,e);f.p||(b.id=a.sTableId+"_paginate",a.aoDrawCallback.push({fn:function(a){if(d){var b=a._iDisplayStart,i=a._iDisplayLength,h=a.fnRecordsDisplay(),l=-1===i,b=l?0:Math.ceil(b/i),i=l?1:Math.ceil(h/i),h=c(b,i),k,l=0;for(k=f.p.length;lf&& -(d=0)):"first"==b?d=0:"previous"==b?(d=0<=e?d-e:0,0>d&&(d=0)):"next"==b?d+e",{id:!a.aanFeatures.r?a.sTableId+"_processing":null,"class":a.oClasses.sProcessing}).html(a.oLanguage.sProcessing).insertBefore(a.nTable)[0]}function C(a,b){a.oFeatures.bProcessing&&h(a.aanFeatures.r).css("display",b?"block":"none"); -s(a,null,"processing",[a,b])}function tb(a){var b=h(a.nTable);b.attr("role","grid");var c=a.oScroll;if(""===c.sX&&""===c.sY)return a.nTable;var d=c.sX,e=c.sY,f=a.oClasses,g=b.children("caption"),j=g.length?g[0]._captionSide:null,i=h(b[0].cloneNode(!1)),n=h(b[0].cloneNode(!1)),l=b.children("tfoot");l.length||(l=null);i=h("
    ",{"class":f.sScrollWrapper}).append(h("
    ",{"class":f.sScrollHead}).css({overflow:"hidden",position:"relative",border:0,width:d?!d?null:v(d):"100%"}).append(h("
    ", -{"class":f.sScrollHeadInner}).css({"box-sizing":"content-box",width:c.sXInner||"100%"}).append(i.removeAttr("id").css("margin-left",0).append("top"===j?g:null).append(b.children("thead"))))).append(h("
    ",{"class":f.sScrollBody}).css({position:"relative",overflow:"auto",width:!d?null:v(d)}).append(b));l&&i.append(h("
    ",{"class":f.sScrollFoot}).css({overflow:"hidden",border:0,width:d?!d?null:v(d):"100%"}).append(h("
    ",{"class":f.sScrollFootInner}).append(n.removeAttr("id").css("margin-left", -0).append("bottom"===j?g:null).append(b.children("tfoot")))));var b=i.children(),k=b[0],f=b[1],r=l?b[2]:null;if(d)h(f).on("scroll.DT",function(){var a=this.scrollLeft;k.scrollLeft=a;l&&(r.scrollLeft=a)});h(f).css(e&&c.bCollapse?"max-height":"height",e);a.nScrollHead=k;a.nScrollBody=f;a.nScrollFoot=r;a.aoDrawCallback.push({fn:ma,sName:"scrolling"});return i[0]}function ma(a){var b=a.oScroll,c=b.sX,d=b.sXInner,e=b.sY,b=b.iBarWidth,f=h(a.nScrollHead),g=f[0].style,j=f.children("div"),i=j[0].style,n=j.children("table"), -j=a.nScrollBody,l=h(j),q=j.style,r=h(a.nScrollFoot).children("div"),m=r.children("table"),p=h(a.nTHead),o=h(a.nTable),t=o[0],s=t.style,u=a.nTFoot?h(a.nTFoot):null,x=a.oBrowser,U=x.bScrollOversize,ac=D(a.aoColumns,"nTh"),P,L,Q,w,Wa=[],y=[],z=[],A=[],B,C=function(a){a=a.style;a.paddingTop="0";a.paddingBottom="0";a.borderTopWidth="0";a.borderBottomWidth="0";a.height=0};L=j.scrollHeight>j.clientHeight;if(a.scrollBarVis!==L&&a.scrollBarVis!==k)a.scrollBarVis=L,Z(a);else{a.scrollBarVis=L;o.children("thead, tfoot").remove(); -u&&(Q=u.clone().prependTo(o),P=u.find("tr"),Q=Q.find("tr"));w=p.clone().prependTo(o);p=p.find("tr");L=w.find("tr");w.find("th, td").removeAttr("tabindex");c||(q.width="100%",f[0].style.width="100%");h.each(ta(a,w),function(b,c){B=$(a,b);c.style.width=a.aoColumns[B].sWidth});u&&I(function(a){a.style.width=""},Q);f=o.outerWidth();if(""===c){s.width="100%";if(U&&(o.find("tbody").height()>j.offsetHeight||"scroll"==l.css("overflow-y")))s.width=v(o.outerWidth()-b);f=o.outerWidth()}else""!==d&&(s.width= -v(d),f=o.outerWidth());I(C,L);I(function(a){z.push(a.innerHTML);Wa.push(v(h(a).css("width")))},L);I(function(a,b){if(h.inArray(a,ac)!==-1)a.style.width=Wa[b]},p);h(L).height(0);u&&(I(C,Q),I(function(a){A.push(a.innerHTML);y.push(v(h(a).css("width")))},Q),I(function(a,b){a.style.width=y[b]},P),h(Q).height(0));I(function(a,b){a.innerHTML='
    '+z[b]+"
    ";a.style.width=Wa[b]},L);u&&I(function(a,b){a.innerHTML='
    '+ -A[b]+"
    ";a.style.width=y[b]},Q);if(o.outerWidth()j.offsetHeight||"scroll"==l.css("overflow-y")?f+b:f;if(U&&(j.scrollHeight>j.offsetHeight||"scroll"==l.css("overflow-y")))s.width=v(P-b);(""===c||""!==d)&&K(a,1,"Possible column misalignment",6)}else P="100%";q.width=v(P);g.width=v(P);u&&(a.nScrollFoot.style.width=v(P));!e&&U&&(q.height=v(t.offsetHeight+b));c=o.outerWidth();n[0].style.width=v(c);i.width=v(c);d=o.height()>j.clientHeight||"scroll"==l.css("overflow-y");e="padding"+ -(x.bScrollbarLeft?"Left":"Right");i[e]=d?b+"px":"0px";u&&(m[0].style.width=v(c),r[0].style.width=v(c),r[0].style[e]=d?b+"px":"0px");o.children("colgroup").insertBefore(o.children("thead"));l.scroll();if((a.bSorted||a.bFiltered)&&!a._drawHold)j.scrollTop=0}}function I(a,b,c){for(var d=0,e=0,f=b.length,g,j;e").appendTo(j.find("tbody")); -j.find("thead, tfoot").remove();j.append(h(a.nTHead).clone()).append(h(a.nTFoot).clone());j.find("tfoot th, tfoot td").css("width","");n=ta(a,j.find("thead")[0]);for(m=0;m").css({width:p.sWidthOrig,margin:0,padding:0,border:0,height:1}));if(a.aoData.length)for(m=0;m").css(f||e?{position:"absolute",top:0,left:0,height:1,right:0,overflow:"hidden"}:{}).append(j).appendTo(k);f&&g?j.width(g):f?(j.css("width","auto"),j.removeAttr("width"),j.width()").css("width",v(a)).appendTo(b||H.body),d=c[0].offsetWidth;c.remove();return d}function Hb(a,b){var c=Ib(a,b);if(0>c)return null;var d=a.aoData[c];return!d.nTr?h("
    ").html(B(a,c,b,"display"))[0]:d.anCells[b]}function Ib(a,b){for(var c,d=-1,e=-1,f=0,g=a.aoData.length;fd&&(d=c.length,e=f);return e}function v(a){return null===a?"0px":"number"==typeof a?0>a?"0px":a+"px":a.match(/\d$/)?a+"px":a}function W(a){var b,c,d=[],e=a.aoColumns,f,g,j,i;b=a.aaSortingFixed;c=h.isPlainObject(b);var n=[];f=function(a){a.length&&!h.isArray(a[0])?n.push(a):h.merge(n,a)};h.isArray(b)&&f(b);c&&b.pre&&f(b.pre);f(a.aaSorting);c&&b.post&&f(b.post);for(a=0;ae?1:0,0!==c)return"asc"===j.dir?c:-c;c=d[a];e=d[b];return ce?1:0}):i.sort(function(a,b){var c,g,j,i,k=h.length,m=f[a]._aSortData,p=f[b]._aSortData;for(j=0;jg?1:0})}a.bSorted=!0}function Kb(a){for(var b,c,d=a.aoColumns,e=W(a),a=a.oLanguage.oAria,f=0,g=d.length;f/g, -"");var i=c.nTh;i.removeAttribute("aria-sort");c.bSortable&&(0e?e+1:3));e=0;for(f=d.length;ee?e+1:3))}a.aLastSort=d}function Jb(a,b){var c=a.aoColumns[b],d=m.ext.order[c.sSortDataType],e;d&&(e=d.call(a.oInstance,a,b,aa(a,b)));for(var f,g=m.ext.type.order[c.sType+"-pre"],j=0,i=a.aoData.length;j=f.length?[0,c[1]]:c)}));b.search!== -k&&h.extend(a.oPreviousSearch,Db(b.search));if(b.columns){d=0;for(e=b.columns.length;d=c&&(b=c-d);b-=b%d;if(-1===d||0>b)b=0;a._iDisplayStart=b}function Pa(a,b){var c=a.renderer,d=m.ext.renderer[b];return h.isPlainObject(c)&&c[b]?d[c[b]]||d._:"string"===typeof c?d[c]||d._:d._}function y(a){return a.oFeatures.bServerSide?"ssp":a.ajax||a.sAjaxSource?"ajax":"dom"}function ia(a,b){var c=[],c=Nb.numbers_length,d=Math.floor(c/2);b<=c?c=X(0,b):a<=d?(c=X(0, -c-2),c.push("ellipsis"),c.push(b-1)):(a>=b-1-d?c=X(b-(c-2),b):(c=X(a-d+2,a+d-1),c.push("ellipsis"),c.push(b-1)),c.splice(0,0,"ellipsis"),c.splice(0,0,0));c.DT_el="span";return c}function fb(a){h.each({num:function(b){return Ba(b,a)},"num-fmt":function(b){return Ba(b,a,Za)},"html-num":function(b){return Ba(b,a,Ca)},"html-num-fmt":function(b){return Ba(b,a,Ca,Za)}},function(b,c){x.type.order[b+a+"-pre"]=c;b.match(/^html\-/)&&(x.type.search[b+a]=x.type.search.html)})}function Ob(a){return function(){var b= -[Aa(this[m.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return m.ext.internal[a].apply(this,b)}}var m=function(a){this.$=function(a,b){return this.api(!0).$(a,b)};this._=function(a,b){return this.api(!0).rows(a,b).data()};this.api=function(a){return a?new t(Aa(this[x.iApiIndex])):new t(this)};this.fnAddData=function(a,b){var c=this.api(!0),d=h.isArray(a)&&(h.isArray(a[0])||h.isPlainObject(a[0]))?c.rows.add(a):c.row.add(a);(b===k||b)&&c.draw();return d.flatten().toArray()};this.fnAdjustColumnSizing= -function(a){var b=this.api(!0).columns.adjust(),c=b.settings()[0],d=c.oScroll;a===k||a?b.draw(!1):(""!==d.sX||""!==d.sY)&&ma(c)};this.fnClearTable=function(a){var b=this.api(!0).clear();(a===k||a)&&b.draw()};this.fnClose=function(a){this.api(!0).row(a).child.hide()};this.fnDeleteRow=function(a,b,c){var d=this.api(!0),a=d.rows(a),e=a.settings()[0],h=e.aoData[a[0][0]];a.remove();b&&b.call(this,e,h);(c===k||c)&&d.draw();return h};this.fnDestroy=function(a){this.api(!0).destroy(a)};this.fnDraw=function(a){this.api(!0).draw(a)}; -this.fnFilter=function(a,b,c,d,e,h){e=this.api(!0);null===b||b===k?e.search(a,c,d,h):e.column(b).search(a,c,d,h);e.draw()};this.fnGetData=function(a,b){var c=this.api(!0);if(a!==k){var d=a.nodeName?a.nodeName.toLowerCase():"";return b!==k||"td"==d||"th"==d?c.cell(a,b).data():c.row(a).data()||null}return c.data().toArray()};this.fnGetNodes=function(a){var b=this.api(!0);return a!==k?b.row(a).node():b.rows().nodes().flatten().toArray()};this.fnGetPosition=function(a){var b=this.api(!0),c=a.nodeName.toUpperCase(); -return"TR"==c?b.row(a).index():"TD"==c||"TH"==c?(a=b.cell(a).index(),[a.row,a.columnVisible,a.column]):null};this.fnIsOpen=function(a){return this.api(!0).row(a).child.isShown()};this.fnOpen=function(a,b,c){return this.api(!0).row(a).child(b,c).show().child()[0]};this.fnPageChange=function(a,b){var c=this.api(!0).page(a);(b===k||b)&&c.draw(!1)};this.fnSetColumnVis=function(a,b,c){a=this.api(!0).column(a).visible(b);(c===k||c)&&a.columns.adjust().draw()};this.fnSettings=function(){return Aa(this[x.iApiIndex])}; -this.fnSort=function(a){this.api(!0).order(a).draw()};this.fnSortListener=function(a,b,c){this.api(!0).order.listener(a,b,c)};this.fnUpdate=function(a,b,c,d,e){var h=this.api(!0);c===k||null===c?h.row(b).data(a):h.cell(b,c).data(a);(e===k||e)&&h.columns.adjust();(d===k||d)&&h.draw();return 0};this.fnVersionCheck=x.fnVersionCheck;var b=this,c=a===k,d=this.length;c&&(a={});this.oApi=this.internal=x.internal;for(var e in m.ext.internal)e&&(this[e]=Ob(e));this.each(function(){var e={},g=1t<"F"ip>'),o.renderer)?h.isPlainObject(o.renderer)&& -!o.renderer.header&&(o.renderer.header="jqueryui"):o.renderer="jqueryui":h.extend(u,m.ext.classes,g.oClasses);q.addClass(u.sTable);o.iInitDisplayStart===k&&(o.iInitDisplayStart=g.iDisplayStart,o._iDisplayStart=g.iDisplayStart);null!==g.iDeferLoading&&(o.bDeferLoading=!0,e=h.isArray(g.iDeferLoading),o._iRecordsDisplay=e?g.iDeferLoading[0]:g.iDeferLoading,o._iRecordsTotal=e?g.iDeferLoading[1]:g.iDeferLoading);var v=o.oLanguage;h.extend(!0,v,g.oLanguage);v.sUrl&&(h.ajax({dataType:"json",url:v.sUrl,success:function(a){Fa(a); -J(l.oLanguage,a);h.extend(true,v,a);ha(o)},error:function(){ha(o)}}),n=!0);null===g.asStripeClasses&&(o.asStripeClasses=[u.sStripeOdd,u.sStripeEven]);var e=o.asStripeClasses,x=q.children("tbody").find("tr").eq(0);-1!==h.inArray(!0,h.map(e,function(a){return x.hasClass(a)}))&&(h("tbody tr",this).removeClass(e.join(" ")),o.asDestroyStripes=e.slice());e=[];r=this.getElementsByTagName("thead");0!==r.length&&(ea(o.aoHeader,r[0]),e=ta(o));if(null===g.aoColumns){r=[];j=0;for(i=e.length;j").appendTo(q)); -o.nTHead=b[0];b=q.children("tbody");b.length===0&&(b=h("
    ",{valign:"top",colSpan:oa(a),"class":a.oClasses.sRowEmpty}).html(e))[0];F(a,"aoHeaderCallback","header",[l(a.nTHead).children("tr")[0],db(a),m,n,k]);F(a,"aoFooterCallback", +"footer",[l(a.nTFoot).children("tr")[0],db(a),m,n,k]);d=l(a.nTBody);d.children().detach();d.append(l(c));F(a,"aoDrawCallback","draw",[a]);a.bSorted=!1;a.bFiltered=!1;a.bDrawing=!1}}function ka(a,b){var c=a.oFeatures,d=c.bFilter;c.bSort&&Hb(a);d?za(a,a.oPreviousSearch):a.aiDisplay=a.aiDisplayMaster.slice();!0!==b&&(a._iDisplayStart=0);a._drawHold=b;ja(a);a._drawHold=!1}function Ib(a){var b=a.oClasses,c=l(a.nTable);c=l("
    ").insertBefore(c);var d=a.oFeatures,e=l("
    ",{id:a.sTableId+"_wrapper", +"class":b.sWrapper+(a.nTFoot?"":" "+b.sNoFooter)});a.nHolding=c[0];a.nTableWrapper=e[0];a.nTableReinsertBefore=a.nTable.nextSibling;for(var h=a.sDom.split(""),f,g,k,m,n,p,t=0;t")[0];m=h[t+1];if("'"==m||'"'==m){n="";for(p=2;h[t+p]!=m;)n+=h[t+p],p++;"H"==n?n=b.sJUIHeader:"F"==n&&(n=b.sJUIFooter);-1!=n.indexOf(".")?(m=n.split("."),k.id=m[0].substr(1,m[0].length-1),k.className=m[1]):"#"==n.charAt(0)?k.id=n.substr(1,n.length-1):k.className=n;t+=p}e.append(k); +e=l(k)}else if(">"==g)e=e.parent();else if("l"==g&&d.bPaginate&&d.bLengthChange)f=Jb(a);else if("f"==g&&d.bFilter)f=Kb(a);else if("r"==g&&d.bProcessing)f=Lb(a);else if("t"==g)f=Mb(a);else if("i"==g&&d.bInfo)f=Nb(a);else if("p"==g&&d.bPaginate)f=Ob(a);else if(0!==u.ext.feature.length)for(k=u.ext.feature,p=0,m=k.length;p',g=d.sSearch;g=g.match(/_INPUT_/)?g.replace("_INPUT_",f):g+f;b=l("
    ",{id:h.f?null:c+"_filter","class":b.sFilter}).append(l("
    ").addClass(b.sLength);a.aanFeatures.l||(k[0].id=c+"_length");k.children().append(a.oLanguage.sLengthMenu.replace("_MENU_",e[0].outerHTML));l("select",k).val(a._iDisplayLength).on("change.DT",function(m){kb(a,l(this).val());ja(a)});l(a.nTable).on("length.dt.DT",function(m,n,p){a===n&&l("select",k).val(p)});return k[0]}function Ob(a){var b=a.sPaginationType,c=u.ext.pager[b],d="function"===typeof c,e=function(f){ja(f)};b=l("
    ").addClass(a.oClasses.sPaging+b)[0]; +var h=a.aanFeatures;d||c.fnInit(a,b,e);h.p||(b.id=a.sTableId+"_paginate",a.aoDrawCallback.push({fn:function(f){if(d){var g=f._iDisplayStart,k=f._iDisplayLength,m=f.fnRecordsDisplay(),n=-1===k;g=n?0:Math.ceil(g/k);k=n?1:Math.ceil(m/k);m=c(g,k);var p;n=0;for(p=h.p.length;nh&& +(d=0)):"first"==b?d=0:"previous"==b?(d=0<=e?d-e:0,0>d&&(d=0)):"next"==b?d+e",{id:a.aanFeatures.r?null:a.sTableId+"_processing","class":a.oClasses.sProcessing}).html(a.oLanguage.sProcessing).insertBefore(a.nTable)[0]}function V(a,b){a.oFeatures.bProcessing&&l(a.aanFeatures.r).css("display",b?"block":"none"); +F(a,null,"processing",[a,b])}function Mb(a){var b=l(a.nTable),c=a.oScroll;if(""===c.sX&&""===c.sY)return a.nTable;var d=c.sX,e=c.sY,h=a.oClasses,f=b.children("caption"),g=f.length?f[0]._captionSide:null,k=l(b[0].cloneNode(!1)),m=l(b[0].cloneNode(!1)),n=b.children("tfoot");n.length||(n=null);k=l("
    ",{"class":h.sScrollWrapper}).append(l("
    ",{"class":h.sScrollHead}).css({overflow:"hidden",position:"relative",border:0,width:d?d?K(d):null:"100%"}).append(l("
    ",{"class":h.sScrollHeadInner}).css({"box-sizing":"content-box", +width:c.sXInner||"100%"}).append(k.removeAttr("id").css("margin-left",0).append("top"===g?f:null).append(b.children("thead"))))).append(l("
    ",{"class":h.sScrollBody}).css({position:"relative",overflow:"auto",width:d?K(d):null}).append(b));n&&k.append(l("
    ",{"class":h.sScrollFoot}).css({overflow:"hidden",border:0,width:d?d?K(d):null:"100%"}).append(l("
    ",{"class":h.sScrollFootInner}).append(m.removeAttr("id").css("margin-left",0).append("bottom"===g?f:null).append(b.children("tfoot"))))); +b=k.children();var p=b[0];h=b[1];var t=n?b[2]:null;if(d)l(h).on("scroll.DT",function(v){v=this.scrollLeft;p.scrollLeft=v;n&&(t.scrollLeft=v)});l(h).css("max-height",e);c.bCollapse||l(h).css("height",e);a.nScrollHead=p;a.nScrollBody=h;a.nScrollFoot=t;a.aoDrawCallback.push({fn:Ha,sName:"scrolling"});return k[0]}function Ha(a){var b=a.oScroll,c=b.sX,d=b.sXInner,e=b.sY;b=b.iBarWidth;var h=l(a.nScrollHead),f=h[0].style,g=h.children("div"),k=g[0].style,m=g.children("table");g=a.nScrollBody;var n=l(g),p= +g.style,t=l(a.nScrollFoot).children("div"),v=t.children("table"),x=l(a.nTHead),w=l(a.nTable),r=w[0],C=r.style,G=a.nTFoot?l(a.nTFoot):null,aa=a.oBrowser,L=aa.bScrollOversize;U(a.aoColumns,"nTh");var O=[],I=[],H=[],ea=[],Y,Ca=function(D){D=D.style;D.paddingTop="0";D.paddingBottom="0";D.borderTopWidth="0";D.borderBottomWidth="0";D.height=0};var fa=g.scrollHeight>g.clientHeight;if(a.scrollBarVis!==fa&&a.scrollBarVis!==q)a.scrollBarVis=fa,ta(a);else{a.scrollBarVis=fa;w.children("thead, tfoot").remove(); +if(G){var ba=G.clone().prependTo(w);var la=G.find("tr");ba=ba.find("tr")}var mb=x.clone().prependTo(w);x=x.find("tr");fa=mb.find("tr");mb.find("th, td").removeAttr("tabindex");c||(p.width="100%",h[0].style.width="100%");l.each(Na(a,mb),function(D,W){Y=ua(a,D);W.style.width=a.aoColumns[Y].sWidth});G&&ca(function(D){D.style.width=""},ba);h=w.outerWidth();""===c?(C.width="100%",L&&(w.find("tbody").height()>g.offsetHeight||"scroll"==n.css("overflow-y"))&&(C.width=K(w.outerWidth()-b)),h=w.outerWidth()): +""!==d&&(C.width=K(d),h=w.outerWidth());ca(Ca,fa);ca(function(D){var W=z.getComputedStyle?z.getComputedStyle(D).width:K(l(D).width());H.push(D.innerHTML);O.push(W)},fa);ca(function(D,W){D.style.width=O[W]},x);l(fa).height(0);G&&(ca(Ca,ba),ca(function(D){ea.push(D.innerHTML);I.push(K(l(D).css("width")))},ba),ca(function(D,W){D.style.width=I[W]},la),l(ba).height(0));ca(function(D,W){D.innerHTML='
    '+H[W]+"
    ";D.childNodes[0].style.height="0";D.childNodes[0].style.overflow= +"hidden";D.style.width=O[W]},fa);G&&ca(function(D,W){D.innerHTML='
    '+ea[W]+"
    ";D.childNodes[0].style.height="0";D.childNodes[0].style.overflow="hidden";D.style.width=I[W]},ba);Math.round(w.outerWidth())g.offsetHeight||"scroll"==n.css("overflow-y")?h+b:h,L&&(g.scrollHeight>g.offsetHeight||"scroll"==n.css("overflow-y"))&&(C.width=K(la-b)),""!==c&&""===d||da(a,1,"Possible column misalignment",6)):la="100%";p.width=K(la);f.width=K(la); +G&&(a.nScrollFoot.style.width=K(la));!e&&L&&(p.height=K(r.offsetHeight+b));c=w.outerWidth();m[0].style.width=K(c);k.width=K(c);d=w.height()>g.clientHeight||"scroll"==n.css("overflow-y");e="padding"+(aa.bScrollbarLeft?"Left":"Right");k[e]=d?b+"px":"0px";G&&(v[0].style.width=K(c),t[0].style.width=K(c),t[0].style[e]=d?b+"px":"0px");w.children("colgroup").insertBefore(w.children("thead"));n.trigger("scroll");!a.bSorted&&!a.bFiltered||a._drawHold||(g.scrollTop=0)}}function ca(a,b,c){for(var d=0,e=0,h= +b.length,f,g;e").appendTo(g.find("tbody"));g.find("thead, tfoot").remove();g.append(l(a.nTHead).clone()).append(l(a.nTFoot).clone());g.find("tfoot th, tfoot td").css("width","");m=Na(a,g.find("thead")[0]);for(v=0;v").css({width:w.sWidthOrig,margin:0,padding:0,border:0,height:1}));if(a.aoData.length)for(v=0;v").css(h||e?{position:"absolute",top:0,left:0,height:1,right:0,overflow:"hidden"}:{}).append(g).appendTo(p);h&&f?g.width(f):h?(g.css("width","auto"),g.removeAttr("width"),g.width()").css("width",K(a)).appendTo(b||A.body);b=a[0].offsetWidth;a.remove();return b}function $b(a,b){var c= +ac(a,b);if(0>c)return null;var d=a.aoData[c];return d.nTr?d.anCells[b]:l("
    ").html(T(a,c,b,"display"))[0]}function ac(a,b){for(var c,d=-1,e=-1,h=0,f=a.aoData.length;hd&&(d=c.length,e=h);return e}function K(a){return null===a?"0px":"number"==typeof a?0>a?"0px":a+"px":a.match(/\d$/)?a+"px":a}function pa(a){var b=[],c=a.aoColumns;var d=a.aaSortingFixed;var e=l.isPlainObject(d);var h=[];var f=function(n){n.length&& +!Array.isArray(n[0])?h.push(n):l.merge(h,n)};Array.isArray(d)&&f(d);e&&d.pre&&f(d.pre);f(a.aaSorting);e&&d.post&&f(d.post);for(a=0;aG?1:0;if(0!==C)return"asc"===r.dir?C:-C}C=c[n];G=c[p];return CG?1:0}):f.sort(function(n,p){var t,v=g.length,x=e[n]._aSortData,w=e[p]._aSortData;for(t=0;tG?1:0})}a.bSorted=!0}function cc(a){var b=a.aoColumns,c=pa(a);a=a.oLanguage.oAria;for(var d=0,e=b.length;d/g,"");var k=h.nTh;k.removeAttribute("aria-sort");h.bSortable&&(0e?e+1:3))}e= +0;for(h=d.length;ee?e+1:3))}a.aLastSort=d}function bc(a,b){var c=a.aoColumns[b],d=u.ext.order[c.sSortDataType],e;d&&(e=d.call(a.oInstance,a,b,va(a,b)));for(var h,f=u.ext.type.order[c.sType+"-pre"],g=0,k=a.aoData.length;g=e.length?[0,m[1]]:m)}));b.search!==q&&l.extend(a.oPreviousSearch,Wb(b.search));if(b.columns){f=0;for(d=b.columns.length;f=c&&(b=c-d);b-=b%d;if(-1===d||0>b)b=0;a._iDisplayStart=b}function gb(a,b){a=a.renderer;var c=u.ext.renderer[b];return l.isPlainObject(a)&&a[b]?c[a[b]]||c._:"string"===typeof a?c[a]||c._:c._}function Q(a){return a.oFeatures.bServerSide? +"ssp":a.ajax||a.sAjaxSource?"ajax":"dom"}function Da(a,b){var c=ec.numbers_length,d=Math.floor(c/2);b<=c?a=ra(0,b):a<=d?(a=ra(0,c-2),a.push("ellipsis"),a.push(b-1)):(a>=b-1-d?a=ra(b-(c-2),b):(a=ra(a-d+2,a+d-1),a.push("ellipsis"),a.push(b-1)),a.splice(0,0,"ellipsis"),a.splice(0,0,0));a.DT_el="span";return a}function Xa(a){l.each({num:function(b){return Ua(b,a)},"num-fmt":function(b){return Ua(b,a,rb)},"html-num":function(b){return Ua(b,a,Va)},"html-num-fmt":function(b){return Ua(b,a,Va,rb)}},function(b, +c){M.type.order[b+a+"-pre"]=c;b.match(/^html\-/)&&(M.type.search[b+a]=M.type.search.html)})}function fc(a){return function(){var b=[Ta(this[u.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return u.ext.internal[a].apply(this,b)}}var u=function(a,b){if(this instanceof u)return l(a).DataTable(b);b=a;this.$=function(f,g){return this.api(!0).$(f,g)};this._=function(f,g){return this.api(!0).rows(f,g).data()};this.api=function(f){return f?new B(Ta(this[M.iApiIndex])):new B(this)};this.fnAddData= +function(f,g){var k=this.api(!0);f=Array.isArray(f)&&(Array.isArray(f[0])||l.isPlainObject(f[0]))?k.rows.add(f):k.row.add(f);(g===q||g)&&k.draw();return f.flatten().toArray()};this.fnAdjustColumnSizing=function(f){var g=this.api(!0).columns.adjust(),k=g.settings()[0],m=k.oScroll;f===q||f?g.draw(!1):(""!==m.sX||""!==m.sY)&&Ha(k)};this.fnClearTable=function(f){var g=this.api(!0).clear();(f===q||f)&&g.draw()};this.fnClose=function(f){this.api(!0).row(f).child.hide()};this.fnDeleteRow=function(f,g,k){var m= +this.api(!0);f=m.rows(f);var n=f.settings()[0],p=n.aoData[f[0][0]];f.remove();g&&g.call(this,n,p);(k===q||k)&&m.draw();return p};this.fnDestroy=function(f){this.api(!0).destroy(f)};this.fnDraw=function(f){this.api(!0).draw(f)};this.fnFilter=function(f,g,k,m,n,p){n=this.api(!0);null===g||g===q?n.search(f,k,m,p):n.column(g).search(f,k,m,p);n.draw()};this.fnGetData=function(f,g){var k=this.api(!0);if(f!==q){var m=f.nodeName?f.nodeName.toLowerCase():"";return g!==q||"td"==m||"th"==m?k.cell(f,g).data(): +k.row(f).data()||null}return k.data().toArray()};this.fnGetNodes=function(f){var g=this.api(!0);return f!==q?g.row(f).node():g.rows().nodes().flatten().toArray()};this.fnGetPosition=function(f){var g=this.api(!0),k=f.nodeName.toUpperCase();return"TR"==k?g.row(f).index():"TD"==k||"TH"==k?(f=g.cell(f).index(),[f.row,f.columnVisible,f.column]):null};this.fnIsOpen=function(f){return this.api(!0).row(f).child.isShown()};this.fnOpen=function(f,g,k){return this.api(!0).row(f).child(g,k).show().child()[0]}; +this.fnPageChange=function(f,g){f=this.api(!0).page(f);(g===q||g)&&f.draw(!1)};this.fnSetColumnVis=function(f,g,k){f=this.api(!0).column(f).visible(g);(k===q||k)&&f.columns.adjust().draw()};this.fnSettings=function(){return Ta(this[M.iApiIndex])};this.fnSort=function(f){this.api(!0).order(f).draw()};this.fnSortListener=function(f,g,k){this.api(!0).order.listener(f,g,k)};this.fnUpdate=function(f,g,k,m,n){var p=this.api(!0);k===q||null===k?p.row(g).data(f):p.cell(g,k).data(f);(n===q||n)&&p.columns.adjust(); +(m===q||m)&&p.draw();return 0};this.fnVersionCheck=M.fnVersionCheck;var c=this,d=b===q,e=this.length;d&&(b={});this.oApi=this.internal=M.internal;for(var h in u.ext.internal)h&&(this[h]=fc(h));this.each(function(){var f={},g=1").appendTo(t));r.nTHead=H[0];var ea=t.children("tbody");0===ea.length&&(ea=l("
    '+a.title+": "+a.data+"
    ').append(a)}}};j.defaults={breakpoints:j.breakpoints,auto:!0,details:{display:j.display.childRow,renderer:j.renderer.listHidden(),target:0,type:"inline"},orthogonal:"display"};var o=c.fn.dataTable.Api; -o.register("responsive()",function(){return this});o.register("responsive.index()",function(b){b=c(b);return{column:b.data("dtr-index"),row:b.parent().data("dtr-index")}});o.register("responsive.rebuild()",function(){return this.iterator("table",function(b){b._responsive&&b._responsive._classLogic()})});o.register("responsive.recalc()",function(){return this.iterator("table",function(b){b._responsive&&(b._responsive._resizeAuto(),b._responsive._resize())})});o.register("responsive.hasHidden()",function(){var b= -this.context[0];return b._responsive?-1!==c.inArray(!1,b._responsive.s.current):!1});j.version="2.1.1";c.fn.dataTable.Responsive=j;c.fn.DataTable.Responsive=j;c(k).on("preInit.dt.dtr",function(b,a){if("dt"===b.namespace&&(c(a.nTable).hasClass("responsive")||c(a.nTable).hasClass("dt-responsive")||a.oInit.responsive||m.defaults.responsive)){var d=a.oInit.responsive;!1!==d&&new j(a,c.isPlainObject(d)?d:{})}});return j}); +var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.findInternal=function(b,k,m){b instanceof String&&(b=String(b));for(var n=b.length,p=0;ptd, >th", +g).each(function(e){e=c.column.index("toData",e);!1===a.s.current[e]&&b(this).css("display","none")})});c.on("destroy.dtr",function(){c.off(".dtr");b(c.table().body()).off(".dtr");b(k).off("resize.dtr orientationchange.dtr");c.cells(".dtr-control").nodes().to$().removeClass("dtr-control");b.each(a.s.current,function(g,l){!1===l&&a._setColumnVis(g,!0)})});this.c.breakpoints.sort(function(g,l){return g.widthl.width?-1:0});this._classLogic();this._resizeAuto();d=this.c.details;!1!== +d.type&&(a._detailsInit(),c.on("column-visibility.dtr",function(){a._timer&&clearTimeout(a._timer);a._timer=setTimeout(function(){a._timer=null;a._classLogic();a._resizeAuto();a._resize(!0);a._redrawChildren()},100)}),c.on("draw.dtr",function(){a._redrawChildren()}),b(c.table().node()).addClass("dtr-"+d.type));c.on("column-reorder.dtr",function(g,l,h){a._classLogic();a._resizeAuto();a._resize(!0)});c.on("column-sizing.dtr",function(){a._resizeAuto();a._resize()});c.on("preXhr.dtr",function(){var g= +[];c.rows().every(function(){this.child.isShown()&&g.push(this.id(!0))});c.one("draw.dtr",function(){a._resizeAuto();a._resize();c.rows(g).every(function(){a._detailsDisplay(this,!1)})})});c.on("draw.dtr",function(){a._controlClass()}).on("init.dtr",function(g,l,h){"dt"===g.namespace&&(a._resizeAuto(),a._resize(),b.inArray(!1,a.s.current)&&c.columns.adjust())});this._resize()},_columnsVisiblity:function(a){var c=this.s.dt,d=this.s.columns,f,g=d.map(function(t,v){return{columnIdx:v,priority:t.priority}}).sort(function(t, +v){return t.priority!==v.priority?t.priority-v.priority:t.columnIdx-v.columnIdx}),l=b.map(d,function(t,v){return!1===c.column(v).visible()?"not-visible":t.auto&&null===t.minWidth?!1:!0===t.auto?"-":-1!==b.inArray(a,t.includeIn)}),h=0;var e=0;for(f=l.length;eh-d[q].minWidth?(r=!0,l[q]=!1):l[q]=!0,h-=d[q].minWidth)}g=!1;e=0;for(f=d.length;e=q&&g(h,c[e].name);else if("not-"===r)for(e= +0,r=c.length;ef?c.columns().eq(0).length+f:f;if(c.cell(this).index().column!==l)return}l=c.row(b(this).closest("tr"));"click"===g.type?a._detailsDisplay(l,!1):"mousedown"===g.type?b(this).css("outline","none"):"mouseup"===g.type&&b(this).trigger("blur").css("outline","")}})}, +_detailsObj:function(a){var c=this,d=this.s.dt;return b.map(this.s.columns,function(f,g){if(!f.never&&!f.control)return f=d.settings()[0].aoColumns[g],{className:f.sClass,columnIndex:g,data:d.cell(a,g).render(c.c.orthogonal),hidden:d.column(g).visible()&&!c.s.current[g],rowIndex:a,title:null!==f.sTitle?f.sTitle:b(d.column(g).header()).text()}})},_find:function(a){for(var c=this.c.breakpoints,d=0,f=c.length;d").append(h).appendTo(g)}b("").append(l).appendTo(f);"inline"===this.c.details.type&&b(d).addClass("dtr-inline collapsed");b(d).find("[name]").removeAttr("name");b(d).css("position","relative");d=b("
    ").css({width:1,height:1,overflow:"hidden",clear:"both"}).append(d);d.insertBefore(a.table().node());l.each(function(e){e=a.column.index("fromVisible",e);c[e].minWidth=this.offsetWidth||0});d.remove()}},_responsiveOnlyHidden:function(){var a=this.s.dt;return b.map(this.s.current, +function(c,d){return!1===a.column(d).visible()?!0:c})},_setColumnVis:function(a,c){var d=this.s.dt;c=c?"":"none";b(d.column(a).header()).css("display",c);b(d.column(a).footer()).css("display",c);d.column(a).nodes().to$().css("display",c);b.isEmptyObject(A)||d.cells(null,a).indexes().each(function(f){y(d,f.row,f.column)})},_tabIndexes:function(){var a=this.s.dt,c=a.cells({page:"current"}).nodes().to$(),d=a.settings()[0],f=this.c.details.target;c.filter("[data-dtr-keyboard]").removeData("[data-dtr-keyboard]"); +"number"===typeof f?a.cells(null,f,{page:"current"}).nodes().to$().attr("tabIndex",d.iTabIndex).data("dtr-keyboard",1):("td:first-child, th:first-child"===f&&(f=">td:first-child, >th:first-child"),b(f,a.rows({page:"current"}).nodes()).attr("tabIndex",d.iTabIndex).data("dtr-keyboard",1))}});u.breakpoints=[{name:"desktop",width:Infinity},{name:"tablet-l",width:1024},{name:"tablet-p",width:768},{name:"mobile-l",width:480},{name:"mobile-p",width:320}];u.display={childRow:function(a,c,d){if(c){if(b(a.node()).hasClass("parent"))return a.child(d(), +"child").show(),!0}else{if(a.child.isShown())return a.child(!1),b(a.node()).removeClass("parent"),!1;a.child(d(),"child").show();b(a.node()).addClass("parent");return!0}},childRowImmediate:function(a,c,d){if(!c&&a.child.isShown()||!a.responsive.hasHidden())return a.child(!1),b(a.node()).removeClass("parent"),!1;a.child(d(),"child").show();b(a.node()).addClass("parent");return!0},modal:function(a){return function(c,d,f){if(d)b("div.dtr-modal-content").empty().append(f());else{var g=function(){l.remove(); +b(m).off("keypress.dtr")},l=b('
    ').append(b('
    ').append(b('
    ').append(f())).append(b('
    ×
    ').click(function(){g()}))).append(b('
    ').click(function(){g()})).appendTo("body");b(m).on("keyup.dtr",function(h){27===h.keyCode&&(h.stopPropagation(),g())})}a&&a.header&&b("div.dtr-modal-content").prepend("

    "+a.header(c)+"

    ")}}};var A={};u.renderer= +{listHiddenNodes:function(){return function(a,c,d){var f=b('
      '),g=!1;b.each(d,function(l,h){h.hidden&&(b("
    • '+h.title+"
    • ").append(b('').append(p(a,h.rowIndex,h.columnIndex))).appendTo(f),g=!0)});return g?f:!1}},listHidden:function(){return function(a, +c,d){return(a=b.map(d,function(f){var g=f.className?'class="'+f.className+'"':"";return f.hidden?"
    • '+f.title+' '+f.data+"
    • ":""}).join(""))?b('
        ').append(a):!1}},tableAll:function(a){a=b.extend({tableClass:""},a);return function(c,d,f){c=b.map(f,function(g){return"
    "}).join("");return b('
    '+g.title+": "+g.data+"
    ').append(c)}}};u.defaults={breakpoints:u.breakpoints,auto:!0,details:{display:u.display.childRow,renderer:u.renderer.listHidden(),target:0,type:"inline"},orthogonal:"display"};var C=b.fn.dataTable.Api;C.register("responsive()",function(){return this});C.register("responsive.index()", +function(a){a=b(a);return{column:a.data("dtr-index"),row:a.parent().data("dtr-index")}});C.register("responsive.rebuild()",function(){return this.iterator("table",function(a){a._responsive&&a._responsive._classLogic()})});C.register("responsive.recalc()",function(){return this.iterator("table",function(a){a._responsive&&(a._responsive._resizeAuto(),a._responsive._resize())})});C.register("responsive.hasHidden()",function(){var a=this.context[0];return a._responsive?-1!==b.inArray(!1,a._responsive._responsiveOnlyHidden()): +!1});C.registerPlural("columns().responsiveHidden()","column().responsiveHidden()",function(){return this.iterator("column",function(a,c){return a._responsive?a._responsive._responsiveOnlyHidden()[c]:!1},1)});u.version="2.2.9";b.fn.dataTable.Responsive=u;b.fn.DataTable.Responsive=u;b(m).on("preInit.dt.dtr",function(a,c,d){"dt"===a.namespace&&(b(c.nTable).hasClass("responsive")||b(c.nTable).hasClass("dt-responsive")||c.oInit.responsive||z.defaults.responsive)&&(a=c.oInit.responsive,!1!==a&&new u(c, +b.isPlainObject(a)?a:{}))});return u}); + + +/*! DataTables styling wrapper for Responsive + * ©2018 SpryMedia Ltd - datatables.net/license + */ + +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net-dt', 'datatables.net-responsive'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + module.exports = function (root, $) { + if ( ! root ) { + root = window; + } + + if ( ! $ || ! $.fn.dataTable ) { + $ = require('datatables.net-dt')(root, $).$; + } + + if ( ! $.fn.dataTable.Responsive ) { + require('datatables.net-responsive')(root, $); + } + + return factory( $, root, root.document ); + }; + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { + +return $.fn.dataTable; + +})); + +/*! + SearchBuilder 1.3.1 + ©SpryMedia Ltd - datatables.net/license/mit +*/ +var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.SIMPLE_FROUND_POLYFILL=!1;$jscomp.ISOLATE_POLYFILLS=!1;$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(k,m,l){if(k==Array.prototype||k==Object.prototype)return k;k[m]=l.value;return k}; +$jscomp.getGlobal=function(k){k=["object"==typeof globalThis&&globalThis,k,"object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global];for(var m=0;ml&&(l=Math.max(l+p,0));l=t}},"es6","es3"); +$jscomp.polyfill("String.prototype.endsWith",function(k){return k?k:function(m,l){var h=$jscomp.checkStringArgs(this,m,"endsWith");m+="";void 0===l&&(l=h.length);l=Math.max(0,Math.min(l|0,h.length));for(var p=m.length;0=p}},"es6","es3"); +(function(){function k(c){h=c;p=c.fn.dataTable}function m(c){B=c;E=c.fn.dataTable}function l(c){x=c;C=c.fn.DataTable}var h,p,t=window.moment,v=window.luxon,r=function(){function c(a,b,d,e,f){var g=this;void 0===e&&(e=0);void 0===f&&(f=1);if(!p||!p.versionCheck||!p.versionCheck("1.10.0"))throw Error("SearchPane requires DataTables 1.10 or newer");this.classes=h.extend(!0,{},c.classes);this.c=h.extend(!0,{},c.defaults,h.fn.dataTable.ext.searchBuilder,b);b=this.c.i18n;this.s={condition:void 0,conditions:{}, +data:void 0,dataIdx:-1,dataPoints:[],dateFormat:!1,depth:f,dt:a,filled:!1,index:e,origData:void 0,topGroup:d,type:"",value:[]};this.dom={buttons:h("
    ").addClass(this.classes.buttonContainer),condition:h("").addClass(this.classes.data).addClass(this.classes.dropDown).addClass(this.classes.italic),dataTitle:h('
    ').insertAfter(thead); - } - oSettings.nTBody = tbody[0]; - - var tfoot = $this.children('tfoot'); - if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) { - // If we are a scrolling table, and no footer has been given, then we need to create - // a tfoot element for the caption element to be appended to - tfoot = $('').appendTo($this); - } - - if ( tfoot.length === 0 || tfoot.children().length === 0 ) { - $this.addClass( oClasses.sNoFooter ); - } - else if ( tfoot.length > 0 ) { - oSettings.nTFoot = tfoot[0]; - _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot ); - } - - /* Check if there is data passing into the constructor */ - if ( oInit.aaData ) { - for ( i=0 ; i/g; - - // This is not strict ISO8601 - Date.parse() is quite lax, although - // implementations differ between browsers. - var _re_date = /^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/; - - // Escape regular expression special characters - var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' ); - - // http://en.wikipedia.org/wiki/Foreign_exchange_market - // - \u20BD - Russian ruble. - // - \u20a9 - South Korean Won - // - \u20BA - Turkish Lira - // - \u20B9 - Indian Rupee - // - R - Brazil (R$) and South Africa - // - fr - Swiss Franc - // - kr - Swedish krona, Norwegian krone and Danish krone - // - \u2009 is thin space and \u202F is narrow no-break space, both used in many - // - Ƀ - Bitcoin - // - Ξ - Ethereum - // standards as thousands separators. - var _re_formatted_numeric = /['\u00A0,$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi; - - - var _empty = function ( d ) { - return !d || d === true || d === '-' ? true : false; - }; - - - var _intVal = function ( s ) { - var integer = parseInt( s, 10 ); - return !isNaN(integer) && isFinite(s) ? integer : null; - }; - - // Convert from a formatted number with characters other than `.` as the - // decimal place, to a Javascript number - var _numToDecimal = function ( num, decimalPoint ) { - // Cache created regular expressions for speed as this function is called often - if ( ! _re_dic[ decimalPoint ] ) { - _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' ); - } - return typeof num === 'string' && decimalPoint !== '.' ? - num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) : - num; - }; - - - var _isNumber = function ( d, decimalPoint, formatted ) { - var strType = typeof d === 'string'; - - // If empty return immediately so there must be a number if it is a - // formatted string (this stops the string "k", or "kr", etc being detected - // as a formatted number for currency - if ( _empty( d ) ) { - return true; - } - - if ( decimalPoint && strType ) { - d = _numToDecimal( d, decimalPoint ); - } - - if ( formatted && strType ) { - d = d.replace( _re_formatted_numeric, '' ); - } - - return !isNaN( parseFloat(d) ) && isFinite( d ); - }; - - - // A string without HTML in it can be considered to be HTML still - var _isHtml = function ( d ) { - return _empty( d ) || typeof d === 'string'; - }; - - - var _htmlNumeric = function ( d, decimalPoint, formatted ) { - if ( _empty( d ) ) { - return true; - } - - var html = _isHtml( d ); - return ! html ? - null : - _isNumber( _stripHtml( d ), decimalPoint, formatted ) ? - true : - null; - }; - - - var _pluck = function ( a, prop, prop2 ) { - var out = []; - var i=0, ien=a.length; - - // Could have the test in the loop for slightly smaller code, but speed - // is essential here - if ( prop2 !== undefined ) { - for ( ; i') - .css( { - position: 'fixed', - top: 0, - left: $(window).scrollLeft()*-1, // allow for scrolling - height: 1, - width: 1, - overflow: 'hidden' - } ) - .append( - $('
    ') - .css( { - position: 'absolute', - top: 1, - left: 1, - width: 100, - overflow: 'scroll' - } ) - .append( - $('
    ') - .css( { - width: '100%', - height: 10 - } ) - ) - ) - .appendTo( 'body' ); - - var outer = n.children(); - var inner = outer.children(); - - // Numbers below, in order, are: - // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth - // - // IE6 XP: 100 100 100 83 - // IE7 Vista: 100 100 100 83 - // IE 8+ Windows: 83 83 100 83 - // Evergreen Windows: 83 83 100 83 - // Evergreen Mac with scrollbars: 85 85 100 85 - // Evergreen Mac without scrollbars: 100 100 100 100 - - // Get scrollbar width - browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth; - - // IE6/7 will oversize a width 100% element inside a scrolling element, to - // include the width of the scrollbar, while other browsers ensure the inner - // element is contained without forcing scrolling - browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100; - - // In rtl text layout, some browsers (most, but not all) will place the - // scrollbar on the left, rather than the right. - browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1; - - // IE8- don't provide height and width for getBoundingClientRect - browser.bBounding = n[0].getBoundingClientRect().width ? true : false; - - n.remove(); - } - - $.extend( settings.oBrowser, DataTable.__browser ); - settings.oScroll.iBarWidth = DataTable.__browser.barWidth; - } - - - /** - * Array.prototype reduce[Right] method, used for browsers which don't support - * JS 1.6. Done this way to reduce code size, since we iterate either way - * @param {object} settings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnReduce ( that, fn, init, start, end, inc ) - { - var - i = start, - value, - isSet = false; - - if ( init !== undefined ) { - value = init; - isSet = true; - } - - while ( i !== end ) { - if ( ! that.hasOwnProperty(i) ) { - continue; - } - - value = isSet ? - fn( value, that[i], i, that ) : - that[i]; - - isSet = true; - i += inc; - } - - return value; - } - - /** - * Add a column to the list used for the table with default values - * @param {object} oSettings dataTables settings object - * @param {node} nTh The th element for this column - * @memberof DataTable#oApi - */ - function _fnAddColumn( oSettings, nTh ) - { - // Add column to aoColumns array - var oDefaults = DataTable.defaults.column; - var iCol = oSettings.aoColumns.length; - var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, { - "nTh": nTh ? nTh : document.createElement('th'), - "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '', - "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol], - "mData": oDefaults.mData ? oDefaults.mData : iCol, - idx: iCol - } ); - oSettings.aoColumns.push( oCol ); - - // Add search object for column specific search. Note that the `searchCols[ iCol ]` - // passed into extend can be undefined. This allows the user to give a default - // with only some of the parameters defined, and also not give a default - var searchCols = oSettings.aoPreSearchCols; - searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] ); - - // Use the default column options function to initialise classes etc - _fnColumnOptions( oSettings, iCol, $(nTh).data() ); - } - - - /** - * Apply options for a column - * @param {object} oSettings dataTables settings object - * @param {int} iCol column index to consider - * @param {object} oOptions object with sType, bVisible and bSearchable etc - * @memberof DataTable#oApi - */ - function _fnColumnOptions( oSettings, iCol, oOptions ) - { - var oCol = oSettings.aoColumns[ iCol ]; - var oClasses = oSettings.oClasses; - var th = $(oCol.nTh); - - // Try to get width information from the DOM. We can't get it from CSS - // as we'd need to parse the CSS stylesheet. `width` option can override - if ( ! oCol.sWidthOrig ) { - // Width attribute - oCol.sWidthOrig = th.attr('width') || null; - - // Style attribute - var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/); - if ( t ) { - oCol.sWidthOrig = t[1]; - } - } - - /* User specified column options */ - if ( oOptions !== undefined && oOptions !== null ) - { - // Backwards compatibility - _fnCompatCols( oOptions ); - - // Map camel case parameters to their Hungarian counterparts - _fnCamelToHungarian( DataTable.defaults.column, oOptions, true ); - - /* Backwards compatibility for mDataProp */ - if ( oOptions.mDataProp !== undefined && !oOptions.mData ) - { - oOptions.mData = oOptions.mDataProp; - } - - if ( oOptions.sType ) - { - oCol._sManualType = oOptions.sType; - } - - // `class` is a reserved word in Javascript, so we need to provide - // the ability to use a valid name for the camel case input - if ( oOptions.className && ! oOptions.sClass ) - { - oOptions.sClass = oOptions.className; - } - if ( oOptions.sClass ) { - th.addClass( oOptions.sClass ); - } - - $.extend( oCol, oOptions ); - _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" ); - - /* iDataSort to be applied (backwards compatibility), but aDataSort will take - * priority if defined - */ - if ( oOptions.iDataSort !== undefined ) - { - oCol.aDataSort = [ oOptions.iDataSort ]; - } - _fnMap( oCol, oOptions, "aDataSort" ); - } - - /* Cache the data get and set functions for speed */ - var mDataSrc = oCol.mData; - var mData = _fnGetObjectDataFn( mDataSrc ); - var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null; - - var attrTest = function( src ) { - return typeof src === 'string' && src.indexOf('@') !== -1; - }; - oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && ( - attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter) - ); - oCol._setter = null; - - oCol.fnGetData = function (rowData, type, meta) { - var innerData = mData( rowData, type, undefined, meta ); - - return mRender && type ? - mRender( innerData, type, rowData, meta ) : - innerData; - }; - oCol.fnSetData = function ( rowData, val, meta ) { - return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta ); - }; - - // Indicate if DataTables should read DOM data as an object or array - // Used in _fnGetRowElements - if ( typeof mDataSrc !== 'number' ) { - oSettings._rowReadObject = true; - } - - /* Feature sorting overrides column specific when off */ - if ( !oSettings.oFeatures.bSort ) - { - oCol.bSortable = false; - th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called - } - - /* Check that the class assignment is correct for sorting */ - var bAsc = $.inArray('asc', oCol.asSorting) !== -1; - var bDesc = $.inArray('desc', oCol.asSorting) !== -1; - if ( !oCol.bSortable || (!bAsc && !bDesc) ) - { - oCol.sSortingClass = oClasses.sSortableNone; - oCol.sSortingClassJUI = ""; - } - else if ( bAsc && !bDesc ) - { - oCol.sSortingClass = oClasses.sSortableAsc; - oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed; - } - else if ( !bAsc && bDesc ) - { - oCol.sSortingClass = oClasses.sSortableDesc; - oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed; - } - else - { - oCol.sSortingClass = oClasses.sSortable; - oCol.sSortingClassJUI = oClasses.sSortJUI; - } - } - - - /** - * Adjust the table column widths for new data. Note: you would probably want to - * do a redraw after calling this function! - * @param {object} settings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnAdjustColumnSizing ( settings ) - { - /* Not interested in doing column width calculation if auto-width is disabled */ - if ( settings.oFeatures.bAutoWidth !== false ) - { - var columns = settings.aoColumns; - - _fnCalculateColumnWidths( settings ); - for ( var i=0 , iLen=columns.length ; i
    ').addClass( k ); - $('td', created) - .addClass( k ) - .html( r ) - [0].colSpan = _fnVisbleColumns( ctx ); - - rows.push( created[0] ); - } - }; - - addRow( data, klass ); - - if ( row._details ) { - row._details.detach(); - } - - row._details = $(rows); - - // If the children were already shown, that state should be retained - if ( row._detailsShow ) { - row._details.insertAfter( row.nTr ); - } - }; - - - var __details_remove = function ( api, idx ) - { - var ctx = api.context; - - if ( ctx.length ) { - var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ]; - - if ( row && row._details ) { - row._details.remove(); - - row._detailsShow = undefined; - row._details = undefined; - $( row.nTr ).removeClass( 'dt-hasChild' ); - _fnSaveState( ctx[0] ); - } - } - }; - - - var __details_display = function ( api, show ) { - var ctx = api.context; - - if ( ctx.length && api.length ) { - var row = ctx[0].aoData[ api[0] ]; - - if ( row._details ) { - row._detailsShow = show; - - if ( show ) { - row._details.insertAfter( row.nTr ); - $( row.nTr ).addClass( 'dt-hasChild' ); - } - else { - row._details.detach(); - $( row.nTr ).removeClass( 'dt-hasChild' ); - } - - _fnCallbackFire( ctx[0], null, 'childRow', [ show, api.row( api[0] ) ] ) - - __details_events( ctx[0] ); - _fnSaveState( ctx[0] ); - } - } - }; - - - var __details_events = function ( settings ) - { - var api = new _Api( settings ); - var namespace = '.dt.DT_details'; - var drawEvent = 'draw'+namespace; - var colvisEvent = 'column-visibility'+namespace; - var destroyEvent = 'destroy'+namespace; - var data = settings.aoData; - - api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent ); - - if ( _pluck( data, '_details' ).length > 0 ) { - // On each draw, insert the required elements into the document - api.on( drawEvent, function ( e, ctx ) { - if ( settings !== ctx ) { - return; - } - - api.rows( {page:'current'} ).eq(0).each( function (idx) { - // Internal data grab - var row = data[ idx ]; - - if ( row._detailsShow ) { - row._details.insertAfter( row.nTr ); - } - } ); - } ); - - // Column visibility change - update the colspan - api.on( colvisEvent, function ( e, ctx, idx, vis ) { - if ( settings !== ctx ) { - return; - } - - // Update the colspan for the details rows (note, only if it already has - // a colspan) - var row, visible = _fnVisbleColumns( ctx ); - - for ( var i=0, ien=data.length ; i=0 count from left, <0 count from right) - * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right) - * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right) - * "{string}:name" - column name - * "{string}" - jQuery selector on column header nodes - * - */ - - // can be an array of these items, comma separated list, or an array of comma - // separated lists - - var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/; - - - // r1 and r2 are redundant - but it means that the parameters match for the - // iterator callback in columns().data() - var __columnData = function ( settings, column, r1, r2, rows ) { - var a = []; - for ( var row=0, ien=rows.length ; row= 0 ? - selInt : // Count from left - columns.length + selInt // Count from right (+ because its a negative value) - ]; - } - - // Selector = function - if ( typeof s === 'function' ) { - var rows = _selector_row_indexes( settings, opts ); - - return $.map( columns, function (col, idx) { - return s( - idx, - __columnData( settings, idx, 0, 0, rows ), - nodes[ idx ] - ) ? idx : null; - } ); - } - - // jQuery or string selector - var match = typeof s === 'string' ? - s.match( __re_column_selector ) : - ''; - - if ( match ) { - switch( match[2] ) { - case 'visIdx': - case 'visible': - var idx = parseInt( match[1], 10 ); - // Visible index given, convert to column index - if ( idx < 0 ) { - // Counting from the right - var visColumns = $.map( columns, function (col,i) { - return col.bVisible ? i : null; - } ); - return [ visColumns[ visColumns.length + idx ] ]; - } - // Counting from the left - return [ _fnVisibleToColumnIndex( settings, idx ) ]; - - case 'name': - // match by name. `names` is column index complete and in order - return $.map( names, function (name, i) { - return name === match[1] ? i : null; - } ); - - default: - return []; - } - } - - // Cell in the table body - if ( s.nodeName && s._DT_CellIndex ) { - return [ s._DT_CellIndex.column ]; - } - - // jQuery selector on the TH elements for the columns - var jqResult = $( nodes ) - .filter( s ) - .map( function () { - return $.inArray( this, nodes ); // `nodes` is column index complete and in order - } ) - .toArray(); - - if ( jqResult.length || ! s.nodeName ) { - return jqResult; - } - - // Otherwise a node which might have a `dt-column` data attribute, or be - // a child or such an element - var host = $(s).closest('*[data-dt-column]'); - return host.length ? - [ host.data('dt-column') ] : - []; - }; - - return _selector_run( 'column', selector, run, settings, opts ); - }; - - - var __setColumnVis = function ( settings, column, vis ) { - var - cols = settings.aoColumns, - col = cols[ column ], - data = settings.aoData, - row, cells, i, ien, tr; - - // Get - if ( vis === undefined ) { - return col.bVisible; - } - - // Set - // No change - if ( col.bVisible === vis ) { - return; - } - - if ( vis ) { - // Insert column - // Need to decide if we should use appendChild or insertBefore - var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 ); - - for ( i=0, ien=data.length ; i iThat; - } - - return true; - }; - - - /** - * Check if a `
    ', { - 'valign': 'top', - 'colSpan': _fnVisbleColumns( oSettings ), - 'class': oSettings.oClasses.sRowEmpty - } ).html( sZero ) )[0]; - } - - /* Header and footer callbacks */ - _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0], - _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); - - _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0], - _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); - - var body = $(oSettings.nTBody); - - body.children().detach(); - body.append( $(anRows) ); - - /* Call all required callback functions for the end of a draw */ - _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] ); - - /* Draw is complete, sorting and filtering must be as well */ - oSettings.bSorted = false; - oSettings.bFiltered = false; - oSettings.bDrawing = false; - } - - - /** - * Redraw the table - taking account of the various features which are enabled - * @param {object} oSettings dataTables settings object - * @param {boolean} [holdPosition] Keep the current paging position. By default - * the paging is reset to the first page - * @memberof DataTable#oApi - */ - function _fnReDraw( settings, holdPosition ) - { - var - features = settings.oFeatures, - sort = features.bSort, - filter = features.bFilter; - - if ( sort ) { - _fnSort( settings ); - } - - if ( filter ) { - _fnFilterComplete( settings, settings.oPreviousSearch ); - } - else { - // No filtering, so we want to just use the display master - settings.aiDisplay = settings.aiDisplayMaster.slice(); - } - - if ( holdPosition !== true ) { - settings._iDisplayStart = 0; - } - - // Let any modules know about the draw hold position state (used by - // scrolling internally) - settings._drawHold = holdPosition; - - _fnDraw( settings ); - - settings._drawHold = false; - } - - - /** - * Add the options to the page HTML for the table - * @param {object} oSettings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnAddOptionsHtml ( oSettings ) - { - var classes = oSettings.oClasses; - var table = $(oSettings.nTable); - var holding = $('
    ').insertBefore( table ); // Holding element for speed - var features = oSettings.oFeatures; - - // All DataTables are wrapped in a div - var insert = $('
    ', { - id: oSettings.sTableId+'_wrapper', - 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter) - } ); - - oSettings.nHolding = holding[0]; - oSettings.nTableWrapper = insert[0]; - oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling; - - /* Loop over the user set positioning and place the elements as needed */ - var aDom = oSettings.sDom.split(''); - var featureNode, cOption, nNewNode, cNext, sAttr, j; - for ( var i=0 ; i')[0]; - - /* Check to see if we should append an id and/or a class name to the container */ - cNext = aDom[i+1]; - if ( cNext == "'" || cNext == '"' ) - { - sAttr = ""; - j = 2; - while ( aDom[i+j] != cNext ) - { - sAttr += aDom[i+j]; - j++; - } - - /* Replace jQuery UI constants @todo depreciated */ - if ( sAttr == "H" ) - { - sAttr = classes.sJUIHeader; - } - else if ( sAttr == "F" ) - { - sAttr = classes.sJUIFooter; - } - - /* The attribute can be in the format of "#id.class", "#id" or "class" This logic - * breaks the string into parts and applies them as needed - */ - if ( sAttr.indexOf('.') != -1 ) - { - var aSplit = sAttr.split('.'); - nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1); - nNewNode.className = aSplit[1]; - } - else if ( sAttr.charAt(0) == "#" ) - { - nNewNode.id = sAttr.substr(1, sAttr.length-1); - } - else - { - nNewNode.className = sAttr; - } - - i += j; /* Move along the position array */ - } - - insert.append( nNewNode ); - insert = $(nNewNode); - } - else if ( cOption == '>' ) - { - /* End container div */ - insert = insert.parent(); - } - // @todo Move options into their own plugins? - else if ( cOption == 'l' && features.bPaginate && features.bLengthChange ) - { - /* Length */ - featureNode = _fnFeatureHtmlLength( oSettings ); - } - else if ( cOption == 'f' && features.bFilter ) - { - /* Filter */ - featureNode = _fnFeatureHtmlFilter( oSettings ); - } - else if ( cOption == 'r' && features.bProcessing ) - { - /* pRocessing */ - featureNode = _fnFeatureHtmlProcessing( oSettings ); - } - else if ( cOption == 't' ) - { - /* Table */ - featureNode = _fnFeatureHtmlTable( oSettings ); - } - else if ( cOption == 'i' && features.bInfo ) - { - /* Info */ - featureNode = _fnFeatureHtmlInfo( oSettings ); - } - else if ( cOption == 'p' && features.bPaginate ) - { - /* Pagination */ - featureNode = _fnFeatureHtmlPaginate( oSettings ); - } - else if ( DataTable.ext.feature.length !== 0 ) - { - /* Plug-in features */ - var aoFeatures = DataTable.ext.feature; - for ( var k=0, kLen=aoFeatures.length ; k= oSettings.fnRecordsDisplay() ? - 0 : - iInitDisplayStart; - - oSettings.iInitDisplayStart = -1; - } - } - - /** - * Create an Ajax call based on the table's settings, taking into account that - * parameters can have multiple forms, and backwards compatibility. - * - * @param {object} oSettings dataTables settings object - * @param {array} data Data to send to the server, required by - * DataTables - may be augmented by developer callbacks - * @param {function} fn Callback function to run when data is obtained - */ - function _fnBuildAjax( oSettings, data, fn ) - { - // Compatibility with 1.9-, allow fnServerData and event to manipulate - _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] ); - - // Convert to object based for 1.10+ if using the old array scheme which can - // come from server-side processing or serverParams - if ( data && Array.isArray(data) ) { - var tmp = {}; - var rbracket = /(.*?)\[\]$/; - - $.each( data, function (key, val) { - var match = val.name.match(rbracket); - - if ( match ) { - // Support for arrays - var name = match[0]; - - if ( ! tmp[ name ] ) { - tmp[ name ] = []; - } - tmp[ name ].push( val.value ); - } - else { - tmp[val.name] = val.value; - } - } ); - data = tmp; - } - - var ajaxData; - var ajax = oSettings.ajax; - var instance = oSettings.oInstance; - var callback = function ( json ) { - var status = oSettings.jqXHR - ? oSettings.jqXHR.status - : null; - - if ( json === null || (typeof status === 'number' && status == 204 ) ) { - json = {}; - _fnAjaxDataSrc( oSettings, json, [] ); - } - - var error = json.error || json.sError; - if ( error ) { - _fnLog( oSettings, 0, error ); - } - - oSettings.json = json; - - _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] ); - fn( json ); - }; - - if ( $.isPlainObject( ajax ) && ajax.data ) - { - ajaxData = ajax.data; - - var newData = typeof ajaxData === 'function' ? - ajaxData( data, oSettings ) : // fn can manipulate data or return - ajaxData; // an object object or array to merge - - // If the function returned something, use that alone - data = typeof ajaxData === 'function' && newData ? - newData : - $.extend( true, data, newData ); - - // Remove the data property as we've resolved it already and don't want - // jQuery to do it again (it is restored at the end of the function) - delete ajax.data; - } - - var baseAjax = { - "data": data, - "success": callback, - "dataType": "json", - "cache": false, - "type": oSettings.sServerMethod, - "error": function (xhr, error, thrown) { - var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] ); - - if ( $.inArray( true, ret ) === -1 ) { - if ( error == "parsererror" ) { - _fnLog( oSettings, 0, 'Invalid JSON response', 1 ); - } - else if ( xhr.readyState === 4 ) { - _fnLog( oSettings, 0, 'Ajax error', 7 ); - } - } - - _fnProcessingDisplay( oSettings, false ); - } - }; - - // Store the data submitted for the API - oSettings.oAjaxData = data; - - // Allow plug-ins and external processes to modify the data - _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] ); - - if ( oSettings.fnServerData ) - { - // DataTables 1.9- compatibility - oSettings.fnServerData.call( instance, - oSettings.sAjaxSource, - $.map( data, function (val, key) { // Need to convert back to 1.9 trad format - return { name: key, value: val }; - } ), - callback, - oSettings - ); - } - else if ( oSettings.sAjaxSource || typeof ajax === 'string' ) - { - // DataTables 1.9- compatibility - oSettings.jqXHR = $.ajax( $.extend( baseAjax, { - url: ajax || oSettings.sAjaxSource - } ) ); - } - else if ( typeof ajax === 'function' ) - { - // Is a function - let the caller define what needs to be done - oSettings.jqXHR = ajax.call( instance, data, callback, oSettings ); - } - else - { - // Object to extend the base settings - oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) ); - - // Restore for next time around - ajax.data = ajaxData; - } - } - - - /** - * Update the table using an Ajax call - * @param {object} settings dataTables settings object - * @returns {boolean} Block the table drawing or not - * @memberof DataTable#oApi - */ - function _fnAjaxUpdate( settings ) - { - settings.iDraw++; - _fnProcessingDisplay( settings, true ); - - _fnBuildAjax( - settings, - _fnAjaxParameters( settings ), - function(json) { - _fnAjaxUpdateDraw( settings, json ); - } - ); - } - - - /** - * Build up the parameters in an object needed for a server-side processing - * request. Note that this is basically done twice, is different ways - a modern - * method which is used by default in DataTables 1.10 which uses objects and - * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if - * the sAjaxSource option is used in the initialisation, or the legacyAjax - * option is set. - * @param {object} oSettings dataTables settings object - * @returns {bool} block the table drawing or not - * @memberof DataTable#oApi - */ - function _fnAjaxParameters( settings ) - { - var - columns = settings.aoColumns, - columnCount = columns.length, - features = settings.oFeatures, - preSearch = settings.oPreviousSearch, - preColSearch = settings.aoPreSearchCols, - i, data = [], dataProp, column, columnSearch, - sort = _fnSortFlatten( settings ), - displayStart = settings._iDisplayStart, - displayLength = features.bPaginate !== false ? - settings._iDisplayLength : - -1; - - var param = function ( name, value ) { - data.push( { 'name': name, 'value': value } ); - }; - - // DataTables 1.9- compatible method - param( 'sEcho', settings.iDraw ); - param( 'iColumns', columnCount ); - param( 'sColumns', _pluck( columns, 'sName' ).join(',') ); - param( 'iDisplayStart', displayStart ); - param( 'iDisplayLength', displayLength ); - - // DataTables 1.10+ method - var d = { - draw: settings.iDraw, - columns: [], - order: [], - start: displayStart, - length: displayLength, - search: { - value: preSearch.sSearch, - regex: preSearch.bRegex - } - }; - - for ( i=0 ; i'; - - var str = language.sSearch; - str = str.match(/_INPUT_/) ? - str.replace('_INPUT_', input) : - str+input; - - var filter = $('
    ', { - 'id': ! features.f ? tableId+'_filter' : null, - 'class': classes.sFilter - } ) - .append( $('
    ').addClass( classes.sLength ); - if ( ! settings.aanFeatures.l ) { - div[0].id = tableId+'_length'; - } - - div.children().append( - settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML ) - ); - - // Can't use `select` variable as user might provide their own and the - // reference is broken by the use of outerHTML - $('select', div) - .val( settings._iDisplayLength ) - .on( 'change.DT', function(e) { - _fnLengthChange( settings, $(this).val() ); - _fnDraw( settings ); - } ); - - // Update node value whenever anything changes the table's length - $(settings.nTable).on( 'length.dt.DT', function (e, s, len) { - if ( settings === s ) { - $('select', div).val( len ); - } - } ); - - return div[0]; - } - - - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Note that most of the paging logic is done in - * DataTable.ext.pager - */ - - /** - * Generate the node required for default pagination - * @param {object} oSettings dataTables settings object - * @returns {node} Pagination feature node - * @memberof DataTable#oApi - */ - function _fnFeatureHtmlPaginate ( settings ) - { - var - type = settings.sPaginationType, - plugin = DataTable.ext.pager[ type ], - modern = typeof plugin === 'function', - redraw = function( settings ) { - _fnDraw( settings ); - }, - node = $('
    ').addClass( settings.oClasses.sPaging + type )[0], - features = settings.aanFeatures; - - if ( ! modern ) { - plugin.fnInit( settings, node, redraw ); - } - - /* Add a draw callback for the pagination on first instance, to update the paging display */ - if ( ! features.p ) - { - node.id = settings.sTableId+'_paginate'; - - settings.aoDrawCallback.push( { - "fn": function( settings ) { - if ( modern ) { - var - start = settings._iDisplayStart, - len = settings._iDisplayLength, - visRecords = settings.fnRecordsDisplay(), - all = len === -1, - page = all ? 0 : Math.ceil( start / len ), - pages = all ? 1 : Math.ceil( visRecords / len ), - buttons = plugin(page, pages), - i, ien; - - for ( i=0, ien=features.p.length ; i records ) - { - start = 0; - } - } - else if ( action == "first" ) - { - start = 0; - } - else if ( action == "previous" ) - { - start = len >= 0 ? - start - len : - 0; - - if ( start < 0 ) - { - start = 0; - } - } - else if ( action == "next" ) - { - if ( start + len < records ) - { - start += len; - } - } - else if ( action == "last" ) - { - start = Math.floor( (records-1) / len) * len; - } - else - { - _fnLog( settings, 0, "Unknown paging action: "+action, 5 ); - } - - var changed = settings._iDisplayStart !== start; - settings._iDisplayStart = start; - - if ( changed ) { - _fnCallbackFire( settings, null, 'page', [settings] ); - - if ( redraw ) { - _fnDraw( settings ); - } - } - - return changed; - } - - - - /** - * Generate the node required for the processing node - * @param {object} settings dataTables settings object - * @returns {node} Processing element - * @memberof DataTable#oApi - */ - function _fnFeatureHtmlProcessing ( settings ) - { - return $('
    ', { - 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null, - 'class': settings.oClasses.sProcessing - } ) - .html( settings.oLanguage.sProcessing ) - .insertBefore( settings.nTable )[0]; - } - - - /** - * Display or hide the processing indicator - * @param {object} settings dataTables settings object - * @param {bool} show Show the processing indicator (true) or not (false) - * @memberof DataTable#oApi - */ - function _fnProcessingDisplay ( settings, show ) - { - if ( settings.oFeatures.bProcessing ) { - $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' ); - } - - _fnCallbackFire( settings, null, 'processing', [settings, show] ); - } - - /** - * Add any control elements for the table - specifically scrolling - * @param {object} settings dataTables settings object - * @returns {node} Node to add to the DOM - * @memberof DataTable#oApi - */ - function _fnFeatureHtmlTable ( settings ) - { - var table = $(settings.nTable); - - // Scrolling from here on in - var scroll = settings.oScroll; - - if ( scroll.sX === '' && scroll.sY === '' ) { - return settings.nTable; - } - - var scrollX = scroll.sX; - var scrollY = scroll.sY; - var classes = settings.oClasses; - var caption = table.children('caption'); - var captionSide = caption.length ? caption[0]._captionSide : null; - var headerClone = $( table[0].cloneNode(false) ); - var footerClone = $( table[0].cloneNode(false) ); - var footer = table.children('tfoot'); - var _div = '
    '; - var size = function ( s ) { - return !s ? null : _fnStringToCss( s ); - }; - - if ( ! footer.length ) { - footer = null; - } - - /* - * The HTML structure that we want to generate in this function is: - * div - scroller - * div - scroll head - * div - scroll head inner - * table - scroll head table - * thead - thead - * div - scroll body - * table - table (master table) - * thead - thead clone for sizing - * tbody - tbody - * div - scroll foot - * div - scroll foot inner - * table - scroll foot table - * tfoot - tfoot - */ - var scroller = $( _div, { 'class': classes.sScrollWrapper } ) - .append( - $(_div, { 'class': classes.sScrollHead } ) - .css( { - overflow: 'hidden', - position: 'relative', - border: 0, - width: scrollX ? size(scrollX) : '100%' - } ) - .append( - $(_div, { 'class': classes.sScrollHeadInner } ) - .css( { - 'box-sizing': 'content-box', - width: scroll.sXInner || '100%' - } ) - .append( - headerClone - .removeAttr('id') - .css( 'margin-left', 0 ) - .append( captionSide === 'top' ? caption : null ) - .append( - table.children('thead') - ) - ) - ) - ) - .append( - $(_div, { 'class': classes.sScrollBody } ) - .css( { - position: 'relative', - overflow: 'auto', - width: size( scrollX ) - } ) - .append( table ) - ); - - if ( footer ) { - scroller.append( - $(_div, { 'class': classes.sScrollFoot } ) - .css( { - overflow: 'hidden', - border: 0, - width: scrollX ? size(scrollX) : '100%' - } ) - .append( - $(_div, { 'class': classes.sScrollFootInner } ) - .append( - footerClone - .removeAttr('id') - .css( 'margin-left', 0 ) - .append( captionSide === 'bottom' ? caption : null ) - .append( - table.children('tfoot') - ) - ) - ) - ); - } - - var children = scroller.children(); - var scrollHead = children[0]; - var scrollBody = children[1]; - var scrollFoot = footer ? children[2] : null; - - // When the body is scrolled, then we also want to scroll the headers - if ( scrollX ) { - $(scrollBody).on( 'scroll.DT', function (e) { - var scrollLeft = this.scrollLeft; - - scrollHead.scrollLeft = scrollLeft; - - if ( footer ) { - scrollFoot.scrollLeft = scrollLeft; - } - } ); - } - - $(scrollBody).css('max-height', scrollY); - if (! scroll.bCollapse) { - $(scrollBody).css('height', scrollY); - } - - settings.nScrollHead = scrollHead; - settings.nScrollBody = scrollBody; - settings.nScrollFoot = scrollFoot; - - // On redraw - align columns - settings.aoDrawCallback.push( { - "fn": _fnScrollDraw, - "sName": "scrolling" - } ); - - return scroller[0]; - } - - - - /** - * Update the header, footer and body tables for resizing - i.e. column - * alignment. - * - * Welcome to the most horrible function DataTables. The process that this - * function follows is basically: - * 1. Re-create the table inside the scrolling div - * 2. Take live measurements from the DOM - * 3. Apply the measurements to align the columns - * 4. Clean up - * - * @param {object} settings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnScrollDraw ( settings ) - { - // Given that this is such a monster function, a lot of variables are use - // to try and keep the minimised size as small as possible - var - scroll = settings.oScroll, - scrollX = scroll.sX, - scrollXInner = scroll.sXInner, - scrollY = scroll.sY, - barWidth = scroll.iBarWidth, - divHeader = $(settings.nScrollHead), - divHeaderStyle = divHeader[0].style, - divHeaderInner = divHeader.children('div'), - divHeaderInnerStyle = divHeaderInner[0].style, - divHeaderTable = divHeaderInner.children('table'), - divBodyEl = settings.nScrollBody, - divBody = $(divBodyEl), - divBodyStyle = divBodyEl.style, - divFooter = $(settings.nScrollFoot), - divFooterInner = divFooter.children('div'), - divFooterTable = divFooterInner.children('table'), - header = $(settings.nTHead), - table = $(settings.nTable), - tableEl = table[0], - tableStyle = tableEl.style, - footer = settings.nTFoot ? $(settings.nTFoot) : null, - browser = settings.oBrowser, - ie67 = browser.bScrollOversize, - dtHeaderCells = _pluck( settings.aoColumns, 'nTh' ), - headerTrgEls, footerTrgEls, - headerSrcEls, footerSrcEls, - headerCopy, footerCopy, - headerWidths=[], footerWidths=[], - headerContent=[], footerContent=[], - idx, correction, sanityWidth, - zeroOut = function(nSizer) { - var style = nSizer.style; - style.paddingTop = "0"; - style.paddingBottom = "0"; - style.borderTopWidth = "0"; - style.borderBottomWidth = "0"; - style.height = 0; - }; - - // If the scrollbar visibility has changed from the last draw, we need to - // adjust the column sizes as the table width will have changed to account - // for the scrollbar - var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight; - - if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) { - settings.scrollBarVis = scrollBarVis; - _fnAdjustColumnSizing( settings ); - return; // adjust column sizing will call this function again - } - else { - settings.scrollBarVis = scrollBarVis; - } - - /* - * 1. Re-create the table inside the scrolling div - */ - - // Remove the old minimised thead and tfoot elements in the inner table - table.children('thead, tfoot').remove(); - - if ( footer ) { - footerCopy = footer.clone().prependTo( table ); - footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized - footerSrcEls = footerCopy.find('tr'); - } - - // Clone the current header and footer elements and then place it into the inner table - headerCopy = header.clone().prependTo( table ); - headerTrgEls = header.find('tr'); // original header is in its own table - headerSrcEls = headerCopy.find('tr'); - headerCopy.find('th, td').removeAttr('tabindex'); - - - /* - * 2. Take live measurements from the DOM - do not alter the DOM itself! - */ - - // Remove old sizing and apply the calculated column widths - // Get the unique column headers in the newly created (cloned) header. We want to apply the - // calculated sizes to this header - if ( ! scrollX ) - { - divBodyStyle.width = '100%'; - divHeader[0].style.width = '100%'; - } - - $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) { - idx = _fnVisibleToColumnIndex( settings, i ); - el.style.width = settings.aoColumns[idx].sWidth; - } ); - - if ( footer ) { - _fnApplyToChildren( function(n) { - n.style.width = ""; - }, footerSrcEls ); - } - - // Size the table as a whole - sanityWidth = table.outerWidth(); - if ( scrollX === "" ) { - // No x scrolling - tableStyle.width = "100%"; - - // IE7 will make the width of the table when 100% include the scrollbar - // - which is shouldn't. When there is a scrollbar we need to take this - // into account. - if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight || - divBody.css('overflow-y') == "scroll") - ) { - tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth); - } - - // Recalculate the sanity width - sanityWidth = table.outerWidth(); - } - else if ( scrollXInner !== "" ) { - // legacy x scroll inner has been given - use it - tableStyle.width = _fnStringToCss(scrollXInner); - - // Recalculate the sanity width - sanityWidth = table.outerWidth(); - } - - // Hidden header should have zero height, so remove padding and borders. Then - // set the width based on the real headers - - // Apply all styles in one pass - _fnApplyToChildren( zeroOut, headerSrcEls ); - - // Read all widths in next pass - _fnApplyToChildren( function(nSizer) { - var style = window.getComputedStyle ? - window.getComputedStyle(nSizer).width : - _fnStringToCss( $(nSizer).width() ); - - headerContent.push( nSizer.innerHTML ); - headerWidths.push( style ); - }, headerSrcEls ); - - // Apply all widths in final pass - _fnApplyToChildren( function(nToSize, i) { - nToSize.style.width = headerWidths[i]; - }, headerTrgEls ); - - $(headerSrcEls).height(0); - - /* Same again with the footer if we have one */ - if ( footer ) - { - _fnApplyToChildren( zeroOut, footerSrcEls ); - - _fnApplyToChildren( function(nSizer) { - footerContent.push( nSizer.innerHTML ); - footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); - }, footerSrcEls ); - - _fnApplyToChildren( function(nToSize, i) { - nToSize.style.width = footerWidths[i]; - }, footerTrgEls ); - - $(footerSrcEls).height(0); - } - - - /* - * 3. Apply the measurements - */ - - // "Hide" the header and footer that we used for the sizing. We need to keep - // the content of the cell so that the width applied to the header and body - // both match, but we want to hide it completely. We want to also fix their - // width to what they currently are - _fnApplyToChildren( function(nSizer, i) { - nSizer.innerHTML = '
    '+headerContent[i]+'
    '; - nSizer.childNodes[0].style.height = "0"; - nSizer.childNodes[0].style.overflow = "hidden"; - nSizer.style.width = headerWidths[i]; - }, headerSrcEls ); - - if ( footer ) - { - _fnApplyToChildren( function(nSizer, i) { - nSizer.innerHTML = '
    '+footerContent[i]+'
    '; - nSizer.childNodes[0].style.height = "0"; - nSizer.childNodes[0].style.overflow = "hidden"; - nSizer.style.width = footerWidths[i]; - }, footerSrcEls ); - } - - // Sanity check that the table is of a sensible width. If not then we are going to get - // misalignment - try to prevent this by not allowing the table to shrink below its min width - if ( Math.round(table.outerWidth()) < Math.round(sanityWidth) ) - { - // The min width depends upon if we have a vertical scrollbar visible or not */ - correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight || - divBody.css('overflow-y') == "scroll")) ? - sanityWidth+barWidth : - sanityWidth; - - // IE6/7 are a law unto themselves... - if ( ie67 && (divBodyEl.scrollHeight > - divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll") - ) { - tableStyle.width = _fnStringToCss( correction-barWidth ); - } - - // And give the user a warning that we've stopped the table getting too small - if ( scrollX === "" || scrollXInner !== "" ) { - _fnLog( settings, 1, 'Possible column misalignment', 6 ); - } - } - else - { - correction = '100%'; - } - - // Apply to the container elements - divBodyStyle.width = _fnStringToCss( correction ); - divHeaderStyle.width = _fnStringToCss( correction ); - - if ( footer ) { - settings.nScrollFoot.style.width = _fnStringToCss( correction ); - } - - - /* - * 4. Clean up - */ - if ( ! scrollY ) { - /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting - * the scrollbar height from the visible display, rather than adding it on. We need to - * set the height in order to sort this. Don't want to do it in any other browsers. - */ - if ( ie67 ) { - divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth ); - } - } - - /* Finally set the width's of the header and footer tables */ - var iOuterWidth = table.outerWidth(); - divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth ); - divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth ); - - // Figure out if there are scrollbar present - if so then we need a the header and footer to - // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar) - var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll"; - var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' ); - divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px"; - - if ( footer ) { - divFooterTable[0].style.width = _fnStringToCss( iOuterWidth ); - divFooterInner[0].style.width = _fnStringToCss( iOuterWidth ); - divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px"; - } - - // Correct DOM ordering for colgroup - comes before the thead - table.children('colgroup').insertBefore( table.children('thead') ); - - /* Adjust the position of the header in case we loose the y-scrollbar */ - divBody.trigger('scroll'); - - // If sorting or filtering has occurred, jump the scrolling back to the top - // only if we aren't holding the position - if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) { - divBodyEl.scrollTop = 0; - } - } - - - - /** - * Apply a given function to the display child nodes of an element array (typically - * TD children of TR rows - * @param {function} fn Method to apply to the objects - * @param array {nodes} an1 List of elements to look through for display children - * @param array {nodes} an2 Another list (identical structure to the first) - optional - * @memberof DataTable#oApi - */ - function _fnApplyToChildren( fn, an1, an2 ) - { - var index=0, i=0, iLen=an1.length; - var nNode1, nNode2; - - while ( i < iLen ) { - nNode1 = an1[i].firstChild; - nNode2 = an2 ? an2[i].firstChild : null; - - while ( nNode1 ) { - if ( nNode1.nodeType === 1 ) { - if ( an2 ) { - fn( nNode1, nNode2, index ); - } - else { - fn( nNode1, index ); - } - - index++; - } - - nNode1 = nNode1.nextSibling; - nNode2 = an2 ? nNode2.nextSibling : null; - } - - i++; - } - } - - - - var __re_html_remove = /<.*?>/g; - - - /** - * Calculate the width of columns for the table - * @param {object} oSettings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnCalculateColumnWidths ( oSettings ) - { - var - table = oSettings.nTable, - columns = oSettings.aoColumns, - scroll = oSettings.oScroll, - scrollY = scroll.sY, - scrollX = scroll.sX, - scrollXInner = scroll.sXInner, - columnCount = columns.length, - visibleColumns = _fnGetColumns( oSettings, 'bVisible' ), - headerCells = $('th', oSettings.nTHead), - tableWidthAttr = table.getAttribute('width'), // from DOM element - tableContainer = table.parentNode, - userInputs = false, - i, column, columnIdx, width, outerWidth, - browser = oSettings.oBrowser, - ie67 = browser.bScrollOversize; - - var styleWidth = table.style.width; - if ( styleWidth && styleWidth.indexOf('%') !== -1 ) { - tableWidthAttr = styleWidth; - } - - /* Convert any user input sizes into pixel sizes */ - for ( i=0 ; i').appendTo( tmpTable.find('tbody') ); - - // Clone the table header and footer - we can't use the header / footer - // from the cloned table, since if scrolling is active, the table's - // real header and footer are contained in different table tags - tmpTable.find('thead, tfoot').remove(); - tmpTable - .append( $(oSettings.nTHead).clone() ) - .append( $(oSettings.nTFoot).clone() ); - - // Remove any assigned widths from the footer (from scrolling) - tmpTable.find('tfoot th, tfoot td').css('width', ''); - - // Apply custom sizing to the cloned header - headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] ); - - for ( i=0 ; i').css( { - width: column.sWidthOrig, - margin: 0, - padding: 0, - border: 0, - height: 1 - } ) ); - } - } - - // Find the widest cell for each column and put it into the table - if ( oSettings.aoData.length ) { - for ( i=0 ; i').css( scrollX || scrollY ? - { - position: 'absolute', - top: 0, - left: 0, - height: 1, - right: 0, - overflow: 'hidden' - } : - {} - ) - .append( tmpTable ) - .appendTo( tableContainer ); - - // When scrolling (X or Y) we want to set the width of the table as - // appropriate. However, when not scrolling leave the table width as it - // is. This results in slightly different, but I think correct behaviour - if ( scrollX && scrollXInner ) { - tmpTable.width( scrollXInner ); - } - else if ( scrollX ) { - tmpTable.css( 'width', 'auto' ); - tmpTable.removeAttr('width'); - - // If there is no width attribute or style, then allow the table to - // collapse - if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) { - tmpTable.width( tableContainer.clientWidth ); - } - } - else if ( scrollY ) { - tmpTable.width( tableContainer.clientWidth ); - } - else if ( tableWidthAttr ) { - tmpTable.width( tableWidthAttr ); - } - - // Get the width of each column in the constructed table - we need to - // know the inner width (so it can be assigned to the other table's - // cells) and the outer width so we can calculate the full width of the - // table. This is safe since DataTables requires a unique cell for each - // column, but if ever a header can span multiple columns, this will - // need to be modified. - var total = 0; - for ( i=0 ; i') - .css( 'width', _fnStringToCss( width ) ) - .appendTo( parent || document.body ); - - var val = n[0].offsetWidth; - n.remove(); - - return val; - } - - - /** - * Get the widest node - * @param {object} settings dataTables settings object - * @param {int} colIdx column of interest - * @returns {node} widest table node - * @memberof DataTable#oApi - */ - function _fnGetWidestNode( settings, colIdx ) - { - var idx = _fnGetMaxLenString( settings, colIdx ); - if ( idx < 0 ) { - return null; - } - - var data = settings.aoData[ idx ]; - return ! data.nTr ? // Might not have been created when deferred rendering - $('
    ').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] : - data.anCells[ colIdx ]; - } - - - /** - * Get the maximum strlen for each data column - * @param {object} settings dataTables settings object - * @param {int} colIdx column of interest - * @returns {string} max string length for each column - * @memberof DataTable#oApi - */ - function _fnGetMaxLenString( settings, colIdx ) - { - var s, max=-1, maxIdx = -1; - - for ( var i=0, ien=settings.aoData.length ; i max ) { - max = s.length; - maxIdx = i; - } - } - - return maxIdx; - } - - - /** - * Append a CSS unit (only if required) to a string - * @param {string} value to css-ify - * @returns {string} value with css unit - * @memberof DataTable#oApi - */ - function _fnStringToCss( s ) - { - if ( s === null ) { - return '0px'; - } - - if ( typeof s == 'number' ) { - return s < 0 ? - '0px' : - s+'px'; - } - - // Check it has a unit character already - return s.match(/\d$/) ? - s+'px' : - s; - } - - - - function _fnSortFlatten ( settings ) - { - var - i, iLen, k, kLen, - aSort = [], - aiOrig = [], - aoColumns = settings.aoColumns, - aDataSort, iCol, sType, srcCol, - fixed = settings.aaSortingFixed, - fixedObj = $.isPlainObject( fixed ), - nestedSort = [], - add = function ( a ) { - if ( a.length && ! Array.isArray( a[0] ) ) { - // 1D array - nestedSort.push( a ); - } - else { - // 2D array - $.merge( nestedSort, a ); - } - }; - - // Build the sort array, with pre-fix and post-fix options if they have been - // specified - if ( Array.isArray( fixed ) ) { - add( fixed ); - } - - if ( fixedObj && fixed.pre ) { - add( fixed.pre ); - } - - add( settings.aaSorting ); - - if (fixedObj && fixed.post ) { - add( fixed.post ); - } - - for ( i=0 ; iy ? 1 : 0; - if ( test !== 0 ) { - return sort.dir === 'asc' ? test : -test; - } - } - - x = aiOrig[a]; - y = aiOrig[b]; - return xy ? 1 : 0; - } ); - } - else { - // Depreciated - remove in 1.11 (providing a plug-in option) - // Not all sort types have formatting methods, so we have to call their sorting - // methods. - displayMaster.sort( function ( a, b ) { - var - x, y, k, l, test, sort, fn, - len=aSort.length, - dataA = aoData[a]._aSortData, - dataB = aoData[b]._aSortData; - - for ( k=0 ; ky ? 1 : 0; - } ); - } - } - - /* Tell the draw function that we have sorted the data */ - oSettings.bSorted = true; - } - - - function _fnSortAria ( settings ) - { - var label; - var nextSort; - var columns = settings.aoColumns; - var aSort = _fnSortFlatten( settings ); - var oAria = settings.oLanguage.oAria; - - // ARIA attributes - need to loop all columns, to update all (removing old - // attributes as needed) - for ( var i=0, iLen=columns.length ; i/g, "" ); - var th = col.nTh; - - // IE7 is throwing an error when setting these properties with jQuery's - // attr() and removeAttr() methods... - th.removeAttribute('aria-sort'); - - /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */ - if ( col.bSortable ) { - if ( aSort.length > 0 && aSort[0].col == i ) { - th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" ); - nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0]; - } - else { - nextSort = asSorting[0]; - } - - label = sTitle + ( nextSort === "asc" ? - oAria.sSortAscending : - oAria.sSortDescending - ); - } - else { - label = sTitle; - } - - th.setAttribute('aria-label', label); - } - } - - - /** - * Function to run on user sort request - * @param {object} settings dataTables settings object - * @param {node} attachTo node to attach the handler to - * @param {int} colIdx column sorting index - * @param {boolean} [append=false] Append the requested sort to the existing - * sort if true (i.e. multi-column sort) - * @param {function} [callback] callback function - * @memberof DataTable#oApi - */ - function _fnSortListener ( settings, colIdx, append, callback ) - { - var col = settings.aoColumns[ colIdx ]; - var sorting = settings.aaSorting; - var asSorting = col.asSorting; - var nextSortIdx; - var next = function ( a, overflow ) { - var idx = a._idx; - if ( idx === undefined ) { - idx = $.inArray( a[1], asSorting ); - } - - return idx+1 < asSorting.length ? - idx+1 : - overflow ? - null : - 0; - }; - - // Convert to 2D array if needed - if ( typeof sorting[0] === 'number' ) { - sorting = settings.aaSorting = [ sorting ]; - } - - // If appending the sort then we are multi-column sorting - if ( append && settings.oFeatures.bSortMulti ) { - // Are we already doing some kind of sort on this column? - var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') ); - - if ( sortIdx !== -1 ) { - // Yes, modify the sort - nextSortIdx = next( sorting[sortIdx], true ); - - if ( nextSortIdx === null && sorting.length === 1 ) { - nextSortIdx = 0; // can't remove sorting completely - } - - if ( nextSortIdx === null ) { - sorting.splice( sortIdx, 1 ); - } - else { - sorting[sortIdx][1] = asSorting[ nextSortIdx ]; - sorting[sortIdx]._idx = nextSortIdx; - } - } - else { - // No sort on this column yet - sorting.push( [ colIdx, asSorting[0], 0 ] ); - sorting[sorting.length-1]._idx = 0; - } - } - else if ( sorting.length && sorting[0][0] == colIdx ) { - // Single column - already sorting on this column, modify the sort - nextSortIdx = next( sorting[0] ); - - sorting.length = 1; - sorting[0][1] = asSorting[ nextSortIdx ]; - sorting[0]._idx = nextSortIdx; - } - else { - // Single column - sort only on this column - sorting.length = 0; - sorting.push( [ colIdx, asSorting[0] ] ); - sorting[0]._idx = 0; - } - - // Run the sort by calling a full redraw - _fnReDraw( settings ); - - // callback used for async user interaction - if ( typeof callback == 'function' ) { - callback( settings ); - } - } - - - /** - * Attach a sort handler (click) to a node - * @param {object} settings dataTables settings object - * @param {node} attachTo node to attach the handler to - * @param {int} colIdx column sorting index - * @param {function} [callback] callback function - * @memberof DataTable#oApi - */ - function _fnSortAttachListener ( settings, attachTo, colIdx, callback ) - { - var col = settings.aoColumns[ colIdx ]; - - _fnBindAction( attachTo, {}, function (e) { - /* If the column is not sortable - don't to anything */ - if ( col.bSortable === false ) { - return; - } - - // If processing is enabled use a timeout to allow the processing - // display to be shown - otherwise to it synchronously - if ( settings.oFeatures.bProcessing ) { - _fnProcessingDisplay( settings, true ); - - setTimeout( function() { - _fnSortListener( settings, colIdx, e.shiftKey, callback ); - - // In server-side processing, the draw callback will remove the - // processing display - if ( _fnDataSource( settings ) !== 'ssp' ) { - _fnProcessingDisplay( settings, false ); - } - }, 0 ); - } - else { - _fnSortListener( settings, colIdx, e.shiftKey, callback ); - } - } ); - } - - - /** - * Set the sorting classes on table's body, Note: it is safe to call this function - * when bSort and bSortClasses are false - * @param {object} oSettings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnSortingClasses( settings ) - { - var oldSort = settings.aLastSort; - var sortClass = settings.oClasses.sSortColumn; - var sort = _fnSortFlatten( settings ); - var features = settings.oFeatures; - var i, ien, colIdx; - - if ( features.bSort && features.bSortClasses ) { - // Remove old sorting classes - for ( i=0, ien=oldSort.length ; i 0 && s.time < +new Date() - (duration*1000) ) { - settings._bLoadingState = false; - callback(); - return; - } - - // Number of columns have changed - all bets are off, no restore of settings - if ( s.columns && columns.length !== s.columns.length ) { - settings._bLoadingState = false; - callback(); - return; - } - - // Store the saved state so it might be accessed at any time - settings.oLoadedState = $.extend( true, {}, s ); - - // Restore key features - todo - for 1.11 this needs to be done by - // subscribed events - if ( s.start !== undefined ) { - if(api === null) { - settings._iDisplayStart = s.start; - settings.iInitDisplayStart = s.start; - } - else { - _fnPageChange(settings, s.start/s.length); - - } - } - if ( s.length !== undefined ) { - settings._iDisplayLength = s.length; - } - - // Order - if ( s.order !== undefined ) { - settings.aaSorting = []; - $.each( s.order, function ( i, col ) { - settings.aaSorting.push( col[0] >= columns.length ? - [ 0, col[1] ] : - col - ); - } ); - } - - // Search - if ( s.search !== undefined ) { - $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) ); - } - - // Columns - if ( s.columns ) { - for ( i=0, ien=s.columns.length ; i= end ) - { - start = end - len; - } - - // Keep the start record on the current page - start -= (start % len); - - if ( len === -1 || start < 0 ) - { - start = 0; - } - - settings._iDisplayStart = start; - } - - - function _fnRenderer( settings, type ) - { - var renderer = settings.renderer; - var host = DataTable.ext.renderer[type]; - - if ( $.isPlainObject( renderer ) && renderer[type] ) { - // Specific renderer for this type. If available use it, otherwise use - // the default. - return host[renderer[type]] || host._; - } - else if ( typeof renderer === 'string' ) { - // Common renderer - if there is one available for this type use it, - // otherwise use the default - return host[renderer] || host._; - } - - // Use the default - return host._; - } - - - /** - * Detect the data source being used for the table. Used to simplify the code - * a little (ajax) and to make it compress a little smaller. - * - * @param {object} settings dataTables settings object - * @returns {string} Data source - * @memberof DataTable#oApi - */ - function _fnDataSource ( settings ) - { - if ( settings.oFeatures.bServerSide ) { - return 'ssp'; - } - else if ( settings.ajax || settings.sAjaxSource ) { - return 'ajax'; - } - return 'dom'; - } - - - - - /** - * Computed structure of the DataTables API, defined by the options passed to - * `DataTable.Api.register()` when building the API. - * - * The structure is built in order to speed creation and extension of the Api - * objects since the extensions are effectively pre-parsed. - * - * The array is an array of objects with the following structure, where this - * base array represents the Api prototype base: - * - * [ - * { - * name: 'data' -- string - Property name - * val: function () {}, -- function - Api method (or undefined if just an object - * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result - * propExt: [ ... ] -- array - Array of Api object definitions to extend the property - * }, - * { - * name: 'row' - * val: {}, - * methodExt: [ ... ], - * propExt: [ - * { - * name: 'data' - * val: function () {}, - * methodExt: [ ... ], - * propExt: [ ... ] - * }, - * ... - * ] - * } - * ] - * - * @type {Array} - * @ignore - */ - var __apiStruct = []; - - - /** - * `Array.prototype` reference. - * - * @type object - * @ignore - */ - var __arrayProto = Array.prototype; - - - /** - * Abstraction for `context` parameter of the `Api` constructor to allow it to - * take several different forms for ease of use. - * - * Each of the input parameter types will be converted to a DataTables settings - * object where possible. - * - * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one - * of: - * - * * `string` - jQuery selector. Any DataTables' matching the given selector - * with be found and used. - * * `node` - `TABLE` node which has already been formed into a DataTable. - * * `jQuery` - A jQuery object of `TABLE` nodes. - * * `object` - DataTables settings object - * * `DataTables.Api` - API instance - * @return {array|null} Matching DataTables settings objects. `null` or - * `undefined` is returned if no matching DataTable is found. - * @ignore - */ - var _toSettings = function ( mixed ) - { - var idx, jq; - var settings = DataTable.settings; - var tables = $.map( settings, function (el, i) { - return el.nTable; - } ); - - if ( ! mixed ) { - return []; - } - else if ( mixed.nTable && mixed.oApi ) { - // DataTables settings object - return [ mixed ]; - } - else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) { - // Table node - idx = $.inArray( mixed, tables ); - return idx !== -1 ? [ settings[idx] ] : null; - } - else if ( mixed && typeof mixed.settings === 'function' ) { - return mixed.settings().toArray(); - } - else if ( typeof mixed === 'string' ) { - // jQuery selector - jq = $(mixed); - } - else if ( mixed instanceof $ ) { - // jQuery object (also DataTables instance) - jq = mixed; - } - - if ( jq ) { - return jq.map( function(i) { - idx = $.inArray( this, tables ); - return idx !== -1 ? settings[idx] : null; - } ).toArray(); - } - }; - - - /** - * DataTables API class - used to control and interface with one or more - * DataTables enhanced tables. - * - * The API class is heavily based on jQuery, presenting a chainable interface - * that you can use to interact with tables. Each instance of the API class has - * a "context" - i.e. the tables that it will operate on. This could be a single - * table, all tables on a page or a sub-set thereof. - * - * Additionally the API is designed to allow you to easily work with the data in - * the tables, retrieving and manipulating it as required. This is done by - * presenting the API class as an array like interface. The contents of the - * array depend upon the actions requested by each method (for example - * `rows().nodes()` will return an array of nodes, while `rows().data()` will - * return an array of objects or arrays depending upon your table's - * configuration). The API object has a number of array like methods (`push`, - * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`, - * `unique` etc) to assist your working with the data held in a table. - * - * Most methods (those which return an Api instance) are chainable, which means - * the return from a method call also has all of the methods available that the - * top level object had. For example, these two calls are equivalent: - * - * // Not chained - * api.row.add( {...} ); - * api.draw(); - * - * // Chained - * api.row.add( {...} ).draw(); - * - * @class DataTable.Api - * @param {array|object|string|jQuery} context DataTable identifier. This is - * used to define which DataTables enhanced tables this API will operate on. - * Can be one of: - * - * * `string` - jQuery selector. Any DataTables' matching the given selector - * with be found and used. - * * `node` - `TABLE` node which has already been formed into a DataTable. - * * `jQuery` - A jQuery object of `TABLE` nodes. - * * `object` - DataTables settings object - * @param {array} [data] Data to initialise the Api instance with. - * - * @example - * // Direct initialisation during DataTables construction - * var api = $('#example').DataTable(); - * - * @example - * // Initialisation using a DataTables jQuery object - * var api = $('#example').dataTable().api(); - * - * @example - * // Initialisation as a constructor - * var api = new $.fn.DataTable.Api( 'table.dataTable' ); - */ - _Api = function ( context, data ) - { - if ( ! (this instanceof _Api) ) { - return new _Api( context, data ); - } - - var settings = []; - var ctxSettings = function ( o ) { - var a = _toSettings( o ); - if ( a ) { - settings.push.apply( settings, a ); - } - }; - - if ( Array.isArray( context ) ) { - for ( var i=0, ien=context.length ; i idx ? - new _Api( ctx[idx], this[idx] ) : - null; - }, - - - filter: function ( fn ) - { - var a = []; - - if ( __arrayProto.filter ) { - a = __arrayProto.filter.call( this, fn, this ); - } - else { - // Compatibility for browsers without EMCA-252-5 (JS 1.6) - for ( var i=0, ien=this.length ; i 0 ) { - return ctx[0].json; - } - - // else return undefined; - } ); - - - /** - * Get the data submitted in the last Ajax request - */ - _api_register( 'ajax.params()', function () { - var ctx = this.context; - - if ( ctx.length > 0 ) { - return ctx[0].oAjaxData; - } - - // else return undefined; - } ); - - - /** - * Reload tables from the Ajax data source. Note that this function will - * automatically re-draw the table when the remote data has been loaded. - * - * @param {boolean} [reset=true] Reset (default) or hold the current paging - * position. A full re-sort and re-filter is performed when this method is - * called, which is why the pagination reset is the default action. - * @returns {DataTables.Api} this - */ - _api_register( 'ajax.reload()', function ( callback, resetPaging ) { - return this.iterator( 'table', function (settings) { - __reload( settings, resetPaging===false, callback ); - } ); - } ); - - - /** - * Get the current Ajax URL. Note that this returns the URL from the first - * table in the current context. - * - * @return {string} Current Ajax source URL - *//** - * Set the Ajax URL. Note that this will set the URL for all tables in the - * current context. - * - * @param {string} url URL to set. - * @returns {DataTables.Api} this - */ - _api_register( 'ajax.url()', function ( url ) { - var ctx = this.context; - - if ( url === undefined ) { - // get - if ( ctx.length === 0 ) { - return undefined; - } - ctx = ctx[0]; - - return ctx.ajax ? - $.isPlainObject( ctx.ajax ) ? - ctx.ajax.url : - ctx.ajax : - ctx.sAjaxSource; - } - - // set - return this.iterator( 'table', function ( settings ) { - if ( $.isPlainObject( settings.ajax ) ) { - settings.ajax.url = url; - } - else { - settings.ajax = url; - } - // No need to consider sAjaxSource here since DataTables gives priority - // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any - // value of `sAjaxSource` redundant. - } ); - } ); - - - /** - * Load data from the newly set Ajax URL. Note that this method is only - * available when `ajax.url()` is used to set a URL. Additionally, this method - * has the same effect as calling `ajax.reload()` but is provided for - * convenience when setting a new URL. Like `ajax.reload()` it will - * automatically redraw the table once the remote data has been loaded. - * - * @returns {DataTables.Api} this - */ - _api_register( 'ajax.url().load()', function ( callback, resetPaging ) { - // Same as a reload, but makes sense to present it for easy access after a - // url change - return this.iterator( 'table', function ( ctx ) { - __reload( ctx, resetPaging===false, callback ); - } ); - } ); - - - - - var _selector_run = function ( type, selector, selectFn, settings, opts ) - { - var - out = [], res, - a, i, ien, j, jen, - selectorType = typeof selector; - - // Can't just check for isArray here, as an API or jQuery instance might be - // given with their array like look - if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) { - selector = [ selector ]; - } - - for ( i=0, ien=selector.length ; i 0 ) { - // Assign the first element to the first item in the instance - // and truncate the instance and context - inst[0] = inst[i]; - inst[0].length = 1; - inst.length = 1; - inst.context = [ inst.context[i] ]; - - return inst; - } - } - - // Not found - return an empty instance - inst.length = 0; - return inst; - }; - - - var _selector_row_indexes = function ( settings, opts ) - { - var - i, ien, tmp, a=[], - displayFiltered = settings.aiDisplay, - displayMaster = settings.aiDisplayMaster; - - var - search = opts.search, // none, applied, removed - order = opts.order, // applied, current, index (original - compatibility with 1.9) - page = opts.page; // all, current - - if ( _fnDataSource( settings ) == 'ssp' ) { - // In server-side processing mode, most options are irrelevant since - // rows not shown don't exist and the index order is the applied order - // Removed is a special case - for consistency just return an empty - // array - return search === 'removed' ? - [] : - _range( 0, displayMaster.length ); - } - else if ( page == 'current' ) { - // Current page implies that order=current and filter=applied, since it is - // fairly senseless otherwise, regardless of what order and search actually - // are - for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i= 0 && search == 'applied') ) - { - a.push( i ); - } - } - } - } - - return a; - }; - - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Rows - * - * {} - no selector - use all available rows - * {integer} - row aoData index - * {node} - TR node - * {string} - jQuery selector to apply to the TR elements - * {array} - jQuery array of nodes, or simply an array of TR nodes - * - */ - var __row_selector = function ( settings, selector, opts ) - { - var rows; - var run = function ( sel ) { - var selInt = _intVal( sel ); - var i, ien; - var aoData = settings.aoData; - - // Short cut - selector is a number and no options provided (default is - // all records, so no need to check if the index is in there, since it - // must be - dev error if the index doesn't exist). - if ( selInt !== null && ! opts ) { - return [ selInt ]; - } - - if ( ! rows ) { - rows = _selector_row_indexes( settings, opts ); - } - - if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) { - // Selector - integer - return [ selInt ]; - } - else if ( sel === null || sel === undefined || sel === '' ) { - // Selector - none - return rows; - } - - // Selector - function - if ( typeof sel === 'function' ) { - return $.map( rows, function (idx) { - var row = aoData[ idx ]; - return sel( idx, row._aData, row.nTr ) ? idx : null; - } ); - } - - // Selector - node - if ( sel.nodeName ) { - var rowIdx = sel._DT_RowIndex; // Property added by DT for fast lookup - var cellIdx = sel._DT_CellIndex; - - if ( rowIdx !== undefined ) { - // Make sure that the row is actually still present in the table - return aoData[ rowIdx ] && aoData[ rowIdx ].nTr === sel ? - [ rowIdx ] : - []; - } - else if ( cellIdx ) { - return aoData[ cellIdx.row ] && aoData[ cellIdx.row ].nTr === sel.parentNode ? - [ cellIdx.row ] : - []; - } - else { - var host = $(sel).closest('*[data-dt-row]'); - return host.length ? - [ host.data('dt-row') ] : - []; - } - } - - // ID selector. Want to always be able to select rows by id, regardless - // of if the tr element has been created or not, so can't rely upon - // jQuery here - hence a custom implementation. This does not match - // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything, - // but to select it using a CSS selector engine (like Sizzle or - // querySelect) it would need to need to be escaped for some characters. - // DataTables simplifies this for row selectors since you can select - // only a row. A # indicates an id any anything that follows is the id - - // unescaped. - if ( typeof sel === 'string' && sel.charAt(0) === '#' ) { - // get row index from id - var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ]; - if ( rowObj !== undefined ) { - return [ rowObj.idx ]; - } - - // need to fall through to jQuery in case there is DOM id that - // matches - } - - // Get nodes in the order from the `rows` array with null values removed - var nodes = _removeEmpty( - _pluck_order( settings.aoData, rows, 'nTr' ) - ); - - // Selector - jQuery selector string, array of nodes or jQuery object/ - // As jQuery's .filter() allows jQuery objects to be passed in filter, - // it also allows arrays, so this will cope with all three options - return $(nodes) - .filter( sel ) - .map( function () { - return this._DT_RowIndex; - } ) - .toArray(); - }; - - return _selector_run( 'row', selector, run, settings, opts ); - }; - - - _api_register( 'rows()', function ( selector, opts ) { - // argument shifting - if ( selector === undefined ) { - selector = ''; - } - else if ( $.isPlainObject( selector ) ) { - opts = selector; - selector = ''; - } - - opts = _selector_opts( opts ); - - var inst = this.iterator( 'table', function ( settings ) { - return __row_selector( settings, selector, opts ); - }, 1 ); - - // Want argument shifting here and in __row_selector? - inst.selector.rows = selector; - inst.selector.opts = opts; - - return inst; - } ); - - _api_register( 'rows().nodes()', function () { - return this.iterator( 'row', function ( settings, row ) { - return settings.aoData[ row ].nTr || undefined; - }, 1 ); - } ); - - _api_register( 'rows().data()', function () { - return this.iterator( true, 'rows', function ( settings, rows ) { - return _pluck_order( settings.aoData, rows, '_aData' ); - }, 1 ); - } ); - - _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) { - return this.iterator( 'row', function ( settings, row ) { - var r = settings.aoData[ row ]; - return type === 'search' ? r._aFilterData : r._aSortData; - }, 1 ); - } ); - - _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) { - return this.iterator( 'row', function ( settings, row ) { - _fnInvalidate( settings, row, src ); - } ); - } ); - - _api_registerPlural( 'rows().indexes()', 'row().index()', function () { - return this.iterator( 'row', function ( settings, row ) { - return row; - }, 1 ); - } ); - - _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) { - var a = []; - var context = this.context; - - // `iterator` will drop undefined values, but in this case we want them - for ( var i=0, ien=context.length ; i 0 ) { - settings._iRecordsDisplay--; - } - - // Check for an 'overflow' they case for displaying the table - _fnLengthOverflow( settings ); - - // Remove the row's ID reference if there is one - var id = settings.rowIdFn( rowData._aData ); - if ( id !== undefined ) { - delete settings.aIds[ id ]; - } - } ); - - this.iterator( 'table', function ( settings ) { - for ( var i=0, ien=settings.aoData.length ; i
    ` node is a DataTable table already or not. - * - * @param {node|jquery|string} table Table node, jQuery object or jQuery - * selector for the table to test. Note that if more than more than one - * table is passed on, only the first will be checked - * @returns {boolean} true the table given is a DataTable, or false otherwise - * @static - * @dtopt API-Static - * - * @example - * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) { - * $('#example').dataTable(); - * } - */ - DataTable.isDataTable = DataTable.fnIsDataTable = function ( table ) - { - var t = $(table).get(0); - var is = false; - - if ( table instanceof DataTable.Api ) { - return true; - } - - $.each( DataTable.settings, function (i, o) { - var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null; - var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null; - - if ( o.nTable === t || head === t || foot === t ) { - is = true; - } - } ); - - return is; - }; - - - /** - * Get all DataTable tables that have been initialised - optionally you can - * select to get only currently visible tables. - * - * @param {boolean} [visible=false] Flag to indicate if you want all (default) - * or visible tables only. - * @returns {array} Array of `table` nodes (not DataTable instances) which are - * DataTables - * @static - * @dtopt API-Static - * - * @example - * $.each( $.fn.dataTable.tables(true), function () { - * $(table).DataTable().columns.adjust(); - * } ); - */ - DataTable.tables = DataTable.fnTables = function ( visible ) - { - var api = false; - - if ( $.isPlainObject( visible ) ) { - api = visible.api; - visible = visible.visible; - } - - var a = $.map( DataTable.settings, function (o) { - if ( !visible || (visible && $(o.nTable).is(':visible')) ) { - return o.nTable; - } - } ); - - return api ? - new _Api( a ) : - a; - }; - - - /** - * Convert from camel case parameters to Hungarian notation. This is made public - * for the extensions to provide the same ability as DataTables core to accept - * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase - * parameters. - * - * @param {object} src The model object which holds all parameters that can be - * mapped. - * @param {object} user The object to convert from camel case to Hungarian. - * @param {boolean} force When set to `true`, properties which already have a - * Hungarian value in the `user` object will be overwritten. Otherwise they - * won't be. - */ - DataTable.camelToHungarian = _fnCamelToHungarian; - - - - /** - * - */ - _api_register( '$()', function ( selector, opts ) { - var - rows = this.rows( opts ).nodes(), // Get all rows - jqRows = $(rows); - - return $( [].concat( - jqRows.filter( selector ).toArray(), - jqRows.find( selector ).toArray() - ) ); - } ); - - - // jQuery functions to operate on the tables - $.each( [ 'on', 'one', 'off' ], function (i, key) { - _api_register( key+'()', function ( /* event, handler */ ) { - var args = Array.prototype.slice.call(arguments); - - // Add the `dt` namespace automatically if it isn't already present - args[0] = $.map( args[0].split( /\s/ ), function ( e ) { - return ! e.match(/\.dt\b/) ? - e+'.dt' : - e; - } ).join( ' ' ); - - var inst = $( this.tables().nodes() ); - inst[key].apply( inst, args ); - return this; - } ); - } ); - - - _api_register( 'clear()', function () { - return this.iterator( 'table', function ( settings ) { - _fnClearTable( settings ); - } ); - } ); - - - _api_register( 'settings()', function () { - return new _Api( this.context, this.context ); - } ); - - - _api_register( 'init()', function () { - var ctx = this.context; - return ctx.length ? ctx[0].oInit : null; - } ); - - - _api_register( 'data()', function () { - return this.iterator( 'table', function ( settings ) { - return _pluck( settings.aoData, '_aData' ); - } ).flatten(); - } ); - - - _api_register( 'destroy()', function ( remove ) { - remove = remove || false; - - return this.iterator( 'table', function ( settings ) { - var orig = settings.nTableWrapper.parentNode; - var classes = settings.oClasses; - var table = settings.nTable; - var tbody = settings.nTBody; - var thead = settings.nTHead; - var tfoot = settings.nTFoot; - var jqTable = $(table); - var jqTbody = $(tbody); - var jqWrapper = $(settings.nTableWrapper); - var rows = $.map( settings.aoData, function (r) { return r.nTr; } ); - var i, ien; - - // Flag to note that the table is currently being destroyed - no action - // should be taken - settings.bDestroying = true; - - // Fire off the destroy callbacks for plug-ins etc - _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] ); - - // If not being removed from the document, make all columns visible - if ( ! remove ) { - new _Api( settings ).columns().visible( true ); - } - - // Blitz all `DT` namespaced events (these are internal events, the - // lowercase, `dt` events are user subscribed and they are responsible - // for removing them - jqWrapper.off('.DT').find(':not(tbody *)').off('.DT'); - $(window).off('.DT-'+settings.sInstance); - - // When scrolling we had to break the table up - restore it - if ( table != thead.parentNode ) { - jqTable.children('thead').detach(); - jqTable.append( thead ); - } - - if ( tfoot && table != tfoot.parentNode ) { - jqTable.children('tfoot').detach(); - jqTable.append( tfoot ); - } - - settings.aaSorting = []; - settings.aaSortingFixed = []; - _fnSortingClasses( settings ); - - $( rows ).removeClass( settings.asStripeClasses.join(' ') ); - - $('th, td', thead).removeClass( classes.sSortable+' '+ - classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone - ); - - // Add the TR elements back into the table in their original order - jqTbody.children().detach(); - jqTbody.append( rows ); - - // Remove the DataTables generated nodes, events and classes - var removedMethod = remove ? 'remove' : 'detach'; - jqTable[ removedMethod ](); - jqWrapper[ removedMethod ](); - - // If we need to reattach the table to the document - if ( ! remove && orig ) { - // insertBefore acts like appendChild if !arg[1] - orig.insertBefore( table, settings.nTableReinsertBefore ); - - // Restore the width of the original table - was read from the style property, - // so we can restore directly to that - jqTable - .css( 'width', settings.sDestroyWidth ) - .removeClass( classes.sTable ); - - // If the were originally stripe classes - then we add them back here. - // Note this is not fool proof (for example if not all rows had stripe - // classes - but it's a good effort without getting carried away - ien = settings.asDestroyStripes.length; - - if ( ien ) { - jqTbody.children().each( function (i) { - $(this).addClass( settings.asDestroyStripes[i % ien] ); - } ); - } - } - - /* Remove the settings object from the settings array */ - var idx = $.inArray( settings, DataTable.settings ); - if ( idx !== -1 ) { - DataTable.settings.splice( idx, 1 ); - } - } ); - } ); - - - // Add the `every()` method for rows, columns and cells in a compact form - $.each( [ 'column', 'row', 'cell' ], function ( i, type ) { - _api_register( type+'s().every()', function ( fn ) { - var opts = this.selector.opts; - var api = this; - - return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) { - // Rows and columns: - // arg1 - index - // arg2 - table counter - // arg3 - loop counter - // arg4 - undefined - // Cells: - // arg1 - row index - // arg2 - column index - // arg3 - table counter - // arg4 - loop counter - fn.call( - api[ type ]( - arg1, - type==='cell' ? arg2 : opts, - type==='cell' ? opts : undefined - ), - arg1, arg2, arg3, arg4 - ); - } ); - } ); - } ); - - - // i18n method for extensions to be able to use the language object from the - // DataTable - _api_register( 'i18n()', function ( token, def, plural ) { - var ctx = this.context[0]; - var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage ); - - if ( resolved === undefined ) { - resolved = def; - } - - if ( plural !== undefined && $.isPlainObject( resolved ) ) { - resolved = resolved[ plural ] !== undefined ? - resolved[ plural ] : - resolved._; - } - - return resolved.replace( '%d', plural ); // nb: plural might be undefined, - } ); - /** - * Version string for plug-ins to check compatibility. Allowed format is - * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used - * only for non-release builds. See http://semver.org/ for more information. - * @member - * @type string - * @default Version number - */ - DataTable.version = "1.11.4"; - - /** - * Private data store, containing all of the settings objects that are - * created for the tables on a given page. - * - * Note that the `DataTable.settings` object is aliased to - * `jQuery.fn.dataTableExt` through which it may be accessed and - * manipulated, or `jQuery.fn.dataTable.settings`. - * @member - * @type array - * @default [] - * @private - */ - DataTable.settings = []; - - /** - * Object models container, for the various models that DataTables has - * available to it. These models define the objects that are used to hold - * the active state and configuration of the table. - * @namespace - */ - DataTable.models = {}; - - - - /** - * Template object for the way in which DataTables holds information about - * search information for the global filter and individual column filters. - * @namespace - */ - DataTable.models.oSearch = { - /** - * Flag to indicate if the filtering should be case insensitive or not - * @type boolean - * @default true - */ - "bCaseInsensitive": true, - - /** - * Applied search term - * @type string - * @default Empty string - */ - "sSearch": "", - - /** - * Flag to indicate if the search term should be interpreted as a - * regular expression (true) or not (false) and therefore and special - * regex characters escaped. - * @type boolean - * @default false - */ - "bRegex": false, - - /** - * Flag to indicate if DataTables is to use its smart filtering or not. - * @type boolean - * @default true - */ - "bSmart": true, - - /** - * Flag to indicate if DataTables should only trigger a search when - * the return key is pressed. - * @type boolean - * @default false - */ - "return": false - }; - - - - - /** - * Template object for the way in which DataTables holds information about - * each individual row. This is the object format used for the settings - * aoData array. - * @namespace - */ - DataTable.models.oRow = { - /** - * TR element for the row - * @type node - * @default null - */ - "nTr": null, - - /** - * Array of TD elements for each row. This is null until the row has been - * created. - * @type array nodes - * @default [] - */ - "anCells": null, - - /** - * Data object from the original data source for the row. This is either - * an array if using the traditional form of DataTables, or an object if - * using mData options. The exact type will depend on the passed in - * data from the data source, or will be an array if using DOM a data - * source. - * @type array|object - * @default [] - */ - "_aData": [], - - /** - * Sorting data cache - this array is ostensibly the same length as the - * number of columns (although each index is generated only as it is - * needed), and holds the data that is used for sorting each column in the - * row. We do this cache generation at the start of the sort in order that - * the formatting of the sort data need be done only once for each cell - * per sort. This array should not be read from or written to by anything - * other than the master sorting methods. - * @type array - * @default null - * @private - */ - "_aSortData": null, - - /** - * Per cell filtering data cache. As per the sort data cache, used to - * increase the performance of the filtering in DataTables - * @type array - * @default null - * @private - */ - "_aFilterData": null, - - /** - * Filtering data cache. This is the same as the cell filtering cache, but - * in this case a string rather than an array. This is easily computed with - * a join on `_aFilterData`, but is provided as a cache so the join isn't - * needed on every search (memory traded for performance) - * @type array - * @default null - * @private - */ - "_sFilterRow": null, - - /** - * Cache of the class name that DataTables has applied to the row, so we - * can quickly look at this variable rather than needing to do a DOM check - * on className for the nTr property. - * @type string - * @default Empty string - * @private - */ - "_sRowStripe": "", - - /** - * Denote if the original data source was from the DOM, or the data source - * object. This is used for invalidating data, so DataTables can - * automatically read data from the original source, unless uninstructed - * otherwise. - * @type string - * @default null - * @private - */ - "src": null, - - /** - * Index in the aoData array. This saves an indexOf lookup when we have the - * object, but want to know the index - * @type integer - * @default -1 - * @private - */ - "idx": -1 - }; - - - /** - * Template object for the column information object in DataTables. This object - * is held in the settings aoColumns array and contains all the information that - * DataTables needs about each individual column. - * - * Note that this object is related to {@link DataTable.defaults.column} - * but this one is the internal data store for DataTables's cache of columns. - * It should NOT be manipulated outside of DataTables. Any configuration should - * be done through the initialisation options. - * @namespace - */ - DataTable.models.oColumn = { - /** - * Column index. This could be worked out on-the-fly with $.inArray, but it - * is faster to just hold it as a variable - * @type integer - * @default null - */ - "idx": null, - - /** - * A list of the columns that sorting should occur on when this column - * is sorted. That this property is an array allows multi-column sorting - * to be defined for a column (for example first name / last name columns - * would benefit from this). The values are integers pointing to the - * columns to be sorted on (typically it will be a single integer pointing - * at itself, but that doesn't need to be the case). - * @type array - */ - "aDataSort": null, - - /** - * Define the sorting directions that are applied to the column, in sequence - * as the column is repeatedly sorted upon - i.e. the first value is used - * as the sorting direction when the column if first sorted (clicked on). - * Sort it again (click again) and it will move on to the next index. - * Repeat until loop. - * @type array - */ - "asSorting": null, - - /** - * Flag to indicate if the column is searchable, and thus should be included - * in the filtering or not. - * @type boolean - */ - "bSearchable": null, - - /** - * Flag to indicate if the column is sortable or not. - * @type boolean - */ - "bSortable": null, - - /** - * Flag to indicate if the column is currently visible in the table or not - * @type boolean - */ - "bVisible": null, - - /** - * Store for manual type assignment using the `column.type` option. This - * is held in store so we can manipulate the column's `sType` property. - * @type string - * @default null - * @private - */ - "_sManualType": null, - - /** - * Flag to indicate if HTML5 data attributes should be used as the data - * source for filtering or sorting. True is either are. - * @type boolean - * @default false - * @private - */ - "_bAttrSrc": false, - - /** - * Developer definable function that is called whenever a cell is created (Ajax source, - * etc) or processed for input (DOM source). This can be used as a compliment to mRender - * allowing you to modify the DOM element (add background colour for example) when the - * element is available. - * @type function - * @param {element} nTd The TD node that has been created - * @param {*} sData The Data for the cell - * @param {array|object} oData The data for the whole row - * @param {int} iRow The row index for the aoData data store - * @default null - */ - "fnCreatedCell": null, - - /** - * Function to get data from a cell in a column. You should never - * access data directly through _aData internally in DataTables - always use - * the method attached to this property. It allows mData to function as - * required. This function is automatically assigned by the column - * initialisation method - * @type function - * @param {array|object} oData The data array/object for the array - * (i.e. aoData[]._aData) - * @param {string} sSpecific The specific data type you want to get - - * 'display', 'type' 'filter' 'sort' - * @returns {*} The data for the cell from the given row's data - * @default null - */ - "fnGetData": null, - - /** - * Function to set data for a cell in the column. You should never - * set the data directly to _aData internally in DataTables - always use - * this method. It allows mData to function as required. This function - * is automatically assigned by the column initialisation method - * @type function - * @param {array|object} oData The data array/object for the array - * (i.e. aoData[]._aData) - * @param {*} sValue Value to set - * @default null - */ - "fnSetData": null, - - /** - * Property to read the value for the cells in the column from the data - * source array / object. If null, then the default content is used, if a - * function is given then the return from the function is used. - * @type function|int|string|null - * @default null - */ - "mData": null, - - /** - * Partner property to mData which is used (only when defined) to get - * the data - i.e. it is basically the same as mData, but without the - * 'set' option, and also the data fed to it is the result from mData. - * This is the rendering method to match the data method of mData. - * @type function|int|string|null - * @default null - */ - "mRender": null, - - /** - * Unique header TH/TD element for this column - this is what the sorting - * listener is attached to (if sorting is enabled.) - * @type node - * @default null - */ - "nTh": null, - - /** - * Unique footer TH/TD element for this column (if there is one). Not used - * in DataTables as such, but can be used for plug-ins to reference the - * footer for each column. - * @type node - * @default null - */ - "nTf": null, - - /** - * The class to apply to all TD elements in the table's TBODY for the column - * @type string - * @default null - */ - "sClass": null, - - /** - * When DataTables calculates the column widths to assign to each column, - * it finds the longest string in each column and then constructs a - * temporary table and reads the widths from that. The problem with this - * is that "mmm" is much wider then "iiii", but the latter is a longer - * string - thus the calculation can go wrong (doing it properly and putting - * it into an DOM object and measuring that is horribly(!) slow). Thus as - * a "work around" we provide this option. It will append its value to the - * text that is found to be the longest string for the column - i.e. padding. - * @type string - */ - "sContentPadding": null, - - /** - * Allows a default value to be given for a column's data, and will be used - * whenever a null data source is encountered (this can be because mData - * is set to null, or because the data source itself is null). - * @type string - * @default null - */ - "sDefaultContent": null, - - /** - * Name for the column, allowing reference to the column by name as well as - * by index (needs a lookup to work by name). - * @type string - */ - "sName": null, - - /** - * Custom sorting data type - defines which of the available plug-ins in - * afnSortData the custom sorting will use - if any is defined. - * @type string - * @default std - */ - "sSortDataType": 'std', - - /** - * Class to be applied to the header element when sorting on this column - * @type string - * @default null - */ - "sSortingClass": null, - - /** - * Class to be applied to the header element when sorting on this column - - * when jQuery UI theming is used. - * @type string - * @default null - */ - "sSortingClassJUI": null, - - /** - * Title of the column - what is seen in the TH element (nTh). - * @type string - */ - "sTitle": null, - - /** - * Column sorting and filtering type - * @type string - * @default null - */ - "sType": null, - - /** - * Width of the column - * @type string - * @default null - */ - "sWidth": null, - - /** - * Width of the column when it was first "encountered" - * @type string - * @default null - */ - "sWidthOrig": null - }; - - - /* - * Developer note: The properties of the object below are given in Hungarian - * notation, that was used as the interface for DataTables prior to v1.10, however - * from v1.10 onwards the primary interface is camel case. In order to avoid - * breaking backwards compatibility utterly with this change, the Hungarian - * version is still, internally the primary interface, but is is not documented - * - hence the @name tags in each doc comment. This allows a Javascript function - * to create a map from Hungarian notation to camel case (going the other direction - * would require each property to be listed, which would add around 3K to the size - * of DataTables, while this method is about a 0.5K hit). - * - * Ultimately this does pave the way for Hungarian notation to be dropped - * completely, but that is a massive amount of work and will break current - * installs (therefore is on-hold until v2). - */ - - /** - * Initialisation options that can be given to DataTables at initialisation - * time. - * @namespace - */ - DataTable.defaults = { - /** - * An array of data to use for the table, passed in at initialisation which - * will be used in preference to any data which is already in the DOM. This is - * particularly useful for constructing tables purely in Javascript, for - * example with a custom Ajax call. - * @type array - * @default null - * - * @dtopt Option - * @name DataTable.defaults.data - * - * @example - * // Using a 2D array data source - * $(document).ready( function () { - * $('#example').dataTable( { - * "data": [ - * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'], - * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'], - * ], - * "columns": [ - * { "title": "Engine" }, - * { "title": "Browser" }, - * { "title": "Platform" }, - * { "title": "Version" }, - * { "title": "Grade" } - * ] - * } ); - * } ); - * - * @example - * // Using an array of objects as a data source (`data`) - * $(document).ready( function () { - * $('#example').dataTable( { - * "data": [ - * { - * "engine": "Trident", - * "browser": "Internet Explorer 4.0", - * "platform": "Win 95+", - * "version": 4, - * "grade": "X" - * }, - * { - * "engine": "Trident", - * "browser": "Internet Explorer 5.0", - * "platform": "Win 95+", - * "version": 5, - * "grade": "C" - * } - * ], - * "columns": [ - * { "title": "Engine", "data": "engine" }, - * { "title": "Browser", "data": "browser" }, - * { "title": "Platform", "data": "platform" }, - * { "title": "Version", "data": "version" }, - * { "title": "Grade", "data": "grade" } - * ] - * } ); - * } ); - */ - "aaData": null, - - - /** - * If ordering is enabled, then DataTables will perform a first pass sort on - * initialisation. You can define which column(s) the sort is performed - * upon, and the sorting direction, with this variable. The `sorting` array - * should contain an array for each column to be sorted initially containing - * the column's index and a direction string ('asc' or 'desc'). - * @type array - * @default [[0,'asc']] - * - * @dtopt Option - * @name DataTable.defaults.order - * - * @example - * // Sort by 3rd column first, and then 4th column - * $(document).ready( function() { - * $('#example').dataTable( { - * "order": [[2,'asc'], [3,'desc']] - * } ); - * } ); - * - * // No initial sorting - * $(document).ready( function() { - * $('#example').dataTable( { - * "order": [] - * } ); - * } ); - */ - "aaSorting": [[0,'asc']], - - - /** - * This parameter is basically identical to the `sorting` parameter, but - * cannot be overridden by user interaction with the table. What this means - * is that you could have a column (visible or hidden) which the sorting - * will always be forced on first - any sorting after that (from the user) - * will then be performed as required. This can be useful for grouping rows - * together. - * @type array - * @default null - * - * @dtopt Option - * @name DataTable.defaults.orderFixed - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "orderFixed": [[0,'asc']] - * } ); - * } ) - */ - "aaSortingFixed": [], - - - /** - * DataTables can be instructed to load data to display in the table from a - * Ajax source. This option defines how that Ajax call is made and where to. - * - * The `ajax` property has three different modes of operation, depending on - * how it is defined. These are: - * - * * `string` - Set the URL from where the data should be loaded from. - * * `object` - Define properties for `jQuery.ajax`. - * * `function` - Custom data get function - * - * `string` - * -------- - * - * As a string, the `ajax` property simply defines the URL from which - * DataTables will load data. - * - * `object` - * -------- - * - * As an object, the parameters in the object are passed to - * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control - * of the Ajax request. DataTables has a number of default parameters which - * you can override using this option. Please refer to the jQuery - * documentation for a full description of the options available, although - * the following parameters provide additional options in DataTables or - * require special consideration: - * - * * `data` - As with jQuery, `data` can be provided as an object, but it - * can also be used as a function to manipulate the data DataTables sends - * to the server. The function takes a single parameter, an object of - * parameters with the values that DataTables has readied for sending. An - * object may be returned which will be merged into the DataTables - * defaults, or you can add the items to the object that was passed in and - * not return anything from the function. This supersedes `fnServerParams` - * from DataTables 1.9-. - * - * * `dataSrc` - By default DataTables will look for the property `data` (or - * `aaData` for compatibility with DataTables 1.9-) when obtaining data - * from an Ajax source or for server-side processing - this parameter - * allows that property to be changed. You can use Javascript dotted - * object notation to get a data source for multiple levels of nesting, or - * it my be used as a function. As a function it takes a single parameter, - * the JSON returned from the server, which can be manipulated as - * required, with the returned value being that used by DataTables as the - * data source for the table. This supersedes `sAjaxDataProp` from - * DataTables 1.9-. - * - * * `success` - Should not be overridden it is used internally in - * DataTables. To manipulate / transform the data returned by the server - * use `ajax.dataSrc`, or use `ajax` as a function (see below). - * - * `function` - * ---------- - * - * As a function, making the Ajax call is left up to yourself allowing - * complete control of the Ajax request. Indeed, if desired, a method other - * than Ajax could be used to obtain the required data, such as Web storage - * or an AIR database. - * - * The function is given four parameters and no return is required. The - * parameters are: - * - * 1. _object_ - Data to send to the server - * 2. _function_ - Callback function that must be executed when the required - * data has been obtained. That data should be passed into the callback - * as the only parameter - * 3. _object_ - DataTables settings object for the table - * - * Note that this supersedes `fnServerData` from DataTables 1.9-. - * - * @type string|object|function - * @default null - * - * @dtopt Option - * @name DataTable.defaults.ajax - * @since 1.10.0 - * - * @example - * // Get JSON data from a file via Ajax. - * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default). - * $('#example').dataTable( { - * "ajax": "data.json" - * } ); - * - * @example - * // Get JSON data from a file via Ajax, using `dataSrc` to change - * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`) - * $('#example').dataTable( { - * "ajax": { - * "url": "data.json", - * "dataSrc": "tableData" - * } - * } ); - * - * @example - * // Get JSON data from a file via Ajax, using `dataSrc` to read data - * // from a plain array rather than an array in an object - * $('#example').dataTable( { - * "ajax": { - * "url": "data.json", - * "dataSrc": "" - * } - * } ); - * - * @example - * // Manipulate the data returned from the server - add a link to data - * // (note this can, should, be done using `render` for the column - this - * // is just a simple example of how the data can be manipulated). - * $('#example').dataTable( { - * "ajax": { - * "url": "data.json", - * "dataSrc": function ( json ) { - * for ( var i=0, ien=json.length ; iView message'; - * } - * return json; - * } - * } - * } ); - * - * @example - * // Add data to the request - * $('#example').dataTable( { - * "ajax": { - * "url": "data.json", - * "data": function ( d ) { - * return { - * "extra_search": $('#extra').val() - * }; - * } - * } - * } ); - * - * @example - * // Send request as POST - * $('#example').dataTable( { - * "ajax": { - * "url": "data.json", - * "type": "POST" - * } - * } ); - * - * @example - * // Get the data from localStorage (could interface with a form for - * // adding, editing and removing rows). - * $('#example').dataTable( { - * "ajax": function (data, callback, settings) { - * callback( - * JSON.parse( localStorage.getItem('dataTablesData') ) - * ); - * } - * } ); - */ - "ajax": null, - - - /** - * This parameter allows you to readily specify the entries in the length drop - * down menu that DataTables shows when pagination is enabled. It can be - * either a 1D array of options which will be used for both the displayed - * option and the value, or a 2D array which will use the array in the first - * position as the value, and the array in the second position as the - * displayed options (useful for language strings such as 'All'). - * - * Note that the `pageLength` property will be automatically set to the - * first value given in this array, unless `pageLength` is also provided. - * @type array - * @default [ 10, 25, 50, 100 ] - * - * @dtopt Option - * @name DataTable.defaults.lengthMenu - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]] - * } ); - * } ); - */ - "aLengthMenu": [ 10, 25, 50, 100 ], - - - /** - * The `columns` option in the initialisation parameter allows you to define - * details about the way individual columns behave. For a full list of - * column options that can be set, please see - * {@link DataTable.defaults.column}. Note that if you use `columns` to - * define your columns, you must have an entry in the array for every single - * column that you have in your table (these can be null if you don't which - * to specify any options). - * @member - * - * @name DataTable.defaults.column - */ - "aoColumns": null, - - /** - * Very similar to `columns`, `columnDefs` allows you to target a specific - * column, multiple columns, or all columns, using the `targets` property of - * each object in the array. This allows great flexibility when creating - * tables, as the `columnDefs` arrays can be of any length, targeting the - * columns you specifically want. `columnDefs` may use any of the column - * options available: {@link DataTable.defaults.column}, but it _must_ - * have `targets` defined in each object in the array. Values in the `targets` - * array may be: - *
      - *
    • a string - class name will be matched on the TH for the column
    • - *
    • 0 or a positive integer - column index counting from the left
    • - *
    • a negative integer - column index counting from the right
    • - *
    • the string "_all" - all columns (i.e. assign a default)
    • - *
    - * @member - * - * @name DataTable.defaults.columnDefs - */ - "aoColumnDefs": null, - - - /** - * Basically the same as `search`, this parameter defines the individual column - * filtering state at initialisation time. The array must be of the same size - * as the number of columns, and each element be an object with the parameters - * `search` and `escapeRegex` (the latter is optional). 'null' is also - * accepted and the default will be used. - * @type array - * @default [] - * - * @dtopt Option - * @name DataTable.defaults.searchCols - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "searchCols": [ - * null, - * { "search": "My filter" }, - * null, - * { "search": "^[0-9]", "escapeRegex": false } - * ] - * } ); - * } ) - */ - "aoSearchCols": [], - - - /** - * An array of CSS classes that should be applied to displayed rows. This - * array may be of any length, and DataTables will apply each class - * sequentially, looping when required. - * @type array - * @default null Will take the values determined by the `oClasses.stripe*` - * options - * - * @dtopt Option - * @name DataTable.defaults.stripeClasses - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ] - * } ); - * } ) - */ - "asStripeClasses": null, - - - /** - * Enable or disable automatic column width calculation. This can be disabled - * as an optimisation (it takes some time to calculate the widths) if the - * tables widths are passed in using `columns`. - * @type boolean - * @default true - * - * @dtopt Features - * @name DataTable.defaults.autoWidth - * - * @example - * $(document).ready( function () { - * $('#example').dataTable( { - * "autoWidth": false - * } ); - * } ); - */ - "bAutoWidth": true, - - - /** - * Deferred rendering can provide DataTables with a huge speed boost when you - * are using an Ajax or JS data source for the table. This option, when set to - * true, will cause DataTables to defer the creation of the table elements for - * each row until they are needed for a draw - saving a significant amount of - * time. - * @type boolean - * @default false - * - * @dtopt Features - * @name DataTable.defaults.deferRender - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "ajax": "sources/arrays.txt", - * "deferRender": true - * } ); - * } ); - */ - "bDeferRender": false, - - - /** - * Replace a DataTable which matches the given selector and replace it with - * one which has the properties of the new initialisation object passed. If no - * table matches the selector, then the new DataTable will be constructed as - * per normal. - * @type boolean - * @default false - * - * @dtopt Options - * @name DataTable.defaults.destroy - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "srollY": "200px", - * "paginate": false - * } ); - * - * // Some time later.... - * $('#example').dataTable( { - * "filter": false, - * "destroy": true - * } ); - * } ); - */ - "bDestroy": false, - - - /** - * Enable or disable filtering of data. Filtering in DataTables is "smart" in - * that it allows the end user to input multiple words (space separated) and - * will match a row containing those words, even if not in the order that was - * specified (this allow matching across multiple columns). Note that if you - * wish to use filtering in DataTables this must remain 'true' - to remove the - * default filtering input box and retain filtering abilities, please use - * {@link DataTable.defaults.dom}. - * @type boolean - * @default true - * - * @dtopt Features - * @name DataTable.defaults.searching - * - * @example - * $(document).ready( function () { - * $('#example').dataTable( { - * "searching": false - * } ); - * } ); - */ - "bFilter": true, - - - /** - * Enable or disable the table information display. This shows information - * about the data that is currently visible on the page, including information - * about filtered data if that action is being performed. - * @type boolean - * @default true - * - * @dtopt Features - * @name DataTable.defaults.info - * - * @example - * $(document).ready( function () { - * $('#example').dataTable( { - * "info": false - * } ); - * } ); - */ - "bInfo": true, - - - /** - * Allows the end user to select the size of a formatted page from a select - * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`). - * @type boolean - * @default true - * - * @dtopt Features - * @name DataTable.defaults.lengthChange - * - * @example - * $(document).ready( function () { - * $('#example').dataTable( { - * "lengthChange": false - * } ); - * } ); - */ - "bLengthChange": true, - - - /** - * Enable or disable pagination. - * @type boolean - * @default true - * - * @dtopt Features - * @name DataTable.defaults.paging - * - * @example - * $(document).ready( function () { - * $('#example').dataTable( { - * "paging": false - * } ); - * } ); - */ - "bPaginate": true, - - - /** - * Enable or disable the display of a 'processing' indicator when the table is - * being processed (e.g. a sort). This is particularly useful for tables with - * large amounts of data where it can take a noticeable amount of time to sort - * the entries. - * @type boolean - * @default false - * - * @dtopt Features - * @name DataTable.defaults.processing - * - * @example - * $(document).ready( function () { - * $('#example').dataTable( { - * "processing": true - * } ); - * } ); - */ - "bProcessing": false, - - - /** - * Retrieve the DataTables object for the given selector. Note that if the - * table has already been initialised, this parameter will cause DataTables - * to simply return the object that has already been set up - it will not take - * account of any changes you might have made to the initialisation object - * passed to DataTables (setting this parameter to true is an acknowledgement - * that you understand this). `destroy` can be used to reinitialise a table if - * you need. - * @type boolean - * @default false - * - * @dtopt Options - * @name DataTable.defaults.retrieve - * - * @example - * $(document).ready( function() { - * initTable(); - * tableActions(); - * } ); - * - * function initTable () - * { - * return $('#example').dataTable( { - * "scrollY": "200px", - * "paginate": false, - * "retrieve": true - * } ); - * } - * - * function tableActions () - * { - * var table = initTable(); - * // perform API operations with oTable - * } - */ - "bRetrieve": false, - - - /** - * When vertical (y) scrolling is enabled, DataTables will force the height of - * the table's viewport to the given height at all times (useful for layout). - * However, this can look odd when filtering data down to a small data set, - * and the footer is left "floating" further down. This parameter (when - * enabled) will cause DataTables to collapse the table's viewport down when - * the result set will fit within the given Y height. - * @type boolean - * @default false - * - * @dtopt Options - * @name DataTable.defaults.scrollCollapse - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "scrollY": "200", - * "scrollCollapse": true - * } ); - * } ); - */ - "bScrollCollapse": false, - - - /** - * Configure DataTables to use server-side processing. Note that the - * `ajax` parameter must also be given in order to give DataTables a - * source to obtain the required data for each draw. - * @type boolean - * @default false - * - * @dtopt Features - * @dtopt Server-side - * @name DataTable.defaults.serverSide - * - * @example - * $(document).ready( function () { - * $('#example').dataTable( { - * "serverSide": true, - * "ajax": "xhr.php" - * } ); - * } ); - */ - "bServerSide": false, - - - /** - * Enable or disable sorting of columns. Sorting of individual columns can be - * disabled by the `sortable` option for each column. - * @type boolean - * @default true - * - * @dtopt Features - * @name DataTable.defaults.ordering - * - * @example - * $(document).ready( function () { - * $('#example').dataTable( { - * "ordering": false - * } ); - * } ); - */ - "bSort": true, - - - /** - * Enable or display DataTables' ability to sort multiple columns at the - * same time (activated by shift-click by the user). - * @type boolean - * @default true - * - * @dtopt Options - * @name DataTable.defaults.orderMulti - * - * @example - * // Disable multiple column sorting ability - * $(document).ready( function () { - * $('#example').dataTable( { - * "orderMulti": false - * } ); - * } ); - */ - "bSortMulti": true, - - - /** - * Allows control over whether DataTables should use the top (true) unique - * cell that is found for a single column, or the bottom (false - default). - * This is useful when using complex headers. - * @type boolean - * @default false - * - * @dtopt Options - * @name DataTable.defaults.orderCellsTop - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "orderCellsTop": true - * } ); - * } ); - */ - "bSortCellsTop": false, - - - /** - * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and - * `sorting\_3` to the columns which are currently being sorted on. This is - * presented as a feature switch as it can increase processing time (while - * classes are removed and added) so for large data sets you might want to - * turn this off. - * @type boolean - * @default true - * - * @dtopt Features - * @name DataTable.defaults.orderClasses - * - * @example - * $(document).ready( function () { - * $('#example').dataTable( { - * "orderClasses": false - * } ); - * } ); - */ - "bSortClasses": true, - - - /** - * Enable or disable state saving. When enabled HTML5 `localStorage` will be - * used to save table display information such as pagination information, - * display length, filtering and sorting. As such when the end user reloads - * the page the display display will match what thy had previously set up. - * - * Due to the use of `localStorage` the default state saving is not supported - * in IE6 or 7. If state saving is required in those browsers, use - * `stateSaveCallback` to provide a storage solution such as cookies. - * @type boolean - * @default false - * - * @dtopt Features - * @name DataTable.defaults.stateSave - * - * @example - * $(document).ready( function () { - * $('#example').dataTable( { - * "stateSave": true - * } ); - * } ); - */ - "bStateSave": false, - - - /** - * This function is called when a TR element is created (and all TD child - * elements have been inserted), or registered if using a DOM source, allowing - * manipulation of the TR element (adding classes etc). - * @type function - * @param {node} row "TR" element for the current row - * @param {array} data Raw data array for this row - * @param {int} dataIndex The index of this row in the internal aoData array - * - * @dtopt Callbacks - * @name DataTable.defaults.createdRow - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "createdRow": function( row, data, dataIndex ) { - * // Bold the grade for all 'A' grade browsers - * if ( data[4] == "A" ) - * { - * $('td:eq(4)', row).html( 'A' ); - * } - * } - * } ); - * } ); - */ - "fnCreatedRow": null, - - - /** - * This function is called on every 'draw' event, and allows you to - * dynamically modify any aspect you want about the created DOM. - * @type function - * @param {object} settings DataTables settings object - * - * @dtopt Callbacks - * @name DataTable.defaults.drawCallback - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "drawCallback": function( settings ) { - * alert( 'DataTables has redrawn the table' ); - * } - * } ); - * } ); - */ - "fnDrawCallback": null, - - - /** - * Identical to fnHeaderCallback() but for the table footer this function - * allows you to modify the table footer on every 'draw' event. - * @type function - * @param {node} foot "TR" element for the footer - * @param {array} data Full table data (as derived from the original HTML) - * @param {int} start Index for the current display starting point in the - * display array - * @param {int} end Index for the current display ending point in the - * display array - * @param {array int} display Index array to translate the visual position - * to the full data array - * - * @dtopt Callbacks - * @name DataTable.defaults.footerCallback - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "footerCallback": function( tfoot, data, start, end, display ) { - * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start; - * } - * } ); - * } ) - */ - "fnFooterCallback": null, - - - /** - * When rendering large numbers in the information element for the table - * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers - * to have a comma separator for the 'thousands' units (e.g. 1 million is - * rendered as "1,000,000") to help readability for the end user. This - * function will override the default method DataTables uses. - * @type function - * @member - * @param {int} toFormat number to be formatted - * @returns {string} formatted string for DataTables to show the number - * - * @dtopt Callbacks - * @name DataTable.defaults.formatNumber - * - * @example - * // Format a number using a single quote for the separator (note that - * // this can also be done with the language.thousands option) - * $(document).ready( function() { - * $('#example').dataTable( { - * "formatNumber": function ( toFormat ) { - * return toFormat.toString().replace( - * /\B(?=(\d{3})+(?!\d))/g, "'" - * ); - * }; - * } ); - * } ); - */ - "fnFormatNumber": function ( toFormat ) { - return toFormat.toString().replace( - /\B(?=(\d{3})+(?!\d))/g, - this.oLanguage.sThousands - ); - }, - - - /** - * This function is called on every 'draw' event, and allows you to - * dynamically modify the header row. This can be used to calculate and - * display useful information about the table. - * @type function - * @param {node} head "TR" element for the header - * @param {array} data Full table data (as derived from the original HTML) - * @param {int} start Index for the current display starting point in the - * display array - * @param {int} end Index for the current display ending point in the - * display array - * @param {array int} display Index array to translate the visual position - * to the full data array - * - * @dtopt Callbacks - * @name DataTable.defaults.headerCallback - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "fheaderCallback": function( head, data, start, end, display ) { - * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records"; - * } - * } ); - * } ) - */ - "fnHeaderCallback": null, - - - /** - * The information element can be used to convey information about the current - * state of the table. Although the internationalisation options presented by - * DataTables are quite capable of dealing with most customisations, there may - * be times where you wish to customise the string further. This callback - * allows you to do exactly that. - * @type function - * @param {object} oSettings DataTables settings object - * @param {int} start Starting position in data for the draw - * @param {int} end End position in data for the draw - * @param {int} max Total number of rows in the table (regardless of - * filtering) - * @param {int} total Total number of rows in the data set, after filtering - * @param {string} pre The string that DataTables has formatted using it's - * own rules - * @returns {string} The string to be displayed in the information element. - * - * @dtopt Callbacks - * @name DataTable.defaults.infoCallback - * - * @example - * $('#example').dataTable( { - * "infoCallback": function( settings, start, end, max, total, pre ) { - * return start +" to "+ end; - * } - * } ); - */ - "fnInfoCallback": null, - - - /** - * Called when the table has been initialised. Normally DataTables will - * initialise sequentially and there will be no need for this function, - * however, this does not hold true when using external language information - * since that is obtained using an async XHR call. - * @type function - * @param {object} settings DataTables settings object - * @param {object} json The JSON object request from the server - only - * present if client-side Ajax sourced data is used - * - * @dtopt Callbacks - * @name DataTable.defaults.initComplete - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "initComplete": function(settings, json) { - * alert( 'DataTables has finished its initialisation.' ); - * } - * } ); - * } ) - */ - "fnInitComplete": null, - - - /** - * Called at the very start of each table draw and can be used to cancel the - * draw by returning false, any other return (including undefined) results in - * the full draw occurring). - * @type function - * @param {object} settings DataTables settings object - * @returns {boolean} False will cancel the draw, anything else (including no - * return) will allow it to complete. - * - * @dtopt Callbacks - * @name DataTable.defaults.preDrawCallback - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "preDrawCallback": function( settings ) { - * if ( $('#test').val() == 1 ) { - * return false; - * } - * } - * } ); - * } ); - */ - "fnPreDrawCallback": null, - - - /** - * This function allows you to 'post process' each row after it have been - * generated for each table draw, but before it is rendered on screen. This - * function might be used for setting the row class name etc. - * @type function - * @param {node} row "TR" element for the current row - * @param {array} data Raw data array for this row - * @param {int} displayIndex The display index for the current table draw - * @param {int} displayIndexFull The index of the data in the full list of - * rows (after filtering) - * - * @dtopt Callbacks - * @name DataTable.defaults.rowCallback - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "rowCallback": function( row, data, displayIndex, displayIndexFull ) { - * // Bold the grade for all 'A' grade browsers - * if ( data[4] == "A" ) { - * $('td:eq(4)', row).html( 'A' ); - * } - * } - * } ); - * } ); - */ - "fnRowCallback": null, - - - /** - * __Deprecated__ The functionality provided by this parameter has now been - * superseded by that provided through `ajax`, which should be used instead. - * - * This parameter allows you to override the default function which obtains - * the data from the server so something more suitable for your application. - * For example you could use POST data, or pull information from a Gears or - * AIR database. - * @type function - * @member - * @param {string} source HTTP source to obtain the data from (`ajax`) - * @param {array} data A key/value pair object containing the data to send - * to the server - * @param {function} callback to be called on completion of the data get - * process that will draw the data on the page. - * @param {object} settings DataTables settings object - * - * @dtopt Callbacks - * @dtopt Server-side - * @name DataTable.defaults.serverData - * - * @deprecated 1.10. Please use `ajax` for this functionality now. - */ - "fnServerData": null, - - - /** - * __Deprecated__ The functionality provided by this parameter has now been - * superseded by that provided through `ajax`, which should be used instead. - * - * It is often useful to send extra data to the server when making an Ajax - * request - for example custom filtering information, and this callback - * function makes it trivial to send extra information to the server. The - * passed in parameter is the data set that has been constructed by - * DataTables, and you can add to this or modify it as you require. - * @type function - * @param {array} data Data array (array of objects which are name/value - * pairs) that has been constructed by DataTables and will be sent to the - * server. In the case of Ajax sourced data with server-side processing - * this will be an empty array, for server-side processing there will be a - * significant number of parameters! - * @returns {undefined} Ensure that you modify the data array passed in, - * as this is passed by reference. - * - * @dtopt Callbacks - * @dtopt Server-side - * @name DataTable.defaults.serverParams - * - * @deprecated 1.10. Please use `ajax` for this functionality now. - */ - "fnServerParams": null, - - - /** - * Load the table state. With this function you can define from where, and how, the - * state of a table is loaded. By default DataTables will load from `localStorage` - * but you might wish to use a server-side database or cookies. - * @type function - * @member - * @param {object} settings DataTables settings object - * @param {object} callback Callback that can be executed when done. It - * should be passed the loaded state object. - * @return {object} The DataTables state object to be loaded - * - * @dtopt Callbacks - * @name DataTable.defaults.stateLoadCallback - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "stateSave": true, - * "stateLoadCallback": function (settings, callback) { - * $.ajax( { - * "url": "/state_load", - * "dataType": "json", - * "success": function (json) { - * callback( json ); - * } - * } ); - * } - * } ); - * } ); - */ - "fnStateLoadCallback": function ( settings ) { - try { - return JSON.parse( - (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem( - 'DataTables_'+settings.sInstance+'_'+location.pathname - ) - ); - } catch (e) { - return {}; - } - }, - - - /** - * Callback which allows modification of the saved state prior to loading that state. - * This callback is called when the table is loading state from the stored data, but - * prior to the settings object being modified by the saved state. Note that for - * plug-in authors, you should use the `stateLoadParams` event to load parameters for - * a plug-in. - * @type function - * @param {object} settings DataTables settings object - * @param {object} data The state object that is to be loaded - * - * @dtopt Callbacks - * @name DataTable.defaults.stateLoadParams - * - * @example - * // Remove a saved filter, so filtering is never loaded - * $(document).ready( function() { - * $('#example').dataTable( { - * "stateSave": true, - * "stateLoadParams": function (settings, data) { - * data.oSearch.sSearch = ""; - * } - * } ); - * } ); - * - * @example - * // Disallow state loading by returning false - * $(document).ready( function() { - * $('#example').dataTable( { - * "stateSave": true, - * "stateLoadParams": function (settings, data) { - * return false; - * } - * } ); - * } ); - */ - "fnStateLoadParams": null, - - - /** - * Callback that is called when the state has been loaded from the state saving method - * and the DataTables settings object has been modified as a result of the loaded state. - * @type function - * @param {object} settings DataTables settings object - * @param {object} data The state object that was loaded - * - * @dtopt Callbacks - * @name DataTable.defaults.stateLoaded - * - * @example - * // Show an alert with the filtering value that was saved - * $(document).ready( function() { - * $('#example').dataTable( { - * "stateSave": true, - * "stateLoaded": function (settings, data) { - * alert( 'Saved filter was: '+data.oSearch.sSearch ); - * } - * } ); - * } ); - */ - "fnStateLoaded": null, - - - /** - * Save the table state. This function allows you to define where and how the state - * information for the table is stored By default DataTables will use `localStorage` - * but you might wish to use a server-side database or cookies. - * @type function - * @member - * @param {object} settings DataTables settings object - * @param {object} data The state object to be saved - * - * @dtopt Callbacks - * @name DataTable.defaults.stateSaveCallback - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "stateSave": true, - * "stateSaveCallback": function (settings, data) { - * // Send an Ajax request to the server with the state object - * $.ajax( { - * "url": "/state_save", - * "data": data, - * "dataType": "json", - * "method": "POST" - * "success": function () {} - * } ); - * } - * } ); - * } ); - */ - "fnStateSaveCallback": function ( settings, data ) { - try { - (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem( - 'DataTables_'+settings.sInstance+'_'+location.pathname, - JSON.stringify( data ) - ); - } catch (e) {} - }, - - - /** - * Callback which allows modification of the state to be saved. Called when the table - * has changed state a new state save is required. This method allows modification of - * the state saving object prior to actually doing the save, including addition or - * other state properties or modification. Note that for plug-in authors, you should - * use the `stateSaveParams` event to save parameters for a plug-in. - * @type function - * @param {object} settings DataTables settings object - * @param {object} data The state object to be saved - * - * @dtopt Callbacks - * @name DataTable.defaults.stateSaveParams - * - * @example - * // Remove a saved filter, so filtering is never saved - * $(document).ready( function() { - * $('#example').dataTable( { - * "stateSave": true, - * "stateSaveParams": function (settings, data) { - * data.oSearch.sSearch = ""; - * } - * } ); - * } ); - */ - "fnStateSaveParams": null, - - - /** - * Duration for which the saved state information is considered valid. After this period - * has elapsed the state will be returned to the default. - * Value is given in seconds. - * @type int - * @default 7200 (2 hours) - * - * @dtopt Options - * @name DataTable.defaults.stateDuration - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "stateDuration": 60*60*24; // 1 day - * } ); - * } ) - */ - "iStateDuration": 7200, - - - /** - * When enabled DataTables will not make a request to the server for the first - * page draw - rather it will use the data already on the page (no sorting etc - * will be applied to it), thus saving on an XHR at load time. `deferLoading` - * is used to indicate that deferred loading is required, but it is also used - * to tell DataTables how many records there are in the full table (allowing - * the information element and pagination to be displayed correctly). In the case - * where a filtering is applied to the table on initial load, this can be - * indicated by giving the parameter as an array, where the first element is - * the number of records available after filtering and the second element is the - * number of records without filtering (allowing the table information element - * to be shown correctly). - * @type int | array - * @default null - * - * @dtopt Options - * @name DataTable.defaults.deferLoading - * - * @example - * // 57 records available in the table, no filtering applied - * $(document).ready( function() { - * $('#example').dataTable( { - * "serverSide": true, - * "ajax": "scripts/server_processing.php", - * "deferLoading": 57 - * } ); - * } ); - * - * @example - * // 57 records after filtering, 100 without filtering (an initial filter applied) - * $(document).ready( function() { - * $('#example').dataTable( { - * "serverSide": true, - * "ajax": "scripts/server_processing.php", - * "deferLoading": [ 57, 100 ], - * "search": { - * "search": "my_filter" - * } - * } ); - * } ); - */ - "iDeferLoading": null, - - - /** - * Number of rows to display on a single page when using pagination. If - * feature enabled (`lengthChange`) then the end user will be able to override - * this to a custom setting using a pop-up menu. - * @type int - * @default 10 - * - * @dtopt Options - * @name DataTable.defaults.pageLength - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "pageLength": 50 - * } ); - * } ) - */ - "iDisplayLength": 10, - - - /** - * Define the starting point for data display when using DataTables with - * pagination. Note that this parameter is the number of records, rather than - * the page number, so if you have 10 records per page and want to start on - * the third page, it should be "20". - * @type int - * @default 0 - * - * @dtopt Options - * @name DataTable.defaults.displayStart - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "displayStart": 20 - * } ); - * } ) - */ - "iDisplayStart": 0, - - - /** - * By default DataTables allows keyboard navigation of the table (sorting, paging, - * and filtering) by adding a `tabindex` attribute to the required elements. This - * allows you to tab through the controls and press the enter key to activate them. - * The tabindex is default 0, meaning that the tab follows the flow of the document. - * You can overrule this using this parameter if you wish. Use a value of -1 to - * disable built-in keyboard navigation. - * @type int - * @default 0 - * - * @dtopt Options - * @name DataTable.defaults.tabIndex - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "tabIndex": 1 - * } ); - * } ); - */ - "iTabIndex": 0, - - - /** - * Classes that DataTables assigns to the various components and features - * that it adds to the HTML table. This allows classes to be configured - * during initialisation in addition to through the static - * {@link DataTable.ext.oStdClasses} object). - * @namespace - * @name DataTable.defaults.classes - */ - "oClasses": {}, - - - /** - * All strings that DataTables uses in the user interface that it creates - * are defined in this object, allowing you to modified them individually or - * completely replace them all as required. - * @namespace - * @name DataTable.defaults.language - */ - "oLanguage": { - /** - * Strings that are used for WAI-ARIA labels and controls only (these are not - * actually visible on the page, but will be read by screenreaders, and thus - * must be internationalised as well). - * @namespace - * @name DataTable.defaults.language.aria - */ - "oAria": { - /** - * ARIA label that is added to the table headers when the column may be - * sorted ascending by activing the column (click or return when focused). - * Note that the column header is prefixed to this string. - * @type string - * @default : activate to sort column ascending - * - * @dtopt Language - * @name DataTable.defaults.language.aria.sortAscending - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "aria": { - * "sortAscending": " - click/return to sort ascending" - * } - * } - * } ); - * } ); - */ - "sSortAscending": ": activate to sort column ascending", - - /** - * ARIA label that is added to the table headers when the column may be - * sorted descending by activing the column (click or return when focused). - * Note that the column header is prefixed to this string. - * @type string - * @default : activate to sort column ascending - * - * @dtopt Language - * @name DataTable.defaults.language.aria.sortDescending - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "aria": { - * "sortDescending": " - click/return to sort descending" - * } - * } - * } ); - * } ); - */ - "sSortDescending": ": activate to sort column descending" - }, - - /** - * Pagination string used by DataTables for the built-in pagination - * control types. - * @namespace - * @name DataTable.defaults.language.paginate - */ - "oPaginate": { - /** - * Text to use when using the 'full_numbers' type of pagination for the - * button to take the user to the first page. - * @type string - * @default First - * - * @dtopt Language - * @name DataTable.defaults.language.paginate.first - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "paginate": { - * "first": "First page" - * } - * } - * } ); - * } ); - */ - "sFirst": "First", - - - /** - * Text to use when using the 'full_numbers' type of pagination for the - * button to take the user to the last page. - * @type string - * @default Last - * - * @dtopt Language - * @name DataTable.defaults.language.paginate.last - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "paginate": { - * "last": "Last page" - * } - * } - * } ); - * } ); - */ - "sLast": "Last", - - - /** - * Text to use for the 'next' pagination button (to take the user to the - * next page). - * @type string - * @default Next - * - * @dtopt Language - * @name DataTable.defaults.language.paginate.next - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "paginate": { - * "next": "Next page" - * } - * } - * } ); - * } ); - */ - "sNext": "Next", - - - /** - * Text to use for the 'previous' pagination button (to take the user to - * the previous page). - * @type string - * @default Previous - * - * @dtopt Language - * @name DataTable.defaults.language.paginate.previous - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "paginate": { - * "previous": "Previous page" - * } - * } - * } ); - * } ); - */ - "sPrevious": "Previous" - }, - - /** - * This string is shown in preference to `zeroRecords` when the table is - * empty of data (regardless of filtering). Note that this is an optional - * parameter - if it is not given, the value of `zeroRecords` will be used - * instead (either the default or given value). - * @type string - * @default No data available in table - * - * @dtopt Language - * @name DataTable.defaults.language.emptyTable - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "emptyTable": "No data available in table" - * } - * } ); - * } ); - */ - "sEmptyTable": "No data available in table", - - - /** - * This string gives information to the end user about the information - * that is current on display on the page. The following tokens can be - * used in the string and will be dynamically replaced as the table - * display updates. This tokens can be placed anywhere in the string, or - * removed as needed by the language requires: - * - * * `\_START\_` - Display index of the first record on the current page - * * `\_END\_` - Display index of the last record on the current page - * * `\_TOTAL\_` - Number of records in the table after filtering - * * `\_MAX\_` - Number of records in the table without filtering - * * `\_PAGE\_` - Current page number - * * `\_PAGES\_` - Total number of pages of data in the table - * - * @type string - * @default Showing _START_ to _END_ of _TOTAL_ entries - * - * @dtopt Language - * @name DataTable.defaults.language.info - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "info": "Showing page _PAGE_ of _PAGES_" - * } - * } ); - * } ); - */ - "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries", - - - /** - * Display information string for when the table is empty. Typically the - * format of this string should match `info`. - * @type string - * @default Showing 0 to 0 of 0 entries - * - * @dtopt Language - * @name DataTable.defaults.language.infoEmpty - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "infoEmpty": "No entries to show" - * } - * } ); - * } ); - */ - "sInfoEmpty": "Showing 0 to 0 of 0 entries", - - - /** - * When a user filters the information in a table, this string is appended - * to the information (`info`) to give an idea of how strong the filtering - * is. The variable _MAX_ is dynamically updated. - * @type string - * @default (filtered from _MAX_ total entries) - * - * @dtopt Language - * @name DataTable.defaults.language.infoFiltered - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "infoFiltered": " - filtering from _MAX_ records" - * } - * } ); - * } ); - */ - "sInfoFiltered": "(filtered from _MAX_ total entries)", - - - /** - * If can be useful to append extra information to the info string at times, - * and this variable does exactly that. This information will be appended to - * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are - * being used) at all times. - * @type string - * @default Empty string - * - * @dtopt Language - * @name DataTable.defaults.language.infoPostFix - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "infoPostFix": "All records shown are derived from real information." - * } - * } ); - * } ); - */ - "sInfoPostFix": "", - - - /** - * This decimal place operator is a little different from the other - * language options since DataTables doesn't output floating point - * numbers, so it won't ever use this for display of a number. Rather, - * what this parameter does is modify the sort methods of the table so - * that numbers which are in a format which has a character other than - * a period (`.`) as a decimal place will be sorted numerically. - * - * Note that numbers with different decimal places cannot be shown in - * the same table and still be sortable, the table must be consistent. - * However, multiple different tables on the page can use different - * decimal place characters. - * @type string - * @default - * - * @dtopt Language - * @name DataTable.defaults.language.decimal - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "decimal": "," - * "thousands": "." - * } - * } ); - * } ); - */ - "sDecimal": "", - - - /** - * DataTables has a build in number formatter (`formatNumber`) which is - * used to format large numbers that are used in the table information. - * By default a comma is used, but this can be trivially changed to any - * character you wish with this parameter. - * @type string - * @default , - * - * @dtopt Language - * @name DataTable.defaults.language.thousands - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "thousands": "'" - * } - * } ); - * } ); - */ - "sThousands": ",", - - - /** - * Detail the action that will be taken when the drop down menu for the - * pagination length option is changed. The '_MENU_' variable is replaced - * with a default select list of 10, 25, 50 and 100, and can be replaced - * with a custom select box if required. - * @type string - * @default Show _MENU_ entries - * - * @dtopt Language - * @name DataTable.defaults.language.lengthMenu - * - * @example - * // Language change only - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "lengthMenu": "Display _MENU_ records" - * } - * } ); - * } ); - * - * @example - * // Language and options change - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "lengthMenu": 'Display records' - * } - * } ); - * } ); - */ - "sLengthMenu": "Show _MENU_ entries", - - - /** - * When using Ajax sourced data and during the first draw when DataTables is - * gathering the data, this message is shown in an empty row in the table to - * indicate to the end user the the data is being loaded. Note that this - * parameter is not used when loading data by server-side processing, just - * Ajax sourced data with client-side processing. - * @type string - * @default Loading... - * - * @dtopt Language - * @name DataTable.defaults.language.loadingRecords - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "loadingRecords": "Please wait - loading..." - * } - * } ); - * } ); - */ - "sLoadingRecords": "Loading...", - - - /** - * Text which is displayed when the table is processing a user action - * (usually a sort command or similar). - * @type string - * @default Processing... - * - * @dtopt Language - * @name DataTable.defaults.language.processing - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "processing": "DataTables is currently busy" - * } - * } ); - * } ); - */ - "sProcessing": "Processing...", - - - /** - * Details the actions that will be taken when the user types into the - * filtering input text box. The variable "_INPUT_", if used in the string, - * is replaced with the HTML text box for the filtering input allowing - * control over where it appears in the string. If "_INPUT_" is not given - * then the input box is appended to the string automatically. - * @type string - * @default Search: - * - * @dtopt Language - * @name DataTable.defaults.language.search - * - * @example - * // Input text box will be appended at the end automatically - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "search": "Filter records:" - * } - * } ); - * } ); - * - * @example - * // Specify where the filter should appear - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "search": "Apply filter _INPUT_ to table" - * } - * } ); - * } ); - */ - "sSearch": "Search:", - - - /** - * Assign a `placeholder` attribute to the search `input` element - * @type string - * @default - * - * @dtopt Language - * @name DataTable.defaults.language.searchPlaceholder - */ - "sSearchPlaceholder": "", - - - /** - * All of the language information can be stored in a file on the - * server-side, which DataTables will look up if this parameter is passed. - * It must store the URL of the language file, which is in a JSON format, - * and the object has the same properties as the oLanguage object in the - * initialiser object (i.e. the above parameters). Please refer to one of - * the example language files to see how this works in action. - * @type string - * @default Empty string - i.e. disabled - * - * @dtopt Language - * @name DataTable.defaults.language.url - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt" - * } - * } ); - * } ); - */ - "sUrl": "", - - - /** - * Text shown inside the table records when the is no information to be - * displayed after filtering. `emptyTable` is shown when there is simply no - * information in the table at all (regardless of filtering). - * @type string - * @default No matching records found - * - * @dtopt Language - * @name DataTable.defaults.language.zeroRecords - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "language": { - * "zeroRecords": "No records to display" - * } - * } ); - * } ); - */ - "sZeroRecords": "No matching records found" - }, - - - /** - * This parameter allows you to have define the global filtering state at - * initialisation time. As an object the `search` parameter must be - * defined, but all other parameters are optional. When `regex` is true, - * the search string will be treated as a regular expression, when false - * (default) it will be treated as a straight string. When `smart` - * DataTables will use it's smart filtering methods (to word match at - * any point in the data), when false this will not be done. - * @namespace - * @extends DataTable.models.oSearch - * - * @dtopt Options - * @name DataTable.defaults.search - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "search": {"search": "Initial search"} - * } ); - * } ) - */ - "oSearch": $.extend( {}, DataTable.models.oSearch ), - - - /** - * __Deprecated__ The functionality provided by this parameter has now been - * superseded by that provided through `ajax`, which should be used instead. - * - * By default DataTables will look for the property `data` (or `aaData` for - * compatibility with DataTables 1.9-) when obtaining data from an Ajax - * source or for server-side processing - this parameter allows that - * property to be changed. You can use Javascript dotted object notation to - * get a data source for multiple levels of nesting. - * @type string - * @default data - * - * @dtopt Options - * @dtopt Server-side - * @name DataTable.defaults.ajaxDataProp - * - * @deprecated 1.10. Please use `ajax` for this functionality now. - */ - "sAjaxDataProp": "data", - - - /** - * __Deprecated__ The functionality provided by this parameter has now been - * superseded by that provided through `ajax`, which should be used instead. - * - * You can instruct DataTables to load data from an external - * source using this parameter (use aData if you want to pass data in you - * already have). Simply provide a url a JSON object can be obtained from. - * @type string - * @default null - * - * @dtopt Options - * @dtopt Server-side - * @name DataTable.defaults.ajaxSource - * - * @deprecated 1.10. Please use `ajax` for this functionality now. - */ - "sAjaxSource": null, - - - /** - * This initialisation variable allows you to specify exactly where in the - * DOM you want DataTables to inject the various controls it adds to the page - * (for example you might want the pagination controls at the top of the - * table). DIV elements (with or without a custom class) can also be added to - * aid styling. The follow syntax is used: - *
      - *
    • The following options are allowed: - *
        - *
      • 'l' - Length changing
      • - *
      • 'f' - Filtering input
      • - *
      • 't' - The table!
      • - *
      • 'i' - Information
      • - *
      • 'p' - Pagination
      • - *
      • 'r' - pRocessing
      • - *
      - *
    • - *
    • The following constants are allowed: - *
        - *
      • 'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')
      • - *
      • 'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')
      • - *
      - *
    • - *
    • The following syntax is expected: - *
        - *
      • '<' and '>' - div elements
      • - *
      • '<"class" and '>' - div with a class
      • - *
      • '<"#id" and '>' - div with an ID
      • - *
      - *
    • - *
    • Examples: - *
        - *
      • '<"wrapper"flipt>'
      • - *
      • '<lf<t>ip>'
      • - *
      - *
    • - *
    - * @type string - * @default lfrtip (when `jQueryUI` is false) or - * <"H"lfr>t<"F"ip> (when `jQueryUI` is true) - * - * @dtopt Options - * @name DataTable.defaults.dom - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "dom": '<"top"i>rt<"bottom"flp><"clear">' - * } ); - * } ); - */ - "sDom": "lfrtip", - - - /** - * Search delay option. This will throttle full table searches that use the - * DataTables provided search input element (it does not effect calls to - * `dt-api search()`, providing a delay before the search is made. - * @type integer - * @default 0 - * - * @dtopt Options - * @name DataTable.defaults.searchDelay - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "searchDelay": 200 - * } ); - * } ) - */ - "searchDelay": null, - - - /** - * DataTables features six different built-in options for the buttons to - * display for pagination control: - * - * * `numbers` - Page number buttons only - * * `simple` - 'Previous' and 'Next' buttons only - * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers - * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons - * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers - * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers - * - * Further methods can be added using {@link DataTable.ext.oPagination}. - * @type string - * @default simple_numbers - * - * @dtopt Options - * @name DataTable.defaults.pagingType - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "pagingType": "full_numbers" - * } ); - * } ) - */ - "sPaginationType": "simple_numbers", - - - /** - * Enable horizontal scrolling. When a table is too wide to fit into a - * certain layout, or you have a large number of columns in the table, you - * can enable x-scrolling to show the table in a viewport, which can be - * scrolled. This property can be `true` which will allow the table to - * scroll horizontally when needed, or any CSS unit, or a number (in which - * case it will be treated as a pixel measurement). Setting as simply `true` - * is recommended. - * @type boolean|string - * @default blank string - i.e. disabled - * - * @dtopt Features - * @name DataTable.defaults.scrollX - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "scrollX": true, - * "scrollCollapse": true - * } ); - * } ); - */ - "sScrollX": "", - - - /** - * This property can be used to force a DataTable to use more width than it - * might otherwise do when x-scrolling is enabled. For example if you have a - * table which requires to be well spaced, this parameter is useful for - * "over-sizing" the table, and thus forcing scrolling. This property can by - * any CSS unit, or a number (in which case it will be treated as a pixel - * measurement). - * @type string - * @default blank string - i.e. disabled - * - * @dtopt Options - * @name DataTable.defaults.scrollXInner - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "scrollX": "100%", - * "scrollXInner": "110%" - * } ); - * } ); - */ - "sScrollXInner": "", - - - /** - * Enable vertical scrolling. Vertical scrolling will constrain the DataTable - * to the given height, and enable scrolling for any data which overflows the - * current viewport. This can be used as an alternative to paging to display - * a lot of data in a small area (although paging and scrolling can both be - * enabled at the same time). This property can be any CSS unit, or a number - * (in which case it will be treated as a pixel measurement). - * @type string - * @default blank string - i.e. disabled - * - * @dtopt Features - * @name DataTable.defaults.scrollY - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "scrollY": "200px", - * "paginate": false - * } ); - * } ); - */ - "sScrollY": "", - - - /** - * __Deprecated__ The functionality provided by this parameter has now been - * superseded by that provided through `ajax`, which should be used instead. - * - * Set the HTTP method that is used to make the Ajax call for server-side - * processing or Ajax sourced data. - * @type string - * @default GET - * - * @dtopt Options - * @dtopt Server-side - * @name DataTable.defaults.serverMethod - * - * @deprecated 1.10. Please use `ajax` for this functionality now. - */ - "sServerMethod": "GET", - - - /** - * DataTables makes use of renderers when displaying HTML elements for - * a table. These renderers can be added or modified by plug-ins to - * generate suitable mark-up for a site. For example the Bootstrap - * integration plug-in for DataTables uses a paging button renderer to - * display pagination buttons in the mark-up required by Bootstrap. - * - * For further information about the renderers available see - * DataTable.ext.renderer - * @type string|object - * @default null - * - * @name DataTable.defaults.renderer - * - */ - "renderer": null, - - - /** - * Set the data property name that DataTables should use to get a row's id - * to set as the `id` property in the node. - * @type string - * @default DT_RowId - * - * @name DataTable.defaults.rowId - */ - "rowId": "DT_RowId" - }; - - _fnHungarianMap( DataTable.defaults ); - - - - /* - * Developer note - See note in model.defaults.js about the use of Hungarian - * notation and camel case. - */ - - /** - * Column options that can be given to DataTables at initialisation time. - * @namespace - */ - DataTable.defaults.column = { - /** - * Define which column(s) an order will occur on for this column. This - * allows a column's ordering to take multiple columns into account when - * doing a sort or use the data from a different column. For example first - * name / last name columns make sense to do a multi-column sort over the - * two columns. - * @type array|int - * @default null Takes the value of the column index automatically - * - * @name DataTable.defaults.column.orderData - * @dtopt Columns - * - * @example - * // Using `columnDefs` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ - * { "orderData": [ 0, 1 ], "targets": [ 0 ] }, - * { "orderData": [ 1, 0 ], "targets": [ 1 ] }, - * { "orderData": 2, "targets": [ 2 ] } - * ] - * } ); - * } ); - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * { "orderData": [ 0, 1 ] }, - * { "orderData": [ 1, 0 ] }, - * { "orderData": 2 }, - * null, - * null - * ] - * } ); - * } ); - */ - "aDataSort": null, - "iDataSort": -1, - - - /** - * You can control the default ordering direction, and even alter the - * behaviour of the sort handler (i.e. only allow ascending ordering etc) - * using this parameter. - * @type array - * @default [ 'asc', 'desc' ] - * - * @name DataTable.defaults.column.orderSequence - * @dtopt Columns - * - * @example - * // Using `columnDefs` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ - * { "orderSequence": [ "asc" ], "targets": [ 1 ] }, - * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] }, - * { "orderSequence": [ "desc" ], "targets": [ 3 ] } - * ] - * } ); - * } ); - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * null, - * { "orderSequence": [ "asc" ] }, - * { "orderSequence": [ "desc", "asc", "asc" ] }, - * { "orderSequence": [ "desc" ] }, - * null - * ] - * } ); - * } ); - */ - "asSorting": [ 'asc', 'desc' ], - - - /** - * Enable or disable filtering on the data in this column. - * @type boolean - * @default true - * - * @name DataTable.defaults.column.searchable - * @dtopt Columns - * - * @example - * // Using `columnDefs` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ - * { "searchable": false, "targets": [ 0 ] } - * ] } ); - * } ); - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * { "searchable": false }, - * null, - * null, - * null, - * null - * ] } ); - * } ); - */ - "bSearchable": true, - - - /** - * Enable or disable ordering on this column. - * @type boolean - * @default true - * - * @name DataTable.defaults.column.orderable - * @dtopt Columns - * - * @example - * // Using `columnDefs` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ - * { "orderable": false, "targets": [ 0 ] } - * ] } ); - * } ); - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * { "orderable": false }, - * null, - * null, - * null, - * null - * ] } ); - * } ); - */ - "bSortable": true, - - - /** - * Enable or disable the display of this column. - * @type boolean - * @default true - * - * @name DataTable.defaults.column.visible - * @dtopt Columns - * - * @example - * // Using `columnDefs` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ - * { "visible": false, "targets": [ 0 ] } - * ] } ); - * } ); - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * { "visible": false }, - * null, - * null, - * null, - * null - * ] } ); - * } ); - */ - "bVisible": true, - - - /** - * Developer definable function that is called whenever a cell is created (Ajax source, - * etc) or processed for input (DOM source). This can be used as a compliment to mRender - * allowing you to modify the DOM element (add background colour for example) when the - * element is available. - * @type function - * @param {element} td The TD node that has been created - * @param {*} cellData The Data for the cell - * @param {array|object} rowData The data for the whole row - * @param {int} row The row index for the aoData data store - * @param {int} col The column index for aoColumns - * - * @name DataTable.defaults.column.createdCell - * @dtopt Columns - * - * @example - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ { - * "targets": [3], - * "createdCell": function (td, cellData, rowData, row, col) { - * if ( cellData == "1.7" ) { - * $(td).css('color', 'blue') - * } - * } - * } ] - * }); - * } ); - */ - "fnCreatedCell": null, - - - /** - * This parameter has been replaced by `data` in DataTables to ensure naming - * consistency. `dataProp` can still be used, as there is backwards - * compatibility in DataTables for this option, but it is strongly - * recommended that you use `data` in preference to `dataProp`. - * @name DataTable.defaults.column.dataProp - */ - - - /** - * This property can be used to read data from any data source property, - * including deeply nested objects / properties. `data` can be given in a - * number of different ways which effect its behaviour: - * - * * `integer` - treated as an array index for the data source. This is the - * default that DataTables uses (incrementally increased for each column). - * * `string` - read an object property from the data source. There are - * three 'special' options that can be used in the string to alter how - * DataTables reads the data from the source object: - * * `.` - Dotted Javascript notation. Just as you use a `.` in - * Javascript to read from nested objects, so to can the options - * specified in `data`. For example: `browser.version` or - * `browser.name`. If your object parameter name contains a period, use - * `\\` to escape it - i.e. `first\\.name`. - * * `[]` - Array notation. DataTables can automatically combine data - * from and array source, joining the data with the characters provided - * between the two brackets. For example: `name[, ]` would provide a - * comma-space separated list from the source array. If no characters - * are provided between the brackets, the original array source is - * returned. - * * `()` - Function notation. Adding `()` to the end of a parameter will - * execute a function of the name given. For example: `browser()` for a - * simple function on the data source, `browser.version()` for a - * function in a nested property or even `browser().version` to get an - * object property if the function called returns an object. Note that - * function notation is recommended for use in `render` rather than - * `data` as it is much simpler to use as a renderer. - * * `null` - use the original data source for the row rather than plucking - * data directly from it. This action has effects on two other - * initialisation options: - * * `defaultContent` - When null is given as the `data` option and - * `defaultContent` is specified for the column, the value defined by - * `defaultContent` will be used for the cell. - * * `render` - When null is used for the `data` option and the `render` - * option is specified for the column, the whole data source for the - * row is used for the renderer. - * * `function` - the function given will be executed whenever DataTables - * needs to set or get the data for a cell in the column. The function - * takes three parameters: - * * Parameters: - * * `{array|object}` The data source for the row - * * `{string}` The type call data requested - this will be 'set' when - * setting data or 'filter', 'display', 'type', 'sort' or undefined - * when gathering data. Note that when `undefined` is given for the - * type DataTables expects to get the raw data for the object back< - * * `{*}` Data to set when the second parameter is 'set'. - * * Return: - * * The return value from the function is not required when 'set' is - * the type of call, but otherwise the return is what will be used - * for the data requested. - * - * Note that `data` is a getter and setter option. If you just require - * formatting of data for output, you will likely want to use `render` which - * is simply a getter and thus simpler to use. - * - * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The - * name change reflects the flexibility of this property and is consistent - * with the naming of mRender. If 'mDataProp' is given, then it will still - * be used by DataTables, as it automatically maps the old name to the new - * if required. - * - * @type string|int|function|null - * @default null Use automatically calculated column index - * - * @name DataTable.defaults.column.data - * @dtopt Columns - * - * @example - * // Read table data from objects - * // JSON structure for each row: - * // { - * // "engine": {value}, - * // "browser": {value}, - * // "platform": {value}, - * // "version": {value}, - * // "grade": {value} - * // } - * $(document).ready( function() { - * $('#example').dataTable( { - * "ajaxSource": "sources/objects.txt", - * "columns": [ - * { "data": "engine" }, - * { "data": "browser" }, - * { "data": "platform" }, - * { "data": "version" }, - * { "data": "grade" } - * ] - * } ); - * } ); - * - * @example - * // Read information from deeply nested objects - * // JSON structure for each row: - * // { - * // "engine": {value}, - * // "browser": {value}, - * // "platform": { - * // "inner": {value} - * // }, - * // "details": [ - * // {value}, {value} - * // ] - * // } - * $(document).ready( function() { - * $('#example').dataTable( { - * "ajaxSource": "sources/deep.txt", - * "columns": [ - * { "data": "engine" }, - * { "data": "browser" }, - * { "data": "platform.inner" }, - * { "data": "details.0" }, - * { "data": "details.1" } - * ] - * } ); - * } ); - * - * @example - * // Using `data` as a function to provide different information for - * // sorting, filtering and display. In this case, currency (price) - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ { - * "targets": [ 0 ], - * "data": function ( source, type, val ) { - * if (type === 'set') { - * source.price = val; - * // Store the computed display and filter values for efficiency - * source.price_display = val=="" ? "" : "$"+numberFormat(val); - * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val; - * return; - * } - * else if (type === 'display') { - * return source.price_display; - * } - * else if (type === 'filter') { - * return source.price_filter; - * } - * // 'sort', 'type' and undefined all just use the integer - * return source.price; - * } - * } ] - * } ); - * } ); - * - * @example - * // Using default content - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ { - * "targets": [ 0 ], - * "data": null, - * "defaultContent": "Click to edit" - * } ] - * } ); - * } ); - * - * @example - * // Using array notation - outputting a list from an array - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ { - * "targets": [ 0 ], - * "data": "name[, ]" - * } ] - * } ); - * } ); - * - */ - "mData": null, - - - /** - * This property is the rendering partner to `data` and it is suggested that - * when you want to manipulate data for display (including filtering, - * sorting etc) without altering the underlying data for the table, use this - * property. `render` can be considered to be the the read only companion to - * `data` which is read / write (then as such more complex). Like `data` - * this option can be given in a number of different ways to effect its - * behaviour: - * - * * `integer` - treated as an array index for the data source. This is the - * default that DataTables uses (incrementally increased for each column). - * * `string` - read an object property from the data source. There are - * three 'special' options that can be used in the string to alter how - * DataTables reads the data from the source object: - * * `.` - Dotted Javascript notation. Just as you use a `.` in - * Javascript to read from nested objects, so to can the options - * specified in `data`. For example: `browser.version` or - * `browser.name`. If your object parameter name contains a period, use - * `\\` to escape it - i.e. `first\\.name`. - * * `[]` - Array notation. DataTables can automatically combine data - * from and array source, joining the data with the characters provided - * between the two brackets. For example: `name[, ]` would provide a - * comma-space separated list from the source array. If no characters - * are provided between the brackets, the original array source is - * returned. - * * `()` - Function notation. Adding `()` to the end of a parameter will - * execute a function of the name given. For example: `browser()` for a - * simple function on the data source, `browser.version()` for a - * function in a nested property or even `browser().version` to get an - * object property if the function called returns an object. - * * `object` - use different data for the different data types requested by - * DataTables ('filter', 'display', 'type' or 'sort'). The property names - * of the object is the data type the property refers to and the value can - * defined using an integer, string or function using the same rules as - * `render` normally does. Note that an `_` option _must_ be specified. - * This is the default value to use if you haven't specified a value for - * the data type requested by DataTables. - * * `function` - the function given will be executed whenever DataTables - * needs to set or get the data for a cell in the column. The function - * takes three parameters: - * * Parameters: - * * {array|object} The data source for the row (based on `data`) - * * {string} The type call data requested - this will be 'filter', - * 'display', 'type' or 'sort'. - * * {array|object} The full data source for the row (not based on - * `data`) - * * Return: - * * The return value from the function is what will be used for the - * data requested. - * - * @type string|int|function|object|null - * @default null Use the data source value. - * - * @name DataTable.defaults.column.render - * @dtopt Columns - * - * @example - * // Create a comma separated list from an array of objects - * $(document).ready( function() { - * $('#example').dataTable( { - * "ajaxSource": "sources/deep.txt", - * "columns": [ - * { "data": "engine" }, - * { "data": "browser" }, - * { - * "data": "platform", - * "render": "[, ].name" - * } - * ] - * } ); - * } ); - * - * @example - * // Execute a function to obtain data - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ { - * "targets": [ 0 ], - * "data": null, // Use the full data source object for the renderer's source - * "render": "browserName()" - * } ] - * } ); - * } ); - * - * @example - * // As an object, extracting different data for the different types - * // This would be used with a data source such as: - * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" } - * // Here the `phone` integer is used for sorting and type detection, while `phone_filter` - * // (which has both forms) is used for filtering for if a user inputs either format, while - * // the formatted phone number is the one that is shown in the table. - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ { - * "targets": [ 0 ], - * "data": null, // Use the full data source object for the renderer's source - * "render": { - * "_": "phone", - * "filter": "phone_filter", - * "display": "phone_display" - * } - * } ] - * } ); - * } ); - * - * @example - * // Use as a function to create a link from the data source - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ { - * "targets": [ 0 ], - * "data": "download_link", - * "render": function ( data, type, full ) { - * return 'Download'; - * } - * } ] - * } ); - * } ); - */ - "mRender": null, - - - /** - * Change the cell type created for the column - either TD cells or TH cells. This - * can be useful as TH cells have semantic meaning in the table body, allowing them - * to act as a header for a row (you may wish to add scope='row' to the TH elements). - * @type string - * @default td - * - * @name DataTable.defaults.column.cellType - * @dtopt Columns - * - * @example - * // Make the first column use TH cells - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ { - * "targets": [ 0 ], - * "cellType": "th" - * } ] - * } ); - * } ); - */ - "sCellType": "td", - - - /** - * Class to give to each cell in this column. - * @type string - * @default Empty string - * - * @name DataTable.defaults.column.class - * @dtopt Columns - * - * @example - * // Using `columnDefs` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ - * { "class": "my_class", "targets": [ 0 ] } - * ] - * } ); - * } ); - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * { "class": "my_class" }, - * null, - * null, - * null, - * null - * ] - * } ); - * } ); - */ - "sClass": "", - - /** - * When DataTables calculates the column widths to assign to each column, - * it finds the longest string in each column and then constructs a - * temporary table and reads the widths from that. The problem with this - * is that "mmm" is much wider then "iiii", but the latter is a longer - * string - thus the calculation can go wrong (doing it properly and putting - * it into an DOM object and measuring that is horribly(!) slow). Thus as - * a "work around" we provide this option. It will append its value to the - * text that is found to be the longest string for the column - i.e. padding. - * Generally you shouldn't need this! - * @type string - * @default Empty string - * - * @name DataTable.defaults.column.contentPadding - * @dtopt Columns - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * null, - * null, - * null, - * { - * "contentPadding": "mmm" - * } - * ] - * } ); - * } ); - */ - "sContentPadding": "", - - - /** - * Allows a default value to be given for a column's data, and will be used - * whenever a null data source is encountered (this can be because `data` - * is set to null, or because the data source itself is null). - * @type string - * @default null - * - * @name DataTable.defaults.column.defaultContent - * @dtopt Columns - * - * @example - * // Using `columnDefs` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ - * { - * "data": null, - * "defaultContent": "Edit", - * "targets": [ -1 ] - * } - * ] - * } ); - * } ); - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * null, - * null, - * null, - * { - * "data": null, - * "defaultContent": "Edit" - * } - * ] - * } ); - * } ); - */ - "sDefaultContent": null, - - - /** - * This parameter is only used in DataTables' server-side processing. It can - * be exceptionally useful to know what columns are being displayed on the - * client side, and to map these to database fields. When defined, the names - * also allow DataTables to reorder information from the server if it comes - * back in an unexpected order (i.e. if you switch your columns around on the - * client-side, your server-side code does not also need updating). - * @type string - * @default Empty string - * - * @name DataTable.defaults.column.name - * @dtopt Columns - * - * @example - * // Using `columnDefs` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ - * { "name": "engine", "targets": [ 0 ] }, - * { "name": "browser", "targets": [ 1 ] }, - * { "name": "platform", "targets": [ 2 ] }, - * { "name": "version", "targets": [ 3 ] }, - * { "name": "grade", "targets": [ 4 ] } - * ] - * } ); - * } ); - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * { "name": "engine" }, - * { "name": "browser" }, - * { "name": "platform" }, - * { "name": "version" }, - * { "name": "grade" } - * ] - * } ); - * } ); - */ - "sName": "", - - - /** - * Defines a data source type for the ordering which can be used to read - * real-time information from the table (updating the internally cached - * version) prior to ordering. This allows ordering to occur on user - * editable elements such as form inputs. - * @type string - * @default std - * - * @name DataTable.defaults.column.orderDataType - * @dtopt Columns - * - * @example - * // Using `columnDefs` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ - * { "orderDataType": "dom-text", "targets": [ 2, 3 ] }, - * { "type": "numeric", "targets": [ 3 ] }, - * { "orderDataType": "dom-select", "targets": [ 4 ] }, - * { "orderDataType": "dom-checkbox", "targets": [ 5 ] } - * ] - * } ); - * } ); - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * null, - * null, - * { "orderDataType": "dom-text" }, - * { "orderDataType": "dom-text", "type": "numeric" }, - * { "orderDataType": "dom-select" }, - * { "orderDataType": "dom-checkbox" } - * ] - * } ); - * } ); - */ - "sSortDataType": "std", - - - /** - * The title of this column. - * @type string - * @default null Derived from the 'TH' value for this column in the - * original HTML table. - * - * @name DataTable.defaults.column.title - * @dtopt Columns - * - * @example - * // Using `columnDefs` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ - * { "title": "My column title", "targets": [ 0 ] } - * ] - * } ); - * } ); - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * { "title": "My column title" }, - * null, - * null, - * null, - * null - * ] - * } ); - * } ); - */ - "sTitle": null, - - - /** - * The type allows you to specify how the data for this column will be - * ordered. Four types (string, numeric, date and html (which will strip - * HTML tags before ordering)) are currently available. Note that only date - * formats understood by Javascript's Date() object will be accepted as type - * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string', - * 'numeric', 'date' or 'html' (by default). Further types can be adding - * through plug-ins. - * @type string - * @default null Auto-detected from raw data - * - * @name DataTable.defaults.column.type - * @dtopt Columns - * - * @example - * // Using `columnDefs` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ - * { "type": "html", "targets": [ 0 ] } - * ] - * } ); - * } ); - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * { "type": "html" }, - * null, - * null, - * null, - * null - * ] - * } ); - * } ); - */ - "sType": null, - - - /** - * Defining the width of the column, this parameter may take any CSS value - * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not - * been given a specific width through this interface ensuring that the table - * remains readable. - * @type string - * @default null Automatic - * - * @name DataTable.defaults.column.width - * @dtopt Columns - * - * @example - * // Using `columnDefs` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columnDefs": [ - * { "width": "20%", "targets": [ 0 ] } - * ] - * } ); - * } ); - * - * @example - * // Using `columns` - * $(document).ready( function() { - * $('#example').dataTable( { - * "columns": [ - * { "width": "20%" }, - * null, - * null, - * null, - * null - * ] - * } ); - * } ); - */ - "sWidth": null - }; - - _fnHungarianMap( DataTable.defaults.column ); - - - - /** - * DataTables settings object - this holds all the information needed for a - * given table, including configuration, data and current application of the - * table options. DataTables does not have a single instance for each DataTable - * with the settings attached to that instance, but rather instances of the - * DataTable "class" are created on-the-fly as needed (typically by a - * $().dataTable() call) and the settings object is then applied to that - * instance. - * - * Note that this object is related to {@link DataTable.defaults} but this - * one is the internal data store for DataTables's cache of columns. It should - * NOT be manipulated outside of DataTables. Any configuration should be done - * through the initialisation options. - * @namespace - * @todo Really should attach the settings object to individual instances so we - * don't need to create new instances on each $().dataTable() call (if the - * table already exists). It would also save passing oSettings around and - * into every single function. However, this is a very significant - * architecture change for DataTables and will almost certainly break - * backwards compatibility with older installations. This is something that - * will be done in 2.0. - */ - DataTable.models.oSettings = { - /** - * Primary features of DataTables and their enablement state. - * @namespace - */ - "oFeatures": { - - /** - * Flag to say if DataTables should automatically try to calculate the - * optimum table and columns widths (true) or not (false). - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bAutoWidth": null, - - /** - * Delay the creation of TR and TD elements until they are actually - * needed by a driven page draw. This can give a significant speed - * increase for Ajax source and Javascript source data, but makes no - * difference at all for DOM and server-side processing tables. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bDeferRender": null, - - /** - * Enable filtering on the table or not. Note that if this is disabled - * then there is no filtering at all on the table, including fnFilter. - * To just remove the filtering input use sDom and remove the 'f' option. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bFilter": null, - - /** - * Table information element (the 'Showing x of y records' div) enable - * flag. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bInfo": null, - - /** - * Present a user control allowing the end user to change the page size - * when pagination is enabled. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bLengthChange": null, - - /** - * Pagination enabled or not. Note that if this is disabled then length - * changing must also be disabled. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bPaginate": null, - - /** - * Processing indicator enable flag whenever DataTables is enacting a - * user request - typically an Ajax request for server-side processing. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bProcessing": null, - - /** - * Server-side processing enabled flag - when enabled DataTables will - * get all data from the server for every draw - there is no filtering, - * sorting or paging done on the client-side. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bServerSide": null, - - /** - * Sorting enablement flag. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bSort": null, - - /** - * Multi-column sorting - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bSortMulti": null, - - /** - * Apply a class to the columns which are being sorted to provide a - * visual highlight or not. This can slow things down when enabled since - * there is a lot of DOM interaction. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bSortClasses": null, - - /** - * State saving enablement flag. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bStateSave": null - }, - - - /** - * Scrolling settings for a table. - * @namespace - */ - "oScroll": { - /** - * When the table is shorter in height than sScrollY, collapse the - * table container down to the height of the table (when true). - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bCollapse": null, - - /** - * Width of the scrollbar for the web-browser's platform. Calculated - * during table initialisation. - * @type int - * @default 0 - */ - "iBarWidth": 0, - - /** - * Viewport width for horizontal scrolling. Horizontal scrolling is - * disabled if an empty string. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type string - */ - "sX": null, - - /** - * Width to expand the table to when using x-scrolling. Typically you - * should not need to use this. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type string - * @deprecated - */ - "sXInner": null, - - /** - * Viewport height for vertical scrolling. Vertical scrolling is disabled - * if an empty string. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type string - */ - "sY": null - }, - - /** - * Language information for the table. - * @namespace - * @extends DataTable.defaults.oLanguage - */ - "oLanguage": { - /** - * Information callback function. See - * {@link DataTable.defaults.fnInfoCallback} - * @type function - * @default null - */ - "fnInfoCallback": null - }, - - /** - * Browser support parameters - * @namespace - */ - "oBrowser": { - /** - * Indicate if the browser incorrectly calculates width:100% inside a - * scrolling element (IE6/7) - * @type boolean - * @default false - */ - "bScrollOversize": false, - - /** - * Determine if the vertical scrollbar is on the right or left of the - * scrolling container - needed for rtl language layout, although not - * all browsers move the scrollbar (Safari). - * @type boolean - * @default false - */ - "bScrollbarLeft": false, - - /** - * Flag for if `getBoundingClientRect` is fully supported or not - * @type boolean - * @default false - */ - "bBounding": false, - - /** - * Browser scrollbar width - * @type integer - * @default 0 - */ - "barWidth": 0 - }, - - - "ajax": null, - - - /** - * Array referencing the nodes which are used for the features. The - * parameters of this object match what is allowed by sDom - i.e. - *
      - *
    • 'l' - Length changing
    • - *
    • 'f' - Filtering input
    • - *
    • 't' - The table!
    • - *
    • 'i' - Information
    • - *
    • 'p' - Pagination
    • - *
    • 'r' - pRocessing
    • - *
    - * @type array - * @default [] - */ - "aanFeatures": [], - - /** - * Store data information - see {@link DataTable.models.oRow} for detailed - * information. - * @type array - * @default [] - */ - "aoData": [], - - /** - * Array of indexes which are in the current display (after filtering etc) - * @type array - * @default [] - */ - "aiDisplay": [], - - /** - * Array of indexes for display - no filtering - * @type array - * @default [] - */ - "aiDisplayMaster": [], - - /** - * Map of row ids to data indexes - * @type object - * @default {} - */ - "aIds": {}, - - /** - * Store information about each column that is in use - * @type array - * @default [] - */ - "aoColumns": [], - - /** - * Store information about the table's header - * @type array - * @default [] - */ - "aoHeader": [], - - /** - * Store information about the table's footer - * @type array - * @default [] - */ - "aoFooter": [], - - /** - * Store the applied global search information in case we want to force a - * research or compare the old search to a new one. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @namespace - * @extends DataTable.models.oSearch - */ - "oPreviousSearch": {}, - - /** - * Store the applied search for each column - see - * {@link DataTable.models.oSearch} for the format that is used for the - * filtering information for each column. - * @type array - * @default [] - */ - "aoPreSearchCols": [], - - /** - * Sorting that is applied to the table. Note that the inner arrays are - * used in the following manner: - *
      - *
    • Index 0 - column number
    • - *
    • Index 1 - current sorting direction
    • - *
    - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type array - * @todo These inner arrays should really be objects - */ - "aaSorting": null, - - /** - * Sorting that is always applied to the table (i.e. prefixed in front of - * aaSorting). - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type array - * @default [] - */ - "aaSortingFixed": [], - - /** - * Classes to use for the striping of a table. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type array - * @default [] - */ - "asStripeClasses": null, - - /** - * If restoring a table - we should restore its striping classes as well - * @type array - * @default [] - */ - "asDestroyStripes": [], - - /** - * If restoring a table - we should restore its width - * @type int - * @default 0 - */ - "sDestroyWidth": 0, - - /** - * Callback functions array for every time a row is inserted (i.e. on a draw). - * @type array - * @default [] - */ - "aoRowCallback": [], - - /** - * Callback functions for the header on each draw. - * @type array - * @default [] - */ - "aoHeaderCallback": [], - - /** - * Callback function for the footer on each draw. - * @type array - * @default [] - */ - "aoFooterCallback": [], - - /** - * Array of callback functions for draw callback functions - * @type array - * @default [] - */ - "aoDrawCallback": [], - - /** - * Array of callback functions for row created function - * @type array - * @default [] - */ - "aoRowCreatedCallback": [], - - /** - * Callback functions for just before the table is redrawn. A return of - * false will be used to cancel the draw. - * @type array - * @default [] - */ - "aoPreDrawCallback": [], - - /** - * Callback functions for when the table has been initialised. - * @type array - * @default [] - */ - "aoInitComplete": [], - - - /** - * Callbacks for modifying the settings to be stored for state saving, prior to - * saving state. - * @type array - * @default [] - */ - "aoStateSaveParams": [], - - /** - * Callbacks for modifying the settings that have been stored for state saving - * prior to using the stored values to restore the state. - * @type array - * @default [] - */ - "aoStateLoadParams": [], - - /** - * Callbacks for operating on the settings object once the saved state has been - * loaded - * @type array - * @default [] - */ - "aoStateLoaded": [], - - /** - * Cache the table ID for quick access - * @type string - * @default Empty string - */ - "sTableId": "", - - /** - * The TABLE node for the main table - * @type node - * @default null - */ - "nTable": null, - - /** - * Permanent ref to the thead element - * @type node - * @default null - */ - "nTHead": null, - - /** - * Permanent ref to the tfoot element - if it exists - * @type node - * @default null - */ - "nTFoot": null, - - /** - * Permanent ref to the tbody element - * @type node - * @default null - */ - "nTBody": null, - - /** - * Cache the wrapper node (contains all DataTables controlled elements) - * @type node - * @default null - */ - "nTableWrapper": null, - - /** - * Indicate if when using server-side processing the loading of data - * should be deferred until the second draw. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - * @default false - */ - "bDeferLoading": false, - - /** - * Indicate if all required information has been read in - * @type boolean - * @default false - */ - "bInitialised": false, - - /** - * Information about open rows. Each object in the array has the parameters - * 'nTr' and 'nParent' - * @type array - * @default [] - */ - "aoOpenRows": [], - - /** - * Dictate the positioning of DataTables' control elements - see - * {@link DataTable.model.oInit.sDom}. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type string - * @default null - */ - "sDom": null, - - /** - * Search delay (in mS) - * @type integer - * @default null - */ - "searchDelay": null, - - /** - * Which type of pagination should be used. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type string - * @default two_button - */ - "sPaginationType": "two_button", - - /** - * The state duration (for `stateSave`) in seconds. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type int - * @default 0 - */ - "iStateDuration": 0, - - /** - * Array of callback functions for state saving. Each array element is an - * object with the following parameters: - *
      - *
    • function:fn - function to call. Takes two parameters, oSettings - * and the JSON string to save that has been thus far created. Returns - * a JSON string to be inserted into a json object - * (i.e. '"param": [ 0, 1, 2]')
    • - *
    • string:sName - name of callback
    • - *
    - * @type array - * @default [] - */ - "aoStateSave": [], - - /** - * Array of callback functions for state loading. Each array element is an - * object with the following parameters: - *
      - *
    • function:fn - function to call. Takes two parameters, oSettings - * and the object stored. May return false to cancel state loading
    • - *
    • string:sName - name of callback
    • - *
    - * @type array - * @default [] - */ - "aoStateLoad": [], - - /** - * State that was saved. Useful for back reference - * @type object - * @default null - */ - "oSavedState": null, - - /** - * State that was loaded. Useful for back reference - * @type object - * @default null - */ - "oLoadedState": null, - - /** - * Source url for AJAX data for the table. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type string - * @default null - */ - "sAjaxSource": null, - - /** - * Property from a given object from which to read the table data from. This - * can be an empty string (when not server-side processing), in which case - * it is assumed an an array is given directly. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type string - */ - "sAjaxDataProp": null, - - /** - * The last jQuery XHR object that was used for server-side data gathering. - * This can be used for working with the XHR information in one of the - * callbacks - * @type object - * @default null - */ - "jqXHR": null, - - /** - * JSON returned from the server in the last Ajax request - * @type object - * @default undefined - */ - "json": undefined, - - /** - * Data submitted as part of the last Ajax request - * @type object - * @default undefined - */ - "oAjaxData": undefined, - - /** - * Function to get the server-side data. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type function - */ - "fnServerData": null, - - /** - * Functions which are called prior to sending an Ajax request so extra - * parameters can easily be sent to the server - * @type array - * @default [] - */ - "aoServerParams": [], - - /** - * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if - * required). - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type string - */ - "sServerMethod": null, - - /** - * Format numbers for display. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type function - */ - "fnFormatNumber": null, - - /** - * List of options that can be used for the user selectable length menu. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type array - * @default [] - */ - "aLengthMenu": null, - - /** - * Counter for the draws that the table does. Also used as a tracker for - * server-side processing - * @type int - * @default 0 - */ - "iDraw": 0, - - /** - * Indicate if a redraw is being done - useful for Ajax - * @type boolean - * @default false - */ - "bDrawing": false, - - /** - * Draw index (iDraw) of the last error when parsing the returned data - * @type int - * @default -1 - */ - "iDrawError": -1, - - /** - * Paging display length - * @type int - * @default 10 - */ - "_iDisplayLength": 10, - - /** - * Paging start point - aiDisplay index - * @type int - * @default 0 - */ - "_iDisplayStart": 0, - - /** - * Server-side processing - number of records in the result set - * (i.e. before filtering), Use fnRecordsTotal rather than - * this property to get the value of the number of records, regardless of - * the server-side processing setting. - * @type int - * @default 0 - * @private - */ - "_iRecordsTotal": 0, - - /** - * Server-side processing - number of records in the current display set - * (i.e. after filtering). Use fnRecordsDisplay rather than - * this property to get the value of the number of records, regardless of - * the server-side processing setting. - * @type boolean - * @default 0 - * @private - */ - "_iRecordsDisplay": 0, - - /** - * The classes to use for the table - * @type object - * @default {} - */ - "oClasses": {}, - - /** - * Flag attached to the settings object so you can check in the draw - * callback if filtering has been done in the draw. Deprecated in favour of - * events. - * @type boolean - * @default false - * @deprecated - */ - "bFiltered": false, - - /** - * Flag attached to the settings object so you can check in the draw - * callback if sorting has been done in the draw. Deprecated in favour of - * events. - * @type boolean - * @default false - * @deprecated - */ - "bSorted": false, - - /** - * Indicate that if multiple rows are in the header and there is more than - * one unique cell per column, if the top one (true) or bottom one (false) - * should be used for sorting / title by DataTables. - * Note that this parameter will be set by the initialisation routine. To - * set a default use {@link DataTable.defaults}. - * @type boolean - */ - "bSortCellsTop": null, - - /** - * Initialisation object that is used for the table - * @type object - * @default null - */ - "oInit": null, - - /** - * Destroy callback functions - for plug-ins to attach themselves to the - * destroy so they can clean up markup and events. - * @type array - * @default [] - */ - "aoDestroyCallback": [], - - - /** - * Get the number of records in the current record set, before filtering - * @type function - */ - "fnRecordsTotal": function () - { - return _fnDataSource( this ) == 'ssp' ? - this._iRecordsTotal * 1 : - this.aiDisplayMaster.length; - }, - - /** - * Get the number of records in the current record set, after filtering - * @type function - */ - "fnRecordsDisplay": function () - { - return _fnDataSource( this ) == 'ssp' ? - this._iRecordsDisplay * 1 : - this.aiDisplay.length; - }, - - /** - * Get the display end point - aiDisplay index - * @type function - */ - "fnDisplayEnd": function () - { - var - len = this._iDisplayLength, - start = this._iDisplayStart, - calc = start + len, - records = this.aiDisplay.length, - features = this.oFeatures, - paginate = features.bPaginate; - - if ( features.bServerSide ) { - return paginate === false || len === -1 ? - start + records : - Math.min( start+len, this._iRecordsDisplay ); - } - else { - return ! paginate || calc>records || len===-1 ? - records : - calc; - } - }, - - /** - * The DataTables object for this table - * @type object - * @default null - */ - "oInstance": null, - - /** - * Unique identifier for each instance of the DataTables object. If there - * is an ID on the table node, then it takes that value, otherwise an - * incrementing internal counter is used. - * @type string - * @default null - */ - "sInstance": null, - - /** - * tabindex attribute value that is added to DataTables control elements, allowing - * keyboard navigation of the table and its controls. - */ - "iTabIndex": 0, - - /** - * DIV container for the footer scrolling table if scrolling - */ - "nScrollHead": null, - - /** - * DIV container for the footer scrolling table if scrolling - */ - "nScrollFoot": null, - - /** - * Last applied sort - * @type array - * @default [] - */ - "aLastSort": [], - - /** - * Stored plug-in instances - * @type object - * @default {} - */ - "oPlugins": {}, - - /** - * Function used to get a row's id from the row's data - * @type function - * @default null - */ - "rowIdFn": null, - - /** - * Data location where to store a row's id - * @type string - * @default null - */ - "rowId": null - }; - - /** - * Extension object for DataTables that is used to provide all extension - * options. - * - * Note that the `DataTable.ext` object is available through - * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is - * also aliased to `jQuery.fn.dataTableExt` for historic reasons. - * @namespace - * @extends DataTable.models.ext - */ - - - /** - * DataTables extensions - * - * This namespace acts as a collection area for plug-ins that can be used to - * extend DataTables capabilities. Indeed many of the build in methods - * use this method to provide their own capabilities (sorting methods for - * example). - * - * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy - * reasons - * - * @namespace - */ - DataTable.ext = _ext = { - /** - * Buttons. For use with the Buttons extension for DataTables. This is - * defined here so other extensions can define buttons regardless of load - * order. It is _not_ used by DataTables core. - * - * @type object - * @default {} - */ - buttons: {}, - - - /** - * Element class names - * - * @type object - * @default {} - */ - classes: {}, - - - /** - * DataTables build type (expanded by the download builder) - * - * @type string - */ - build:"dt/dt-1.11.4/fc-4.0.1/fh-3.2.1/r-2.2.9/sb-1.3.1", - - - /** - * Error reporting. - * - * How should DataTables report an error. Can take the value 'alert', - * 'throw', 'none' or a function. - * - * @type string|function - * @default alert - */ - errMode: "alert", - - - /** - * Feature plug-ins. - * - * This is an array of objects which describe the feature plug-ins that are - * available to DataTables. These feature plug-ins are then available for - * use through the `dom` initialisation option. - * - * Each feature plug-in is described by an object which must have the - * following properties: - * - * * `fnInit` - function that is used to initialise the plug-in, - * * `cFeature` - a character so the feature can be enabled by the `dom` - * instillation option. This is case sensitive. - * - * The `fnInit` function has the following input parameters: - * - * 1. `{object}` DataTables settings object: see - * {@link DataTable.models.oSettings} - * - * And the following return is expected: - * - * * {node|null} The element which contains your feature. Note that the - * return may also be void if your plug-in does not require to inject any - * DOM elements into DataTables control (`dom`) - for example this might - * be useful when developing a plug-in which allows table control via - * keyboard entry - * - * @type array - * - * @example - * $.fn.dataTable.ext.features.push( { - * "fnInit": function( oSettings ) { - * return new TableTools( { "oDTSettings": oSettings } ); - * }, - * "cFeature": "T" - * } ); - */ - feature: [], - - - /** - * Row searching. - * - * This method of searching is complimentary to the default type based - * searching, and a lot more comprehensive as it allows you complete control - * over the searching logic. Each element in this array is a function - * (parameters described below) that is called for every row in the table, - * and your logic decides if it should be included in the searching data set - * or not. - * - * Searching functions have the following input parameters: - * - * 1. `{object}` DataTables settings object: see - * {@link DataTable.models.oSettings} - * 2. `{array|object}` Data for the row to be processed (same as the - * original format that was passed in as the data source, or an array - * from a DOM data source - * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which - * can be useful to retrieve the `TR` element if you need DOM interaction. - * - * And the following return is expected: - * - * * {boolean} Include the row in the searched result set (true) or not - * (false) - * - * Note that as with the main search ability in DataTables, technically this - * is "filtering", since it is subtractive. However, for consistency in - * naming we call it searching here. - * - * @type array - * @default [] - * - * @example - * // The following example shows custom search being applied to the - * // fourth column (i.e. the data[3] index) based on two input values - * // from the end-user, matching the data in a certain range. - * $.fn.dataTable.ext.search.push( - * function( settings, data, dataIndex ) { - * var min = document.getElementById('min').value * 1; - * var max = document.getElementById('max').value * 1; - * var version = data[3] == "-" ? 0 : data[3]*1; - * - * if ( min == "" && max == "" ) { - * return true; - * } - * else if ( min == "" && version < max ) { - * return true; - * } - * else if ( min < version && "" == max ) { - * return true; - * } - * else if ( min < version && version < max ) { - * return true; - * } - * return false; - * } - * ); - */ - search: [], - - - /** - * Selector extensions - * - * The `selector` option can be used to extend the options available for the - * selector modifier options (`selector-modifier` object data type) that - * each of the three built in selector types offer (row, column and cell + - * their plural counterparts). For example the Select extension uses this - * mechanism to provide an option to select only rows, columns and cells - * that have been marked as selected by the end user (`{selected: true}`), - * which can be used in conjunction with the existing built in selector - * options. - * - * Each property is an array to which functions can be pushed. The functions - * take three attributes: - * - * * Settings object for the host table - * * Options object (`selector-modifier` object type) - * * Array of selected item indexes - * - * The return is an array of the resulting item indexes after the custom - * selector has been applied. - * - * @type object - */ - selector: { - cell: [], - column: [], - row: [] - }, - - - /** - * Internal functions, exposed for used in plug-ins. - * - * Please note that you should not need to use the internal methods for - * anything other than a plug-in (and even then, try to avoid if possible). - * The internal function may change between releases. - * - * @type object - * @default {} - */ - internal: {}, - - - /** - * Legacy configuration options. Enable and disable legacy options that - * are available in DataTables. - * - * @type object - */ - legacy: { - /** - * Enable / disable DataTables 1.9 compatible server-side processing - * requests - * - * @type boolean - * @default null - */ - ajax: null - }, - - - /** - * Pagination plug-in methods. - * - * Each entry in this object is a function and defines which buttons should - * be shown by the pagination rendering method that is used for the table: - * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the - * buttons are displayed in the document, while the functions here tell it - * what buttons to display. This is done by returning an array of button - * descriptions (what each button will do). - * - * Pagination types (the four built in options and any additional plug-in - * options defined here) can be used through the `paginationType` - * initialisation parameter. - * - * The functions defined take two parameters: - * - * 1. `{int} page` The current page index - * 2. `{int} pages` The number of pages in the table - * - * Each function is expected to return an array where each element of the - * array can be one of: - * - * * `first` - Jump to first page when activated - * * `last` - Jump to last page when activated - * * `previous` - Show previous page when activated - * * `next` - Show next page when activated - * * `{int}` - Show page of the index given - * * `{array}` - A nested array containing the above elements to add a - * containing 'DIV' element (might be useful for styling). - * - * Note that DataTables v1.9- used this object slightly differently whereby - * an object with two functions would be defined for each plug-in. That - * ability is still supported by DataTables 1.10+ to provide backwards - * compatibility, but this option of use is now decremented and no longer - * documented in DataTables 1.10+. - * - * @type object - * @default {} - * - * @example - * // Show previous, next and current page buttons only - * $.fn.dataTableExt.oPagination.current = function ( page, pages ) { - * return [ 'previous', page, 'next' ]; - * }; - */ - pager: {}, - - - renderer: { - pageButton: {}, - header: {} - }, - - - /** - * Ordering plug-ins - custom data source - * - * The extension options for ordering of data available here is complimentary - * to the default type based ordering that DataTables typically uses. It - * allows much greater control over the the data that is being used to - * order a column, but is necessarily therefore more complex. - * - * This type of ordering is useful if you want to do ordering based on data - * live from the DOM (for example the contents of an 'input' element) rather - * than just the static string that DataTables knows of. - * - * The way these plug-ins work is that you create an array of the values you - * wish to be ordering for the column in question and then return that - * array. The data in the array much be in the index order of the rows in - * the table (not the currently ordering order!). Which order data gathering - * function is run here depends on the `dt-init columns.orderDataType` - * parameter that is used for the column (if any). - * - * The functions defined take two parameters: - * - * 1. `{object}` DataTables settings object: see - * {@link DataTable.models.oSettings} - * 2. `{int}` Target column index - * - * Each function is expected to return an array: - * - * * `{array}` Data for the column to be ordering upon - * - * @type array - * - * @example - * // Ordering using `input` node values - * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col ) - * { - * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) { - * return $('input', td).val(); - * } ); - * } - */ - order: {}, - - - /** - * Type based plug-ins. - * - * Each column in DataTables has a type assigned to it, either by automatic - * detection or by direct assignment using the `type` option for the column. - * The type of a column will effect how it is ordering and search (plug-ins - * can also make use of the column type if required). - * - * @namespace - */ - type: { - /** - * Type detection functions. - * - * The functions defined in this object are used to automatically detect - * a column's type, making initialisation of DataTables super easy, even - * when complex data is in the table. - * - * The functions defined take two parameters: - * - * 1. `{*}` Data from the column cell to be analysed - * 2. `{settings}` DataTables settings object. This can be used to - * perform context specific type detection - for example detection - * based on language settings such as using a comma for a decimal - * place. Generally speaking the options from the settings will not - * be required - * - * Each function is expected to return: - * - * * `{string|null}` Data type detected, or null if unknown (and thus - * pass it on to the other type detection functions. - * - * @type array - * - * @example - * // Currency type detection plug-in: - * $.fn.dataTable.ext.type.detect.push( - * function ( data, settings ) { - * // Check the numeric part - * if ( ! data.substring(1).match(/[0-9]/) ) { - * return null; - * } - * - * // Check prefixed by currency - * if ( data.charAt(0) == '$' || data.charAt(0) == '£' ) { - * return 'currency'; - * } - * return null; - * } - * ); - */ - detect: [], - - - /** - * Type based search formatting. - * - * The type based searching functions can be used to pre-format the - * data to be search on. For example, it can be used to strip HTML - * tags or to de-format telephone numbers for numeric only searching. - * - * Note that is a search is not defined for a column of a given type, - * no search formatting will be performed. - * - * Pre-processing of searching data plug-ins - When you assign the sType - * for a column (or have it automatically detected for you by DataTables - * or a type detection plug-in), you will typically be using this for - * custom sorting, but it can also be used to provide custom searching - * by allowing you to pre-processing the data and returning the data in - * the format that should be searched upon. This is done by adding - * functions this object with a parameter name which matches the sType - * for that target column. This is the corollary of afnSortData - * for searching data. - * - * The functions defined take a single parameter: - * - * 1. `{*}` Data from the column cell to be prepared for searching - * - * Each function is expected to return: - * - * * `{string|null}` Formatted string that will be used for the searching. - * - * @type object - * @default {} - * - * @example - * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) { - * return d.replace(/\n/g," ").replace( /<.*?>/g, "" ); - * } - */ - search: {}, - - - /** - * Type based ordering. - * - * The column type tells DataTables what ordering to apply to the table - * when a column is sorted upon. The order for each type that is defined, - * is defined by the functions available in this object. - * - * Each ordering option can be described by three properties added to - * this object: - * - * * `{type}-pre` - Pre-formatting function - * * `{type}-asc` - Ascending order function - * * `{type}-desc` - Descending order function - * - * All three can be used together, only `{type}-pre` or only - * `{type}-asc` and `{type}-desc` together. It is generally recommended - * that only `{type}-pre` is used, as this provides the optimal - * implementation in terms of speed, although the others are provided - * for compatibility with existing Javascript sort functions. - * - * `{type}-pre`: Functions defined take a single parameter: - * - * 1. `{*}` Data from the column cell to be prepared for ordering - * - * And return: - * - * * `{*}` Data to be sorted upon - * - * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort - * functions, taking two parameters: - * - * 1. `{*}` Data to compare to the second parameter - * 2. `{*}` Data to compare to the first parameter - * - * And returning: - * - * * `{*}` Ordering match: <0 if first parameter should be sorted lower - * than the second parameter, ===0 if the two parameters are equal and - * >0 if the first parameter should be sorted height than the second - * parameter. - * - * @type object - * @default {} - * - * @example - * // Numeric ordering of formatted numbers with a pre-formatter - * $.extend( $.fn.dataTable.ext.type.order, { - * "string-pre": function(x) { - * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" ); - * return parseFloat( a ); - * } - * } ); - * - * @example - * // Case-sensitive string ordering, with no pre-formatting method - * $.extend( $.fn.dataTable.ext.order, { - * "string-case-asc": function(x,y) { - * return ((x < y) ? -1 : ((x > y) ? 1 : 0)); - * }, - * "string-case-desc": function(x,y) { - * return ((x < y) ? 1 : ((x > y) ? -1 : 0)); - * } - * } ); - */ - order: {} - }, - - /** - * Unique DataTables instance counter - * - * @type int - * @private - */ - _unique: 0, - - - // - // Depreciated - // The following properties are retained for backwards compatibility only. - // The should not be used in new projects and will be removed in a future - // version - // - - /** - * Version check function. - * @type function - * @depreciated Since 1.10 - */ - fnVersionCheck: DataTable.fnVersionCheck, - - - /** - * Index for what 'this' index API functions should use - * @type int - * @deprecated Since v1.10 - */ - iApiIndex: 0, - - - /** - * jQuery UI class container - * @type object - * @deprecated Since v1.10 - */ - oJUIClasses: {}, - - - /** - * Software version - * @type string - * @deprecated Since v1.10 - */ - sVersion: DataTable.version - }; - - - // - // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts - // - $.extend( _ext, { - afnFiltering: _ext.search, - aTypes: _ext.type.detect, - ofnSearch: _ext.type.search, - oSort: _ext.type.order, - afnSortData: _ext.order, - aoFeatures: _ext.feature, - oApi: _ext.internal, - oStdClasses: _ext.classes, - oPagination: _ext.pager - } ); - - - $.extend( DataTable.ext.classes, { - "sTable": "dataTable", - "sNoFooter": "no-footer", - - /* Paging buttons */ - "sPageButton": "paginate_button", - "sPageButtonActive": "current", - "sPageButtonDisabled": "disabled", - - /* Striping classes */ - "sStripeOdd": "odd", - "sStripeEven": "even", - - /* Empty row */ - "sRowEmpty": "dataTables_empty", - - /* Features */ - "sWrapper": "dataTables_wrapper", - "sFilter": "dataTables_filter", - "sInfo": "dataTables_info", - "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */ - "sLength": "dataTables_length", - "sProcessing": "dataTables_processing", - - /* Sorting */ - "sSortAsc": "sorting_asc", - "sSortDesc": "sorting_desc", - "sSortable": "sorting", /* Sortable in both directions */ - "sSortableAsc": "sorting_desc_disabled", - "sSortableDesc": "sorting_asc_disabled", - "sSortableNone": "sorting_disabled", - "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */ - - /* Filtering */ - "sFilterInput": "", - - /* Page length */ - "sLengthSelect": "", - - /* Scrolling */ - "sScrollWrapper": "dataTables_scroll", - "sScrollHead": "dataTables_scrollHead", - "sScrollHeadInner": "dataTables_scrollHeadInner", - "sScrollBody": "dataTables_scrollBody", - "sScrollFoot": "dataTables_scrollFoot", - "sScrollFootInner": "dataTables_scrollFootInner", - - /* Misc */ - "sHeaderTH": "", - "sFooterTH": "", - - // Deprecated - "sSortJUIAsc": "", - "sSortJUIDesc": "", - "sSortJUI": "", - "sSortJUIAscAllowed": "", - "sSortJUIDescAllowed": "", - "sSortJUIWrapper": "", - "sSortIcon": "", - "sJUIHeader": "", - "sJUIFooter": "" - } ); - - - var extPagination = DataTable.ext.pager; - - function _numbers ( page, pages ) { - var - numbers = [], - buttons = extPagination.numbers_length, - half = Math.floor( buttons / 2 ), - i = 1; - - if ( pages <= buttons ) { - numbers = _range( 0, pages ); - } - else if ( page <= half ) { - numbers = _range( 0, buttons-2 ); - numbers.push( 'ellipsis' ); - numbers.push( pages-1 ); - } - else if ( page >= pages - 1 - half ) { - numbers = _range( pages-(buttons-2), pages ); - numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6 - numbers.splice( 0, 0, 0 ); - } - else { - numbers = _range( page-half+2, page+half-1 ); - numbers.push( 'ellipsis' ); - numbers.push( pages-1 ); - numbers.splice( 0, 0, 'ellipsis' ); - numbers.splice( 0, 0, 0 ); - } - - numbers.DT_el = 'span'; - return numbers; - } - - - $.extend( extPagination, { - simple: function ( page, pages ) { - return [ 'previous', 'next' ]; - }, - - full: function ( page, pages ) { - return [ 'first', 'previous', 'next', 'last' ]; - }, - - numbers: function ( page, pages ) { - return [ _numbers(page, pages) ]; - }, - - simple_numbers: function ( page, pages ) { - return [ 'previous', _numbers(page, pages), 'next' ]; - }, - - full_numbers: function ( page, pages ) { - return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ]; - }, - - first_last_numbers: function (page, pages) { - return ['first', _numbers(page, pages), 'last']; - }, - - // For testing and plug-ins to use - _numbers: _numbers, - - // Number of number buttons (including ellipsis) to show. _Must be odd!_ - numbers_length: 7 - } ); - - - $.extend( true, DataTable.ext.renderer, { - pageButton: { - _: function ( settings, host, idx, buttons, page, pages ) { - var classes = settings.oClasses; - var lang = settings.oLanguage.oPaginate; - var aria = settings.oLanguage.oAria.paginate || {}; - var btnDisplay, btnClass, counter=0; - - var attach = function( container, buttons ) { - var i, ien, node, button, tabIndex; - var disabledClass = classes.sPageButtonDisabled; - var clickHandler = function ( e ) { - _fnPageChange( settings, e.data.action, true ); - }; - - for ( i=0, ien=buttons.length ; i' ) - .appendTo( container ); - attach( inner, button ); - } - else { - btnDisplay = null; - btnClass = button; - tabIndex = settings.iTabIndex; - - switch ( button ) { - case 'ellipsis': - container.append(''); - break; - - case 'first': - btnDisplay = lang.sFirst; - - if ( page === 0 ) { - tabIndex = -1; - btnClass += ' ' + disabledClass; - } - break; - - case 'previous': - btnDisplay = lang.sPrevious; - - if ( page === 0 ) { - tabIndex = -1; - btnClass += ' ' + disabledClass; - } - break; - - case 'next': - btnDisplay = lang.sNext; - - if ( pages === 0 || page === pages-1 ) { - tabIndex = -1; - btnClass += ' ' + disabledClass; - } - break; - - case 'last': - btnDisplay = lang.sLast; - - if ( pages === 0 || page === pages-1 ) { - tabIndex = -1; - btnClass += ' ' + disabledClass; - } - break; - - default: - btnDisplay = settings.fnFormatNumber( button + 1 ); - btnClass = page === button ? - classes.sPageButtonActive : ''; - break; - } - - if ( btnDisplay !== null ) { - node = $('', { - 'class': classes.sPageButton+' '+btnClass, - 'aria-controls': settings.sTableId, - 'aria-label': aria[ button ], - 'data-dt-idx': counter, - 'tabindex': tabIndex, - 'id': idx === 0 && typeof button === 'string' ? - settings.sTableId +'_'+ button : - null - } ) - .html( btnDisplay ) - .appendTo( container ); - - _fnBindAction( - node, {action: button}, clickHandler - ); - - counter++; - } - } - } - }; - - // IE9 throws an 'unknown error' if document.activeElement is used - // inside an iframe or frame. Try / catch the error. Not good for - // accessibility, but neither are frames. - var activeEl; - - try { - // Because this approach is destroying and recreating the paging - // elements, focus is lost on the select button which is bad for - // accessibility. So we want to restore focus once the draw has - // completed - activeEl = $(host).find(document.activeElement).data('dt-idx'); - } - catch (e) {} - - attach( $(host).empty(), buttons ); - - if ( activeEl !== undefined ) { - $(host).find( '[data-dt-idx='+activeEl+']' ).trigger('focus'); - } - } - } - } ); - - - - // Built in type detection. See model.ext.aTypes for information about - // what is required from this methods. - $.extend( DataTable.ext.type.detect, [ - // Plain numbers - first since V8 detects some plain numbers as dates - // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...). - function ( d, settings ) - { - var decimal = settings.oLanguage.sDecimal; - return _isNumber( d, decimal ) ? 'num'+decimal : null; - }, - - // Dates (only those recognised by the browser's Date.parse) - function ( d, settings ) - { - // V8 tries _very_ hard to make a string passed into `Date.parse()` - // valid, so we need to use a regex to restrict date formats. Use a - // plug-in for anything other than ISO8601 style strings - if ( d && !(d instanceof Date) && ! _re_date.test(d) ) { - return null; - } - var parsed = Date.parse(d); - return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null; - }, - - // Formatted numbers - function ( d, settings ) - { - var decimal = settings.oLanguage.sDecimal; - return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null; - }, - - // HTML numeric - function ( d, settings ) - { - var decimal = settings.oLanguage.sDecimal; - return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null; - }, - - // HTML numeric, formatted - function ( d, settings ) - { - var decimal = settings.oLanguage.sDecimal; - return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null; - }, - - // HTML (this is strict checking - there must be html) - function ( d, settings ) - { - return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ? - 'html' : null; - } - ] ); - - - - // Filter formatting functions. See model.ext.ofnSearch for information about - // what is required from these methods. - // - // Note that additional search methods are added for the html numbers and - // html formatted numbers by `_addNumericSort()` when we know what the decimal - // place is - - - $.extend( DataTable.ext.type.search, { - html: function ( data ) { - return _empty(data) ? - data : - typeof data === 'string' ? - data - .replace( _re_new_lines, " " ) - .replace( _re_html, "" ) : - ''; - }, - - string: function ( data ) { - return _empty(data) ? - data : - typeof data === 'string' ? - data.replace( _re_new_lines, " " ) : - data; - } - } ); - - - - var __numericReplace = function ( d, decimalPlace, re1, re2 ) { - if ( d !== 0 && (!d || d === '-') ) { - return -Infinity; - } - - // If a decimal place other than `.` is used, it needs to be given to the - // function so we can detect it and replace with a `.` which is the only - // decimal place Javascript recognises - it is not locale aware. - if ( decimalPlace ) { - d = _numToDecimal( d, decimalPlace ); - } - - if ( d.replace ) { - if ( re1 ) { - d = d.replace( re1, '' ); - } - - if ( re2 ) { - d = d.replace( re2, '' ); - } - } - - return d * 1; - }; - - - // Add the numeric 'deformatting' functions for sorting and search. This is done - // in a function to provide an easy ability for the language options to add - // additional methods if a non-period decimal place is used. - function _addNumericSort ( decimalPlace ) { - $.each( - { - // Plain numbers - "num": function ( d ) { - return __numericReplace( d, decimalPlace ); - }, - - // Formatted numbers - "num-fmt": function ( d ) { - return __numericReplace( d, decimalPlace, _re_formatted_numeric ); - }, - - // HTML numeric - "html-num": function ( d ) { - return __numericReplace( d, decimalPlace, _re_html ); - }, - - // HTML numeric, formatted - "html-num-fmt": function ( d ) { - return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric ); - } - }, - function ( key, fn ) { - // Add the ordering method - _ext.type.order[ key+decimalPlace+'-pre' ] = fn; - - // For HTML types add a search formatter that will strip the HTML - if ( key.match(/^html\-/) ) { - _ext.type.search[ key+decimalPlace ] = _ext.type.search.html; - } - } - ); - } - - - // Default sort methods - $.extend( _ext.type.order, { - // Dates - "date-pre": function ( d ) { - var ts = Date.parse( d ); - return isNaN(ts) ? -Infinity : ts; - }, - - // html - "html-pre": function ( a ) { - return _empty(a) ? - '' : - a.replace ? - a.replace( /<.*?>/g, "" ).toLowerCase() : - a+''; - }, - - // string - "string-pre": function ( a ) { - // This is a little complex, but faster than always calling toString, - // http://jsperf.com/tostring-v-check - return _empty(a) ? - '' : - typeof a === 'string' ? - a.toLowerCase() : - ! a.toString ? - '' : - a.toString(); - }, - - // string-asc and -desc are retained only for compatibility with the old - // sort methods - "string-asc": function ( x, y ) { - return ((x < y) ? -1 : ((x > y) ? 1 : 0)); - }, - - "string-desc": function ( x, y ) { - return ((x < y) ? 1 : ((x > y) ? -1 : 0)); - } - } ); - - - // Numeric sorting types - order doesn't matter here - _addNumericSort( '' ); - - - $.extend( true, DataTable.ext.renderer, { - header: { - _: function ( settings, cell, column, classes ) { - // No additional mark-up required - // Attach a sort listener to update on sort - note that using the - // `DT` namespace will allow the event to be removed automatically - // on destroy, while the `dt` namespaced event is the one we are - // listening for - $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { - if ( settings !== ctx ) { // need to check this this is the host - return; // table, not a nested one - } - - var colIdx = column.idx; - - cell - .removeClass( - classes.sSortAsc +' '+ - classes.sSortDesc - ) - .addClass( columns[ colIdx ] == 'asc' ? - classes.sSortAsc : columns[ colIdx ] == 'desc' ? - classes.sSortDesc : - column.sSortingClass - ); - } ); - }, - - jqueryui: function ( settings, cell, column, classes ) { - $('
    ') - .addClass( classes.sSortJUIWrapper ) - .append( cell.contents() ) - .append( $('') - .addClass( classes.sSortIcon+' '+column.sSortingClassJUI ) - ) - .appendTo( cell ); - - // Attach a sort listener to update on sort - $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { - if ( settings !== ctx ) { - return; - } - - var colIdx = column.idx; - - cell - .removeClass( classes.sSortAsc +" "+classes.sSortDesc ) - .addClass( columns[ colIdx ] == 'asc' ? - classes.sSortAsc : columns[ colIdx ] == 'desc' ? - classes.sSortDesc : - column.sSortingClass - ); - - cell - .find( 'span.'+classes.sSortIcon ) - .removeClass( - classes.sSortJUIAsc +" "+ - classes.sSortJUIDesc +" "+ - classes.sSortJUI +" "+ - classes.sSortJUIAscAllowed +" "+ - classes.sSortJUIDescAllowed - ) - .addClass( columns[ colIdx ] == 'asc' ? - classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ? - classes.sSortJUIDesc : - column.sSortingClassJUI - ); - } ); - } - } - } ); - - /* - * Public helper functions. These aren't used internally by DataTables, or - * called by any of the options passed into DataTables, but they can be used - * externally by developers working with DataTables. They are helper functions - * to make working with DataTables a little bit easier. - */ - - var __htmlEscapeEntities = function ( d ) { - if (Array.isArray(d)) { - d = d.join(','); - } - - return typeof d === 'string' ? - d - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') : - d; - }; - - /** - * Helpers for `columns.render`. - * - * The options defined here can be used with the `columns.render` initialisation - * option to provide a display renderer. The following functions are defined: - * - * * `number` - Will format numeric data (defined by `columns.data`) for - * display, retaining the original unformatted data for sorting and filtering. - * It takes 5 parameters: - * * `string` - Thousands grouping separator - * * `string` - Decimal point indicator - * * `integer` - Number of decimal points to show - * * `string` (optional) - Prefix. - * * `string` (optional) - Postfix (/suffix). - * * `text` - Escape HTML to help prevent XSS attacks. It has no optional - * parameters. - * - * @example - * // Column definition using the number renderer - * { - * data: "salary", - * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' ) - * } - * - * @namespace - */ - DataTable.render = { - number: function ( thousands, decimal, precision, prefix, postfix ) { - return { - display: function ( d ) { - if ( typeof d !== 'number' && typeof d !== 'string' ) { - return d; - } - - var negative = d < 0 ? '-' : ''; - var flo = parseFloat( d ); - - // If NaN then there isn't much formatting that we can do - just - // return immediately, escaping any HTML (this was supposed to - // be a number after all) - if ( isNaN( flo ) ) { - return __htmlEscapeEntities( d ); - } - - flo = flo.toFixed( precision ); - d = Math.abs( flo ); - - var intPart = parseInt( d, 10 ); - var floatPart = precision ? - decimal+(d - intPart).toFixed( precision ).substring( 2 ): - ''; - - // If zero, then can't have a negative prefix - if (intPart === 0 && parseFloat(floatPart) === 0) { - negative = ''; - } - - return negative + (prefix||'') + - intPart.toString().replace( - /\B(?=(\d{3})+(?!\d))/g, thousands - ) + - floatPart + - (postfix||''); - } - }; - }, - - text: function () { - return { - display: __htmlEscapeEntities, - filter: __htmlEscapeEntities - }; - } - }; - - - /* - * This is really a good bit rubbish this method of exposing the internal methods - * publicly... - To be fixed in 2.0 using methods on the prototype - */ - - - /** - * Create a wrapper function for exporting an internal functions to an external API. - * @param {string} fn API function name - * @returns {function} wrapped function - * @memberof DataTable#internal - */ - function _fnExternApiFunc (fn) - { - return function() { - var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat( - Array.prototype.slice.call(arguments) - ); - return DataTable.ext.internal[fn].apply( this, args ); - }; - } - - - /** - * Reference to internal functions for use by plug-in developers. Note that - * these methods are references to internal functions and are considered to be - * private. If you use these methods, be aware that they are liable to change - * between versions. - * @namespace - */ - $.extend( DataTable.ext.internal, { - _fnExternApiFunc: _fnExternApiFunc, - _fnBuildAjax: _fnBuildAjax, - _fnAjaxUpdate: _fnAjaxUpdate, - _fnAjaxParameters: _fnAjaxParameters, - _fnAjaxUpdateDraw: _fnAjaxUpdateDraw, - _fnAjaxDataSrc: _fnAjaxDataSrc, - _fnAddColumn: _fnAddColumn, - _fnColumnOptions: _fnColumnOptions, - _fnAdjustColumnSizing: _fnAdjustColumnSizing, - _fnVisibleToColumnIndex: _fnVisibleToColumnIndex, - _fnColumnIndexToVisible: _fnColumnIndexToVisible, - _fnVisbleColumns: _fnVisbleColumns, - _fnGetColumns: _fnGetColumns, - _fnColumnTypes: _fnColumnTypes, - _fnApplyColumnDefs: _fnApplyColumnDefs, - _fnHungarianMap: _fnHungarianMap, - _fnCamelToHungarian: _fnCamelToHungarian, - _fnLanguageCompat: _fnLanguageCompat, - _fnBrowserDetect: _fnBrowserDetect, - _fnAddData: _fnAddData, - _fnAddTr: _fnAddTr, - _fnNodeToDataIndex: _fnNodeToDataIndex, - _fnNodeToColumnIndex: _fnNodeToColumnIndex, - _fnGetCellData: _fnGetCellData, - _fnSetCellData: _fnSetCellData, - _fnSplitObjNotation: _fnSplitObjNotation, - _fnGetObjectDataFn: _fnGetObjectDataFn, - _fnSetObjectDataFn: _fnSetObjectDataFn, - _fnGetDataMaster: _fnGetDataMaster, - _fnClearTable: _fnClearTable, - _fnDeleteIndex: _fnDeleteIndex, - _fnInvalidate: _fnInvalidate, - _fnGetRowElements: _fnGetRowElements, - _fnCreateTr: _fnCreateTr, - _fnBuildHead: _fnBuildHead, - _fnDrawHead: _fnDrawHead, - _fnDraw: _fnDraw, - _fnReDraw: _fnReDraw, - _fnAddOptionsHtml: _fnAddOptionsHtml, - _fnDetectHeader: _fnDetectHeader, - _fnGetUniqueThs: _fnGetUniqueThs, - _fnFeatureHtmlFilter: _fnFeatureHtmlFilter, - _fnFilterComplete: _fnFilterComplete, - _fnFilterCustom: _fnFilterCustom, - _fnFilterColumn: _fnFilterColumn, - _fnFilter: _fnFilter, - _fnFilterCreateSearch: _fnFilterCreateSearch, - _fnEscapeRegex: _fnEscapeRegex, - _fnFilterData: _fnFilterData, - _fnFeatureHtmlInfo: _fnFeatureHtmlInfo, - _fnUpdateInfo: _fnUpdateInfo, - _fnInfoMacros: _fnInfoMacros, - _fnInitialise: _fnInitialise, - _fnInitComplete: _fnInitComplete, - _fnLengthChange: _fnLengthChange, - _fnFeatureHtmlLength: _fnFeatureHtmlLength, - _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate, - _fnPageChange: _fnPageChange, - _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing, - _fnProcessingDisplay: _fnProcessingDisplay, - _fnFeatureHtmlTable: _fnFeatureHtmlTable, - _fnScrollDraw: _fnScrollDraw, - _fnApplyToChildren: _fnApplyToChildren, - _fnCalculateColumnWidths: _fnCalculateColumnWidths, - _fnThrottle: _fnThrottle, - _fnConvertToWidth: _fnConvertToWidth, - _fnGetWidestNode: _fnGetWidestNode, - _fnGetMaxLenString: _fnGetMaxLenString, - _fnStringToCss: _fnStringToCss, - _fnSortFlatten: _fnSortFlatten, - _fnSort: _fnSort, - _fnSortAria: _fnSortAria, - _fnSortListener: _fnSortListener, - _fnSortAttachListener: _fnSortAttachListener, - _fnSortingClasses: _fnSortingClasses, - _fnSortData: _fnSortData, - _fnSaveState: _fnSaveState, - _fnLoadState: _fnLoadState, - _fnImplementState: _fnImplementState, - _fnSettingsFromNode: _fnSettingsFromNode, - _fnLog: _fnLog, - _fnMap: _fnMap, - _fnBindAction: _fnBindAction, - _fnCallbackReg: _fnCallbackReg, - _fnCallbackFire: _fnCallbackFire, - _fnLengthOverflow: _fnLengthOverflow, - _fnRenderer: _fnRenderer, - _fnDataSource: _fnDataSource, - _fnRowAttributes: _fnRowAttributes, - _fnExtend: _fnExtend, - _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant - // in 1.10, so this dead-end function is - // added to prevent errors - } ); - - - // jQuery access - $.fn.dataTable = DataTable; - - // Provide access to the host jQuery object (circular reference) - DataTable.$ = $; - - // Legacy aliases - $.fn.dataTableSettings = DataTable.settings; - $.fn.dataTableExt = DataTable.ext; - - // With a capital `D` we return a DataTables API instance rather than a - // jQuery object - $.fn.DataTable = function ( opts ) { - return $(this).dataTable( opts ).api(); - }; - - // All properties that are available to $.fn.dataTable should also be - // available on $.fn.DataTable - $.each( DataTable, function ( prop, val ) { - $.fn.DataTable[ prop ] = val; - } ); - - return DataTable; -})); - - -/*! DataTables styling integration - * ©2018 SpryMedia Ltd - datatables.net/license - */ - -(function( factory ){ - if ( typeof define === 'function' && define.amd ) { - // AMD - define( ['jquery', 'datatables.net'], function ( $ ) { - return factory( $, window, document ); - } ); - } - else if ( typeof exports === 'object' ) { - // CommonJS - module.exports = function (root, $) { - if ( ! root ) { - root = window; - } - - if ( ! $ || ! $.fn.dataTable ) { - // Require DataTables, which attaches to jQuery, including - // jQuery if needed and have a $ property so we can access the - // jQuery object that is used - $ = require('datatables.net')(root, $).$; - } - - return factory( $, root, root.document ); - }; - } - else { - // Browser - factory( jQuery, window, document ); - } -}(function( $, window, document, undefined ) { - -return $.fn.dataTable; - -})); - - -/*! FixedColumns 4.0.1 - * 2019-2021 SpryMedia Ltd - datatables.net/license - */ -(function () { - 'use strict'; - - var $; - var dataTable; - function setJQuery(jq) { - $ = jq; - dataTable = $.fn.dataTable; - } - var FixedColumns = /** @class */ (function () { - function FixedColumns(settings, opts) { - var _this = this; - // Check that the required version of DataTables is included - if (!dataTable || !dataTable.versionCheck || !dataTable.versionCheck('1.10.0')) { - throw new Error('StateRestore requires DataTables 1.10 or newer'); - } - var table = new dataTable.Api(settings); - this.classes = $.extend(true, {}, FixedColumns.classes); - // Get options from user - this.c = $.extend(true, {}, FixedColumns.defaults, opts); - // Backwards compatibility for deprecated leftColumns - if (opts.left === undefined && this.c.leftColumns !== undefined) { - this.c.left = this.c.leftColumns; - } - // Backwards compatibility for deprecated rightColumns - if (opts.right === undefined && this.c.rightColumns !== undefined) { - this.c.right = this.c.rightColumns; - } - this.s = { - barWidth: 0, - dt: table, - rtl: $(table.table().node()).css('direction') === 'rtl' - }; - // Common CSS for all blockers - var blockerCSS = { - 'background-color': 'white', - 'bottom': '0px', - 'display': 'block', - 'position': 'absolute', - 'width': this.s.barWidth + 1 + 'px' - }; - this.dom = { - leftBottomBlocker: $('
    ') - .css(blockerCSS) - .css('left', 0) - .addClass(this.classes.leftBottomBlocker), - leftTopBlocker: $('
    ') - .css(blockerCSS) - .css({ - left: 0, - top: 0 - }) - .addClass(this.classes.leftTopBlocker), - rightBottomBlocker: $('
    ') - .css(blockerCSS) - .css('right', 0) - .addClass(this.classes.rightBottomBlocker), - rightTopBlocker: $('
    ') - .css(blockerCSS) - .css({ - right: 0, - top: 0 - }) - .addClass(this.classes.rightTopBlocker) - }; - if (this.s.dt.settings()[0]._bInitComplete) { - // Fixed Columns Initialisation - this._addStyles(); - this._setKeyTableListener(); - } - else { - table.one('preInit.dt', function () { - // Fixed Columns Initialisation - _this._addStyles(); - _this._setKeyTableListener(); - }); - } - // Make class available through dt object - table.settings()[0]._fixedColumns = this; - return this; - } - /** - * Getter/Setter for the `fixedColumns.left` property - * - * @param newVal Optional. If present this will be the new value for the number of left fixed columns - * @returns The number of left fixed columns - */ - FixedColumns.prototype.left = function (newVal) { - // If the value is to change - if (newVal !== undefined) { - // Set the new values and redraw the columns - this.c.left = newVal; - this._addStyles(); - } - return this.c.left; - }; - /** - * Getter/Setter for the `fixedColumns.left` property - * - * @param newVal Optional. If present this will be the new value for the number of right fixed columns - * @returns The number of right fixed columns - */ - FixedColumns.prototype.right = function (newVal) { - // If the value is to change - if (newVal !== undefined) { - // Set the new values and redraw the columns - this.c.right = newVal; - this._addStyles(); - } - return this.c.right; - }; - /** - * Iterates over the columns, fixing the appropriate ones to the left and right - */ - FixedColumns.prototype._addStyles = function () { - // Set the bar width if vertical scrolling is enabled - if (this.s.dt.settings()[0].oScroll.sY) { - var scroll_1 = $(this.s.dt.table().node()).closest('div.dataTables_scrollBody')[0]; - var barWidth = this.s.dt.settings()[0].oBrowser.barWidth; - if (scroll_1.offsetWidth - scroll_1.clientWidth >= barWidth) { - this.s.barWidth = barWidth; - } - else { - this.s.barWidth = 0; - } - this.dom.rightTopBlocker.css('width', this.s.barWidth + 1); - this.dom.leftTopBlocker.css('width', this.s.barWidth + 1); - this.dom.rightBottomBlocker.css('width', this.s.barWidth + 1); - this.dom.leftBottomBlocker.css('width', this.s.barWidth + 1); - } - var parentDiv = null; - // Get the header and it's height - var header = this.s.dt.column(0).header(); - var headerHeight = null; - if (header !== null) { - header = $(header); - headerHeight = header.outerHeight() + 1; - parentDiv = $(header.closest('div.dataTables_scroll')).css('position', 'relative'); - } - // Get the footer and it's height - var footer = this.s.dt.column(0).footer(); - var footerHeight = null; - if (footer !== null) { - footer = $(footer); - footerHeight = footer.outerHeight(); - // Only attempt to retrieve the parentDiv if it has not been retrieved already - if (parentDiv === null) { - parentDiv = $(footer.closest('div.dataTables_scroll')).css('position', 'relative'); - } - } - // Get the number of columns in the table - this is used often so better to only make 1 api call - var numCols = this.s.dt.columns().data().toArray().length; - // Tracker for the number of pixels should be left to the left of the table - var distLeft = 0; - // Sometimes the headers have slightly different widths so need to track them individually - var headLeft = 0; - // Get all of the row elements in the table - var rows = $(this.s.dt.table().node()).children('tbody').children('tr'); - var invisibles = 0; - // When working from right to left we need to know how many are invisible before a point, - // without including those that are invisible after - var prevInvisible = new Map(); - // Iterate over all of the columns - for (var i = 0; i < numCols; i++) { - var column = this.s.dt.column(i); - // Set the map for the previous column - if (i > 0) { - prevInvisible.set(i - 1, invisibles); - } - if (!column.visible()) { - invisibles++; - continue; - } - // Get the columns header and footer element - var colHeader = $(column.header()); - var colFooter = $(column.footer()); - // If i is less than the value of left then this column should be fixed left - if (i - invisibles < this.c.left) { - $(this.s.dt.table().node()).addClass(this.classes.tableFixedLeft); - parentDiv.addClass(this.classes.tableFixedLeft); - // Add the width of the previous node - only if we are on atleast the second column - if (i - invisibles > 0) { - var prevIdx = i; - // Simply using the number of hidden columns doesn't work here, - // if the first is hidden then this would be thrown off - while (prevIdx + 1 < numCols) { - var prevCol = this.s.dt.column(prevIdx - 1, { page: 'current' }); - if (prevCol.visible()) { - distLeft += $(prevCol.nodes()[0]).outerWidth(); - headLeft += prevCol.header() ? - $(prevCol.header()).outerWidth() : - prevCol.footer() ? - $(prevCol.header()).outerWidth() : - 0; - break; - } - prevIdx--; - } - } - // Iterate over all of the rows, fixing the cell to the left - for (var _i = 0, rows_1 = rows; _i < rows_1.length; _i++) { - var row = rows_1[_i]; - $($(row).children()[i - invisibles]) - .css(this._getCellCSS(false, distLeft, 'left')) - .addClass(this.classes.fixedLeft); - } - // Add the css for the header and the footer - colHeader - .css(this._getCellCSS(true, headLeft, 'left')) - .addClass(this.classes.fixedLeft); - colFooter - .css(this._getCellCSS(true, headLeft, 'left')) - .addClass(this.classes.fixedLeft); - } - else { - // Iteriate through all of the rows, making sure they aren't currently trying to fix left - for (var _a = 0, rows_2 = rows; _a < rows_2.length; _a++) { - var row = rows_2[_a]; - var cell = $($(row).children()[i - invisibles]); - // If the cell is trying to fix to the left, remove the class and the css - if (cell.hasClass(this.classes.fixedLeft)) { - cell - .css(this._clearCellCSS('left')) - .removeClass(this.classes.fixedLeft); - } - } - // Make sure the header for this column isn't fixed left - if (colHeader.hasClass(this.classes.fixedLeft)) { - colHeader - .css(this._clearCellCSS('left')) - .removeClass(this.classes.fixedLeft); - } - // Make sure the footer for this column isn't fixed left - if (colFooter.hasClass(this.classes.fixedLeft)) { - colFooter - .css(this._clearCellCSS('left')) - .removeClass(this.classes.fixedLeft); - } - } - } - // If there is a header with the index class and reading rtl then add left top blocker - if (header !== null && !header.hasClass('index')) { - if (this.s.rtl) { - this.dom.leftTopBlocker.outerHeight(headerHeight); - parentDiv.append(this.dom.leftTopBlocker); - } - else { - this.dom.rightTopBlocker.outerHeight(headerHeight); - parentDiv.append(this.dom.rightTopBlocker); - } - } - // If there is a footer with the index class and reading rtl then add left bottom blocker - if (footer !== null && !footer.hasClass('index')) { - if (this.s.rtl) { - this.dom.leftBottomBlocker.outerHeight(footerHeight); - parentDiv.append(this.dom.leftBottomBlocker); - } - else { - this.dom.rightBottomBlocker.outerHeight(footerHeight); - parentDiv.append(this.dom.rightBottomBlocker); - } - } - var distRight = 0; - var headRight = 0; - // Counter for the number of invisible columns so far - var rightInvisibles = 0; - for (var i = numCols - 1; i >= 0; i--) { - var column = this.s.dt.column(i); - // If a column is invisible just skip it - if (!column.visible()) { - rightInvisibles++; - continue; - } - // Get the columns header and footer element - var colHeader = $(column.header()); - var colFooter = $(column.footer()); - // Get the number of visible columns that came before this one - var prev = prevInvisible.get(i); - if (prev === undefined) { - // If it wasn't set then it was the last column so just use the final value - prev = invisibles; - } - if (i + rightInvisibles >= numCols - this.c.right) { - $(this.s.dt.table().node()).addClass(this.classes.tableFixedRight); - parentDiv.addClass(this.classes.tableFixedRight); - // Add the widht of the previous node, only if we are on atleast the second column - if (i + 1 + rightInvisibles < numCols) { - var prevIdx = i; - // Simply using the number of hidden columns doesn't work here, - // if the first is hidden then this would be thrown off - while (prevIdx + 1 < numCols) { - var prevCol = this.s.dt.column(prevIdx + 1, { page: 'current' }); - if (prevCol.visible()) { - distRight += $(prevCol.nodes()[0]).outerWidth(); - headRight += prevCol.header() ? - $(prevCol.header()).outerWidth() : - prevCol.footer() ? - $(prevCol.header()).outerWidth() : - 0; - break; - } - prevIdx++; - } - } - // Iterate over all of the rows, fixing the cell to the right - for (var _b = 0, rows_3 = rows; _b < rows_3.length; _b++) { - var row = rows_3[_b]; - $($(row).children()[i - prev]) - .css(this._getCellCSS(false, distRight, 'right')) - .addClass(this.classes.fixedRight); - } - // Add the css for the header and the footer - colHeader - .css(this._getCellCSS(true, headRight, 'right')) - .addClass(this.classes.fixedRight); - colFooter - .css(this._getCellCSS(true, headRight, 'right')) - .addClass(this.classes.fixedRight); - } - else { - // Iteriate through all of the rows, making sure they aren't currently trying to fix right - for (var _c = 0, rows_4 = rows; _c < rows_4.length; _c++) { - var row = rows_4[_c]; - var cell = $($(row).children()[i - prev]); - // If the cell is trying to fix to the right, remove the class and the css - if (cell.hasClass(this.classes.fixedRight)) { - cell - .css(this._clearCellCSS('right')) - .removeClass(this.classes.fixedRight); - } - } - // Make sure the header for this column isn't fixed right - if (colHeader.hasClass(this.classes.fixedRight)) { - colHeader - .css(this._clearCellCSS('right')) - .removeClass(this.classes.fixedRight); - } - // Make sure the footer for this column isn't fixed right - if (colFooter.hasClass(this.classes.fixedRight)) { - colFooter - .css(this._clearCellCSS('right')) - .removeClass(this.classes.fixedRight); - } - } - } - // If there is a header with the index class and reading rtl then add right top blocker - if (header) { - if (!this.s.rtl) { - this.dom.rightTopBlocker.outerHeight(headerHeight); - parentDiv.append(this.dom.rightTopBlocker); - } - else { - this.dom.leftTopBlocker.outerHeight(headerHeight); - parentDiv.append(this.dom.leftTopBlocker); - } - } - // If there is a footer with the index class and reading rtl then add right bottom blocker - if (footer) { - if (!this.s.rtl) { - this.dom.rightBottomBlocker.outerHeight(footerHeight); - parentDiv.append(this.dom.rightBottomBlocker); - } - else { - this.dom.leftBottomBlocker.outerHeight(footerHeight); - parentDiv.append(this.dom.leftBottomBlocker); - } - } - }; - /** - * Gets the correct CSS for the cell, header or footer based on options provided - * - * @param header Whether this cell is a header or a footer - * @param dist The distance that the cell should be moved away from the edge - * @param lr Indicator of fixing to the left or the right - * @returns An object containing the correct css - */ - FixedColumns.prototype._getCellCSS = function (header, dist, lr) { - if (lr === 'left') { - return !this.s.rtl ? - { - left: dist + 'px', - position: 'sticky' - } : - { - position: 'sticky', - right: dist + (header ? this.s.barWidth : 0) + 'px' - }; - } - else { - return !this.s.rtl ? - { - position: 'sticky', - right: dist + (header ? this.s.barWidth : 0) + 'px' - } : - { - left: dist + 'px', - position: 'sticky' - }; - } - }; - /** - * Gets the css that is required to clear the fixing to a side - * - * @param lr Indicator of fixing to the left or the right - * @returns An object containing the correct css - */ - FixedColumns.prototype._clearCellCSS = function (lr) { - if (lr === 'left') { - return !this.s.rtl ? - { - left: '', - position: '' - } : - { - position: '', - right: '' - }; - } - else { - return !this.s.rtl ? - { - position: '', - right: '' - } : - { - left: '', - position: '' - }; - } - }; - FixedColumns.prototype._setKeyTableListener = function () { - var _this = this; - this.s.dt.on('key-focus', function (e, dt, cell) { - var cellPos = $(cell.node()).offset(); - var scroll = $($(_this.s.dt.table().node()).closest('div.dataTables_scrollBody')); - // If there are fixed columns to the left - if (_this.c.left > 0) { - // Get the rightmost left fixed column header, it's position and it's width - var rightMost = $(_this.s.dt.column(_this.c.left - 1).header()); - var rightMostPos = rightMost.offset(); - var rightMostWidth = rightMost.outerWidth(); - // If the current highlighted cell is left of the rightmost cell on the screen - if (cellPos.left < rightMostPos.left + rightMostWidth) { - // Scroll it into view - var currScroll = scroll.scrollLeft(); - scroll.scrollLeft(currScroll - (rightMostPos.left + rightMostWidth - cellPos.left)); - } - } - // If there are fixed columns to the right - if (_this.c.right > 0) { - // Get the number of columns and the width of the cell as doing right side calc - var numCols = _this.s.dt.columns().data().toArray().length; - var cellWidth = $(cell.node()).outerWidth(); - // Get the leftmost right fixed column header and it's position - var leftMost = $(_this.s.dt.column(numCols - _this.c.right).header()); - var leftMostPos = leftMost.offset(); - // If the current highlighted cell is right of the leftmost cell on the screen - if (cellPos.left + cellWidth > leftMostPos.left) { - // Scroll it into view - var currScroll = scroll.scrollLeft(); - scroll.scrollLeft(currScroll - (leftMostPos.left - (cellPos.left + cellWidth))); - } - } - }); - // Whenever a draw occurs there is potential for the data to have changed and therefore also the column widths - // Therefore it is necessary to recalculate the values for the fixed columns - this.s.dt.on('draw', function () { - _this._addStyles(); - }); - this.s.dt.on('column-reorder', function () { - _this._addStyles(); - }); - this.s.dt.on('column-visibility', function () { - setTimeout(function () { - _this._addStyles(); - }, 50); - }); - }; - FixedColumns.version = '4.0.1'; - FixedColumns.classes = { - fixedLeft: 'dtfc-fixed-left', - fixedRight: 'dtfc-fixed-right', - leftBottomBlocker: 'dtfc-left-bottom-blocker', - leftTopBlocker: 'dtfc-left-top-blocker', - rightBottomBlocker: 'dtfc-right-bottom-blocker', - rightTopBlocker: 'dtfc-right-top-blocker', - tableFixedLeft: 'dtfc-has-left', - tableFixedRight: 'dtfc-has-right' - }; - FixedColumns.defaults = { - i18n: { - button: 'FixedColumns' - }, - left: 1, - right: 0 - }; - return FixedColumns; - }()); - - /*! FixedColumns 4.0.1 - * 2019-2021 SpryMedia Ltd - datatables.net/license - */ - // DataTables extensions common UMD. Note that this allows for AMD, CommonJS - // (with window and jQuery being allowed as parameters to the returned - // function) or just default browser loading. - (function (factory) { - if (typeof define === 'function' && define.amd) { - // AMD - define(['jquery', 'datatables.net'], function ($) { - return factory($, window, document); - }); - } - else if (typeof exports === 'object') { - // CommonJS - module.exports = function (root, $) { - if (!root) { - root = window; - } - if (!$ || !$.fn.dataTable) { - // eslint-disable-next-line @typescript-eslint/no-var-requires - $ = require('datatables.net')(root, $).$; - } - return factory($, root, root.document); - }; - } - else { - // Browser - assume jQuery has already been loaded - factory(window.jQuery, window, document); - } - }(function ($, window, document) { - setJQuery($); - var dataTable = $.fn.dataTable; - $.fn.dataTable.FixedColumns = FixedColumns; - $.fn.DataTable.FixedColumns = FixedColumns; - var apiRegister = $.fn.dataTable.Api.register; - apiRegister('fixedColumns()', function () { - return this; - }); - apiRegister('fixedColumns().left()', function (newVal) { - var ctx = this.context[0]; - if (newVal !== undefined) { - ctx._fixedColumns.left(newVal); - return this; - } - else { - return ctx._fixedColumns.left(); - } - }); - apiRegister('fixedColumns().right()', function (newVal) { - var ctx = this.context[0]; - if (newVal !== undefined) { - ctx._fixedColumns.right(newVal); - return this; - } - else { - return ctx._fixedColumns.right(); - } - }); - $.fn.dataTable.ext.buttons.fixedColumns = { - action: function (e, dt, node, config) { - if ($(node).attr('active')) { - $(node).removeAttr('active').removeClass('active'); - dt.fixedColumns().left(0); - dt.fixedColumns().right(0); - } - else { - $(node).attr('active', true).addClass('active'); - dt.fixedColumns().left(config.config.left); - dt.fixedColumns().right(config.config.right); - } - }, - config: { - left: 1, - right: 0 - }, - init: function (dt, node, config) { - if (dt.settings()[0]._fixedColumns === undefined) { - _init(dt.settings(), config); - } - $(node).attr('active', true).addClass('active'); - dt.button(node).text(config.text || dt.i18n('buttons.fixedColumns', dt.settings()[0]._fixedColumns.c.i18n.button)); - }, - text: null - }; - function _init(settings, options) { - if (options === void 0) { options = null; } - var api = new dataTable.Api(settings); - var opts = options - ? options - : api.init().fixedColumns || dataTable.defaults.fixedColumns; - var fixedColumns = new FixedColumns(api, opts); - return fixedColumns; - } - // Attach a listener to the document which listens for DataTables initialisation - // events so we can automatically initialise - $(document).on('init.dt.dtfc', function (e, settings) { - if (e.namespace !== 'dt') { - return; - } - if (settings.oInit.fixedColumns || - dataTable.defaults.fixedColumns) { - if (!settings._fixedColumns) { - _init(settings, null); - } - } - }); - })); - -}()); - - -/*! FixedHeader 3.2.1 - * ©2009-2021 SpryMedia Ltd - datatables.net/license - */ - -/** - * @summary FixedHeader - * @description Fix a table's header or footer, so it is always visible while - * scrolling - * @version 3.2.1 - * @file dataTables.fixedHeader.js - * @author SpryMedia Ltd (www.sprymedia.co.uk) - * @contact www.sprymedia.co.uk/contact - * @copyright Copyright 2009-2021 SpryMedia Ltd. - * - * This source file is free software, available under the following license: - * MIT license - http://datatables.net/license/mit - * - * This source file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. - * - * For details please refer to: http://www.datatables.net - */ - -(function( factory ){ - if ( typeof define === 'function' && define.amd ) { - // AMD - define( ['jquery', 'datatables.net'], function ( $ ) { - return factory( $, window, document ); - } ); - } - else if ( typeof exports === 'object' ) { - // CommonJS - module.exports = function (root, $) { - if ( ! root ) { - root = window; - } - - if ( ! $ || ! $.fn.dataTable ) { - $ = require('datatables.net')(root, $).$; - } - - return factory( $, root, root.document ); - }; - } - else { - // Browser - factory( jQuery, window, document ); - } -}(function( $, window, document, undefined ) { -'use strict'; -var DataTable = $.fn.dataTable; - - -var _instCounter = 0; - -var FixedHeader = function ( dt, config ) { - // Sanity check - you just know it will happen - if ( ! (this instanceof FixedHeader) ) { - throw "FixedHeader must be initialised with the 'new' keyword."; - } - - // Allow a boolean true for defaults - if ( config === true ) { - config = {}; - } - - dt = new DataTable.Api( dt ); - - this.c = $.extend( true, {}, FixedHeader.defaults, config ); - - this.s = { - dt: dt, - position: { - theadTop: 0, - tbodyTop: 0, - tfootTop: 0, - tfootBottom: 0, - width: 0, - left: 0, - tfootHeight: 0, - theadHeight: 0, - windowHeight: $(window).height(), - visible: true - }, - headerMode: null, - footerMode: null, - autoWidth: dt.settings()[0].oFeatures.bAutoWidth, - namespace: '.dtfc'+(_instCounter++), - scrollLeft: { - header: -1, - footer: -1 - }, - enable: true - }; - - this.dom = { - floatingHeader: null, - thead: $(dt.table().header()), - tbody: $(dt.table().body()), - tfoot: $(dt.table().footer()), - header: { - host: null, - floating: null, - floatingParent: $('
    '), - placeholder: null - }, - footer: { - host: null, - floating: null, - floatingParent: $('
    '), - placeholder: null - } - }; - - this.dom.header.host = this.dom.thead.parent(); - this.dom.footer.host = this.dom.tfoot.parent(); - - var dtSettings = dt.settings()[0]; - if ( dtSettings._fixedHeader ) { - throw "FixedHeader already initialised on table "+dtSettings.nTable.id; - } - - dtSettings._fixedHeader = this; - - this._constructor(); -}; - - -/* - * Variable: FixedHeader - * Purpose: Prototype for FixedHeader - * Scope: global - */ -$.extend( FixedHeader.prototype, { - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * API methods - */ - - /** - * Kill off FH and any events - */ - destroy: function () { - this.s.dt.off( '.dtfc' ); - $(window).off( this.s.namespace ); - - if ( this.c.header ) { - this._modeChange( 'in-place', 'header', true ); - } - - if ( this.c.footer && this.dom.tfoot.length ) { - this._modeChange( 'in-place', 'footer', true ); - } - }, - - /** - * Enable / disable the fixed elements - * - * @param {boolean} enable `true` to enable, `false` to disable - */ - enable: function ( enable, update ) - { - this.s.enable = enable; - - if ( update || update === undefined ) { - this._positions(); - this._scroll( true ); - } - }, - - /** - * Get enabled status - */ - enabled: function () - { - return this.s.enable; - }, - - /** - * Set header offset - * - * @param {int} new value for headerOffset - */ - headerOffset: function ( offset ) - { - if ( offset !== undefined ) { - this.c.headerOffset = offset; - this.update(); - } - - return this.c.headerOffset; - }, - - /** - * Set footer offset - * - * @param {int} new value for footerOffset - */ - footerOffset: function ( offset ) - { - if ( offset !== undefined ) { - this.c.footerOffset = offset; - this.update(); - } - - return this.c.footerOffset; - }, - - - /** - * Recalculate the position of the fixed elements and force them into place - */ - update: function (force) - { - var table = this.s.dt.table().node(); - - if ( $(table).is(':visible') ) { - this.enable( true, false ); - } - else { - this.enable( false, false ); - } - - // Don't update if header is not in the document atm (due to - // async events) - if ($(table).children('thead').length === 0) { - return; - } - - this._positions(); - this._scroll( force !== undefined ? force : true ); - }, - - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Constructor - */ - - /** - * FixedHeader constructor - adding the required event listeners and - * simple initialisation - * - * @private - */ - _constructor: function () - { - var that = this; - var dt = this.s.dt; - - $(window) - .on( 'scroll'+this.s.namespace, function () { - that._scroll(); - } ) - .on( 'resize'+this.s.namespace, DataTable.util.throttle( function () { - that.s.position.windowHeight = $(window).height(); - that.update(); - }, 50 ) ); - - var autoHeader = $('.fh-fixedHeader'); - if ( ! this.c.headerOffset && autoHeader.length ) { - this.c.headerOffset = autoHeader.outerHeight(); - } - - var autoFooter = $('.fh-fixedFooter'); - if ( ! this.c.footerOffset && autoFooter.length ) { - this.c.footerOffset = autoFooter.outerHeight(); - } - - dt - .on( 'column-reorder.dt.dtfc column-visibility.dt.dtfc column-sizing.dt.dtfc responsive-display.dt.dtfc', function (e, ctx) { - that.update(); - } ) - .on( 'draw.dt.dtfc', function (e, ctx) { - // For updates from our own table, don't reclone, but for all others, do - that.update(ctx === dt.settings()[0] ? false : true); - } ); - - dt.on( 'destroy.dtfc', function () { - that.destroy(); - } ); - - this._positions(); - this._scroll(); - }, - - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Private methods - */ - - /** - * Clone a fixed item to act as a place holder for the original element - * which is moved into a clone of the table element, and moved around the - * document to give the fixed effect. - * - * @param {string} item 'header' or 'footer' - * @param {boolean} force Force the clone to happen, or allow automatic - * decision (reuse existing if available) - * @private - */ - _clone: function ( item, force ) - { - var dt = this.s.dt; - var itemDom = this.dom[ item ]; - var itemElement = item === 'header' ? - this.dom.thead : - this.dom.tfoot; - - // If footer and scrolling is enabled then we don't clone - // Instead the table's height is decreased accordingly - see `_scroll()` - if (item === 'footer' && this._scrollEnabled()) { - return; - } - - if ( ! force && itemDom.floating ) { - // existing floating element - reuse it - itemDom.floating.removeClass( 'fixedHeader-floating fixedHeader-locked' ); - } - else { - if ( itemDom.floating ) { - if(itemDom.placeholder !== null) { - itemDom.placeholder.remove(); - } - this._unsize( item ); - itemDom.floating.children().detach(); - itemDom.floating.remove(); - } - - var tableNode = $(dt.table().node()); - var scrollBody = $(tableNode.parent()); - var scrollEnabled = this._scrollEnabled(); - - itemDom.floating = $( dt.table().node().cloneNode( false ) ) - .attr( 'aria-hidden', 'true' ) - .css({ - 'table-layout': 'fixed', - top: 0, - left: 0 - }) - .removeAttr( 'id' ) - .append( itemElement ); - - itemDom.floatingParent - .css({ - width: scrollBody.width(), - overflow: 'hidden', - height: 'fit-content', - position: 'fixed', - left: scrollEnabled ? tableNode.offset().left + scrollBody.scrollLeft() : 0 - }) - .css( - item === 'header' ? - { - top: this.c.headerOffset, - bottom: '' - } : - { - top: '', - bottom: this.c.footerOffset - } - ) - .addClass(item === 'footer' ? 'dtfh-floatingparentfoot' : 'dtfh-floatingparenthead') - .append(itemDom.floating) - .appendTo( 'body' ); - - this._stickyPosition(itemDom.floating, '-'); - - var scrollLeftUpdate = () => { - var scrollLeft = scrollBody.scrollLeft() - this.s.scrollLeft = {footer: scrollLeft, header: scrollLeft}; - itemDom.floatingParent.scrollLeft(this.s.scrollLeft.header); - } - - scrollLeftUpdate(); - scrollBody.scroll(scrollLeftUpdate) - - // Insert a fake thead/tfoot into the DataTable to stop it jumping around - itemDom.placeholder = itemElement.clone( false ); - itemDom.placeholder - .find( '*[id]' ) - .removeAttr( 'id' ); - - itemDom.host.prepend( itemDom.placeholder ); - - // Clone widths - this._matchWidths( itemDom.placeholder, itemDom.floating ); - } - }, - - /** - * This method sets the sticky position of the header elements to match fixed columns - * @param {JQuery} el - * @param {string} sign - */ - _stickyPosition(el, sign) { - if (this._scrollEnabled()) { - var that = this - var rtl = $(that.s.dt.table().node()).css('direction') === 'rtl'; - - el.find('th').each(function() { - // Find out if fixed header has previously set this column - if ($(this).css('position') === 'sticky') { - var right = $(this).css('right'); - var left = $(this).css('left'); - if (right !== 'auto' && !rtl) { - // New position either adds or dismisses the barWidth - var potential = +right.replace(/px/g, '') + (sign === '-' ? -1 : 1) * that.s.dt.settings()[0].oBrowser.barWidth; - $(this).css('right', potential > 0 ? potential : 0); - } - else if(left !== 'auto' && rtl) { - var potential = +left.replace(/px/g, '') + (sign === '-' ? -1 : 1) * that.s.dt.settings()[0].oBrowser.barWidth; - $(this).css('left', potential > 0 ? potential : 0); - } - } - }); - } - }, - - /** - * Copy widths from the cells in one element to another. This is required - * for the footer as the footer in the main table takes its sizes from the - * header columns. That isn't present in the footer so to have it still - * align correctly, the sizes need to be copied over. It is also required - * for the header when auto width is not enabled - * - * @param {jQuery} from Copy widths from - * @param {jQuery} to Copy widths to - * @private - */ - _matchWidths: function ( from, to ) { - var get = function ( name ) { - return $(name, from) - .map( function () { - return $(this).css('width').replace(/[^\d\.]/g, '') * 1; - } ).toArray(); - }; - - var set = function ( name, toWidths ) { - $(name, to).each( function ( i ) { - $(this).css( { - width: toWidths[i], - minWidth: toWidths[i] - } ); - } ); - }; - - var thWidths = get( 'th' ); - var tdWidths = get( 'td' ); - - set( 'th', thWidths ); - set( 'td', tdWidths ); - }, - - /** - * Remove assigned widths from the cells in an element. This is required - * when inserting the footer back into the main table so the size is defined - * by the header columns and also when auto width is disabled in the - * DataTable. - * - * @param {string} item The `header` or `footer` - * @private - */ - _unsize: function ( item ) { - var el = this.dom[ item ].floating; - - if ( el && (item === 'footer' || (item === 'header' && ! this.s.autoWidth)) ) { - $('th, td', el).css( { - width: '', - minWidth: '' - } ); - } - else if ( el && item === 'header' ) { - $('th, td', el).css( 'min-width', '' ); - } - }, - - /** - * Reposition the floating elements to take account of horizontal page - * scroll - * - * @param {string} item The `header` or `footer` - * @param {int} scrollLeft Document scrollLeft - * @private - */ - _horizontal: function ( item, scrollLeft ) - { - var itemDom = this.dom[ item ]; - var position = this.s.position; - var lastScrollLeft = this.s.scrollLeft; - - if ( itemDom.floating && lastScrollLeft[ item ] !== scrollLeft ) { - // If scrolling is enabled we need to match the floating header to the body - if (this._scrollEnabled()) { - var newScrollLeft = $($(this.s.dt.table().node()).parent()).scrollLeft() - itemDom.floating.scrollLeft(newScrollLeft); - itemDom.floatingParent.scrollLeft(newScrollLeft); - } - - lastScrollLeft[ item ] = scrollLeft; - } - }, - - /** - * Change from one display mode to another. Each fixed item can be in one - * of: - * - * * `in-place` - In the main DataTable - * * `in` - Floating over the DataTable - * * `below` - (Header only) Fixed to the bottom of the table body - * * `above` - (Footer only) Fixed to the top of the table body - * - * @param {string} mode Mode that the item should be shown in - * @param {string} item 'header' or 'footer' - * @param {boolean} forceChange Force a redraw of the mode, even if already - * in that mode. - * @private - */ - _modeChange: function ( mode, item, forceChange ) - { - var dt = this.s.dt; - var itemDom = this.dom[ item ]; - var position = this.s.position; - - // Just determine if scroll is enabled once - var scrollEnabled = this._scrollEnabled(); - - // If footer and scrolling is enabled then we don't clone - // Instead the table's height is decreased accordingly - see `_scroll()` - if (item === 'footer' && scrollEnabled) { - return; - } - - // It isn't trivial to add a !important css attribute... - var importantWidth = function (w) { - itemDom.floating.attr('style', function(i,s) { - return (s || '') + 'width: '+w+'px !important;'; - }); - - // If not scrolling also have to update the floatingParent - if (!scrollEnabled) { - itemDom.floatingParent.attr('style', function(i,s) { - return (s || '') + 'width: '+w+'px !important;'; - }); - } - }; - - // Record focus. Browser's will cause input elements to loose focus if - // they are inserted else where in the doc - var tablePart = this.dom[ item==='footer' ? 'tfoot' : 'thead' ]; - var focus = $.contains( tablePart[0], document.activeElement ) ? - document.activeElement : - null; - var scrollBody = $($(this.s.dt.table().node()).parent()); - - if ( mode === 'in-place' ) { - // Insert the header back into the table's real header - if ( itemDom.placeholder ) { - itemDom.placeholder.remove(); - itemDom.placeholder = null; - } - - this._unsize( item ); - - if ( item === 'header' ) { - itemDom.host.prepend( tablePart ); - } - else { - itemDom.host.append( tablePart ); - } - - if ( itemDom.floating ) { - itemDom.floating.remove(); - itemDom.floating = null; - this._stickyPosition(itemDom.host, '+'); - } - - if ( itemDom.floatingParent ) { - itemDom.floatingParent.remove(); - } - - $($(itemDom.host.parent()).parent()).scrollLeft(scrollBody.scrollLeft()) - } - else if ( mode === 'in' ) { - // Remove the header from the read header and insert into a fixed - // positioned floating table clone - this._clone( item, forceChange ); - - // Get useful position values - var scrollOffset = scrollBody.offset(); - var windowTop = $(document).scrollTop(); - var windowHeight = $(window).height(); - var windowBottom = windowTop + windowHeight; - var bodyTop = scrollEnabled ? scrollOffset.top : position.tbodyTop; - var bodyBottom = scrollEnabled ? scrollOffset.top + scrollBody.outerHeight() : position.tfootTop - - // Calculate the amount that the footer or header needs to be shuffled - var shuffle = item === 'footer' ? - // footer and top of body isn't on screen - bodyTop > windowBottom ? - // Yes - push the footer below - position.tfootHeight : - // No - bottom set to the gap between the top of the body and the bottom of the window - bodyTop + position.tfootHeight - windowBottom : - // Otherwise must be a header so get the difference from the bottom of the - // desired floating header and the bottom of the table body - windowTop + this.c.headerOffset + position.theadHeight - bodyBottom - - // Set the top or bottom based off of the offset and the shuffle value - var prop = item === 'header' ? 'top' : 'bottom'; - var val = this.c[item+'Offset'] - (shuffle > 0 ? shuffle : 0); - - itemDom.floating.addClass( 'fixedHeader-floating' ); - itemDom.floatingParent - .css(prop, val) - .css( { - 'left': position.left, - 'height': item === 'header' ? position.theadHeight : position.tfootHeight, - 'z-index': 2 - }) - .append(itemDom.floating); - - importantWidth(position.width); - - if ( item === 'footer' ) { - itemDom.floating.css( 'top', '' ); - } - } - else if ( mode === 'below' ) { // only used for the header - // Fix the position of the floating header at base of the table body - this._clone( item, forceChange ); - - itemDom.floating.addClass( 'fixedHeader-locked' ); - itemDom.floatingParent.css({ - position: 'absolute', - top: position.tfootTop - position.theadHeight, - left: position.left+'px' - }); - - importantWidth(position.width); - } - else if ( mode === 'above' ) { // only used for the footer - // Fix the position of the floating footer at top of the table body - this._clone( item, forceChange ); - - itemDom.floating.addClass( 'fixedHeader-locked' ); - itemDom.floatingParent.css({ - position: 'absolute', - top: position.tbodyTop, - left: position.left+'px' - }); - - importantWidth(position.width); - } - - // Restore focus if it was lost - if ( focus && focus !== document.activeElement ) { - setTimeout( function () { - focus.focus(); - }, 10 ); - } - - this.s.scrollLeft.header = -1; - this.s.scrollLeft.footer = -1; - this.s[item+'Mode'] = mode; - }, - - /** - * Cache the positional information that is required for the mode - * calculations that FixedHeader performs. - * - * @private - */ - _positions: function () - { - var dt = this.s.dt; - var table = dt.table(); - var position = this.s.position; - var dom = this.dom; - var tableNode = $(table.node()); - var scrollEnabled = this._scrollEnabled(); - - // Need to use the header and footer that are in the main table, - // regardless of if they are clones, since they hold the positions we - // want to measure from - var thead = $(dt.table().header()); - var tfoot = $(dt.table().footer()); - var tbody = dom.tbody; - var scrollBody = tableNode.parent(); - - position.visible = tableNode.is(':visible'); - position.width = tableNode.outerWidth(); - position.left = tableNode.offset().left; - position.theadTop = thead.offset().top; - position.tbodyTop = scrollEnabled ? scrollBody.offset().top : tbody.offset().top; - position.tbodyHeight = scrollEnabled ? scrollBody.outerHeight() : tbody.outerHeight(); - position.theadHeight = thead.outerHeight(); - position.theadBottom = position.theadTop + position.theadHeight; - - if ( tfoot.length ) { - position.tfootTop = position.tbodyTop + position.tbodyHeight; //tfoot.offset().top; - position.tfootBottom = position.tfootTop + tfoot.outerHeight(); - position.tfootHeight = tfoot.outerHeight(); - } - else { - position.tfootTop = position.tbodyTop + tbody.outerHeight(); - position.tfootBottom = position.tfootTop; - position.tfootHeight = position.tfootTop; - } - }, - - - /** - * Mode calculation - determine what mode the fixed items should be placed - * into. - * - * @param {boolean} forceChange Force a redraw of the mode, even if already - * in that mode. - * @private - */ - _scroll: function ( forceChange ) - { - // ScrollBody details - var scrollEnabled = this._scrollEnabled(); - var scrollBody = $(this.s.dt.table().node()).parent(); - var scrollOffset = scrollBody.offset(); - var scrollHeight = scrollBody.outerHeight(); - - // Window details - var windowLeft = $(document).scrollLeft(); - var windowTop = $(document).scrollTop(); - var windowHeight = $(window).height(); - var windowBottom = windowHeight + windowTop - - - var position = this.s.position; - var headerMode, footerMode; - - // Body Details - var bodyTop = (scrollEnabled ? scrollOffset.top : position.tbodyTop); - var bodyLeft = (scrollEnabled ? scrollOffset.left : position.left); - var bodyBottom = (scrollEnabled ? scrollOffset.top + scrollHeight : position.tfootTop); - var bodyWidth = (scrollEnabled ? scrollBody.outerWidth() : position.tbodyWidth); - - var windowBottom = windowTop + windowHeight; - - if ( this.c.header ) { - if ( ! this.s.enable ) { - headerMode = 'in-place'; - } - // The header is in it's normal place if the body top is lower than - // the scroll of the window plus the headerOffset and the height of the header - else if ( ! position.visible || windowTop + this.c.headerOffset + position.theadHeight <= bodyTop) { - headerMode = 'in-place'; - } - // The header should be floated if - else if ( - // The scrolling plus the header offset plus the height of the header is lower than the top of the body - windowTop + this.c.headerOffset + position.theadHeight > bodyTop && - // And the scrolling at the top plus the header offset is above the bottom of the body - windowTop + this.c.headerOffset < bodyBottom - ) { - headerMode = 'in'; - var scrollBody = $($(this.s.dt.table().node()).parent()); - - // Further to the above, If the scrolling plus the header offset plus the header height is lower - // than the bottom of the table a shuffle is required so have to force the calculation - if(windowTop + this.c.headerOffset + position.theadHeight > bodyBottom || this.dom.header.floatingParent === undefined){ - forceChange = true; - } - else { - this.dom.header.floatingParent - .css({ - 'top': this.c.headerOffset, - 'position': 'fixed' - }) - .append(this.dom.header.floating); - } - } - // Anything else and the view is below the table - else { - headerMode = 'below'; - } - - if ( forceChange || headerMode !== this.s.headerMode ) { - this._modeChange( headerMode, 'header', forceChange ); - } - - this._horizontal( 'header', windowLeft ); - } - - var header = { - offset: {top: 0, left: 0}, - height: 0 - } - var footer = { - offset: {top: 0, left: 0}, - height: 0 - } - - if ( this.c.footer && this.dom.tfoot.length ) { - if ( ! this.s.enable ) { - footerMode = 'in-place'; - } - else if ( ! position.visible || position.tfootBottom + this.c.footerOffset <= windowBottom ) { - footerMode = 'in-place'; - } - else if ( - bodyBottom + position.tfootHeight + this.c.footerOffset > windowBottom && - bodyTop + this.c.footerOffset < windowBottom - ) { - footerMode = 'in'; - forceChange = true; - } - else { - footerMode = 'above'; - } - - if ( forceChange || footerMode !== this.s.footerMode ) { - this._modeChange( footerMode, 'footer', forceChange ); - } - - this._horizontal( 'footer', windowLeft ); - - var getOffsetHeight = (el) => { - return { - offset: el.offset(), - height: el.outerHeight() - } - } - - header = this.dom.header.floating ? getOffsetHeight(this.dom.header.floating) : getOffsetHeight(this.dom.thead); - footer = this.dom.footer.floating ? getOffsetHeight(this.dom.footer.floating) : getOffsetHeight(this.dom.tfoot); - - // If scrolling is enabled and the footer is off the screen - if (scrollEnabled && footer.offset.top > windowTop){// && footer.offset.top >= windowBottom) { - // Calculate the gap between the top of the scrollBody and the top of the window - var overlap = windowTop - scrollOffset.top; - // The new height is the bottom of the window - var newHeight = windowBottom + - // If the gap between the top of the scrollbody and the window is more than - // the height of the header then the top of the table is still visible so add that gap - // Doing this has effectively calculated the height from the top of the table to the bottom of the current page - (overlap > -header.height ? overlap : 0) - - // Take from that - ( - // The top of the header plus - header.offset.top + - // The header height if the standard header is present - (overlap < -header.height ? header.height : 0) + - // And the height of the footer - footer.height - ) - - // Don't want a negative height - if (newHeight < 0) { - newHeight = 0; - } - - // At the end of the above calculation the space between the header (top of the page if floating) - // and the point just above the footer should be the new value for the height of the table. - scrollBody.outerHeight(newHeight); - - // Need some rounding here as sometimes very small decimal places are encountered - // If the actual height is bigger or equal to the height we just applied then the footer is "Floating" - if(Math.round(scrollBody.outerHeight()) >= Math.round(newHeight)) { - $(this.dom.tfoot.parent()).addClass("fixedHeader-floating"); - } - // Otherwise max-width has kicked in so it is not floating - else { - $(this.dom.tfoot.parent()).removeClass("fixedHeader-floating"); - } - } - } - - if(this.dom.header.floating){ - this.dom.header.floatingParent.css('left', bodyLeft-windowLeft); - } - if(this.dom.footer.floating){ - this.dom.footer.floatingParent.css('left', bodyLeft-windowLeft); - } - - // If fixed columns is being used on this table then the blockers need to be copied across - // Cloning these is cleaner than creating as our own as it will keep consistency with fixedColumns automatically - // ASSUMING that the class remains the same - if (this.s.dt.settings()[0]._fixedColumns !== undefined) { - var adjustBlocker = (side, end, el) => { - if (el === undefined) { - let blocker = $('div.dtfc-'+side+'-'+end+'-blocker'); - el = blocker.length === 0 ? - null : - blocker.clone().appendTo('body').css('z-index', 1); - } - if(el !== null) { - el.css({ - top: end === 'top' ? header.offset.top : footer.offset.top, - left: side === 'right' ? bodyLeft + bodyWidth - el.width() : bodyLeft - }); - } - - return el; - } - - // Adjust all blockers - this.dom.header.rightBlocker = adjustBlocker('right', 'top', this.dom.header.rightBlocker); - this.dom.header.leftBlocker = adjustBlocker('left', 'top', this.dom.header.leftBlocker); - this.dom.footer.rightBlocker = adjustBlocker('right', 'bottom', this.dom.footer.rightBlocker); - this.dom.footer.leftBlocker = adjustBlocker('left', 'bottom', this.dom.footer.leftBlocker); - } - }, - - /** - * Function to check if scrolling is enabled on the table or not - * @returns Boolean value indicating if scrolling on the table is enabled or not - */ - _scrollEnabled: function() { - var oScroll = this.s.dt.settings()[0].oScroll; - if(oScroll.sY !== "" || oScroll.sX !== "") { - return true; - } - return false - } -} ); - - -/** - * Version - * @type {String} - * @static - */ -FixedHeader.version = "3.2.1"; - -/** - * Defaults - * @type {Object} - * @static - */ -FixedHeader.defaults = { - header: true, - footer: false, - headerOffset: 0, - footerOffset: 0 -}; - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * DataTables interfaces - */ - -// Attach for constructor access -$.fn.dataTable.FixedHeader = FixedHeader; -$.fn.DataTable.FixedHeader = FixedHeader; - - -// DataTables creation - check if the FixedHeader option has been defined on the -// table and if so, initialise -$(document).on( 'init.dt.dtfh', function (e, settings, json) { - if ( e.namespace !== 'dt' ) { - return; - } - - var init = settings.oInit.fixedHeader; - var defaults = DataTable.defaults.fixedHeader; - - if ( (init || defaults) && ! settings._fixedHeader ) { - var opts = $.extend( {}, defaults, init ); - - if ( init !== false ) { - new FixedHeader( settings, opts ); - } - } -} ); - -// DataTables API methods -DataTable.Api.register( 'fixedHeader()', function () {} ); - -DataTable.Api.register( 'fixedHeader.adjust()', function () { - return this.iterator( 'table', function ( ctx ) { - var fh = ctx._fixedHeader; - - if ( fh ) { - fh.update(); - } - } ); -} ); - -DataTable.Api.register( 'fixedHeader.enable()', function ( flag ) { - return this.iterator( 'table', function ( ctx ) { - var fh = ctx._fixedHeader; - - flag = ( flag !== undefined ? flag : true ); - if ( fh && flag !== fh.enabled() ) { - fh.enable( flag ); - } - } ); -} ); - -DataTable.Api.register( 'fixedHeader.enabled()', function () { - if ( this.context.length ) { - var fh = this.context[0]._fixedHeader; - - if ( fh ) { - return fh.enabled(); - } - } - - return false; -} ); - -DataTable.Api.register( 'fixedHeader.disable()', function ( ) { - return this.iterator( 'table', function ( ctx ) { - var fh = ctx._fixedHeader; - - if ( fh && fh.enabled() ) { - fh.enable( false ); - } - } ); -} ); - -$.each( ['header', 'footer'], function ( i, el ) { - DataTable.Api.register( 'fixedHeader.'+el+'Offset()', function ( offset ) { - var ctx = this.context; - - if ( offset === undefined ) { - return ctx.length && ctx[0]._fixedHeader ? - ctx[0]._fixedHeader[el +'Offset']() : - undefined; - } - - return this.iterator( 'table', function ( ctx ) { - var fh = ctx._fixedHeader; - - if ( fh ) { - fh[ el +'Offset' ]( offset ); - } - } ); - } ); -} ); - - -return FixedHeader; -})); - - -/*! Responsive 2.2.9 - * 2014-2021 SpryMedia Ltd - datatables.net/license - */ - -/** - * @summary Responsive - * @description Responsive tables plug-in for DataTables - * @version 2.2.9 - * @file dataTables.responsive.js - * @author SpryMedia Ltd (www.sprymedia.co.uk) - * @contact www.sprymedia.co.uk/contact - * @copyright Copyright 2014-2021 SpryMedia Ltd. - * - * This source file is free software, available under the following license: - * MIT license - http://datatables.net/license/mit - * - * This source file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. - * - * For details please refer to: http://www.datatables.net - */ -(function( factory ){ - if ( typeof define === 'function' && define.amd ) { - // AMD - define( ['jquery', 'datatables.net'], function ( $ ) { - return factory( $, window, document ); - } ); - } - else if ( typeof exports === 'object' ) { - // CommonJS - module.exports = function (root, $) { - if ( ! root ) { - root = window; - } - - if ( ! $ || ! $.fn.dataTable ) { - $ = require('datatables.net')(root, $).$; - } - - return factory( $, root, root.document ); - }; - } - else { - // Browser - factory( jQuery, window, document ); - } -}(function( $, window, document, undefined ) { -'use strict'; -var DataTable = $.fn.dataTable; - - -/** - * Responsive is a plug-in for the DataTables library that makes use of - * DataTables' ability to change the visibility of columns, changing the - * visibility of columns so the displayed columns fit into the table container. - * The end result is that complex tables will be dynamically adjusted to fit - * into the viewport, be it on a desktop, tablet or mobile browser. - * - * Responsive for DataTables has two modes of operation, which can used - * individually or combined: - * - * * Class name based control - columns assigned class names that match the - * breakpoint logic can be shown / hidden as required for each breakpoint. - * * Automatic control - columns are automatically hidden when there is no - * room left to display them. Columns removed from the right. - * - * In additional to column visibility control, Responsive also has built into - * options to use DataTables' child row display to show / hide the information - * from the table that has been hidden. There are also two modes of operation - * for this child row display: - * - * * Inline - when the control element that the user can use to show / hide - * child rows is displayed inside the first column of the table. - * * Column - where a whole column is dedicated to be the show / hide control. - * - * Initialisation of Responsive is performed by: - * - * * Adding the class `responsive` or `dt-responsive` to the table. In this case - * Responsive will automatically be initialised with the default configuration - * options when the DataTable is created. - * * Using the `responsive` option in the DataTables configuration options. This - * can also be used to specify the configuration options, or simply set to - * `true` to use the defaults. - * - * @class - * @param {object} settings DataTables settings object for the host table - * @param {object} [opts] Configuration options - * @requires jQuery 1.7+ - * @requires DataTables 1.10.3+ - * - * @example - * $('#example').DataTable( { - * responsive: true - * } ); - * } ); - */ -var Responsive = function ( settings, opts ) { - // Sanity check that we are using DataTables 1.10 or newer - if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.10' ) ) { - throw 'DataTables Responsive requires DataTables 1.10.10 or newer'; - } - - this.s = { - dt: new DataTable.Api( settings ), - columns: [], - current: [] - }; - - // Check if responsive has already been initialised on this table - if ( this.s.dt.settings()[0].responsive ) { - return; - } - - // details is an object, but for simplicity the user can give it as a string - // or a boolean - if ( opts && typeof opts.details === 'string' ) { - opts.details = { type: opts.details }; - } - else if ( opts && opts.details === false ) { - opts.details = { type: false }; - } - else if ( opts && opts.details === true ) { - opts.details = { type: 'inline' }; - } - - this.c = $.extend( true, {}, Responsive.defaults, DataTable.defaults.responsive, opts ); - settings.responsive = this; - this._constructor(); -}; - -$.extend( Responsive.prototype, { - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Constructor - */ - - /** - * Initialise the Responsive instance - * - * @private - */ - _constructor: function () - { - var that = this; - var dt = this.s.dt; - var dtPrivateSettings = dt.settings()[0]; - var oldWindowWidth = $(window).innerWidth(); - - dt.settings()[0]._responsive = this; - - // Use DataTables' throttle function to avoid processor thrashing on - // resize - $(window).on( 'resize.dtr orientationchange.dtr', DataTable.util.throttle( function () { - // iOS has a bug whereby resize can fire when only scrolling - // See: http://stackoverflow.com/questions/8898412 - var width = $(window).innerWidth(); - - if ( width !== oldWindowWidth ) { - that._resize(); - oldWindowWidth = width; - } - } ) ); - - // DataTables doesn't currently trigger an event when a row is added, so - // we need to hook into its private API to enforce the hidden rows when - // new data is added - dtPrivateSettings.oApi._fnCallbackReg( dtPrivateSettings, 'aoRowCreatedCallback', function (tr, data, idx) { - if ( $.inArray( false, that.s.current ) !== -1 ) { - $('>td, >th', tr).each( function ( i ) { - var idx = dt.column.index( 'toData', i ); - - if ( that.s.current[idx] === false ) { - $(this).css('display', 'none'); - } - } ); - } - } ); - - // Destroy event handler - dt.on( 'destroy.dtr', function () { - dt.off( '.dtr' ); - $( dt.table().body() ).off( '.dtr' ); - $(window).off( 'resize.dtr orientationchange.dtr' ); - dt.cells('.dtr-control').nodes().to$().removeClass('dtr-control'); - - // Restore the columns that we've hidden - $.each( that.s.current, function ( i, val ) { - if ( val === false ) { - that._setColumnVis( i, true ); - } - } ); - } ); - - // Reorder the breakpoints array here in case they have been added out - // of order - this.c.breakpoints.sort( function (a, b) { - return a.width < b.width ? 1 : - a.width > b.width ? -1 : 0; - } ); - - this._classLogic(); - this._resizeAuto(); - - // Details handler - var details = this.c.details; - - if ( details.type !== false ) { - that._detailsInit(); - - // DataTables will trigger this event on every column it shows and - // hides individually - dt.on( 'column-visibility.dtr', function () { - // Use a small debounce to allow multiple columns to be set together - if ( that._timer ) { - clearTimeout( that._timer ); - } - - that._timer = setTimeout( function () { - that._timer = null; - - that._classLogic(); - that._resizeAuto(); - that._resize(true); - - that._redrawChildren(); - }, 100 ); - } ); - - // Redraw the details box on each draw which will happen if the data - // has changed. This is used until DataTables implements a native - // `updated` event for rows - dt.on( 'draw.dtr', function () { - that._redrawChildren(); - } ); - - $(dt.table().node()).addClass( 'dtr-'+details.type ); - } - - dt.on( 'column-reorder.dtr', function (e, settings, details) { - that._classLogic(); - that._resizeAuto(); - that._resize(true); - } ); - - // Change in column sizes means we need to calc - dt.on( 'column-sizing.dtr', function () { - that._resizeAuto(); - that._resize(); - }); - - // On Ajax reload we want to reopen any child rows which are displayed - // by responsive - dt.on( 'preXhr.dtr', function () { - var rowIds = []; - dt.rows().every( function () { - if ( this.child.isShown() ) { - rowIds.push( this.id(true) ); - } - } ); - - dt.one( 'draw.dtr', function () { - that._resizeAuto(); - that._resize(); - - dt.rows( rowIds ).every( function () { - that._detailsDisplay( this, false ); - } ); - } ); - }); - - dt - .on( 'draw.dtr', function () { - that._controlClass(); - }) - .on( 'init.dtr', function (e, settings, details) { - if ( e.namespace !== 'dt' ) { - return; - } - - that._resizeAuto(); - that._resize(); - - // If columns were hidden, then DataTables needs to adjust the - // column sizing - if ( $.inArray( false, that.s.current ) ) { - dt.columns.adjust(); - } - } ); - - // First pass - draw the table for the current viewport size - this._resize(); - }, - - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Private methods - */ - - /** - * Calculate the visibility for the columns in a table for a given - * breakpoint. The result is pre-determined based on the class logic if - * class names are used to control all columns, but the width of the table - * is also used if there are columns which are to be automatically shown - * and hidden. - * - * @param {string} breakpoint Breakpoint name to use for the calculation - * @return {array} Array of boolean values initiating the visibility of each - * column. - * @private - */ - _columnsVisiblity: function ( breakpoint ) - { - var dt = this.s.dt; - var columns = this.s.columns; - var i, ien; - - // Create an array that defines the column ordering based first on the - // column's priority, and secondly the column index. This allows the - // columns to be removed from the right if the priority matches - var order = columns - .map( function ( col, idx ) { - return { - columnIdx: idx, - priority: col.priority - }; - } ) - .sort( function ( a, b ) { - if ( a.priority !== b.priority ) { - return a.priority - b.priority; - } - return a.columnIdx - b.columnIdx; - } ); - - // Class logic - determine which columns are in this breakpoint based - // on the classes. If no class control (i.e. `auto`) then `-` is used - // to indicate this to the rest of the function - var display = $.map( columns, function ( col, i ) { - if ( dt.column(i).visible() === false ) { - return 'not-visible'; - } - return col.auto && col.minWidth === null ? - false : - col.auto === true ? - '-' : - $.inArray( breakpoint, col.includeIn ) !== -1; - } ); - - // Auto column control - first pass: how much width is taken by the - // ones that must be included from the non-auto columns - var requiredWidth = 0; - for ( i=0, ien=display.length ; i
    ') - .append( headerCells ) - .appendTo( clonedHeader ); - - // In the inline case extra padding is applied to the first column to - // give space for the show / hide icon. We need to use this in the - // calculation - if ( this.c.details.type === 'inline' ) { - $(clonedTable).addClass( 'dtr-inline collapsed' ); - } - - // It is unsafe to insert elements with the same name into the DOM - // multiple times. For example, cloning and inserting a checked radio - // clears the chcecked state of the original radio. - $( clonedTable ).find( '[name]' ).removeAttr( 'name' ); - - // A position absolute table would take the table out of the flow of - // our container element, bypassing the height and width (Scroller) - $( clonedTable ).css( 'position', 'relative' ) - - var inserted = $('
    ') - .css( { - width: 1, - height: 1, - overflow: 'hidden', - clear: 'both' - } ) - .append( clonedTable ); - - inserted.insertBefore( dt.table().node() ); - - // The cloned header now contains the smallest that each column can be - headerCells.each( function (i) { - var idx = dt.column.index( 'fromVisible', i ); - columns[ idx ].minWidth = this.offsetWidth || 0; - } ); - - inserted.remove(); - }, - - /** - * Get the state of the current hidden columns - controlled by Responsive only - */ - _responsiveOnlyHidden: function () - { - var dt = this.s.dt; - - return $.map( this.s.current, function (v, i) { - // If the column is hidden by DataTables then it can't be hidden by - // Responsive! - if ( dt.column(i).visible() === false ) { - return true; - } - return v; - } ); - }, - - /** - * Set a column's visibility. - * - * We don't use DataTables' column visibility controls in order to ensure - * that column visibility can Responsive can no-exist. Since only IE8+ is - * supported (and all evergreen browsers of course) the control of the - * display attribute works well. - * - * @param {integer} col Column index - * @param {boolean} showHide Show or hide (true or false) - * @private - */ - _setColumnVis: function ( col, showHide ) - { - var dt = this.s.dt; - var display = showHide ? '' : 'none'; // empty string will remove the attr - - $( dt.column( col ).header() ).css( 'display', display ); - $( dt.column( col ).footer() ).css( 'display', display ); - dt.column( col ).nodes().to$().css( 'display', display ); - - // If the are child nodes stored, we might need to reinsert them - if ( ! $.isEmptyObject( _childNodeStore ) ) { - dt.cells( null, col ).indexes().each( function (idx) { - _childNodesRestore( dt, idx.row, idx.column ); - } ); - } - }, - - - /** - * Update the cell tab indexes for keyboard accessibility. This is called on - * every table draw - that is potentially inefficient, but also the least - * complex option given that column visibility can change on the fly. Its a - * shame user-focus was removed from CSS 3 UI, as it would have solved this - * issue with a single CSS statement. - * - * @private - */ - _tabIndexes: function () - { - var dt = this.s.dt; - var cells = dt.cells( { page: 'current' } ).nodes().to$(); - var ctx = dt.settings()[0]; - var target = this.c.details.target; - - cells.filter( '[data-dtr-keyboard]' ).removeData( '[data-dtr-keyboard]' ); - - if ( typeof target === 'number' ) { - dt.cells( null, target, { page: 'current' } ).nodes().to$() - .attr( 'tabIndex', ctx.iTabIndex ) - .data( 'dtr-keyboard', 1 ); - } - else { - // This is a bit of a hack - we need to limit the selected nodes to just - // those of this table - if ( target === 'td:first-child, th:first-child' ) { - target = '>td:first-child, >th:first-child'; - } - - $( target, dt.rows( { page: 'current' } ).nodes() ) - .attr( 'tabIndex', ctx.iTabIndex ) - .data( 'dtr-keyboard', 1 ); - } - } -} ); - - -/** - * List of default breakpoints. Each item in the array is an object with two - * properties: - * - * * `name` - the breakpoint name. - * * `width` - the breakpoint width - * - * @name Responsive.breakpoints - * @static - */ -Responsive.breakpoints = [ - { name: 'desktop', width: Infinity }, - { name: 'tablet-l', width: 1024 }, - { name: 'tablet-p', width: 768 }, - { name: 'mobile-l', width: 480 }, - { name: 'mobile-p', width: 320 } -]; - - -/** - * Display methods - functions which define how the hidden data should be shown - * in the table. - * - * @namespace - * @name Responsive.defaults - * @static - */ -Responsive.display = { - childRow: function ( row, update, render ) { - if ( update ) { - if ( $(row.node()).hasClass('parent') ) { - row.child( render(), 'child' ).show(); - - return true; - } - } - else { - if ( ! row.child.isShown() ) { - row.child( render(), 'child' ).show(); - $( row.node() ).addClass( 'parent' ); - - return true; - } - else { - row.child( false ); - $( row.node() ).removeClass( 'parent' ); - - return false; - } - } - }, - - childRowImmediate: function ( row, update, render ) { - if ( (! update && row.child.isShown()) || ! row.responsive.hasHidden() ) { - // User interaction and the row is show, or nothing to show - row.child( false ); - $( row.node() ).removeClass( 'parent' ); - - return false; - } - else { - // Display - row.child( render(), 'child' ).show(); - $( row.node() ).addClass( 'parent' ); - - return true; - } - }, - - // This is a wrapper so the modal options for Bootstrap and jQuery UI can - // have options passed into them. This specific one doesn't need to be a - // function but it is for consistency in the `modal` name - modal: function ( options ) { - return function ( row, update, render ) { - if ( ! update ) { - // Show a modal - var close = function () { - modal.remove(); // will tidy events for us - $(document).off( 'keypress.dtr' ); - }; - - var modal = $('
    ') - .append( $('
    ') - .append( $('
    ') - .append( render() ) - ) - .append( $('
    ×
    ' ) - .click( function () { - close(); - } ) - ) - ) - .append( $('
    ') - .click( function () { - close(); - } ) - ) - .appendTo( 'body' ); - - $(document).on( 'keyup.dtr', function (e) { - if ( e.keyCode === 27 ) { - e.stopPropagation(); - - close(); - } - } ); - } - else { - $('div.dtr-modal-content') - .empty() - .append( render() ); - } - - if ( options && options.header ) { - $('div.dtr-modal-content').prepend( - '

    '+options.header( row )+'

    ' - ); - } - }; - } -}; - - -var _childNodeStore = {}; - -function _childNodes( dt, row, col ) { - var name = row+'-'+col; - - if ( _childNodeStore[ name ] ) { - return _childNodeStore[ name ]; - } - - // https://jsperf.com/childnodes-array-slice-vs-loop - var nodes = []; - var children = dt.cell( row, col ).node().childNodes; - for ( var i=0, ien=children.length ; i
    '+ - ' '+ - ''+ - ''; - } ).join(''); - - return $('
    '+col.title+':'+''+col.data+'
    ').append( data ); - } - } -}; - -/** - * Responsive default settings for initialisation - * - * @namespace - * @name Responsive.defaults - * @static - */ -Responsive.defaults = { - /** - * List of breakpoints for the instance. Note that this means that each - * instance can have its own breakpoints. Additionally, the breakpoints - * cannot be changed once an instance has been creased. - * - * @type {Array} - * @default Takes the value of `Responsive.breakpoints` - */ - breakpoints: Responsive.breakpoints, - - /** - * Enable / disable auto hiding calculations. It can help to increase - * performance slightly if you disable this option, but all columns would - * need to have breakpoint classes assigned to them - * - * @type {Boolean} - * @default `true` - */ - auto: true, - - /** - * Details control. If given as a string value, the `type` property of the - * default object is set to that value, and the defaults used for the rest - * of the object - this is for ease of implementation. - * - * The object consists of the following properties: - * - * * `display` - A function that is used to show and hide the hidden details - * * `renderer` - function that is called for display of the child row data. - * The default function will show the data from the hidden columns - * * `target` - Used as the selector for what objects to attach the child - * open / close to - * * `type` - `false` to disable the details display, `inline` or `column` - * for the two control types - * - * @type {Object|string} - */ - details: { - display: Responsive.display.childRow, - - renderer: Responsive.renderer.listHidden(), - - target: 0, - - type: 'inline' - }, - - /** - * Orthogonal data request option. This is used to define the data type - * requested when Responsive gets the data to show in the child row. - * - * @type {String} - */ - orthogonal: 'display' -}; - - -/* - * API - */ -var Api = $.fn.dataTable.Api; - -// Doesn't do anything - work around for a bug in DT... Not documented -Api.register( 'responsive()', function () { - return this; -} ); - -Api.register( 'responsive.index()', function ( li ) { - li = $(li); - - return { - column: li.data('dtr-index'), - row: li.parent().data('dtr-index') - }; -} ); - -Api.register( 'responsive.rebuild()', function () { - return this.iterator( 'table', function ( ctx ) { - if ( ctx._responsive ) { - ctx._responsive._classLogic(); - } - } ); -} ); - -Api.register( 'responsive.recalc()', function () { - return this.iterator( 'table', function ( ctx ) { - if ( ctx._responsive ) { - ctx._responsive._resizeAuto(); - ctx._responsive._resize(); - } - } ); -} ); - -Api.register( 'responsive.hasHidden()', function () { - var ctx = this.context[0]; - - return ctx._responsive ? - $.inArray( false, ctx._responsive._responsiveOnlyHidden() ) !== -1 : - false; -} ); - -Api.registerPlural( 'columns().responsiveHidden()', 'column().responsiveHidden()', function () { - return this.iterator( 'column', function ( settings, column ) { - return settings._responsive ? - settings._responsive._responsiveOnlyHidden()[ column ] : - false; - }, 1 ); -} ); - - -/** - * Version information - * - * @name Responsive.version - * @static - */ -Responsive.version = '2.2.9'; - - -$.fn.dataTable.Responsive = Responsive; -$.fn.DataTable.Responsive = Responsive; - -// Attach a listener to the document which listens for DataTables initialisation -// events so we can automatically initialise -$(document).on( 'preInit.dt.dtr', function (e, settings, json) { - if ( e.namespace !== 'dt' ) { - return; - } - - if ( $(settings.nTable).hasClass( 'responsive' ) || - $(settings.nTable).hasClass( 'dt-responsive' ) || - settings.oInit.responsive || - DataTable.defaults.responsive - ) { - var init = settings.oInit.responsive; - - if ( init !== false ) { - new Responsive( settings, $.isPlainObject( init ) ? init : {} ); - } - } -} ); - - -return Responsive; -})); - - -/*! DataTables styling wrapper for Responsive - * ©2018 SpryMedia Ltd - datatables.net/license - */ - -(function( factory ){ - if ( typeof define === 'function' && define.amd ) { - // AMD - define( ['jquery', 'datatables.net-dt', 'datatables.net-responsive'], function ( $ ) { - return factory( $, window, document ); - } ); - } - else if ( typeof exports === 'object' ) { - // CommonJS - module.exports = function (root, $) { - if ( ! root ) { - root = window; - } - - if ( ! $ || ! $.fn.dataTable ) { - $ = require('datatables.net-dt')(root, $).$; - } - - if ( ! $.fn.dataTable.Responsive ) { - require('datatables.net-responsive')(root, $); - } - - return factory( $, root, root.document ); - }; - } - else { - // Browser - factory( jQuery, window, document ); - } -}(function( $, window, document, undefined ) { - -return $.fn.dataTable; - -})); - -/*! SearchBuilder 1.3.1 - * ©SpryMedia Ltd - datatables.net/license/mit - */ -(function () { - 'use strict'; - - var $$2; - var dataTable$2; - // eslint-disable-next-line no-extra-parens - var moment = window.moment; - // eslint-disable-next-line no-extra-parens - var luxon = window.luxon; - /** - * Sets the value of jQuery for use in the file - * - * @param jq the instance of jQuery to be set - */ - function setJQuery$2(jq) { - $$2 = jq; - dataTable$2 = jq.fn.dataTable; - } - /** - * The Criteria class is used within SearchBuilder to represent a search criteria - */ - var Criteria = /** @class */ (function () { - function Criteria(table, opts, topGroup, index, depth) { - var _this = this; - if (index === void 0) { index = 0; } - if (depth === void 0) { depth = 1; } - // Check that the required version of DataTables is included - if (!dataTable$2 || !dataTable$2.versionCheck || !dataTable$2.versionCheck('1.10.0')) { - throw new Error('SearchPane requires DataTables 1.10 or newer'); - } - this.classes = $$2.extend(true, {}, Criteria.classes); - // Get options from user and any extra conditions/column types defined by plug-ins - this.c = $$2.extend(true, {}, Criteria.defaults, $$2.fn.dataTable.ext.searchBuilder, opts); - var i18n = this.c.i18n; - this.s = { - condition: undefined, - conditions: {}, - data: undefined, - dataIdx: -1, - dataPoints: [], - dateFormat: false, - depth: depth, - dt: table, - filled: false, - index: index, - origData: undefined, - topGroup: topGroup, - type: '', - value: [] - }; - this.dom = { - buttons: $$2('
    ') - .addClass(this.classes.buttonContainer), - condition: $$2('') - .addClass(this.classes.data) - .addClass(this.classes.dropDown) - .addClass(this.classes.italic), - dataTitle: $$2('
    ").insertAfter(H));r.nTBody=ea[0];H=t.children("tfoot");0===H.length&&0").appendTo(t));0===H.length||0===H.children().length?t.addClass(C.sNoFooter):0/g,uc=/^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/,vc=/(\/|\.|\*|\+|\?|\||\(|\)|\[|\]|\{|\}|\\|\$|\^|\-)/g,rb=/['\u00A0,$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi,Z=function(a){return a&&!0!==a&&"-"!==a?!1:!0},hc= -function(a){var b=parseInt(a,10);return!isNaN(b)&&isFinite(a)?b:null},ic=function(a,b){sb[b]||(sb[b]=new RegExp(jb(b),"g"));return"string"===typeof a&&"."!==b?a.replace(/\./g,"").replace(sb[b],"."):a},tb=function(a,b,c){var d="string"===typeof a;if(Z(a))return!0;b&&d&&(a=ic(a,b));c&&d&&(a=a.replace(rb,""));return!isNaN(parseFloat(a))&&isFinite(a)},jc=function(a,b,c){return Z(a)?!0:Z(a)||"string"===typeof a?tb(a.replace(Va,""),b,c)?!0:null:null},U=function(a,b,c){var d=[],e=0,h=a.length;if(c!==q)for(;e< -h;e++)a[e]&&a[e][b]&&d.push(a[e][b][c]);else for(;ea.length)){var b=a.slice().sort();for(var c=b[0],d=1,e=b.length;d< -e;d++){if(b[d]===c){b=!1;break a}c=b[d]}}b=!0}if(b)return a.slice();b=[];e=a.length;var h,f=0;d=0;a:for(;d")[0],sc=Qa.textContent!==q,tc=/<.*?>/g,hb=u.util.throttle,nc=[],N=Array.prototype,wc=function(a){var b,c=u.settings,d=l.map(c,function(h,f){return h.nTable});if(a){if(a.nTable&&a.oApi)return[a];if(a.nodeName&&"table"===a.nodeName.toLowerCase()){var e= -l.inArray(a,d);return-1!==e?[c[e]]:null}if(a&&"function"===typeof a.settings)return a.settings().toArray();"string"===typeof a?b=l(a):a instanceof l&&(b=a)}else return[];if(b)return b.map(function(h){e=l.inArray(this,d);return-1!==e?c[e]:null}).toArray()};var B=function(a,b){if(!(this instanceof B))return new B(a,b);var c=[],d=function(f){(f=wc(f))&&c.push.apply(c,f)};if(Array.isArray(a))for(var e=0,h=a.length;ea?new B(b[a],this[a]):null},filter:function(a){var b=[];if(N.filter)b=N.filter.call(this,a,this);else for(var c=0,d=this.length;c").addClass(g),l("td",k).addClass(g).html(f)[0].colSpan=oa(a),e.push(k[0]))};h(c,d);b._details&&b._details.detach();b._details=l(e);b._detailsShow&&b._details.insertAfter(b.nTr)},xb=function(a,b){var c=a.context;c.length&&(a=c[0].aoData[b!==q?b:a[0]])&&a._details&&(a._details.remove(),a._detailsShow=q,a._details= -q,l(a.nTr).removeClass("dt-hasChild"),qa(c[0]))},qc=function(a,b){var c=a.context;if(c.length&&a.length){var d=c[0].aoData[a[0]];d._details&&((d._detailsShow=b)?(d._details.insertAfter(d.nTr),l(d.nTr).addClass("dt-hasChild")):(d._details.detach(),l(d.nTr).removeClass("dt-hasChild")),F(c[0],null,"childRow",[b,a.row(a[0])]),zc(c[0]),qa(c[0]))}},zc=function(a){var b=new B(a),c=a.aoData;b.off("draw.dt.DT_details column-visibility.dt.DT_details destroy.dt.DT_details");0g){var n=l.map(d,function(p,t){return p.bVisible?t:null});return[n[n.length+g]]}return[ua(a,g)];case "name":return l.map(e,function(p,t){return p===m[1]?t:null});default:return[]}if(f.nodeName&&f._DT_CellIndex)return[f._DT_CellIndex.column];g=l(h).filter(f).map(function(){return l.inArray(this,h)}).toArray();if(g.length||!f.nodeName)return g;g=l(f).closest("*[data-dt-column]");return g.length?[g.data("dt-column")]:[]},a,c)};y("columns()",function(a,b){a===q?a="":l.isPlainObject(a)&&(b=a, -a="");b=vb(b);var c=this.iterator("table",function(d){return Bc(d,a,b)},1);c.selector.cols=a;c.selector.opts=b;return c});J("columns().header()","column().header()",function(a,b){return this.iterator("column",function(c,d){return c.aoColumns[d].nTh},1)});J("columns().footer()","column().footer()",function(a,b){return this.iterator("column",function(c,d){return c.aoColumns[d].nTf},1)});J("columns().data()","column().data()",function(){return this.iterator("column-rows",rc,1)});J("columns().dataSrc()", -"column().dataSrc()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].mData},1)});J("columns().cache()","column().cache()",function(a){return this.iterator("column-rows",function(b,c,d,e,h){return Ea(b.aoData,h,"search"===a?"_aFilterData":"_aSortData",c)},1)});J("columns().nodes()","column().nodes()",function(){return this.iterator("column-rows",function(a,b,c,d,e){return Ea(a.aoData,e,"anCells",b)},1)});J("columns().visible()","column().visible()",function(a,b){var c= -this,d=this.iterator("column",function(e,h){if(a===q)return e.aoColumns[h].bVisible;var f=e.aoColumns,g=f[h],k=e.aoData,m;if(a!==q&&g.bVisible!==a){if(a){var n=l.inArray(!0,U(f,"bVisible"),h+1);f=0;for(m=k.length;fd;return!0};u.isDataTable=u.fnIsDataTable=function(a){var b=l(a).get(0),c=!1;if(a instanceof u.Api)return!0;l.each(u.settings,function(d,e){d=e.nScrollHead?l("table",e.nScrollHead)[0]:null;var h=e.nScrollFoot?l("table",e.nScrollFoot)[0]:null;if(e.nTable===b||d===b||h===b)c=!0});return c};u.tables=u.fnTables=function(a){var b= -!1;l.isPlainObject(a)&&(b=a.api,a=a.visible);var c=l.map(u.settings,function(d){if(!a||a&&l(d.nTable).is(":visible"))return d.nTable});return b?new B(c):c};u.camelToHungarian=P;y("$()",function(a,b){b=this.rows(b).nodes();b=l(b);return l([].concat(b.filter(a).toArray(),b.find(a).toArray()))});l.each(["on","one","off"],function(a,b){y(b+"()",function(){var c=Array.prototype.slice.call(arguments);c[0]=l.map(c[0].split(/\s/),function(e){return e.match(/\.dt\b/)?e:e+".dt"}).join(" ");var d=l(this.tables().nodes()); -d[b].apply(d,c);return this})});y("clear()",function(){return this.iterator("table",function(a){Ka(a)})});y("settings()",function(){return new B(this.context,this.context)});y("init()",function(){var a=this.context;return a.length?a[0].oInit:null});y("data()",function(){return this.iterator("table",function(a){return U(a.aoData,"_aData")}).flatten()});y("destroy()",function(a){a=a||!1;return this.iterator("table",function(b){var c=b.nTableWrapper.parentNode,d=b.oClasses,e=b.nTable,h=b.nTBody,f=b.nTHead, -g=b.nTFoot,k=l(e);h=l(h);var m=l(b.nTableWrapper),n=l.map(b.aoData,function(t){return t.nTr}),p;b.bDestroying=!0;F(b,"aoDestroyCallback","destroy",[b]);a||(new B(b)).columns().visible(!0);m.off(".DT").find(":not(tbody *)").off(".DT");l(z).off(".DT-"+b.sInstance);e!=f.parentNode&&(k.children("thead").detach(),k.append(f));g&&e!=g.parentNode&&(k.children("tfoot").detach(),k.append(g));b.aaSorting=[];b.aaSortingFixed=[];Sa(b);l(n).removeClass(b.asStripeClasses.join(" "));l("th, td",f).removeClass(d.sSortable+ -" "+d.sSortableAsc+" "+d.sSortableDesc+" "+d.sSortableNone);h.children().detach();h.append(n);f=a?"remove":"detach";k[f]();m[f]();!a&&c&&(c.insertBefore(e,b.nTableReinsertBefore),k.css("width",b.sDestroyWidth).removeClass(d.sTable),(p=b.asDestroyStripes.length)&&h.children().each(function(t){l(this).addClass(b.asDestroyStripes[t%p])}));c=l.inArray(b,u.settings);-1!==c&&u.settings.splice(c,1)})});l.each(["column","row","cell"],function(a,b){y(b+"s().every()",function(c){var d=this.selector.opts,e= -this;return this.iterator(b,function(h,f,g,k,m){c.call(e[b](f,"cell"===b?g:d,"cell"===b?d:q),f,g,k,m)})})});y("i18n()",function(a,b,c){var d=this.context[0];a=na(a)(d.oLanguage);a===q&&(a=b);c!==q&&l.isPlainObject(a)&&(a=a[c]!==q?a[c]:a._);return a.replace("%d",c)});u.version="1.11.4";u.settings=[];u.models={};u.models.oSearch={bCaseInsensitive:!0,sSearch:"",bRegex:!1,bSmart:!0,"return":!1};u.models.oRow={nTr:null,anCells:null,_aData:[],_aSortData:null,_aFilterData:null,_sFilterRow:null,_sRowStripe:"", -src:null,idx:-1};u.models.oColumn={idx:null,aDataSort:null,asSorting:null,bSearchable:null,bSortable:null,bVisible:null,_sManualType:null,_bAttrSrc:!1,fnCreatedCell:null,fnGetData:null,fnSetData:null,mData:null,mRender:null,nTh:null,nTf:null,sClass:null,sContentPadding:null,sDefaultContent:null,sName:null,sSortDataType:"std",sSortingClass:null,sSortingClassJUI:null,sTitle:null,sType:null,sWidth:null,sWidthOrig:null};u.defaults={aaData:null,aaSorting:[[0,"asc"]],aaSortingFixed:[],ajax:null,aLengthMenu:[10, -25,50,100],aoColumns:null,aoColumnDefs:null,aoSearchCols:[],asStripeClasses:null,bAutoWidth:!0,bDeferRender:!1,bDestroy:!1,bFilter:!0,bInfo:!0,bLengthChange:!0,bPaginate:!0,bProcessing:!1,bRetrieve:!1,bScrollCollapse:!1,bServerSide:!1,bSort:!0,bSortMulti:!0,bSortCellsTop:!1,bSortClasses:!0,bStateSave:!1,fnCreatedRow:null,fnDrawCallback:null,fnFooterCallback:null,fnFormatNumber:function(a){return a.toString().replace(/\B(?=(\d{3})+(?!\d))/g,this.oLanguage.sThousands)},fnHeaderCallback:null,fnInfoCallback:null, -fnInitComplete:null,fnPreDrawCallback:null,fnRowCallback:null,fnServerData:null,fnServerParams:null,fnStateLoadCallback:function(a){try{return JSON.parse((-1===a.iStateDuration?sessionStorage:localStorage).getItem("DataTables_"+a.sInstance+"_"+location.pathname))}catch(b){return{}}},fnStateLoadParams:null,fnStateLoaded:null,fnStateSaveCallback:function(a,b){try{(-1===a.iStateDuration?sessionStorage:localStorage).setItem("DataTables_"+a.sInstance+"_"+location.pathname,JSON.stringify(b))}catch(c){}}, -fnStateSaveParams:null,iStateDuration:7200,iDeferLoading:null,iDisplayLength:10,iDisplayStart:0,iTabIndex:0,oClasses:{},oLanguage:{oAria:{sSortAscending:": activate to sort column ascending",sSortDescending:": activate to sort column descending"},oPaginate:{sFirst:"First",sLast:"Last",sNext:"Next",sPrevious:"Previous"},sEmptyTable:"No data available in table",sInfo:"Showing _START_ to _END_ of _TOTAL_ entries",sInfoEmpty:"Showing 0 to 0 of 0 entries",sInfoFiltered:"(filtered from _MAX_ total entries)", -sInfoPostFix:"",sDecimal:"",sThousands:",",sLengthMenu:"Show _MENU_ entries",sLoadingRecords:"Loading...",sProcessing:"Processing...",sSearch:"Search:",sSearchPlaceholder:"",sUrl:"",sZeroRecords:"No matching records found"},oSearch:l.extend({},u.models.oSearch),sAjaxDataProp:"data",sAjaxSource:null,sDom:"lfrtip",searchDelay:null,sPaginationType:"simple_numbers",sScrollX:"",sScrollXInner:"",sScrollY:"",sServerMethod:"GET",renderer:null,rowId:"DT_RowId"};E(u.defaults);u.defaults.column={aDataSort:null, -iDataSort:-1,asSorting:["asc","desc"],bSearchable:!0,bSortable:!0,bVisible:!0,fnCreatedCell:null,mData:null,mRender:null,sCellType:"td",sClass:"",sContentPadding:"",sDefaultContent:null,sName:"",sSortDataType:"std",sTitle:null,sType:null,sWidth:null};E(u.defaults.column);u.models.oSettings={oFeatures:{bAutoWidth:null,bDeferRender:null,bFilter:null,bInfo:null,bLengthChange:null,bPaginate:null,bProcessing:null,bServerSide:null,bSort:null,bSortMulti:null,bSortClasses:null,bStateSave:null},oScroll:{bCollapse:null, -iBarWidth:0,sX:null,sXInner:null,sY:null},oLanguage:{fnInfoCallback:null},oBrowser:{bScrollOversize:!1,bScrollbarLeft:!1,bBounding:!1,barWidth:0},ajax:null,aanFeatures:[],aoData:[],aiDisplay:[],aiDisplayMaster:[],aIds:{},aoColumns:[],aoHeader:[],aoFooter:[],oPreviousSearch:{},aoPreSearchCols:[],aaSorting:null,aaSortingFixed:[],asStripeClasses:null,asDestroyStripes:[],sDestroyWidth:0,aoRowCallback:[],aoHeaderCallback:[],aoFooterCallback:[],aoDrawCallback:[],aoRowCreatedCallback:[],aoPreDrawCallback:[], -aoInitComplete:[],aoStateSaveParams:[],aoStateLoadParams:[],aoStateLoaded:[],sTableId:"",nTable:null,nTHead:null,nTFoot:null,nTBody:null,nTableWrapper:null,bDeferLoading:!1,bInitialised:!1,aoOpenRows:[],sDom:null,searchDelay:null,sPaginationType:"two_button",iStateDuration:0,aoStateSave:[],aoStateLoad:[],oSavedState:null,oLoadedState:null,sAjaxSource:null,sAjaxDataProp:null,jqXHR:null,json:q,oAjaxData:q,fnServerData:null,aoServerParams:[],sServerMethod:null,fnFormatNumber:null,aLengthMenu:null,iDraw:0, -bDrawing:!1,iDrawError:-1,_iDisplayLength:10,_iDisplayStart:0,_iRecordsTotal:0,_iRecordsDisplay:0,oClasses:{},bFiltered:!1,bSorted:!1,bSortCellsTop:null,oInit:null,aoDestroyCallback:[],fnRecordsTotal:function(){return"ssp"==Q(this)?1*this._iRecordsTotal:this.aiDisplayMaster.length},fnRecordsDisplay:function(){return"ssp"==Q(this)?1*this._iRecordsDisplay:this.aiDisplay.length},fnDisplayEnd:function(){var a=this._iDisplayLength,b=this._iDisplayStart,c=b+a,d=this.aiDisplay.length,e=this.oFeatures,h= -e.bPaginate;return e.bServerSide?!1===h||-1===a?b+d:Math.min(b+a,this._iRecordsDisplay):!h||c>d||-1===a?d:c},oInstance:null,sInstance:null,iTabIndex:0,nScrollHead:null,nScrollFoot:null,aLastSort:[],oPlugins:{},rowIdFn:null,rowId:null};u.ext=M={buttons:{},classes:{},build:"dt/dt-1.11.4/fc-4.0.1/fh-3.2.1/r-2.2.9/sb-1.3.1",errMode:"alert",feature:[],search:[],selector:{cell:[],column:[],row:[]},internal:{},legacy:{ajax:null},pager:{},renderer:{pageButton:{},header:{}},order:{},type:{detect:[],search:{},order:{}},_unique:0,fnVersionCheck:u.fnVersionCheck, -iApiIndex:0,oJUIClasses:{},sVersion:u.version};l.extend(M,{afnFiltering:M.search,aTypes:M.type.detect,ofnSearch:M.type.search,oSort:M.type.order,afnSortData:M.order,aoFeatures:M.feature,oApi:M.internal,oStdClasses:M.classes,oPagination:M.pager});l.extend(u.ext.classes,{sTable:"dataTable",sNoFooter:"no-footer",sPageButton:"paginate_button",sPageButtonActive:"current",sPageButtonDisabled:"disabled",sStripeOdd:"odd",sStripeEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter", -sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_desc_disabled",sSortableDesc:"sorting_asc_disabled",sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sFilterInput:"",sLengthSelect:"",sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead",sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody", -sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sHeaderTH:"",sFooterTH:"",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:"",sSortJUIWrapper:"",sSortIcon:"",sJUIHeader:"",sJUIFooter:""});var ec=u.ext.pager;l.extend(ec,{simple:function(a,b){return["previous","next"]},full:function(a,b){return["first","previous","next","last"]},numbers:function(a,b){return[Da(a,b)]},simple_numbers:function(a,b){return["previous",Da(a,b),"next"]}, -full_numbers:function(a,b){return["first","previous",Da(a,b),"next","last"]},first_last_numbers:function(a,b){return["first",Da(a,b),"last"]},_numbers:Da,numbers_length:7});l.extend(!0,u.ext.renderer,{pageButton:{_:function(a,b,c,d,e,h){var f=a.oClasses,g=a.oLanguage.oPaginate,k=a.oLanguage.oAria.paginate||{},m,n,p=0,t=function(x,w){var r,C=f.sPageButtonDisabled,G=function(I){Ra(a,I.data.action,!0)};var aa=0;for(r=w.length;aa").appendTo(x); -t(O,L)}else{m=null;n=L;O=a.iTabIndex;switch(L){case "ellipsis":x.append('');break;case "first":m=g.sFirst;0===e&&(O=-1,n+=" "+C);break;case "previous":m=g.sPrevious;0===e&&(O=-1,n+=" "+C);break;case "next":m=g.sNext;if(0===h||e===h-1)O=-1,n+=" "+C;break;case "last":m=g.sLast;if(0===h||e===h-1)O=-1,n+=" "+C;break;default:m=a.fnFormatNumber(L+1),n=e===L?f.sPageButtonActive:""}null!==m&&(O=l("",{"class":f.sPageButton+" "+n,"aria-controls":a.sTableId,"aria-label":k[L], -"data-dt-idx":p,tabindex:O,id:0===c&&"string"===typeof L?a.sTableId+"_"+L:null}).html(m).appendTo(x),ob(O,{action:L},G),p++)}}};try{var v=l(b).find(A.activeElement).data("dt-idx")}catch(x){}t(l(b).empty(),d);v!==q&&l(b).find("[data-dt-idx="+v+"]").trigger("focus")}}});l.extend(u.ext.type.detect,[function(a,b){b=b.oLanguage.sDecimal;return tb(a,b)?"num"+b:null},function(a,b){if(a&&!(a instanceof Date)&&!uc.test(a))return null;b=Date.parse(a);return null!==b&&!isNaN(b)||Z(a)?"date":null},function(a, -b){b=b.oLanguage.sDecimal;return tb(a,b,!0)?"num-fmt"+b:null},function(a,b){b=b.oLanguage.sDecimal;return jc(a,b)?"html-num"+b:null},function(a,b){b=b.oLanguage.sDecimal;return jc(a,b,!0)?"html-num-fmt"+b:null},function(a,b){return Z(a)||"string"===typeof a&&-1!==a.indexOf("<")?"html":null}]);l.extend(u.ext.type.search,{html:function(a){return Z(a)?a:"string"===typeof a?a.replace(gc," ").replace(Va,""):""},string:function(a){return Z(a)?a:"string"===typeof a?a.replace(gc," "):a}});var Ua=function(a, -b,c,d){if(0!==a&&(!a||"-"===a))return-Infinity;b&&(a=ic(a,b));a.replace&&(c&&(a=a.replace(c,"")),d&&(a=a.replace(d,"")));return 1*a};l.extend(M.type.order,{"date-pre":function(a){a=Date.parse(a);return isNaN(a)?-Infinity:a},"html-pre":function(a){return Z(a)?"":a.replace?a.replace(/<.*?>/g,"").toLowerCase():a+""},"string-pre":function(a){return Z(a)?"":"string"===typeof a?a.toLowerCase():a.toString?a.toString():""},"string-asc":function(a,b){return ab?1:0},"string-desc":function(a,b){return a< -b?1:a>b?-1:0}});Xa("");l.extend(!0,u.ext.renderer,{header:{_:function(a,b,c,d){l(a.nTable).on("order.dt.DT",function(e,h,f,g){a===h&&(e=c.idx,b.removeClass(d.sSortAsc+" "+d.sSortDesc).addClass("asc"==g[e]?d.sSortAsc:"desc"==g[e]?d.sSortDesc:c.sSortingClass))})},jqueryui:function(a,b,c,d){l("
    ").addClass(d.sSortJUIWrapper).append(b.contents()).append(l("").addClass(d.sSortIcon+" "+c.sSortingClassJUI)).appendTo(b);l(a.nTable).on("order.dt.DT",function(e,h,f,g){a===h&&(e=c.idx,b.removeClass(d.sSortAsc+ -" "+d.sSortDesc).addClass("asc"==g[e]?d.sSortAsc:"desc"==g[e]?d.sSortDesc:c.sSortingClass),b.find("span."+d.sSortIcon).removeClass(d.sSortJUIAsc+" "+d.sSortJUIDesc+" "+d.sSortJUI+" "+d.sSortJUIAscAllowed+" "+d.sSortJUIDescAllowed).addClass("asc"==g[e]?d.sSortJUIAsc:"desc"==g[e]?d.sSortJUIDesc:c.sSortingClassJUI))})}}});var yb=function(a){Array.isArray(a)&&(a=a.join(","));return"string"===typeof a?a.replace(/&/g,"&").replace(//g,">").replace(/"/g,"""):a};u.render= -{number:function(a,b,c,d,e){return{display:function(h){if("number"!==typeof h&&"string"!==typeof h)return h;var f=0>h?"-":"",g=parseFloat(h);if(isNaN(g))return yb(h);g=g.toFixed(c);h=Math.abs(g);g=parseInt(h,10);h=c?b+(h-g).toFixed(c).substring(2):"";0===g&&0===parseFloat(h)&&(f="");return f+(d||"")+g.toString().replace(/\B(?=(\d{3})+(?!\d))/g,a)+h+(e||"")}}},text:function(){return{display:yb,filter:yb}}};l.extend(u.ext.internal,{_fnExternApiFunc:fc,_fnBuildAjax:Oa,_fnAjaxUpdate:Gb,_fnAjaxParameters:Pb, -_fnAjaxUpdateDraw:Qb,_fnAjaxDataSrc:Aa,_fnAddColumn:Ya,_fnColumnOptions:Ga,_fnAdjustColumnSizing:ta,_fnVisibleToColumnIndex:ua,_fnColumnIndexToVisible:va,_fnVisbleColumns:oa,_fnGetColumns:Ia,_fnColumnTypes:$a,_fnApplyColumnDefs:Db,_fnHungarianMap:E,_fnCamelToHungarian:P,_fnLanguageCompat:ma,_fnBrowserDetect:Bb,_fnAddData:ia,_fnAddTr:Ja,_fnNodeToDataIndex:function(a,b){return b._DT_RowIndex!==q?b._DT_RowIndex:null},_fnNodeToColumnIndex:function(a,b,c){return l.inArray(c,a.aoData[b].anCells)},_fnGetCellData:T, -_fnSetCellData:Eb,_fnSplitObjNotation:cb,_fnGetObjectDataFn:na,_fnSetObjectDataFn:ha,_fnGetDataMaster:db,_fnClearTable:Ka,_fnDeleteIndex:La,_fnInvalidate:wa,_fnGetRowElements:bb,_fnCreateTr:ab,_fnBuildHead:Fb,_fnDrawHead:ya,_fnDraw:ja,_fnReDraw:ka,_fnAddOptionsHtml:Ib,_fnDetectHeader:xa,_fnGetUniqueThs:Na,_fnFeatureHtmlFilter:Kb,_fnFilterComplete:za,_fnFilterCustom:Tb,_fnFilterColumn:Sb,_fnFilter:Rb,_fnFilterCreateSearch:ib,_fnEscapeRegex:jb,_fnFilterData:Ub,_fnFeatureHtmlInfo:Nb,_fnUpdateInfo:Xb, -_fnInfoMacros:Yb,_fnInitialise:Ba,_fnInitComplete:Pa,_fnLengthChange:kb,_fnFeatureHtmlLength:Jb,_fnFeatureHtmlPaginate:Ob,_fnPageChange:Ra,_fnFeatureHtmlProcessing:Lb,_fnProcessingDisplay:V,_fnFeatureHtmlTable:Mb,_fnScrollDraw:Ha,_fnApplyToChildren:ca,_fnCalculateColumnWidths:Za,_fnThrottle:hb,_fnConvertToWidth:Zb,_fnGetWidestNode:$b,_fnGetMaxLenString:ac,_fnStringToCss:K,_fnSortFlatten:pa,_fnSort:Hb,_fnSortAria:cc,_fnSortListener:nb,_fnSortAttachListener:fb,_fnSortingClasses:Sa,_fnSortData:bc,_fnSaveState:qa, -_fnLoadState:dc,_fnImplementState:pb,_fnSettingsFromNode:Ta,_fnLog:da,_fnMap:X,_fnBindAction:ob,_fnCallbackReg:R,_fnCallbackFire:F,_fnLengthOverflow:lb,_fnRenderer:gb,_fnDataSource:Q,_fnRowAttributes:eb,_fnExtend:qb,_fnCalculateEnd:function(){}});l.fn.dataTable=u;u.$=l;l.fn.dataTableSettings=u.settings;l.fn.dataTableExt=u.ext;l.fn.DataTable=function(a){return l(this).dataTable(a).api()};l.each(u,function(a,b){l.fn.DataTable[a]=b});return u}); - - -/*! - DataTables styling integration - ©2018 SpryMedia Ltd - datatables.net/license -*/ -(function(c){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(a){return c(a,window,document)}):"object"===typeof exports?module.exports=function(a,b){a||(a=window);b&&b.fn.dataTable||(b=require("datatables.net")(a,b).$);return c(b,a,a.document)}:c(jQuery,window,document)})(function(c,a,b,d){return c.fn.dataTable}); - - -/*! - FixedColumns 4.0.1 - 2019-2021 SpryMedia Ltd - datatables.net/license -*/ -var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.getGlobal=function(a){a=["object"==typeof globalThis&&globalThis,a,"object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global];for(var g=0;g").css(h).css("left",0).addClass(this.classes.leftBottomBlocker),leftTopBlocker:a("
    ").css(h).css({left:0,top:0}).addClass(this.classes.leftTopBlocker),rightBottomBlocker:a("
    ").css(h).css("right",0).addClass(this.classes.rightBottomBlocker),rightTopBlocker:a("
    ").css(h).css({right:0,top:0}).addClass(this.classes.rightTopBlocker)};if(this.s.dt.settings()[0]._bInitComplete)this._addStyles(), -this._setKeyTableListener();else d.one("preInit.dt",function(){m._addStyles();m._setKeyTableListener()});d.settings()[0]._fixedColumns=this;return this}e.prototype.left=function(d){void 0!==d&&(this.c.left=d,this._addStyles());return this.c.left};e.prototype.right=function(d){void 0!==d&&(this.c.right=d,this._addStyles());return this.c.right};e.prototype._addStyles=function(){if(this.s.dt.settings()[0].oScroll.sY){var d=a(this.s.dt.table().node()).closest("div.dataTables_scrollBody")[0],h=this.s.dt.settings()[0].oBrowser.barWidth; -this.s.barWidth=d.offsetWidth-d.clientWidth>=h?h:0;this.dom.rightTopBlocker.css("width",this.s.barWidth+1);this.dom.leftTopBlocker.css("width",this.s.barWidth+1);this.dom.rightBottomBlocker.css("width",this.s.barWidth+1);this.dom.leftBottomBlocker.css("width",this.s.barWidth+1)}d=null;h=this.s.dt.column(0).header();var m=null;null!==h&&(h=a(h),m=h.outerHeight()+1,d=a(h.closest("div.dataTables_scroll")).css("position","relative"));var n=this.s.dt.column(0).footer(),c=null;null!==n&&(n=a(n),c=n.outerHeight(), -null===d&&(d=a(n.closest("div.dataTables_scroll")).css("position","relative")));for(var b=this.s.dt.columns().data().toArray().length,f=0,l=0,u=a(this.s.dt.table().node()).children("tbody").children("tr"),x=0,A=new Map,r=0;r=b-this.c.right){a(this.s.dt.table().node()).addClass(this.classes.tableFixedRight);d.addClass(this.classes.tableFixedRight);if(r+1+vb.left&&(c=m.scrollLeft(),m.scrollLeft(c-(b.left-(h.left+n)))))});this.s.dt.on("draw",function(){d._addStyles()});this.s.dt.on("column-reorder",function(){d._addStyles()});this.s.dt.on("column-visibility",function(){setTimeout(function(){d._addStyles()},50)})};e.version="4.0.1";e.classes={fixedLeft:"dtfc-fixed-left",fixedRight:"dtfc-fixed-right",leftBottomBlocker:"dtfc-left-bottom-blocker",leftTopBlocker:"dtfc-left-top-blocker",rightBottomBlocker:"dtfc-right-bottom-blocker",rightTopBlocker:"dtfc-right-top-blocker", -tableFixedLeft:"dtfc-has-left",tableFixedRight:"dtfc-has-right"};e.defaults={i18n:{button:"FixedColumns"},left:1,right:0};return e}();(function(e){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(d){return e(d,window,document)}):"object"===typeof exports?module.exports=function(d,h){d||(d=window);h&&h.fn.dataTable||(h=require("datatables.net")(d,h).$);return e(h,d,d.document)}:e(window.jQuery,window,document)})(function(e,d,h){function m(c,b){void 0===b&&(b=null); -c=new n.Api(c);b=b?b:c.init().fixedColumns||n.defaults.fixedColumns;return new k(c,b)}a=e;g=a.fn.dataTable;var n=e.fn.dataTable;e.fn.dataTable.FixedColumns=k;e.fn.DataTable.FixedColumns=k;d=e.fn.dataTable.Api.register;d("fixedColumns()",function(){return this});d("fixedColumns().left()",function(c){var b=this.context[0];return void 0!==c?(b._fixedColumns.left(c),this):b._fixedColumns.left()});d("fixedColumns().right()",function(c){var b=this.context[0];return void 0!==c?(b._fixedColumns.right(c), -this):b._fixedColumns.right()});e.fn.dataTable.ext.buttons.fixedColumns={action:function(c,b,f,l){e(f).attr("active")?(e(f).removeAttr("active").removeClass("active"),b.fixedColumns().left(0),b.fixedColumns().right(0)):(e(f).attr("active",!0).addClass("active"),b.fixedColumns().left(l.config.left),b.fixedColumns().right(l.config.right))},config:{left:1,right:0},init:function(c,b,f){void 0===c.settings()[0]._fixedColumns&&m(c.settings(),f);e(b).attr("active",!0).addClass("active");c.button(b).text(f.text|| -c.i18n("buttons.fixedColumns",c.settings()[0]._fixedColumns.c.i18n.button))},text:null};e(h).on("init.dt.dtfc",function(c,b){"dt"===c.namespace&&(b.oInit.fixedColumns||n.defaults.fixedColumns)&&(b._fixedColumns||m(b,null))})})})(); - - -/*! - Copyright 2009-2021 SpryMedia Ltd. - - This source file is free software, available under the following license: - MIT license - http://datatables.net/license/mit - - This source file is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. - - For details please refer to: http://www.datatables.net - FixedHeader 3.2.1 - ©2009-2021 SpryMedia Ltd - datatables.net/license -*/ -var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.findInternal=function(b,g,h){b instanceof String&&(b=String(b));for(var l=b.length,k=0;k'), -placeholder:null},footer:{host:null,floating:null,floatingParent:b('
    '),placeholder:null}};this.dom.header.host=this.dom.thead.parent();this.dom.footer.host=this.dom.tfoot.parent();a=a.settings()[0];if(a._fixedHeader)throw"FixedHeader already initialised on table "+a.nTable.id;a._fixedHeader=this;this._constructor()};b.extend(t.prototype,{destroy:function(){this.s.dt.off(".dtfc");b(g).off(this.s.namespace);this.c.header&&this._modeChange("in-place","header",!0);this.c.footer&& -this.dom.tfoot.length&&this._modeChange("in-place","footer",!0)},enable:function(a,c){this.s.enable=a;if(c||c===l)this._positions(),this._scroll(!0)},enabled:function(){return this.s.enable},headerOffset:function(a){a!==l&&(this.c.headerOffset=a,this.update());return this.c.headerOffset},footerOffset:function(a){a!==l&&(this.c.footerOffset=a,this.update());return this.c.footerOffset},update:function(a){var c=this.s.dt.table().node();b(c).is(":visible")?this.enable(!0,!1):this.enable(!1,!1);0!==b(c).children("thead").length&& -(this._positions(),this._scroll(a!==l?a:!0))},_constructor:function(){var a=this,c=this.s.dt;b(g).on("scroll"+this.s.namespace,function(){a._scroll()}).on("resize"+this.s.namespace,k.util.throttle(function(){a.s.position.windowHeight=b(g).height();a.update()},50));var d=b(".fh-fixedHeader");!this.c.headerOffset&&d.length&&(this.c.headerOffset=d.outerHeight());d=b(".fh-fixedFooter");!this.c.footerOffset&&d.length&&(this.c.footerOffset=d.outerHeight());c.on("column-reorder.dt.dtfc column-visibility.dt.dtfc column-sizing.dt.dtfc responsive-display.dt.dtfc", -function(f,e){a.update()}).on("draw.dt.dtfc",function(f,e){a.update(e===c.settings()[0]?!1:!0)});c.on("destroy.dtfc",function(){a.destroy()});this._positions();this._scroll()},_clone:function(a,c){var d=this,f=this.s.dt,e=this.dom[a],p="header"===a?this.dom.thead:this.dom.tfoot;if("footer"!==a||!this._scrollEnabled())if(!c&&e.floating)e.floating.removeClass("fixedHeader-floating fixedHeader-locked");else{e.floating&&(null!==e.placeholder&&e.placeholder.remove(),this._unsize(a),e.floating.children().detach(), -e.floating.remove());c=b(f.table().node());var n=b(c.parent()),q=this._scrollEnabled();e.floating=b(f.table().node().cloneNode(!1)).attr("aria-hidden","true").css({"table-layout":"fixed",top:0,left:0}).removeAttr("id").append(p);e.floatingParent.css({width:n.width(),overflow:"hidden",height:"fit-content",position:"fixed",left:q?c.offset().left+n.scrollLeft():0}).css("header"===a?{top:this.c.headerOffset,bottom:""}:{top:"",bottom:this.c.footerOffset}).addClass("footer"===a?"dtfh-floatingparentfoot": -"dtfh-floatingparenthead").append(e.floating).appendTo("body");this._stickyPosition(e.floating,"-");a=function(){var r=n.scrollLeft();d.s.scrollLeft={footer:r,header:r};e.floatingParent.scrollLeft(d.s.scrollLeft.header)};a();n.scroll(a);e.placeholder=p.clone(!1);e.placeholder.find("*[id]").removeAttr("id");e.host.prepend(e.placeholder);this._matchWidths(e.placeholder,e.floating)}},_stickyPosition:function(a,c){if(this._scrollEnabled()){var d=this,f="rtl"===b(d.s.dt.table().node()).css("direction"); -a.find("th").each(function(){if("sticky"===b(this).css("position")){var e=b(this).css("right"),p=b(this).css("left");"auto"===e||f?"auto"!==p&&f&&(e=+p.replace(/px/g,"")+("-"===c?-1:1)*d.s.dt.settings()[0].oBrowser.barWidth,b(this).css("left",0y?e.tfootHeight:z+e.tfootHeight-y:d+ -this.c.headerOffset+e.theadHeight-m;m="header"===c?"top":"bottom";d=this.c[c+"Offset"]-(0y&&n+this.c.headerOffsete||this.dom.header.floatingParent===l?a=!0:this.dom.header.floatingParent.css({top:this.c.headerOffset, -position:"fixed"}).append(this.dom.header.floating)):q="below":q="in-place",(a||q!==this.s.headerMode)&&this._modeChange(q,"header",a),this._horizontal("header",p));var w={offset:{top:0,left:0},height:0},x={offset:{top:0,left:0},height:0};this.c.footer&&this.dom.tfoot.length&&(this.s.enable?!m.visible||m.tfootBottom+this.c.footerOffset<=r?m="in-place":e+m.tfootHeight+this.c.footerOffset>r&&y+this.c.footerOffsetn&&(c=n-f.top,r=r+(c>-w.height?c:0)-(w.offset.top+(c<-w.height?w.height:0)+x.height),0>r&&(r=0),d.outerHeight(r),Math.round(d.outerHeight())>=Math.round(r)?b(this.dom.tfoot.parent()).addClass("fixedHeader-floating"):b(this.dom.tfoot.parent()).removeClass("fixedHeader-floating"))); -this.dom.header.floating&&this.dom.header.floatingParent.css("left",z-p);this.dom.footer.floating&&this.dom.footer.floatingParent.css("left",z-p);this.s.dt.settings()[0]._fixedColumns!==l&&(d=function(A,C,u){u===l&&(u=b("div.dtfc-"+A+"-"+C+"-blocker"),u=0===u.length?null:u.clone().appendTo("body").css("z-index",1));null!==u&&u.css({top:"top"===C?w.offset.top:x.offset.top,left:"right"===A?z+B-u.width():z});return u},this.dom.header.rightBlocker=d("right","top",this.dom.header.rightBlocker),this.dom.header.leftBlocker= -d("left","top",this.dom.header.leftBlocker),this.dom.footer.rightBlocker=d("right","bottom",this.dom.footer.rightBlocker),this.dom.footer.leftBlocker=d("left","bottom",this.dom.footer.leftBlocker))},_scrollEnabled:function(){var a=this.s.dt.settings()[0].oScroll;return""!==a.sY||""!==a.sX?!0:!1}});t.version="3.2.1";t.defaults={header:!0,footer:!1,headerOffset:0,footerOffset:0};b.fn.dataTable.FixedHeader=t;b.fn.DataTable.FixedHeader=t;b(h).on("init.dt.dtfh",function(a,c,d){"dt"===a.namespace&&(a=c.oInit.fixedHeader, -d=k.defaults.fixedHeader,!a&&!d||c._fixedHeader||(d=b.extend({},d,a),!1!==a&&new t(c,d)))});k.Api.register("fixedHeader()",function(){});k.Api.register("fixedHeader.adjust()",function(){return this.iterator("table",function(a){(a=a._fixedHeader)&&a.update()})});k.Api.register("fixedHeader.enable()",function(a){return this.iterator("table",function(c){c=c._fixedHeader;a=a!==l?a:!0;c&&a!==c.enabled()&&c.enable(a)})});k.Api.register("fixedHeader.enabled()",function(){if(this.context.length){var a=this.context[0]._fixedHeader; -if(a)return a.enabled()}return!1});k.Api.register("fixedHeader.disable()",function(){return this.iterator("table",function(a){(a=a._fixedHeader)&&a.enabled()&&a.enable(!1)})});b.each(["header","footer"],function(a,c){k.Api.register("fixedHeader."+c+"Offset()",function(d){var f=this.context;return d===l?f.length&&f[0]._fixedHeader?f[0]._fixedHeader[c+"Offset"]():l:this.iterator("table",function(e){if(e=e._fixedHeader)e[c+"Offset"](d)})})});return t}); - - -/*! - Copyright 2014-2021 SpryMedia Ltd. - - This source file is free software, available under the following license: - MIT license - http://datatables.net/license/mit - - This source file is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. - - For details please refer to: http://www.datatables.net - Responsive 2.2.9 - 2014-2021 SpryMedia Ltd - datatables.net/license -*/ -var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.findInternal=function(b,k,m){b instanceof String&&(b=String(b));for(var n=b.length,p=0;ptd, >th", -g).each(function(e){e=c.column.index("toData",e);!1===a.s.current[e]&&b(this).css("display","none")})});c.on("destroy.dtr",function(){c.off(".dtr");b(c.table().body()).off(".dtr");b(k).off("resize.dtr orientationchange.dtr");c.cells(".dtr-control").nodes().to$().removeClass("dtr-control");b.each(a.s.current,function(g,l){!1===l&&a._setColumnVis(g,!0)})});this.c.breakpoints.sort(function(g,l){return g.widthl.width?-1:0});this._classLogic();this._resizeAuto();d=this.c.details;!1!== -d.type&&(a._detailsInit(),c.on("column-visibility.dtr",function(){a._timer&&clearTimeout(a._timer);a._timer=setTimeout(function(){a._timer=null;a._classLogic();a._resizeAuto();a._resize(!0);a._redrawChildren()},100)}),c.on("draw.dtr",function(){a._redrawChildren()}),b(c.table().node()).addClass("dtr-"+d.type));c.on("column-reorder.dtr",function(g,l,h){a._classLogic();a._resizeAuto();a._resize(!0)});c.on("column-sizing.dtr",function(){a._resizeAuto();a._resize()});c.on("preXhr.dtr",function(){var g= -[];c.rows().every(function(){this.child.isShown()&&g.push(this.id(!0))});c.one("draw.dtr",function(){a._resizeAuto();a._resize();c.rows(g).every(function(){a._detailsDisplay(this,!1)})})});c.on("draw.dtr",function(){a._controlClass()}).on("init.dtr",function(g,l,h){"dt"===g.namespace&&(a._resizeAuto(),a._resize(),b.inArray(!1,a.s.current)&&c.columns.adjust())});this._resize()},_columnsVisiblity:function(a){var c=this.s.dt,d=this.s.columns,f,g=d.map(function(t,v){return{columnIdx:v,priority:t.priority}}).sort(function(t, -v){return t.priority!==v.priority?t.priority-v.priority:t.columnIdx-v.columnIdx}),l=b.map(d,function(t,v){return!1===c.column(v).visible()?"not-visible":t.auto&&null===t.minWidth?!1:!0===t.auto?"-":-1!==b.inArray(a,t.includeIn)}),h=0;var e=0;for(f=l.length;eh-d[q].minWidth?(r=!0,l[q]=!1):l[q]=!0,h-=d[q].minWidth)}g=!1;e=0;for(f=d.length;e=q&&g(h,c[e].name);else if("not-"===r)for(e= -0,r=c.length;ef?c.columns().eq(0).length+f:f;if(c.cell(this).index().column!==l)return}l=c.row(b(this).closest("tr"));"click"===g.type?a._detailsDisplay(l,!1):"mousedown"===g.type?b(this).css("outline","none"):"mouseup"===g.type&&b(this).trigger("blur").css("outline","")}})}, -_detailsObj:function(a){var c=this,d=this.s.dt;return b.map(this.s.columns,function(f,g){if(!f.never&&!f.control)return f=d.settings()[0].aoColumns[g],{className:f.sClass,columnIndex:g,data:d.cell(a,g).render(c.c.orthogonal),hidden:d.column(g).visible()&&!c.s.current[g],rowIndex:a,title:null!==f.sTitle?f.sTitle:b(d.column(g).header()).text()}})},_find:function(a){for(var c=this.c.breakpoints,d=0,f=c.length;d").append(h).appendTo(g)}b("
    ").append(l).appendTo(f);"inline"===this.c.details.type&&b(d).addClass("dtr-inline collapsed");b(d).find("[name]").removeAttr("name");b(d).css("position","relative");d=b("
    ").css({width:1,height:1,overflow:"hidden",clear:"both"}).append(d);d.insertBefore(a.table().node());l.each(function(e){e=a.column.index("fromVisible",e);c[e].minWidth=this.offsetWidth||0});d.remove()}},_responsiveOnlyHidden:function(){var a=this.s.dt;return b.map(this.s.current, -function(c,d){return!1===a.column(d).visible()?!0:c})},_setColumnVis:function(a,c){var d=this.s.dt;c=c?"":"none";b(d.column(a).header()).css("display",c);b(d.column(a).footer()).css("display",c);d.column(a).nodes().to$().css("display",c);b.isEmptyObject(A)||d.cells(null,a).indexes().each(function(f){y(d,f.row,f.column)})},_tabIndexes:function(){var a=this.s.dt,c=a.cells({page:"current"}).nodes().to$(),d=a.settings()[0],f=this.c.details.target;c.filter("[data-dtr-keyboard]").removeData("[data-dtr-keyboard]"); -"number"===typeof f?a.cells(null,f,{page:"current"}).nodes().to$().attr("tabIndex",d.iTabIndex).data("dtr-keyboard",1):("td:first-child, th:first-child"===f&&(f=">td:first-child, >th:first-child"),b(f,a.rows({page:"current"}).nodes()).attr("tabIndex",d.iTabIndex).data("dtr-keyboard",1))}});u.breakpoints=[{name:"desktop",width:Infinity},{name:"tablet-l",width:1024},{name:"tablet-p",width:768},{name:"mobile-l",width:480},{name:"mobile-p",width:320}];u.display={childRow:function(a,c,d){if(c){if(b(a.node()).hasClass("parent"))return a.child(d(), -"child").show(),!0}else{if(a.child.isShown())return a.child(!1),b(a.node()).removeClass("parent"),!1;a.child(d(),"child").show();b(a.node()).addClass("parent");return!0}},childRowImmediate:function(a,c,d){if(!c&&a.child.isShown()||!a.responsive.hasHidden())return a.child(!1),b(a.node()).removeClass("parent"),!1;a.child(d(),"child").show();b(a.node()).addClass("parent");return!0},modal:function(a){return function(c,d,f){if(d)b("div.dtr-modal-content").empty().append(f());else{var g=function(){l.remove(); -b(m).off("keypress.dtr")},l=b('
    ').append(b('
    ').append(b('
    ').append(f())).append(b('
    ×
    ').click(function(){g()}))).append(b('
    ').click(function(){g()})).appendTo("body");b(m).on("keyup.dtr",function(h){27===h.keyCode&&(h.stopPropagation(),g())})}a&&a.header&&b("div.dtr-modal-content").prepend("

    "+a.header(c)+"

    ")}}};var A={};u.renderer= -{listHiddenNodes:function(){return function(a,c,d){var f=b('
      '),g=!1;b.each(d,function(l,h){h.hidden&&(b("
    • '+h.title+"
    • ").append(b('').append(p(a,h.rowIndex,h.columnIndex))).appendTo(f),g=!0)});return g?f:!1}},listHidden:function(){return function(a, -c,d){return(a=b.map(d,function(f){var g=f.className?'class="'+f.className+'"':"";return f.hidden?"
    • '+f.title+' '+f.data+"
    • ":""}).join(""))?b('
        ').append(a):!1}},tableAll:function(a){a=b.extend({tableClass:""},a);return function(c,d,f){c=b.map(f,function(g){return"
    "}).join("");return b('
    ",{valign:"top",colSpan:oa(a),"class":a.oClasses.sRowEmpty}).html(e))[0];F(a,"aoHeaderCallback","header",[l(a.nTHead).children("tr")[0],db(a),m,n,k]);F(a,"aoFooterCallback", -"footer",[l(a.nTFoot).children("tr")[0],db(a),m,n,k]);d=l(a.nTBody);d.children().detach();d.append(l(c));F(a,"aoDrawCallback","draw",[a]);a.bSorted=!1;a.bFiltered=!1;a.bDrawing=!1}}function ka(a,b){var c=a.oFeatures,d=c.bFilter;c.bSort&&Hb(a);d?za(a,a.oPreviousSearch):a.aiDisplay=a.aiDisplayMaster.slice();!0!==b&&(a._iDisplayStart=0);a._drawHold=b;ja(a);a._drawHold=!1}function Ib(a){var b=a.oClasses,c=l(a.nTable);c=l("
    ").insertBefore(c);var d=a.oFeatures,e=l("
    ",{id:a.sTableId+"_wrapper", -"class":b.sWrapper+(a.nTFoot?"":" "+b.sNoFooter)});a.nHolding=c[0];a.nTableWrapper=e[0];a.nTableReinsertBefore=a.nTable.nextSibling;for(var h=a.sDom.split(""),f,g,k,m,n,p,t=0;t")[0];m=h[t+1];if("'"==m||'"'==m){n="";for(p=2;h[t+p]!=m;)n+=h[t+p],p++;"H"==n?n=b.sJUIHeader:"F"==n&&(n=b.sJUIFooter);-1!=n.indexOf(".")?(m=n.split("."),k.id=m[0].substr(1,m[0].length-1),k.className=m[1]):"#"==n.charAt(0)?k.id=n.substr(1,n.length-1):k.className=n;t+=p}e.append(k); -e=l(k)}else if(">"==g)e=e.parent();else if("l"==g&&d.bPaginate&&d.bLengthChange)f=Jb(a);else if("f"==g&&d.bFilter)f=Kb(a);else if("r"==g&&d.bProcessing)f=Lb(a);else if("t"==g)f=Mb(a);else if("i"==g&&d.bInfo)f=Nb(a);else if("p"==g&&d.bPaginate)f=Ob(a);else if(0!==u.ext.feature.length)for(k=u.ext.feature,p=0,m=k.length;p',g=d.sSearch;g=g.match(/_INPUT_/)?g.replace("_INPUT_",f):g+f;b=l("
    ",{id:h.f?null:c+"_filter","class":b.sFilter}).append(l("
    ").addClass(b.sLength);a.aanFeatures.l||(k[0].id=c+"_length");k.children().append(a.oLanguage.sLengthMenu.replace("_MENU_",e[0].outerHTML));l("select",k).val(a._iDisplayLength).on("change.DT",function(m){kb(a,l(this).val());ja(a)});l(a.nTable).on("length.dt.DT",function(m,n,p){a===n&&l("select",k).val(p)});return k[0]}function Ob(a){var b=a.sPaginationType,c=u.ext.pager[b],d="function"===typeof c,e=function(f){ja(f)};b=l("
    ").addClass(a.oClasses.sPaging+b)[0]; -var h=a.aanFeatures;d||c.fnInit(a,b,e);h.p||(b.id=a.sTableId+"_paginate",a.aoDrawCallback.push({fn:function(f){if(d){var g=f._iDisplayStart,k=f._iDisplayLength,m=f.fnRecordsDisplay(),n=-1===k;g=n?0:Math.ceil(g/k);k=n?1:Math.ceil(m/k);m=c(g,k);var p;n=0;for(p=h.p.length;nh&& -(d=0)):"first"==b?d=0:"previous"==b?(d=0<=e?d-e:0,0>d&&(d=0)):"next"==b?d+e",{id:a.aanFeatures.r?null:a.sTableId+"_processing","class":a.oClasses.sProcessing}).html(a.oLanguage.sProcessing).insertBefore(a.nTable)[0]}function V(a,b){a.oFeatures.bProcessing&&l(a.aanFeatures.r).css("display",b?"block":"none"); -F(a,null,"processing",[a,b])}function Mb(a){var b=l(a.nTable),c=a.oScroll;if(""===c.sX&&""===c.sY)return a.nTable;var d=c.sX,e=c.sY,h=a.oClasses,f=b.children("caption"),g=f.length?f[0]._captionSide:null,k=l(b[0].cloneNode(!1)),m=l(b[0].cloneNode(!1)),n=b.children("tfoot");n.length||(n=null);k=l("
    ",{"class":h.sScrollWrapper}).append(l("
    ",{"class":h.sScrollHead}).css({overflow:"hidden",position:"relative",border:0,width:d?d?K(d):null:"100%"}).append(l("
    ",{"class":h.sScrollHeadInner}).css({"box-sizing":"content-box", -width:c.sXInner||"100%"}).append(k.removeAttr("id").css("margin-left",0).append("top"===g?f:null).append(b.children("thead"))))).append(l("
    ",{"class":h.sScrollBody}).css({position:"relative",overflow:"auto",width:d?K(d):null}).append(b));n&&k.append(l("
    ",{"class":h.sScrollFoot}).css({overflow:"hidden",border:0,width:d?d?K(d):null:"100%"}).append(l("
    ",{"class":h.sScrollFootInner}).append(m.removeAttr("id").css("margin-left",0).append("bottom"===g?f:null).append(b.children("tfoot"))))); -b=k.children();var p=b[0];h=b[1];var t=n?b[2]:null;if(d)l(h).on("scroll.DT",function(v){v=this.scrollLeft;p.scrollLeft=v;n&&(t.scrollLeft=v)});l(h).css("max-height",e);c.bCollapse||l(h).css("height",e);a.nScrollHead=p;a.nScrollBody=h;a.nScrollFoot=t;a.aoDrawCallback.push({fn:Ha,sName:"scrolling"});return k[0]}function Ha(a){var b=a.oScroll,c=b.sX,d=b.sXInner,e=b.sY;b=b.iBarWidth;var h=l(a.nScrollHead),f=h[0].style,g=h.children("div"),k=g[0].style,m=g.children("table");g=a.nScrollBody;var n=l(g),p= -g.style,t=l(a.nScrollFoot).children("div"),v=t.children("table"),x=l(a.nTHead),w=l(a.nTable),r=w[0],C=r.style,G=a.nTFoot?l(a.nTFoot):null,aa=a.oBrowser,L=aa.bScrollOversize;U(a.aoColumns,"nTh");var O=[],I=[],H=[],ea=[],Y,Ca=function(D){D=D.style;D.paddingTop="0";D.paddingBottom="0";D.borderTopWidth="0";D.borderBottomWidth="0";D.height=0};var fa=g.scrollHeight>g.clientHeight;if(a.scrollBarVis!==fa&&a.scrollBarVis!==q)a.scrollBarVis=fa,ta(a);else{a.scrollBarVis=fa;w.children("thead, tfoot").remove(); -if(G){var ba=G.clone().prependTo(w);var la=G.find("tr");ba=ba.find("tr")}var mb=x.clone().prependTo(w);x=x.find("tr");fa=mb.find("tr");mb.find("th, td").removeAttr("tabindex");c||(p.width="100%",h[0].style.width="100%");l.each(Na(a,mb),function(D,W){Y=ua(a,D);W.style.width=a.aoColumns[Y].sWidth});G&&ca(function(D){D.style.width=""},ba);h=w.outerWidth();""===c?(C.width="100%",L&&(w.find("tbody").height()>g.offsetHeight||"scroll"==n.css("overflow-y"))&&(C.width=K(w.outerWidth()-b)),h=w.outerWidth()): -""!==d&&(C.width=K(d),h=w.outerWidth());ca(Ca,fa);ca(function(D){var W=z.getComputedStyle?z.getComputedStyle(D).width:K(l(D).width());H.push(D.innerHTML);O.push(W)},fa);ca(function(D,W){D.style.width=O[W]},x);l(fa).height(0);G&&(ca(Ca,ba),ca(function(D){ea.push(D.innerHTML);I.push(K(l(D).css("width")))},ba),ca(function(D,W){D.style.width=I[W]},la),l(ba).height(0));ca(function(D,W){D.innerHTML='
    '+H[W]+"
    ";D.childNodes[0].style.height="0";D.childNodes[0].style.overflow= -"hidden";D.style.width=O[W]},fa);G&&ca(function(D,W){D.innerHTML='
    '+ea[W]+"
    ";D.childNodes[0].style.height="0";D.childNodes[0].style.overflow="hidden";D.style.width=I[W]},ba);Math.round(w.outerWidth())g.offsetHeight||"scroll"==n.css("overflow-y")?h+b:h,L&&(g.scrollHeight>g.offsetHeight||"scroll"==n.css("overflow-y"))&&(C.width=K(la-b)),""!==c&&""===d||da(a,1,"Possible column misalignment",6)):la="100%";p.width=K(la);f.width=K(la); -G&&(a.nScrollFoot.style.width=K(la));!e&&L&&(p.height=K(r.offsetHeight+b));c=w.outerWidth();m[0].style.width=K(c);k.width=K(c);d=w.height()>g.clientHeight||"scroll"==n.css("overflow-y");e="padding"+(aa.bScrollbarLeft?"Left":"Right");k[e]=d?b+"px":"0px";G&&(v[0].style.width=K(c),t[0].style.width=K(c),t[0].style[e]=d?b+"px":"0px");w.children("colgroup").insertBefore(w.children("thead"));n.trigger("scroll");!a.bSorted&&!a.bFiltered||a._drawHold||(g.scrollTop=0)}}function ca(a,b,c){for(var d=0,e=0,h= -b.length,f,g;e").appendTo(g.find("tbody"));g.find("thead, tfoot").remove();g.append(l(a.nTHead).clone()).append(l(a.nTFoot).clone());g.find("tfoot th, tfoot td").css("width","");m=Na(a,g.find("thead")[0]);for(v=0;v").css({width:w.sWidthOrig,margin:0,padding:0,border:0,height:1}));if(a.aoData.length)for(v=0;v").css(h||e?{position:"absolute",top:0,left:0,height:1,right:0,overflow:"hidden"}:{}).append(g).appendTo(p);h&&f?g.width(f):h?(g.css("width","auto"),g.removeAttr("width"),g.width()").css("width",K(a)).appendTo(b||A.body);b=a[0].offsetWidth;a.remove();return b}function $b(a,b){var c= -ac(a,b);if(0>c)return null;var d=a.aoData[c];return d.nTr?d.anCells[b]:l("
    ").html(T(a,c,b,"display"))[0]}function ac(a,b){for(var c,d=-1,e=-1,h=0,f=a.aoData.length;hd&&(d=c.length,e=h);return e}function K(a){return null===a?"0px":"number"==typeof a?0>a?"0px":a+"px":a.match(/\d$/)?a+"px":a}function pa(a){var b=[],c=a.aoColumns;var d=a.aaSortingFixed;var e=l.isPlainObject(d);var h=[];var f=function(n){n.length&& -!Array.isArray(n[0])?h.push(n):l.merge(h,n)};Array.isArray(d)&&f(d);e&&d.pre&&f(d.pre);f(a.aaSorting);e&&d.post&&f(d.post);for(a=0;aG?1:0;if(0!==C)return"asc"===r.dir?C:-C}C=c[n];G=c[p];return CG?1:0}):f.sort(function(n,p){var t,v=g.length,x=e[n]._aSortData,w=e[p]._aSortData;for(t=0;tG?1:0})}a.bSorted=!0}function cc(a){var b=a.aoColumns,c=pa(a);a=a.oLanguage.oAria;for(var d=0,e=b.length;d/g,"");var k=h.nTh;k.removeAttribute("aria-sort");h.bSortable&&(0e?e+1:3))}e= -0;for(h=d.length;ee?e+1:3))}a.aLastSort=d}function bc(a,b){var c=a.aoColumns[b],d=u.ext.order[c.sSortDataType],e;d&&(e=d.call(a.oInstance,a,b,va(a,b)));for(var h,f=u.ext.type.order[c.sType+"-pre"],g=0,k=a.aoData.length;g=e.length?[0,m[1]]:m)}));b.search!==q&&l.extend(a.oPreviousSearch,Wb(b.search));if(b.columns){f=0;for(d=b.columns.length;f=c&&(b=c-d);b-=b%d;if(-1===d||0>b)b=0;a._iDisplayStart=b}function gb(a,b){a=a.renderer;var c=u.ext.renderer[b];return l.isPlainObject(a)&&a[b]?c[a[b]]||c._:"string"===typeof a?c[a]||c._:c._}function Q(a){return a.oFeatures.bServerSide? -"ssp":a.ajax||a.sAjaxSource?"ajax":"dom"}function Da(a,b){var c=ec.numbers_length,d=Math.floor(c/2);b<=c?a=ra(0,b):a<=d?(a=ra(0,c-2),a.push("ellipsis"),a.push(b-1)):(a>=b-1-d?a=ra(b-(c-2),b):(a=ra(a-d+2,a+d-1),a.push("ellipsis"),a.push(b-1)),a.splice(0,0,"ellipsis"),a.splice(0,0,0));a.DT_el="span";return a}function Xa(a){l.each({num:function(b){return Ua(b,a)},"num-fmt":function(b){return Ua(b,a,rb)},"html-num":function(b){return Ua(b,a,Va)},"html-num-fmt":function(b){return Ua(b,a,Va,rb)}},function(b, -c){M.type.order[b+a+"-pre"]=c;b.match(/^html\-/)&&(M.type.search[b+a]=M.type.search.html)})}function fc(a){return function(){var b=[Ta(this[u.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return u.ext.internal[a].apply(this,b)}}var u=function(a,b){if(this instanceof u)return l(a).DataTable(b);b=a;this.$=function(f,g){return this.api(!0).$(f,g)};this._=function(f,g){return this.api(!0).rows(f,g).data()};this.api=function(f){return f?new B(Ta(this[M.iApiIndex])):new B(this)};this.fnAddData= -function(f,g){var k=this.api(!0);f=Array.isArray(f)&&(Array.isArray(f[0])||l.isPlainObject(f[0]))?k.rows.add(f):k.row.add(f);(g===q||g)&&k.draw();return f.flatten().toArray()};this.fnAdjustColumnSizing=function(f){var g=this.api(!0).columns.adjust(),k=g.settings()[0],m=k.oScroll;f===q||f?g.draw(!1):(""!==m.sX||""!==m.sY)&&Ha(k)};this.fnClearTable=function(f){var g=this.api(!0).clear();(f===q||f)&&g.draw()};this.fnClose=function(f){this.api(!0).row(f).child.hide()};this.fnDeleteRow=function(f,g,k){var m= -this.api(!0);f=m.rows(f);var n=f.settings()[0],p=n.aoData[f[0][0]];f.remove();g&&g.call(this,n,p);(k===q||k)&&m.draw();return p};this.fnDestroy=function(f){this.api(!0).destroy(f)};this.fnDraw=function(f){this.api(!0).draw(f)};this.fnFilter=function(f,g,k,m,n,p){n=this.api(!0);null===g||g===q?n.search(f,k,m,p):n.column(g).search(f,k,m,p);n.draw()};this.fnGetData=function(f,g){var k=this.api(!0);if(f!==q){var m=f.nodeName?f.nodeName.toLowerCase():"";return g!==q||"td"==m||"th"==m?k.cell(f,g).data(): -k.row(f).data()||null}return k.data().toArray()};this.fnGetNodes=function(f){var g=this.api(!0);return f!==q?g.row(f).node():g.rows().nodes().flatten().toArray()};this.fnGetPosition=function(f){var g=this.api(!0),k=f.nodeName.toUpperCase();return"TR"==k?g.row(f).index():"TD"==k||"TH"==k?(f=g.cell(f).index(),[f.row,f.columnVisible,f.column]):null};this.fnIsOpen=function(f){return this.api(!0).row(f).child.isShown()};this.fnOpen=function(f,g,k){return this.api(!0).row(f).child(g,k).show().child()[0]}; -this.fnPageChange=function(f,g){f=this.api(!0).page(f);(g===q||g)&&f.draw(!1)};this.fnSetColumnVis=function(f,g,k){f=this.api(!0).column(f).visible(g);(k===q||k)&&f.columns.adjust().draw()};this.fnSettings=function(){return Ta(this[M.iApiIndex])};this.fnSort=function(f){this.api(!0).order(f).draw()};this.fnSortListener=function(f,g,k){this.api(!0).order.listener(f,g,k)};this.fnUpdate=function(f,g,k,m,n){var p=this.api(!0);k===q||null===k?p.row(g).data(f):p.cell(g,k).data(f);(n===q||n)&&p.columns.adjust(); -(m===q||m)&&p.draw();return 0};this.fnVersionCheck=M.fnVersionCheck;var c=this,d=b===q,e=this.length;d&&(b={});this.oApi=this.internal=M.internal;for(var h in u.ext.internal)h&&(this[h]=fc(h));this.each(function(){var f={},g=1").appendTo(t));r.nTHead=H[0];var ea=t.children("tbody");0===ea.length&&(ea=l("
    '+g.title+": "+g.data+"
    ').append(c)}}};u.defaults={breakpoints:u.breakpoints,auto:!0,details:{display:u.display.childRow,renderer:u.renderer.listHidden(),target:0,type:"inline"},orthogonal:"display"};var C=b.fn.dataTable.Api;C.register("responsive()",function(){return this});C.register("responsive.index()", -function(a){a=b(a);return{column:a.data("dtr-index"),row:a.parent().data("dtr-index")}});C.register("responsive.rebuild()",function(){return this.iterator("table",function(a){a._responsive&&a._responsive._classLogic()})});C.register("responsive.recalc()",function(){return this.iterator("table",function(a){a._responsive&&(a._responsive._resizeAuto(),a._responsive._resize())})});C.register("responsive.hasHidden()",function(){var a=this.context[0];return a._responsive?-1!==b.inArray(!1,a._responsive._responsiveOnlyHidden()): -!1});C.registerPlural("columns().responsiveHidden()","column().responsiveHidden()",function(){return this.iterator("column",function(a,c){return a._responsive?a._responsive._responsiveOnlyHidden()[c]:!1},1)});u.version="2.2.9";b.fn.dataTable.Responsive=u;b.fn.DataTable.Responsive=u;b(m).on("preInit.dt.dtr",function(a,c,d){"dt"===a.namespace&&(b(c.nTable).hasClass("responsive")||b(c.nTable).hasClass("dt-responsive")||c.oInit.responsive||z.defaults.responsive)&&(a=c.oInit.responsive,!1!==a&&new u(c, -b.isPlainObject(a)?a:{}))});return u}); - - -/*! DataTables styling wrapper for Responsive - * ©2018 SpryMedia Ltd - datatables.net/license - */ - -(function( factory ){ - if ( typeof define === 'function' && define.amd ) { - // AMD - define( ['jquery', 'datatables.net-dt', 'datatables.net-responsive'], function ( $ ) { - return factory( $, window, document ); - } ); - } - else if ( typeof exports === 'object' ) { - // CommonJS - module.exports = function (root, $) { - if ( ! root ) { - root = window; - } - - if ( ! $ || ! $.fn.dataTable ) { - $ = require('datatables.net-dt')(root, $).$; - } - - if ( ! $.fn.dataTable.Responsive ) { - require('datatables.net-responsive')(root, $); - } - - return factory( $, root, root.document ); - }; - } - else { - // Browser - factory( jQuery, window, document ); - } -}(function( $, window, document, undefined ) { - -return $.fn.dataTable; - -})); - -/*! - SearchBuilder 1.3.1 - ©SpryMedia Ltd - datatables.net/license/mit -*/ -var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.SIMPLE_FROUND_POLYFILL=!1;$jscomp.ISOLATE_POLYFILLS=!1;$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(k,m,l){if(k==Array.prototype||k==Object.prototype)return k;k[m]=l.value;return k}; -$jscomp.getGlobal=function(k){k=["object"==typeof globalThis&&globalThis,k,"object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global];for(var m=0;ml&&(l=Math.max(l+p,0));l=t}},"es6","es3"); -$jscomp.polyfill("String.prototype.endsWith",function(k){return k?k:function(m,l){var h=$jscomp.checkStringArgs(this,m,"endsWith");m+="";void 0===l&&(l=h.length);l=Math.max(0,Math.min(l|0,h.length));for(var p=m.length;0=p}},"es6","es3"); -(function(){function k(c){h=c;p=c.fn.dataTable}function m(c){B=c;E=c.fn.dataTable}function l(c){x=c;C=c.fn.DataTable}var h,p,t=window.moment,v=window.luxon,r=function(){function c(a,b,d,e,f){var g=this;void 0===e&&(e=0);void 0===f&&(f=1);if(!p||!p.versionCheck||!p.versionCheck("1.10.0"))throw Error("SearchPane requires DataTables 1.10 or newer");this.classes=h.extend(!0,{},c.classes);this.c=h.extend(!0,{},c.defaults,h.fn.dataTable.ext.searchBuilder,b);b=this.c.i18n;this.s={condition:void 0,conditions:{}, -data:void 0,dataIdx:-1,dataPoints:[],dateFormat:!1,depth:f,dt:a,filled:!1,index:e,origData:void 0,topGroup:d,type:"",value:[]};this.dom={buttons:h("
    ").addClass(this.classes.buttonContainer),condition:h("").addClass(this.classes.data).addClass(this.classes.dropDown).addClass(this.classes.italic),dataTitle:h('
    +
    """ ] if sortcol: # sort table using JS sorttable H.append( """ """ % (int(sortcol)) ) - cells = '' - for i in range(len(F[0]) - 2): - if i in ue_index: - cls = "recap_tit_ue" - else: - cls = "recap_tit" - if ( - i == 0 or F[0][i] == "classement" - ): # Rang: force tri numerique pour sortable - cls = cls + " sortnumeric" - if F[0][i] in cod2mod: # lien vers etat module - modimpl = cod2mod[F[0][i]] - cells += '' % ( - cls, - modimpl.id, - modimpl.module.titre, - sco_users.user_info(modimpl.responsable_id)["nomcomplet"], - F[0][i], - ) - else: - cells += '' % (cls, F[0][i]) - if modejury: - cells += '' - ligne_titres = cells + "" - H.append(ligne_titres) # titres + + ligne_titres_head = _ligne_titres( + ue_index, F, cod2mod, modejury, with_modules_links=False + ) + ligne_titres_foot = _ligne_titres( + ue_index, F, cod2mod, modejury, with_modules_links=True + ) + + H.append("\n" + ligne_titres_head + "\n\n\n") if disable_etudlink: etudlink = "%(name)s" else: @@ -663,6 +629,9 @@ def make_formsemestre_recapcomplet( nblines = len(F) - 1 for l in F[1:]: etudid = l[-1] + if ir == nblines - 6: + H.append("") + H.append("") if ir >= nblines - 6: # dernieres lignes: el = l[1] @@ -692,7 +661,13 @@ def make_formsemestre_recapcomplet( for i in range(len(nsn)): if nsn[i] == "NA": nsn[i] = "-" - cells += '' % nsn[0] # rang + try: + order = int(nsn[0].split()[0]) + except: + order = 99999 + cells += ( + f'' # rang + ) cells += '' % el # nom etud (lien) if not hidebac: cells += '' % nsn[2] # bac @@ -760,7 +735,8 @@ def make_formsemestre_recapcomplet( cells += "" H.append(cells + "") - H.append(ligne_titres) + H.append(ligne_titres_foot) + H.append("") H.append("
    %s%sDécision
    %s{nsn[0]}%s%s
    ") # Form pour choisir partition de classement: @@ -828,6 +804,40 @@ def make_formsemestre_recapcomplet( raise ValueError("unknown format %s" % format) +def _ligne_titres(ue_index, F, cod2mod, modejury, with_modules_links=True): + """Cellules de la ligne de titre (haut ou bas)""" + cells = '' + for i in range(len(F[0]) - 2): + if i in ue_index: + cls = "recap_tit_ue" + else: + cls = "recap_tit" + attr = f'class="{cls}"' + if i == 0 or F[0][i] == "classement": # Rang: force tri numerique + try: + order = int(F[0][i].split()[0]) + except: + order = 99999 + attr += f' data-order="{order:05d}"' + if F[0][i] in cod2mod: # lien vers etat module + modimpl = cod2mod[F[0][i]] + if with_modules_links: + href = url_for( + "notes.moduleimpl_status", + scodoc_dept=g.scodoc_dept, + moduleimpl_id=modimpl.id, + ) + else: + href = "" + cells += f"""{F[0][i]}""" + else: + cells += f"{F[0][i]}" + if modejury: + cells += 'Décision' + return cells + "" + + def _list_notes_evals(evals: list[Evaluation], etudid: int) -> list[str]: """Liste des notes des evaluations completes de ce module (pour table xls avec evals) diff --git a/app/scodoc/sco_undo_notes.py b/app/scodoc/sco_undo_notes.py index 5d169b8bc..5cff6fe44 100644 --- a/app/scodoc/sco_undo_notes.py +++ b/app/scodoc/sco_undo_notes.py @@ -225,7 +225,8 @@ def formsemestre_list_saisies_notes(formsemestre_id, format="html"): columns_ids=columns_ids, rows=r, html_title="

    Saisies de notes dans %s

    " % sem["titreannee"], - html_class="table_leftalign table_coldate", + html_class="table_leftalign table_coldate gt_table_searchable", + html_class_ignore_default=True, html_sortable=True, caption="Saisies de notes dans %s" % sem["titreannee"], preferences=sco_preferences.SemPreferences(formsemestre_id), diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css index 086a130e4..a20816462 100644 --- a/app/static/css/scodoc.css +++ b/app/static/css/scodoc.css @@ -3226,4 +3226,15 @@ span.ext_sem_moy { font-weight: bold; color: rgb(122, 40, 2); font-size: 120%; +} + +/* DataTables */ +table.dataTable tr.odd td { + background-color: #ecf5f4; +} +table.dataTable tr.gt_lastrow th { + text-align: right; +} +table.dataTable td.etudinfo, table.dataTable td.group { + text-align: left; } \ No newline at end of file diff --git a/app/static/js/scodoc.js b/app/static/js/scodoc.js index 7cb5bb626..25f4b26dd 100644 --- a/app/static/js/scodoc.js +++ b/app/static/js/scodoc.js @@ -67,7 +67,6 @@ $(function () { } }); - // Affiche un message transitoire function sco_message(msg, color) { if (color === undefined) { @@ -106,7 +105,7 @@ function get_query_args() { // Tables (gen_tables) $(function () { - $('table.gt_table').DataTable({ + var table_options = { "paging": false, "searching": false, "info": false, @@ -117,7 +116,10 @@ $(function () { }, "orderCellsTop": true, // cellules ligne 1 pour tri "aaSorting": [], // Prevent initial sorting - }); + }; + $('table.gt_table').DataTable(table_options); + table_options["searching"] = true; + $('table.gt_table_searchable').DataTable(table_options); }); From a07c2c247f263d5c03e5020c6a103e4fa722de2a Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Wed, 23 Mar 2022 23:01:42 +0100 Subject: [PATCH 248/287] recap. en style compact --- app/scodoc/sco_recapcomplet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scodoc/sco_recapcomplet.py b/app/scodoc/sco_recapcomplet.py index 58973653d..c85ee67c9 100644 --- a/app/scodoc/sco_recapcomplet.py +++ b/app/scodoc/sco_recapcomplet.py @@ -600,7 +600,7 @@ def make_formsemestre_recapcomplet( document.location=loc; } - +
    """ ] if sortcol: # sort table using JS sorttable From 62feba8f3387e66b679fac34546eb02a8b671ef0 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Wed, 23 Mar 2022 23:02:10 +0100 Subject: [PATCH 249/287] Liste notes BUT: ajout moyennes des moyennes d'UE --- app/scodoc/sco_liste_notes.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/app/scodoc/sco_liste_notes.py b/app/scodoc/sco_liste_notes.py index 29de51587..8818abf47 100644 --- a/app/scodoc/sco_liste_notes.py +++ b/app/scodoc/sco_liste_notes.py @@ -27,6 +27,8 @@ """Liste des notes d'une évaluation """ +from collections import defaultdict +import numpy as np import flask from flask import url_for, g, request @@ -848,15 +850,8 @@ def _add_apc_columns( nt: NotesTableCompat = res_sem.load_formsemestre_results(modimpl.formsemestre) modimpl_results: ModuleImplResults = nt.modimpls_results[modimpl.id] - # XXX A ENLEVER TODO - # modimpl = ModuleImpl.query.get(moduleimpl_id) - - # evals_notes, evaluations, evaluations_completes = moy_mod.df_load_modimpl_notes( - # moduleimpl_id - # ) - # etuds_moy_module = moy_mod.compute_module_moy( - # evals_notes, evals_poids, evaluations, evaluations_completes - # ) + sum_by_ue = defaultdict(float) + nb_notes_by_ue = defaultdict(int) if is_conforme: # valeur des moyennes vers les UEs: for row in rows: @@ -864,6 +859,9 @@ def _add_apc_columns( moy_ue = modimpl_results.etuds_moy_module[ue.id].get(row["etudid"], "?") row[f"moy_ue_{ue.id}"] = scu.fmt_note(moy_ue, keep_numeric=keep_numeric) row[f"_moy_ue_{ue.id}_class"] = "moy_ue" + if isinstance(moy_ue, float) and not np.isnan(moy_ue): + sum_by_ue[ue.id] += moy_ue + nb_notes_by_ue[ue.id] += 1 # Nom et coefs des UE (lignes titres): ue_coefs = modimpl.module.ue_coefs if is_conforme: @@ -878,3 +876,9 @@ def _add_apc_columns( if coefs: row_coefs[f"moy_ue_{ue.id}"] = coefs[0].coef row_coefs[f"_moy_ue_{ue.id}_td_attrs"] = f' class="{coef_class}" ' + modimpl_results.etuds_moy_module[ue.id] + if nb_notes_by_ue[ue.id] > 0: + row_moys[col_id] = "%.3g" % (sum_by_ue[ue.id] / nb_notes_by_ue[ue.id]) + row_moys["_" + col_id + "_help"] = "moyenne des moyennes" + else: + row_moys[col_id] = "" From 1b887858bb4630567fbb98491eaea4fe83c8e3f6 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Wed, 23 Mar 2022 23:21:40 +0100 Subject: [PATCH 250/287] Listes notes BUT: restreint aux UE avec coef non nul --- app/scodoc/sco_liste_notes.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/app/scodoc/sco_liste_notes.py b/app/scodoc/sco_liste_notes.py index f07240acb..4ac234d9c 100644 --- a/app/scodoc/sco_liste_notes.py +++ b/app/scodoc/sco_liste_notes.py @@ -39,14 +39,14 @@ from app.comp import res_sem from app.comp import moy_mod from app.comp.moy_mod import ModuleImplResults from app.comp.res_common import NotesTableCompat +from app.comp.res_but import ResultatsSemestreBUT from app.models import FormSemestre from app.models.evaluations import Evaluation from app.models.moduleimpls import ModuleImpl import app.scodoc.sco_utils as scu import app.scodoc.notesdb as ndb from app.scodoc.TrivialFormulator import TrivialFormulator -from app.scodoc import sco_cache -from app.scodoc import sco_edit_module + from app.scodoc import sco_evaluations from app.scodoc import sco_evaluation_db from app.scodoc import sco_formsemestre @@ -391,7 +391,7 @@ def _make_table_notes( "_css_row_class": "moyenne sortbottom", "_table_part": "foot", #'_nomprenom_td_attrs' : 'colspan="2" ', - "nomprenom": "Moyenne (sans les absents) :", + "nomprenom": "Moyenne :", "comment": "", } # Ajoute les notes de chaque évaluation: @@ -852,9 +852,13 @@ def _add_apc_columns( # => On recharge tout dans les nouveaux modèles # rows est une liste de dict avec une clé "etudid" # on va y ajouter une clé par UE du semestre - nt: NotesTableCompat = res_sem.load_formsemestre_results(modimpl.formsemestre) + nt: ResultatsSemestreBUT = res_sem.load_formsemestre_results(modimpl.formsemestre) modimpl_results: ModuleImplResults = nt.modimpls_results[modimpl.id] - + # les UE dans lesquelles ce module a un coef non nul: + ues_with_coef = nt.modimpl_coefs_df[modimpl.id][ + nt.modimpl_coefs_df[modimpl.id] > 0 + ].index + ues = [ue for ue in ues if ue.id in ues_with_coef] sum_by_ue = defaultdict(float) nb_notes_by_ue = defaultdict(int) if is_conforme: From 41778d59185ef4173f514587df1612cc12eb4193 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Thu, 24 Mar 2022 09:59:44 +0100 Subject: [PATCH 251/287] PDF: affiche liste polices dispo, meilleurs messages d'erreur --- app/but/bulletin_but_pdf.py | 8 +-- app/scodoc/sco_bulletins_legacy.py | 18 +++--- app/scodoc/sco_bulletins_ucac.py | 12 ++-- app/scodoc/sco_pdf.py | 93 +++++++++++++++++------------- app/scodoc/sco_preferences.py | 9 ++- app/scodoc/sco_pvpdf.py | 15 ++--- app/scodoc/sco_trombino_tours.py | 44 +++++++------- 7 files changed, 104 insertions(+), 95 deletions(-) diff --git a/app/but/bulletin_but_pdf.py b/app/but/bulletin_but_pdf.py index 8a87f9005..29b9d6749 100644 --- a/app/but/bulletin_but_pdf.py +++ b/app/but/bulletin_but_pdf.py @@ -6,15 +6,13 @@ """Génération bulletin BUT au format PDF standard """ +from reportlab.lib.colors import blue +from reportlab.lib.units import cm, mm from reportlab.platypus import Paragraph, Spacer -from app.scodoc.sco_pdf import blue, cm, mm - +from app.scodoc.sco_bulletins_standard import BulletinGeneratorStandard from app.scodoc import gen_tables from app.scodoc.sco_codes_parcours import UE_SPORT -from app.scodoc.sco_utils import fmt_note - -from app.scodoc.sco_bulletins_standard import BulletinGeneratorStandard class BulletinGeneratorStandardBUT(BulletinGeneratorStandard): diff --git a/app/scodoc/sco_bulletins_legacy.py b/app/scodoc/sco_bulletins_legacy.py index 7d570d07d..314abb0db 100644 --- a/app/scodoc/sco_bulletins_legacy.py +++ b/app/scodoc/sco_bulletins_legacy.py @@ -34,17 +34,19 @@ CE FORMAT N'EVOLUERA PLUS ET EST CONSIDERE COMME OBSOLETE. """ +from reportlab.lib.colors import Color, blue +from reportlab.lib.units import cm, mm +from reportlab.platypus import Paragraph, Spacer, Table -import app.scodoc.sco_utils as scu -from app.scodoc.sco_permissions import Permission -from app.scodoc import sco_formsemestre -from app.scodoc import sco_pdf -from app.scodoc.sco_pdf import Color, Paragraph, Spacer, Table -from app.scodoc.sco_pdf import blue, cm, mm -from app.scodoc.sco_pdf import SU -from app.scodoc import sco_preferences from app.scodoc import sco_bulletins_generator from app.scodoc import sco_bulletins_pdf +from app.scodoc import sco_formsemestre +from app.scodoc.sco_permissions import Permission +from app.scodoc import sco_pdf +from app.scodoc.sco_pdf import SU +from app.scodoc import sco_preferences +import app.scodoc.sco_utils as scu + # Important: Le nom de la classe ne doit pas changer (bien le choisir), car il sera stocké en base de données (dans les préférences) class BulletinGeneratorLegacy(sco_bulletins_generator.BulletinGenerator): diff --git a/app/scodoc/sco_bulletins_ucac.py b/app/scodoc/sco_bulletins_ucac.py index 2114c60ad..fc49ffd9c 100644 --- a/app/scodoc/sco_bulletins_ucac.py +++ b/app/scodoc/sco_bulletins_ucac.py @@ -32,16 +32,12 @@ On redéfini la table centrale du bulletin de note et hérite de tout le reste d E. Viennet, juillet 2011 """ +from reportlab.lib.colors import Color +from reportlab.lib.units import mm -import app.scodoc.sco_utils as scu -from app.scodoc.sco_pdf import blue, cm, mm -from app.scodoc.sco_pdf import Color, Paragraph, Spacer, Table - -from app.scodoc import sco_preferences - -from app.scodoc import sco_bulletins_generator from app.scodoc import sco_bulletins_standard -from app.scodoc import gen_tables +from app.scodoc import sco_preferences +import app.scodoc.sco_utils as scu class BulletinGeneratorUCAC(sco_bulletins_standard.BulletinGeneratorStandard): diff --git a/app/scodoc/sco_pdf.py b/app/scodoc/sco_pdf.py index 19a778144..2f468ccfc 100755 --- a/app/scodoc/sco_pdf.py +++ b/app/scodoc/sco_pdf.py @@ -44,22 +44,17 @@ import traceback import unicodedata import reportlab -from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Frame, PageBreak -from reportlab.platypus import Table, TableStyle, Image, KeepInFrame +from reportlab.pdfgen import canvas +from reportlab.platypus import Paragraph, Frame from reportlab.platypus.flowables import Flowable from reportlab.platypus.doctemplate import PageTemplate, BaseDocTemplate -from reportlab.lib.styles import getSampleStyleSheet from reportlab.rl_config import defaultPageSize # pylint: disable=no-name-in-module from reportlab.lib.units import inch, cm, mm -from reportlab.lib.colors import pink, black, red, blue, green, magenta, red -from reportlab.lib.colors import Color -from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER, TA_JUSTIFY from reportlab.lib import styles -from reportlab.lib.pagesizes import letter, A4, landscape + from flask import g -import app.scodoc.sco_utils as scu from app.scodoc.sco_utils import CONFIG from app import log from app.scodoc.sco_exceptions import ScoGenError, ScoValueError @@ -89,6 +84,12 @@ def SU(s): return s +def get_available_font_names() -> list[str]: + """List installed font names""" + can = canvas.Canvas(io.StringIO()) + return can.getAvailableFonts() + + def _splitPara(txt): "split a string, returns a list of ... " L = [] @@ -147,12 +148,26 @@ def makeParas(txt, style, suppress_empty=False): except Exception as e: log(traceback.format_exc()) log("Invalid pdf para format: %s" % txt) - result = [ - Paragraph( - SU('Erreur: format invalide'), - style, - ) - ] + try: + result = [ + Paragraph( + SU('Erreur: format invalide'), + style, + ) + ] + except ValueError as e: # probleme font ? essaye sans style + # recupere font en cause ? + m = re.match(r".*family/bold/italic for (.*)", e.args[0], re.DOTALL) + if m: + message = f"police non disponible: {m[1]}" + else: + message = "format invalide" + return [ + Paragraph( + SU(f'Erreur: {message}'), + reportlab.lib.styles.ParagraphStyle({}), + ) + ] return result @@ -166,7 +181,6 @@ def bold_paras(L, tag="b", close=None): if hasattr(L, "keys"): # L is a dict for k in L: - x = L[k] if k[0] != "_": L[k] = b + L[k] or "" + close return L @@ -256,7 +270,7 @@ class ScoDocPageTemplate(PageTemplate): if logo is not None: self.background_image_filename = logo.filepath - def beforeDrawPage(self, canvas, doc): + def beforeDrawPage(self, canv, doc): """Draws (optional) background, logo and contribution message on each page. day : Day of the month as a decimal number [01,31] @@ -271,10 +285,10 @@ class ScoDocPageTemplate(PageTemplate): """ if not self.preferences: return - canvas.saveState() + canv.saveState() # ---- Background image if self.background_image_filename and self.with_page_background: - canvas.drawImage( + canv.drawImage( self.background_image_filename, 0, 0, doc.pagesize[0], doc.pagesize[1] ) @@ -285,32 +299,32 @@ class ScoDocPageTemplate(PageTemplate): (width, height), image, ) = self.logo - canvas.drawImage(image, inch, doc.pagesize[1] - inch, width, height) + canv.drawImage(image, inch, doc.pagesize[1] - inch, width, height) # ---- Add some meta data and bookmarks if self.pdfmeta_author: - canvas.setAuthor(SU(self.pdfmeta_author)) + canv.setAuthor(SU(self.pdfmeta_author)) if self.pdfmeta_title: - canvas.setTitle(SU(self.pdfmeta_title)) + canv.setTitle(SU(self.pdfmeta_title)) if self.pdfmeta_subject: - canvas.setSubject(SU(self.pdfmeta_subject)) + canv.setSubject(SU(self.pdfmeta_subject)) bookmark = self.pagesbookmarks.get(doc.page, None) if bookmark: - canvas.bookmarkPage(bookmark) - canvas.addOutlineEntry(SU(bookmark), bookmark) + canv.bookmarkPage(bookmark) + canv.addOutlineEntry(SU(bookmark), bookmark) - def draw_footer(self, canvas, content): + def draw_footer(self, canv, content): """Print the footer""" - canvas.setFont( + canv.setFont( self.preferences["SCOLAR_FONT"], self.preferences["SCOLAR_FONT_SIZE_FOOT"] ) - canvas.drawString( + canv.drawString( self.preferences["pdf_footer_x"] * mm, self.preferences["pdf_footer_y"] * mm, content, ) - canvas.restoreState() + canv.restoreState() def footer_string(self) -> str: """String contenu du pied de page""" @@ -319,14 +333,14 @@ class ScoDocPageTemplate(PageTemplate): d["server_url"] = self.server_name return SU(self.footer_template % d) - def afterDrawPage(self, canvas, doc): + def afterDrawPage(self, canv, doc): if not self.preferences: return # ---- Footer foot_content = None if hasattr(doc, "current_footer"): foot_content = doc.current_footer - self.draw_footer(canvas, foot_content or self.footer_string()) + self.draw_footer(canv, foot_content or self.footer_string()) # ---- Filigranne (texte en diagonal en haut a gauche de chaque page) filigranne = None if hasattr(doc, "filigranne"): @@ -338,13 +352,13 @@ class ScoDocPageTemplate(PageTemplate): else: filigranne = self.filigranne.get(doc.page, None) if filigranne: - canvas.saveState() - canvas.translate(9 * cm, 27.6 * cm) - canvas.rotate(30) - canvas.scale(4.5, 4.5) - canvas.setFillColorRGB(1.0, 0.65, 0.65, alpha=0.6) - canvas.drawRightString(0, 0, SU(filigranne)) - canvas.restoreState() + canv.saveState() + canv.translate(9 * cm, 27.6 * cm) + canv.rotate(30) + canv.scale(4.5, 4.5) + canv.setFillColorRGB(1.0, 0.65, 0.65, alpha=0.6) + canv.drawRightString(0, 0, SU(filigranne)) + canv.restoreState() doc.filigranne = None def afterPage(self): @@ -443,8 +457,8 @@ class PDFLock(object): return # deja lock pour ce thread try: self.Q.put(1, True, self.timeout) - except queue.Full: - raise ScoGenError(msg="Traitement PDF occupé: ré-essayez") + except queue.Full as e: + raise ScoGenError(msg="Traitement PDF occupé: ré-essayez") from e self.current_thread = threading.get_ident() self.nref = 1 log("PDFLock: granted to %s" % self.current_thread) @@ -471,7 +485,6 @@ class WatchLock: def release(self): t = threading.current_thread() assert (self.native_id == t.native_id) and (self.ident == t.ident) - pass class FakeLock: diff --git a/app/scodoc/sco_preferences.py b/app/scodoc/sco_preferences.py index 5d019f7d2..7f1d8cc41 100644 --- a/app/scodoc/sco_preferences.py +++ b/app/scodoc/sco_preferences.py @@ -121,6 +121,7 @@ from app import log from app.scodoc.sco_exceptions import ScoValueError, ScoException from app.scodoc.TrivialFormulator import TrivialFormulator import app.scodoc.notesdb as ndb +from app.scodoc import sco_pdf import app.scodoc.sco_utils as scu @@ -194,6 +195,8 @@ def _get_pref_default_value_from_config(name, pref_spec): return value +_INSTALLED_FONTS = ", ".join(sco_pdf.get_available_font_names()) + PREF_CATEGORIES = ( # sur page "Paramètres" ("general", {}), @@ -777,7 +780,7 @@ class BasePreferences(object): { "initvalue": "Helvetica", "title": "Police de caractère principale", - "explanation": "pour les pdf (Helvetica est recommandée)", + "explanation": f"pour les pdf (Helvetica est recommandée, parmi {_INSTALLED_FONTS})", "size": 25, "category": "pdf", }, @@ -1140,7 +1143,7 @@ class BasePreferences(object): { "initvalue": "Times-Roman", "title": "Police de caractère pour les PV", - "explanation": "pour les pdf", + "explanation": f"pour les pdf ({_INSTALLED_FONTS})", "size": 25, "category": "pvpdf", }, @@ -1542,7 +1545,7 @@ class BasePreferences(object): { "initvalue": "Times-Roman", "title": "Police titres bulletins", - "explanation": "pour les pdf", + "explanation": f"pour les pdf ({_INSTALLED_FONTS})", "size": 25, "category": "bul", }, diff --git a/app/scodoc/sco_pvpdf.py b/app/scodoc/sco_pvpdf.py index 2e8cdaf66..3ac0096d6 100644 --- a/app/scodoc/sco_pvpdf.py +++ b/app/scodoc/sco_pvpdf.py @@ -28,15 +28,13 @@ """Edition des PV de jury """ import io -import os import re import reportlab from reportlab.lib.units import cm, mm -from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER, TA_JUSTIFY -from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Frame, PageBreak -from reportlab.platypus import Table, TableStyle, Image, KeepInFrame -from reportlab.platypus.flowables import Flowable +from reportlab.lib.enums import TA_RIGHT, TA_JUSTIFY +from reportlab.platypus import Paragraph, Spacer, Frame, PageBreak +from reportlab.platypus import Table, TableStyle, Image from reportlab.platypus.doctemplate import PageTemplate, BaseDocTemplate from reportlab.lib.pagesizes import A4, landscape from reportlab.lib import styles @@ -53,7 +51,6 @@ from app.scodoc import sco_preferences from app.scodoc import sco_etud import sco_version from app.scodoc.sco_logos import find_logo -from app.scodoc.sco_pdf import PDFLOCK from app.scodoc.sco_pdf import SU LOGO_FOOTER_ASPECT = scu.CONFIG.LOGO_FOOTER_ASPECT # XXX A AUTOMATISER @@ -317,14 +314,14 @@ class PVTemplate(CourrierIndividuelTemplate): self.with_footer = self.preferences["PV_WITH_FOOTER"] self.with_page_background = self.preferences["PV_WITH_BACKGROUND"] - def afterDrawPage(self, canvas, doc): + def afterDrawPage(self, canv, doc): """Called after all flowables have been drawn on a page""" pass - def beforeDrawPage(self, canvas, doc): + def beforeDrawPage(self, canv, doc): """Called before any flowables are drawn on a page""" # If the page number is even, force a page break - CourrierIndividuelTemplate.beforeDrawPage(self, canvas, doc) + CourrierIndividuelTemplate.beforeDrawPage(self, canv, doc) # Note: on cherche un moyen de generer un saut de page double # (redémarrer sur page impaire, nouvelle feuille en recto/verso). Pas trouvé en Platypus. # diff --git a/app/scodoc/sco_trombino_tours.py b/app/scodoc/sco_trombino_tours.py index 61d80de2e..56261eb9f 100644 --- a/app/scodoc/sco_trombino_tours.py +++ b/app/scodoc/sco_trombino_tours.py @@ -33,20 +33,23 @@ import io from reportlab.lib import colors -from reportlab.lib import pagesizes +from reportlab.lib.colors import black from reportlab.lib.pagesizes import A4, A3 +from reportlab.lib import styles +from reportlab.lib.pagesizes import landscape +from reportlab.lib.units import cm +from reportlab.platypus import KeepInFrame, Paragraph, Table, TableStyle +from reportlab.platypus.doctemplate import BaseDocTemplate -import app.scodoc.sco_utils as scu -from app import log from app.scodoc import sco_abs +from app.scodoc import sco_etud +from app.scodoc.sco_exceptions import ScoPDFFormatError from app.scodoc import sco_groups from app.scodoc import sco_groups_view from app.scodoc import sco_preferences from app.scodoc import sco_trombino -from app.scodoc import sco_etud -from app.scodoc.sco_exceptions import ScoPDFFormatError -from app.scodoc.sco_pdf import * - +import app.scodoc.sco_utils as scu +from app.scodoc.sco_pdf import SU, ScoDocPageTemplate # Paramétrage de l'aspect graphique: PHOTOWIDTH = 2.8 * cm @@ -55,7 +58,7 @@ N_PER_ROW = 5 def pdf_trombino_tours( - group_ids=[], # liste des groupes à afficher + group_ids=(), # liste des groupes à afficher formsemestre_id=None, # utilisé si pas de groupes selectionné ): """Generation du trombinoscope en fichier PDF""" @@ -66,7 +69,6 @@ def pdf_trombino_tours( DeptName = sco_preferences.get_preference("DeptName") DeptFullName = sco_preferences.get_preference("DeptFullName") - UnivName = sco_preferences.get_preference("UnivName") InstituteName = sco_preferences.get_preference("InstituteName") # Generate PDF page StyleSheet = styles.getSampleStyleSheet() @@ -143,9 +145,7 @@ def pdf_trombino_tours( for group_id in groups_infos.group_ids: if group_id != "None": - members, group, group_tit, sem, nbdem = sco_groups.get_group_infos( - group_id, "I" - ) + members, _, group_tit, sem, _ = sco_groups.get_group_infos(group_id, "I") groups += " %s" % group_tit L = [] currow = [] @@ -286,14 +286,14 @@ def pdf_trombino_tours( def pdf_feuille_releve_absences( - group_ids=[], # liste des groupes à afficher + group_ids=(), # liste des groupes à afficher formsemestre_id=None, # utilisé si pas de groupes selectionné ): """Generation de la feuille d'absence en fichier PDF, avec photos""" NB_CELL_AM = sco_preferences.get_preference("feuille_releve_abs_AM") NB_CELL_PM = sco_preferences.get_preference("feuille_releve_abs_PM") - COLWIDTH = 0.85 * cm + col_width = 0.85 * cm if sco_preferences.get_preference("feuille_releve_abs_samedi"): days = sco_abs.DAYNAMES[:6] # Lundi, ..., Samedi else: @@ -307,7 +307,6 @@ def pdf_feuille_releve_absences( DeptName = sco_preferences.get_preference("DeptName") DeptFullName = sco_preferences.get_preference("DeptFullName") - UnivName = sco_preferences.get_preference("UnivName") InstituteName = sco_preferences.get_preference("InstituteName") # Generate PDF page StyleSheet = styles.getSampleStyleSheet() @@ -340,7 +339,7 @@ def pdf_feuille_releve_absences( currow = [""] * (NB_CELL_AM + 1 + NB_CELL_PM + 1) elem_day = Table( [currow], - colWidths=([COLWIDTH] * (NB_CELL_AM + 1 + NB_CELL_PM + 1)), + colWidths=([col_width] * (NB_CELL_AM + 1 + NB_CELL_PM + 1)), style=TableStyle( [ ("GRID", (0, 0), (NB_CELL_AM - 1, 0), 0.25, black), @@ -362,7 +361,7 @@ def pdf_feuille_releve_absences( elem_week = Table( W, - colWidths=([COLWIDTH * (NB_CELL_AM + 1 + NB_CELL_PM + 1)] * nb_days), + colWidths=([col_width * (NB_CELL_AM + 1 + NB_CELL_PM + 1)] * nb_days), style=TableStyle( [ ("LEFTPADDING", (0, 0), (-1, -1), 0), @@ -378,7 +377,7 @@ def pdf_feuille_releve_absences( elem_day_name = Table( [currow], - colWidths=([COLWIDTH * (NB_CELL_AM + 1 + NB_CELL_PM + 1)] * nb_days), + colWidths=([col_width * (NB_CELL_AM + 1 + NB_CELL_PM + 1)] * nb_days), style=TableStyle( [ ("LEFTPADDING", (0, 0), (-1, -1), 0), @@ -390,9 +389,7 @@ def pdf_feuille_releve_absences( ) for group_id in groups_infos.group_ids: - members, group, group_tit, sem, nbdem = sco_groups.get_group_infos( - group_id, "I" - ) + members, _, group_tit, _, _ = sco_groups.get_group_infos(group_id, "I") L = [] currow = [ @@ -429,7 +426,10 @@ def pdf_feuille_releve_absences( T = Table( L, colWidths=( - [5.0 * cm, (COLWIDTH * (NB_CELL_AM + 1 + NB_CELL_PM + 1) * nb_days)] + [ + 5.0 * cm, + (col_width * (NB_CELL_AM + 1 + NB_CELL_PM + 1) * nb_days), + ] ), style=TableStyle( [ From d9f87d8528872a63f8a8829b0f09d439be77b1a2 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Thu, 24 Mar 2022 14:01:57 +0100 Subject: [PATCH 252/287] =?UTF-8?q?am=C3=A9lioration=20liste=5Fnotes:=20ig?= =?UTF-8?q?nore=20d=C3=A9missionnaires=20dans=20moy.=20de=20groupes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/formsemestre.py | 2 +- app/scodoc/sco_liste_notes.py | 30 +++++++++++++++++++++--------- sco_version.py | 2 +- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py index 060c859ff..3b1c35d0b 100644 --- a/app/models/formsemestre.py +++ b/app/models/formsemestre.py @@ -401,7 +401,7 @@ class FormSemestre(db.Model): @cached_property def etudids_actifs(self) -> set: - "Set des etudids inscrits non démissionnaires" + "Set des etudids inscrits non démissionnaires et non défaillants" return {ins.etudid for ins in self.inscriptions if ins.etat == scu.INSCRIT} @cached_property diff --git a/app/scodoc/sco_liste_notes.py b/app/scodoc/sco_liste_notes.py index 4ac234d9c..1a4d1aa92 100644 --- a/app/scodoc/sco_liste_notes.py +++ b/app/scodoc/sco_liste_notes.py @@ -597,14 +597,15 @@ def _make_table_notes( if not e["eval_state"]["evalcomplete"]: all_complete = False if all_complete: - eval_info = 'Evaluations prises en compte dans les moyennes' + eval_info = 'Evaluations prises en compte dans les moyennes.' else: eval_info = """ Les évaluations en vert et orange sont prises en compte dans les moyennes. Celles en rouge n'ont pas toutes leurs notes.""" - if is_apc: - eval_info += " La moyenne indicative est la moyenne des moyennes d'UE, et n'est pas utilisée en BUT." - eval_info += """""" + if is_apc: + eval_info += """ La moyenne indicative est la moyenne des moyennes d'UE, et n'est pas utilisée en BUT. + Les moyennes sur le groupe sont estimées sans les absents (sauf pour les moyennes des moyennes d'UE) ni les démissionnaires.""" + eval_info += """""" return html_form + eval_info + t + "

    " else: # Une seule evaluation: ajoute histogramme @@ -669,6 +670,7 @@ def _add_eval_columns( notes = [] # liste des notes numeriques, pour calcul histogramme uniquement evaluation_id = e["evaluation_id"] e_o = Evaluation.query.get(evaluation_id) # XXX en attendant ré-écriture + inscrits = e_o.moduleimpl.formsemestre.etudids_actifs # set d'etudids notes_db = sco_evaluation_db.do_evaluation_get_all_notes(evaluation_id) for row in rows: etudid = row["etudid"] @@ -678,8 +680,13 @@ def _add_eval_columns( nb_abs += 1 if val == scu.NOTES_ATTENTE: nb_att += 1 - # calcul moyenne SANS LES ABSENTS - if val != None and val != scu.NOTES_NEUTRALISE and val != scu.NOTES_ATTENTE: + # calcul moyenne SANS LES ABSENTS ni les DEMISSIONNAIRES + if ( + (etudid in inscrits) + and val != None + and val != scu.NOTES_NEUTRALISE + and val != scu.NOTES_ATTENTE + ): if e["note_max"] > 0: valsur20 = val * 20.0 / e["note_max"] # remet sur 20 else: @@ -803,6 +810,7 @@ def _add_moymod_column( col_id = "moymod" formsemestre = FormSemestre.query.get_or_404(formsemestre_id) nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) + inscrits = formsemestre.etudids_actifs nb_notes = 0 sum_notes = 0 @@ -812,7 +820,7 @@ def _add_moymod_column( val = nt.get_etud_mod_moy(moduleimpl_id, etudid) # note sur 20, ou 'NA','NI' row[col_id] = scu.fmt_note(val, keep_numeric=keep_numeric) row["_" + col_id + "_td_attrs"] = ' class="moyenne" ' - if not isinstance(val, str): + if etudid in inscrits and not isinstance(val, str): notes.append(val) nb_notes = nb_notes + 1 sum_notes += val @@ -854,6 +862,7 @@ def _add_apc_columns( # on va y ajouter une clé par UE du semestre nt: ResultatsSemestreBUT = res_sem.load_formsemestre_results(modimpl.formsemestre) modimpl_results: ModuleImplResults = nt.modimpls_results[modimpl.id] + inscrits = modimpl.formsemestre.etudids_actifs # les UE dans lesquelles ce module a un coef non nul: ues_with_coef = nt.modimpl_coefs_df[modimpl.id][ nt.modimpl_coefs_df[modimpl.id] > 0 @@ -868,7 +877,11 @@ def _add_apc_columns( moy_ue = modimpl_results.etuds_moy_module[ue.id].get(row["etudid"], "?") row[f"moy_ue_{ue.id}"] = scu.fmt_note(moy_ue, keep_numeric=keep_numeric) row[f"_moy_ue_{ue.id}_class"] = "moy_ue" - if isinstance(moy_ue, float) and not np.isnan(moy_ue): + if ( + isinstance(moy_ue, float) + and not np.isnan(moy_ue) + and row["etudid"] in inscrits + ): sum_by_ue[ue.id] += moy_ue nb_notes_by_ue[ue.id] += 1 # Nom et coefs des UE (lignes titres): @@ -885,7 +898,6 @@ def _add_apc_columns( if coefs: row_coefs[f"moy_ue_{ue.id}"] = coefs[0].coef row_coefs[f"_moy_ue_{ue.id}_td_attrs"] = f' class="{coef_class}" ' - modimpl_results.etuds_moy_module[ue.id] if nb_notes_by_ue[ue.id] > 0: row_moys[col_id] = "%.3g" % (sum_by_ue[ue.id] / nb_notes_by_ue[ue.id]) row_moys["_" + col_id + "_help"] = "moyenne des moyennes" diff --git a/sco_version.py b/sco_version.py index 469c31229..360966562 100644 --- a/sco_version.py +++ b/sco_version.py @@ -1,7 +1,7 @@ # -*- mode: python -*- # -*- coding: utf-8 -*- -SCOVERSION = "9.1.85" +SCOVERSION = "9.1.86" SCONAME = "ScoDoc" From b68d43454f128ba2b1cc2d9b655a8b33cd965dcc Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sat, 26 Mar 2022 23:33:12 +0100 Subject: [PATCH 253/287] DataTables 1.11.5 + extensions --- .../Buttons-2.2.2/css/buttons.bootstrap.css | 380 + .../css/buttons.bootstrap.min.css | 1 + .../Buttons-2.2.2/css/buttons.bootstrap4.css | 426 + .../css/buttons.bootstrap4.min.css | 1 + .../Buttons-2.2.2/css/buttons.bootstrap5.css | 428 + .../css/buttons.bootstrap5.min.css | 1 + .../Buttons-2.2.2/css/buttons.bulma.css | 425 + .../Buttons-2.2.2/css/buttons.bulma.min.css | 1 + .../Buttons-2.2.2/css/buttons.dataTables.css | 631 + .../css/buttons.dataTables.min.css | 1 + .../Buttons-2.2.2/css/buttons.foundation.css | 367 + .../css/buttons.foundation.min.css | 1 + .../Buttons-2.2.2/css/buttons.jqueryui.css | 395 + .../css/buttons.jqueryui.min.css | 1 + .../Buttons-2.2.2/css/buttons.semanticui.css | 397 + .../css/buttons.semanticui.min.css | 1 + .../DataTables/Buttons-2.2.2/css/common.scss | 101 + .../DataTables/Buttons-2.2.2/css/mixins.scss | 237 + .../Buttons-2.2.2/js/buttons.bootstrap.js | 89 + .../Buttons-2.2.2/js/buttons.bootstrap.min.js | 7 + .../Buttons-2.2.2/js/buttons.bootstrap4.js | 87 + .../js/buttons.bootstrap4.min.js | 7 + .../Buttons-2.2.2/js/buttons.bootstrap5.js | 87 + .../js/buttons.bootstrap5.min.js | 7 + .../Buttons-2.2.2/js/buttons.bulma.js | 98 + .../Buttons-2.2.2/js/buttons.bulma.min.js | 7 + .../Buttons-2.2.2/js/buttons.colVis.js | 235 + .../Buttons-2.2.2/js/buttons.colVis.min.js | 10 + .../Buttons-2.2.2/js/buttons.dataTables.js | 38 + .../js/buttons.dataTables.min.js | 5 + .../Buttons-2.2.2/js/buttons.foundation.js | 116 + .../js/buttons.foundation.min.js | 7 + .../Buttons-2.2.2/js/buttons.html5.js | 1463 + .../Buttons-2.2.2/js/buttons.html5.min.js | 36 + .../Buttons-2.2.2/js/buttons.jqueryui.js | 75 + .../Buttons-2.2.2/js/buttons.jqueryui.min.js | 7 + .../Buttons-2.2.2/js/buttons.print.js | 221 + .../Buttons-2.2.2/js/buttons.print.min.js | 9 + .../Buttons-2.2.2/js/buttons.semanticui.js | 87 + .../js/buttons.semanticui.min.js | 7 + .../Buttons-2.2.2/js/dataTables.buttons.js | 2478 + .../js/dataTables.buttons.min.js | 54 + .../css/colReorder.bootstrap.css | 11 + .../css/colReorder.bootstrap.min.css | 1 + .../css/colReorder.bootstrap4.css | 11 + .../css/colReorder.bootstrap4.min.css | 1 + .../css/colReorder.bootstrap5.css | 11 + .../css/colReorder.bootstrap5.min.css | 1 + .../ColReorder-1.5.5/css/colReorder.bulma.css | 11 + .../css/colReorder.bulma.min.css | 1 + .../css/colReorder.dataTables.css | 11 + .../css/colReorder.dataTables.min.css | 1 + .../css/colReorder.foundation.css | 11 + .../css/colReorder.foundation.min.css | 1 + .../css/colReorder.jqueryui.css | 11 + .../css/colReorder.jqueryui.min.css | 1 + .../css/colReorder.semanticui.css | 11 + .../css/colReorder.semanticui.min.css | 1 + .../js/colReorder.bootstrap.js | 38 + .../js/colReorder.bootstrap.min.js | 5 + .../js/colReorder.bootstrap4.js | 38 + .../js/colReorder.bootstrap4.min.js | 5 + .../js/colReorder.bootstrap5.js | 38 + .../js/colReorder.bootstrap5.min.js | 5 + .../ColReorder-1.5.5/js/colReorder.bulma.js | 38 + .../js/colReorder.bulma.min.js | 5 + .../js/colReorder.dataTables.js | 38 + .../js/colReorder.dataTables.min.js | 5 + .../js/colReorder.foundation.js | 38 + .../js/colReorder.foundation.min.js | 5 + .../js/colReorder.jqueryui.js | 38 + .../js/colReorder.jqueryui.min.js | 5 + .../js/colReorder.semanticui.js | 38 + .../js/colReorder.semanticui.min.js | 5 + .../js/dataTables.colReorder.js | 1498 + .../js/dataTables.colReorder.min.js | 40 + .../css/dataTables.dataTables.css | 555 - .../css/dataTables.dataTables.min.css | 1 - .../css/dataTables.bootstrap.css | 0 .../css/dataTables.bootstrap.min.css | 0 .../css/dataTables.bootstrap4.css | 0 .../css/dataTables.bootstrap4.min.css | 0 .../css/dataTables.bootstrap5.css | 0 .../css/dataTables.bootstrap5.min.css | 0 .../css/dataTables.bulma.css | 0 .../css/dataTables.bulma.min.css | 0 .../css/dataTables.dataTables.css | 0 .../css/dataTables.dataTables.min.css | 0 .../css/dataTables.foundation.css | 0 .../css/dataTables.foundation.min.css | 0 .../css/dataTables.jqueryui.css | 0 .../css/dataTables.jqueryui.min.css | 0 .../css/dataTables.semanticui.css | 0 .../css/dataTables.semanticui.min.css | 0 .../css/jquery.dataTables.css | 0 .../css/jquery.dataTables.min.css | 0 .../images/sort_asc.png | Bin .../images/sort_asc_disabled.png | Bin .../images/sort_both.png | Bin .../images/sort_desc.png | Bin .../images/sort_desc_disabled.png | Bin .../js/dataTables.bootstrap.js | 0 .../js/dataTables.bootstrap.min.js | 0 .../js/dataTables.bootstrap4.js | 0 .../js/dataTables.bootstrap4.min.js | 0 .../js/dataTables.bootstrap5.js | 0 .../js/dataTables.bootstrap5.min.js | 0 .../js/dataTables.bulma.js | 0 .../js/dataTables.bulma.min.js | 0 .../js/dataTables.dataTables.js | 0 .../js/dataTables.dataTables.min.js | 0 .../js/dataTables.foundation.js | 0 .../js/dataTables.foundation.min.js | 0 .../js/dataTables.jqueryui.js | 0 .../js/dataTables.jqueryui.min.js | 0 .../js/dataTables.semanticui.js | 0 .../js/dataTables.semanticui.min.js | 0 .../js/jquery.dataTables.js | 10895 +- .../js/jquery.dataTables.min.js | 126 +- .../css/fixedColumns.bootstrap.min.css | 1 - .../css/fixedColumns.bootstrap4.min.css | 1 - .../css/fixedColumns.bootstrap5.min.css | 1 - .../js/dataTables.fixedColumns.min.js | 40 - .../js/fixedColumns.bootstrap.js | 40 - .../js/fixedColumns.bootstrap4.js | 43 - .../js/fixedColumns.dataTables.js | 43 - .../js/fixedColumns.foundation.js | 43 - .../js/fixedColumns.semanticui.js | 43 - .../css/fixedColumns.bootstrap.css | 29 +- .../css/fixedColumns.bootstrap.min.css | 1 + .../css/fixedColumns.bootstrap4.css | 29 +- .../css/fixedColumns.bootstrap4.min.css | 1 + .../css/fixedColumns.bootstrap5.css | 29 +- .../css/fixedColumns.bootstrap5.min.css | 1 + .../css/fixedColumns.bulma.css | 0 .../css/fixedColumns.bulma.min.css | 0 .../css/fixedColumns.dataTables.css | 0 .../css/fixedColumns.dataTables.min.css | 0 .../css/fixedColumns.foundation.css | 0 .../css/fixedColumns.foundation.min.css | 0 .../css/fixedColumns.jqueryui.css | 0 .../css/fixedColumns.jqueryui.min.css | 0 .../css/fixedColumns.semanticui.css | 0 .../css/fixedColumns.semanticui.min.css | 0 .../js/dataTables.fixedColumns.js | 31 +- .../js/dataTables.fixedColumns.min.js | 40 + .../js/fixedColumns.bootstrap.js | 33 + .../js/fixedColumns.bootstrap.min.js | 0 .../js/fixedColumns.bootstrap4.js} | 27 +- .../js/fixedColumns.bootstrap4.min.js | 0 .../js/fixedColumns.bootstrap5.js | 0 .../js/fixedColumns.bootstrap5.min.js | 0 .../js/fixedColumns.bulma.js | 0 .../js/fixedColumns.bulma.min.js | 0 .../js/fixedColumns.dataTables.js} | 10 +- .../js/fixedColumns.dataTables.min.js | 0 .../js/fixedColumns.foundation.js | 36 + .../js/fixedColumns.foundation.min.js | 0 .../js/fixedColumns.jqueryui.js | 0 .../js/fixedColumns.jqueryui.min.js | 0 .../js/fixedColumns.semanticui.js | 36 + .../js/fixedColumns.semanticui.min.js | 0 .../js/dataTables.fixedHeader.min.js | 42 - .../css/fixedHeader.bootstrap.css | 0 .../css/fixedHeader.bootstrap.min.css | 0 .../css/fixedHeader.bootstrap4.css | 0 .../css/fixedHeader.bootstrap4.min.css | 0 .../css/fixedHeader.bootstrap5.css | 0 .../css/fixedHeader.bootstrap5.min.css | 0 .../css/fixedHeader.bulma.css} | 0 .../css/fixedHeader.bulma.min.css} | 0 .../css/fixedHeader.dataTables.css | 0 .../css/fixedHeader.dataTables.min.css | 0 .../css/fixedHeader.foundation.css} | 4 - .../css/fixedHeader.foundation.min.css} | 2 +- .../css/fixedHeader.jqueryui.css | 0 .../css/fixedHeader.jqueryui.min.css | 0 .../css/fixedHeader.semanticui.css | 0 .../css/fixedHeader.semanticui.min.css | 0 .../js/dataTables.fixedHeader.js | 60 +- .../js/dataTables.fixedHeader.min.js | 43 + .../js/fixedHeader.bootstrap.js | 0 .../js/fixedHeader.bootstrap.min.js | 0 .../js/fixedHeader.bootstrap4.js | 0 .../js/fixedHeader.bootstrap4.min.js | 0 .../js/fixedHeader.bootstrap5.js | 0 .../js/fixedHeader.bootstrap5.min.js | 0 .../js/fixedHeader.bulma.js | 0 .../js/fixedHeader.bulma.min.js | 0 .../js/fixedHeader.dataTables.js | 0 .../js/fixedHeader.dataTables.min.js | 0 .../js/fixedHeader.foundation.js | 0 .../js/fixedHeader.foundation.min.js | 0 .../js/fixedHeader.jqueryui.js | 0 .../js/fixedHeader.jqueryui.min.js | 0 .../js/fixedHeader.semanticui.js | 0 .../js/fixedHeader.semanticui.min.js | 0 app/static/DataTables/JSZip-2.5.0/jszip.js | 9155 ++ .../DataTables/JSZip-2.5.0/jszip.min.js | 14 + .../RowGroup-1.1.4/css/rowGroup.bootstrap.css | 39 + .../css/rowGroup.bootstrap.min.css | 1 + .../css/rowGroup.bootstrap4.css | 39 + .../css/rowGroup.bootstrap4.min.css | 1 + .../css/rowGroup.bootstrap5.css | 58 + .../css/rowGroup.bootstrap5.min.css | 1 + .../RowGroup-1.1.4/css/rowGroup.bulma.css | 39 + .../RowGroup-1.1.4/css/rowGroup.bulma.min.css | 1 + .../css/rowGroup.dataTables.css | 39 + .../css/rowGroup.dataTables.min.css | 1 + .../css/rowGroup.foundation.css | 39 + .../css/rowGroup.foundation.min.css | 1 + .../RowGroup-1.1.4/css/rowGroup.jqueryui.css | 39 + .../css/rowGroup.jqueryui.min.css | 1 + .../css/rowGroup.semanticui.css | 39 + .../css/rowGroup.semanticui.min.css | 1 + .../RowGroup-1.1.4/js/dataTables.rowGroup.js | 486 + .../js/dataTables.rowGroup.min.js | 28 + .../RowGroup-1.1.4/js/rowGroup.bootstrap.js | 38 + .../js/rowGroup.bootstrap.min.js | 5 + .../RowGroup-1.1.4/js/rowGroup.bootstrap4.js | 38 + .../js/rowGroup.bootstrap4.min.js | 5 + .../RowGroup-1.1.4/js/rowGroup.bootstrap5.js | 38 + .../js/rowGroup.bootstrap5.min.js | 5 + .../RowGroup-1.1.4/js/rowGroup.bulma.js | 38 + .../RowGroup-1.1.4/js/rowGroup.bulma.min.js | 5 + .../RowGroup-1.1.4/js/rowGroup.dataTables.js | 38 + .../js/rowGroup.dataTables.min.js | 5 + .../RowGroup-1.1.4/js/rowGroup.foundation.js | 38 + .../js/rowGroup.foundation.min.js | 5 + .../RowGroup-1.1.4/js/rowGroup.jqueryui.js | 38 + .../js/rowGroup.jqueryui.min.js | 5 + .../RowGroup-1.1.4/js/rowGroup.semanticui.js | 38 + .../js/rowGroup.semanticui.min.js | 5 + .../css/rowReorder.bootstrap.css | 22 + .../css/rowReorder.bootstrap.min.css | 1 + .../css/rowReorder.bootstrap4.css | 22 + .../css/rowReorder.bootstrap4.min.css | 1 + .../css/rowReorder.bootstrap5.css | 22 + .../css/rowReorder.bootstrap5.min.css | 1 + .../RowReorder-1.2.8/css/rowReorder.bulma.css | 22 + .../css/rowReorder.bulma.min.css | 1 + .../css/rowReorder.dataTables.css | 22 + .../css/rowReorder.dataTables.min.css | 1 + .../css/rowReorder.foundation.css | 22 + .../css/rowReorder.foundation.min.css | 1 + .../css/rowReorder.jqueryui.css | 22 + .../css/rowReorder.jqueryui.min.css | 1 + .../css/rowReorder.semanticui.css | 22 + .../css/rowReorder.semanticui.min.css | 1 + .../js/dataTables.rowReorder.js | 820 + .../js/dataTables.rowReorder.min.js | 29 + .../js/rowReorder.bootstrap.js | 38 + .../js/rowReorder.bootstrap.min.js | 5 + .../js/rowReorder.bootstrap4.js | 38 + .../js/rowReorder.bootstrap4.min.js | 5 + .../js/rowReorder.bootstrap5.js | 38 + .../js/rowReorder.bootstrap5.min.js | 5 + .../RowReorder-1.2.8/js/rowReorder.bulma.js | 38 + .../js/rowReorder.bulma.min.js | 5 + .../js/rowReorder.dataTables.js | 38 + .../js/rowReorder.dataTables.min.js | 5 + .../js/rowReorder.foundation.js | 38 + .../js/rowReorder.foundation.min.js | 5 + .../js/rowReorder.jqueryui.js | 38 + .../js/rowReorder.jqueryui.min.js | 5 + .../js/rowReorder.semanticui.js | 38 + .../js/rowReorder.semanticui.min.js | 5 + .../css/searchBuilder.bootstrap.css | 142 - .../css/searchBuilder.bootstrap.min.css | 1 - .../css/searchBuilder.bootstrap4.css | 152 - .../css/searchBuilder.bootstrap4.min.css | 1 - .../css/searchBuilder.bootstrap5.css | 158 - .../css/searchBuilder.bootstrap5.min.css | 1 - .../css/searchBuilder.bulma.css | 153 - .../css/searchBuilder.bulma.min.css | 1 - .../css/searchBuilder.dataTables.css | 191 - .../css/searchBuilder.dataTables.min.css | 1 - .../css/searchBuilder.foundation.css | 157 - .../css/searchBuilder.foundation.min.css | 1 - .../css/searchBuilder.jqueryui.css | 141 - .../css/searchBuilder.jqueryui.min.css | 1 - .../css/searchBuilder.semanticui.css | 187 - .../css/searchBuilder.semanticui.min.css | 1 - .../js/dataTables.searchBuilder.js | 3797 - .../js/dataTables.searchBuilder.min.js | 146 - .../js/searchBuilder.bootstrap.js | 52 - .../js/searchBuilder.bootstrap.min.js | 6 - .../js/searchBuilder.bootstrap4.min.js | 2 - .../js/searchBuilder.bootstrap5.js | 54 - .../js/searchBuilder.bootstrap5.min.js | 6 - .../js/searchBuilder.bulma.js | 50 - .../js/searchBuilder.bulma.min.js | 6 - .../js/searchBuilder.dataTables.min.js | 5 - .../js/searchBuilder.foundation.js | 52 - .../js/searchBuilder.foundation.min.js | 6 - .../js/searchBuilder.jqueryui.js | 52 - .../js/searchBuilder.jqueryui.min.js | 7 - .../js/searchBuilder.semanticui.js | 64 - .../js/searchBuilder.semanticui.min.js | 7 - .../Select-1.3.4/css/select.bootstrap.css | 124 + .../Select-1.3.4/css/select.bootstrap.min.css | 1 + .../Select-1.3.4/css/select.bootstrap4.css | 124 + .../css/select.bootstrap4.min.css | 1 + .../Select-1.3.4/css/select.bootstrap5.css | 124 + .../css/select.bootstrap5.min.css | 1 + .../Select-1.3.4/css/select.bulma.css | 123 + .../Select-1.3.4/css/select.bulma.min.css | 1 + .../Select-1.3.4/css/select.dataTables.css | 114 + .../css/select.dataTables.min.css | 1 + .../Select-1.3.4/css/select.foundation.css | 126 + .../css/select.foundation.min.css | 1 + .../Select-1.3.4/css/select.jqueryui.css | 114 + .../Select-1.3.4/css/select.jqueryui.min.css | 1 + .../Select-1.3.4/css/select.semanticui.css | 119 + .../css/select.semanticui.min.css | 1 + .../Select-1.3.4/js/dataTables.select.js | 1265 + .../Select-1.3.4/js/dataTables.select.min.js | 40 + .../Select-1.3.4/js/select.bootstrap.js | 38 + .../Select-1.3.4/js/select.bootstrap.min.js | 5 + .../Select-1.3.4/js/select.bootstrap4.js | 38 + .../Select-1.3.4/js/select.bootstrap4.min.js | 5 + .../Select-1.3.4/js/select.bootstrap5.js | 38 + .../Select-1.3.4/js/select.bootstrap5.min.js | 5 + .../Select-1.3.4/js/select.bulma.js | 38 + .../Select-1.3.4/js/select.bulma.min.js | 5 + .../Select-1.3.4/js/select.dataTables.js | 38 + .../Select-1.3.4/js/select.dataTables.min.js | 5 + .../Select-1.3.4/js/select.foundation.js | 38 + .../Select-1.3.4/js/select.foundation.min.js | 5 + .../Select-1.3.4/js/select.jqueryui.js | 38 + .../Select-1.3.4/js/select.jqueryui.min.js | 5 + .../Select-1.3.4/js/select.semanticui.js | 38 + .../Select-1.3.4/js/select.semanticui.min.js | 5 + app/static/DataTables/datatables.css | 976 +- app/static/DataTables/datatables.js | 82968 ++++++++++++++-- app/static/DataTables/datatables.min.css | 20 +- app/static/DataTables/datatables.min.js | 696 +- .../DataTables/pdfmake-0.1.36/pdfmake.js | 50468 ++++++++++ .../DataTables/pdfmake-0.1.36/pdfmake.min.js | 3 + .../DataTables/pdfmake-0.1.36/vfs_fonts.js | 6 + 340 files changed, 156552 insertions(+), 21850 deletions(-) create mode 100644 app/static/DataTables/Buttons-2.2.2/css/buttons.bootstrap.css create mode 100644 app/static/DataTables/Buttons-2.2.2/css/buttons.bootstrap.min.css create mode 100644 app/static/DataTables/Buttons-2.2.2/css/buttons.bootstrap4.css create mode 100644 app/static/DataTables/Buttons-2.2.2/css/buttons.bootstrap4.min.css create mode 100644 app/static/DataTables/Buttons-2.2.2/css/buttons.bootstrap5.css create mode 100644 app/static/DataTables/Buttons-2.2.2/css/buttons.bootstrap5.min.css create mode 100644 app/static/DataTables/Buttons-2.2.2/css/buttons.bulma.css create mode 100644 app/static/DataTables/Buttons-2.2.2/css/buttons.bulma.min.css create mode 100644 app/static/DataTables/Buttons-2.2.2/css/buttons.dataTables.css create mode 100644 app/static/DataTables/Buttons-2.2.2/css/buttons.dataTables.min.css create mode 100644 app/static/DataTables/Buttons-2.2.2/css/buttons.foundation.css create mode 100644 app/static/DataTables/Buttons-2.2.2/css/buttons.foundation.min.css create mode 100644 app/static/DataTables/Buttons-2.2.2/css/buttons.jqueryui.css create mode 100644 app/static/DataTables/Buttons-2.2.2/css/buttons.jqueryui.min.css create mode 100644 app/static/DataTables/Buttons-2.2.2/css/buttons.semanticui.css create mode 100644 app/static/DataTables/Buttons-2.2.2/css/buttons.semanticui.min.css create mode 100644 app/static/DataTables/Buttons-2.2.2/css/common.scss create mode 100644 app/static/DataTables/Buttons-2.2.2/css/mixins.scss create mode 100644 app/static/DataTables/Buttons-2.2.2/js/buttons.bootstrap.js create mode 100644 app/static/DataTables/Buttons-2.2.2/js/buttons.bootstrap.min.js create mode 100644 app/static/DataTables/Buttons-2.2.2/js/buttons.bootstrap4.js create mode 100644 app/static/DataTables/Buttons-2.2.2/js/buttons.bootstrap4.min.js create mode 100644 app/static/DataTables/Buttons-2.2.2/js/buttons.bootstrap5.js create mode 100644 app/static/DataTables/Buttons-2.2.2/js/buttons.bootstrap5.min.js create mode 100644 app/static/DataTables/Buttons-2.2.2/js/buttons.bulma.js create mode 100644 app/static/DataTables/Buttons-2.2.2/js/buttons.bulma.min.js create mode 100644 app/static/DataTables/Buttons-2.2.2/js/buttons.colVis.js create mode 100644 app/static/DataTables/Buttons-2.2.2/js/buttons.colVis.min.js create mode 100644 app/static/DataTables/Buttons-2.2.2/js/buttons.dataTables.js create mode 100644 app/static/DataTables/Buttons-2.2.2/js/buttons.dataTables.min.js create mode 100644 app/static/DataTables/Buttons-2.2.2/js/buttons.foundation.js create mode 100644 app/static/DataTables/Buttons-2.2.2/js/buttons.foundation.min.js create mode 100644 app/static/DataTables/Buttons-2.2.2/js/buttons.html5.js create mode 100644 app/static/DataTables/Buttons-2.2.2/js/buttons.html5.min.js create mode 100644 app/static/DataTables/Buttons-2.2.2/js/buttons.jqueryui.js create mode 100644 app/static/DataTables/Buttons-2.2.2/js/buttons.jqueryui.min.js create mode 100644 app/static/DataTables/Buttons-2.2.2/js/buttons.print.js create mode 100644 app/static/DataTables/Buttons-2.2.2/js/buttons.print.min.js create mode 100644 app/static/DataTables/Buttons-2.2.2/js/buttons.semanticui.js create mode 100644 app/static/DataTables/Buttons-2.2.2/js/buttons.semanticui.min.js create mode 100644 app/static/DataTables/Buttons-2.2.2/js/dataTables.buttons.js create mode 100644 app/static/DataTables/Buttons-2.2.2/js/dataTables.buttons.min.js create mode 100644 app/static/DataTables/ColReorder-1.5.5/css/colReorder.bootstrap.css create mode 100644 app/static/DataTables/ColReorder-1.5.5/css/colReorder.bootstrap.min.css create mode 100644 app/static/DataTables/ColReorder-1.5.5/css/colReorder.bootstrap4.css create mode 100644 app/static/DataTables/ColReorder-1.5.5/css/colReorder.bootstrap4.min.css create mode 100644 app/static/DataTables/ColReorder-1.5.5/css/colReorder.bootstrap5.css create mode 100644 app/static/DataTables/ColReorder-1.5.5/css/colReorder.bootstrap5.min.css create mode 100644 app/static/DataTables/ColReorder-1.5.5/css/colReorder.bulma.css create mode 100644 app/static/DataTables/ColReorder-1.5.5/css/colReorder.bulma.min.css create mode 100644 app/static/DataTables/ColReorder-1.5.5/css/colReorder.dataTables.css create mode 100644 app/static/DataTables/ColReorder-1.5.5/css/colReorder.dataTables.min.css create mode 100644 app/static/DataTables/ColReorder-1.5.5/css/colReorder.foundation.css create mode 100644 app/static/DataTables/ColReorder-1.5.5/css/colReorder.foundation.min.css create mode 100644 app/static/DataTables/ColReorder-1.5.5/css/colReorder.jqueryui.css create mode 100644 app/static/DataTables/ColReorder-1.5.5/css/colReorder.jqueryui.min.css create mode 100644 app/static/DataTables/ColReorder-1.5.5/css/colReorder.semanticui.css create mode 100644 app/static/DataTables/ColReorder-1.5.5/css/colReorder.semanticui.min.css create mode 100644 app/static/DataTables/ColReorder-1.5.5/js/colReorder.bootstrap.js create mode 100644 app/static/DataTables/ColReorder-1.5.5/js/colReorder.bootstrap.min.js create mode 100644 app/static/DataTables/ColReorder-1.5.5/js/colReorder.bootstrap4.js create mode 100644 app/static/DataTables/ColReorder-1.5.5/js/colReorder.bootstrap4.min.js create mode 100644 app/static/DataTables/ColReorder-1.5.5/js/colReorder.bootstrap5.js create mode 100644 app/static/DataTables/ColReorder-1.5.5/js/colReorder.bootstrap5.min.js create mode 100644 app/static/DataTables/ColReorder-1.5.5/js/colReorder.bulma.js create mode 100644 app/static/DataTables/ColReorder-1.5.5/js/colReorder.bulma.min.js create mode 100644 app/static/DataTables/ColReorder-1.5.5/js/colReorder.dataTables.js create mode 100644 app/static/DataTables/ColReorder-1.5.5/js/colReorder.dataTables.min.js create mode 100644 app/static/DataTables/ColReorder-1.5.5/js/colReorder.foundation.js create mode 100644 app/static/DataTables/ColReorder-1.5.5/js/colReorder.foundation.min.js create mode 100644 app/static/DataTables/ColReorder-1.5.5/js/colReorder.jqueryui.js create mode 100644 app/static/DataTables/ColReorder-1.5.5/js/colReorder.jqueryui.min.js create mode 100644 app/static/DataTables/ColReorder-1.5.5/js/colReorder.semanticui.js create mode 100644 app/static/DataTables/ColReorder-1.5.5/js/colReorder.semanticui.min.js create mode 100644 app/static/DataTables/ColReorder-1.5.5/js/dataTables.colReorder.js create mode 100644 app/static/DataTables/ColReorder-1.5.5/js/dataTables.colReorder.min.js delete mode 100644 app/static/DataTables/DataTables-1.11.4/css/dataTables.dataTables.css delete mode 100644 app/static/DataTables/DataTables-1.11.4/css/dataTables.dataTables.min.css rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/css/dataTables.bootstrap.css (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/css/dataTables.bootstrap.min.css (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/css/dataTables.bootstrap4.css (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/css/dataTables.bootstrap4.min.css (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/css/dataTables.bootstrap5.css (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/css/dataTables.bootstrap5.min.css (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/css/dataTables.bulma.css (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/css/dataTables.bulma.min.css (100%) create mode 100644 app/static/DataTables/DataTables-1.11.5/css/dataTables.dataTables.css create mode 100644 app/static/DataTables/DataTables-1.11.5/css/dataTables.dataTables.min.css rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/css/dataTables.foundation.css (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/css/dataTables.foundation.min.css (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/css/dataTables.jqueryui.css (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/css/dataTables.jqueryui.min.css (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/css/dataTables.semanticui.css (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/css/dataTables.semanticui.min.css (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/css/jquery.dataTables.css (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/css/jquery.dataTables.min.css (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/images/sort_asc.png (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/images/sort_asc_disabled.png (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/images/sort_both.png (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/images/sort_desc.png (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/images/sort_desc_disabled.png (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/js/dataTables.bootstrap.js (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/js/dataTables.bootstrap.min.js (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/js/dataTables.bootstrap4.js (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/js/dataTables.bootstrap4.min.js (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/js/dataTables.bootstrap5.js (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/js/dataTables.bootstrap5.min.js (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/js/dataTables.bulma.js (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/js/dataTables.bulma.min.js (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/js/dataTables.dataTables.js (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/js/dataTables.dataTables.min.js (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/js/dataTables.foundation.js (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/js/dataTables.foundation.min.js (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/js/dataTables.jqueryui.js (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/js/dataTables.jqueryui.min.js (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/js/dataTables.semanticui.js (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/js/dataTables.semanticui.min.js (100%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/js/jquery.dataTables.js (63%) rename app/static/DataTables/{DataTables-1.11.4 => DataTables-1.11.5}/js/jquery.dataTables.min.js (86%) delete mode 100644 app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.bootstrap.min.css delete mode 100644 app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.bootstrap4.min.css delete mode 100644 app/static/DataTables/FixedColumns-4.0.1/css/fixedColumns.bootstrap5.min.css delete mode 100644 app/static/DataTables/FixedColumns-4.0.1/js/dataTables.fixedColumns.min.js delete mode 100644 app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.bootstrap.js delete mode 100644 app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.bootstrap4.js delete mode 100644 app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.dataTables.js delete mode 100644 app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.foundation.js delete mode 100644 app/static/DataTables/FixedColumns-4.0.1/js/fixedColumns.semanticui.js rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/css/fixedColumns.bootstrap.css (75%) create mode 100644 app/static/DataTables/FixedColumns-4.0.2/css/fixedColumns.bootstrap.min.css rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/css/fixedColumns.bootstrap4.css (75%) create mode 100644 app/static/DataTables/FixedColumns-4.0.2/css/fixedColumns.bootstrap4.min.css rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/css/fixedColumns.bootstrap5.css (80%) create mode 100644 app/static/DataTables/FixedColumns-4.0.2/css/fixedColumns.bootstrap5.min.css rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/css/fixedColumns.bulma.css (100%) rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/css/fixedColumns.bulma.min.css (100%) rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/css/fixedColumns.dataTables.css (100%) rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/css/fixedColumns.dataTables.min.css (100%) rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/css/fixedColumns.foundation.css (100%) rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/css/fixedColumns.foundation.min.css (100%) rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/css/fixedColumns.jqueryui.css (100%) rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/css/fixedColumns.jqueryui.min.css (100%) rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/css/fixedColumns.semanticui.css (100%) rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/css/fixedColumns.semanticui.min.css (100%) rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/js/dataTables.fixedColumns.js (97%) create mode 100644 app/static/DataTables/FixedColumns-4.0.2/js/dataTables.fixedColumns.min.js create mode 100644 app/static/DataTables/FixedColumns-4.0.2/js/fixedColumns.bootstrap.js rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/js/fixedColumns.bootstrap.min.js (100%) rename app/static/DataTables/{SearchBuilder-1.3.1/js/searchBuilder.bootstrap4.js => FixedColumns-4.0.2/js/fixedColumns.bootstrap4.js} (51%) rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/js/fixedColumns.bootstrap4.min.js (100%) rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/js/fixedColumns.bootstrap5.js (100%) rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/js/fixedColumns.bootstrap5.min.js (100%) rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/js/fixedColumns.bulma.js (100%) rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/js/fixedColumns.bulma.min.js (100%) rename app/static/DataTables/{SearchBuilder-1.3.1/js/searchBuilder.dataTables.js => FixedColumns-4.0.2/js/fixedColumns.dataTables.js} (73%) rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/js/fixedColumns.dataTables.min.js (100%) create mode 100644 app/static/DataTables/FixedColumns-4.0.2/js/fixedColumns.foundation.js rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/js/fixedColumns.foundation.min.js (100%) rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/js/fixedColumns.jqueryui.js (100%) rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/js/fixedColumns.jqueryui.min.js (100%) create mode 100644 app/static/DataTables/FixedColumns-4.0.2/js/fixedColumns.semanticui.js rename app/static/DataTables/{FixedColumns-4.0.1 => FixedColumns-4.0.2}/js/fixedColumns.semanticui.min.js (100%) delete mode 100644 app/static/DataTables/FixedHeader-3.2.1/js/dataTables.fixedHeader.min.js rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/css/fixedHeader.bootstrap.css (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/css/fixedHeader.bootstrap.min.css (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/css/fixedHeader.bootstrap4.css (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/css/fixedHeader.bootstrap4.min.css (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/css/fixedHeader.bootstrap5.css (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/css/fixedHeader.bootstrap5.min.css (100%) rename app/static/DataTables/{FixedHeader-3.2.1/css/fixedHeader.foundation.css => FixedHeader-3.2.2/css/fixedHeader.bulma.css} (100%) rename app/static/DataTables/{FixedHeader-3.2.1/css/fixedHeader.foundation.min.css => FixedHeader-3.2.2/css/fixedHeader.bulma.min.css} (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/css/fixedHeader.dataTables.css (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/css/fixedHeader.dataTables.min.css (100%) rename app/static/DataTables/{FixedHeader-3.2.1/css/fixedHeader.bulma.css => FixedHeader-3.2.2/css/fixedHeader.foundation.css} (84%) rename app/static/DataTables/{FixedHeader-3.2.1/css/fixedHeader.bulma.min.css => FixedHeader-3.2.2/css/fixedHeader.foundation.min.css} (81%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/css/fixedHeader.jqueryui.css (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/css/fixedHeader.jqueryui.min.css (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/css/fixedHeader.semanticui.css (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/css/fixedHeader.semanticui.min.css (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/js/dataTables.fixedHeader.js (95%) create mode 100644 app/static/DataTables/FixedHeader-3.2.2/js/dataTables.fixedHeader.min.js rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/js/fixedHeader.bootstrap.js (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/js/fixedHeader.bootstrap.min.js (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/js/fixedHeader.bootstrap4.js (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/js/fixedHeader.bootstrap4.min.js (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/js/fixedHeader.bootstrap5.js (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/js/fixedHeader.bootstrap5.min.js (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/js/fixedHeader.bulma.js (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/js/fixedHeader.bulma.min.js (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/js/fixedHeader.dataTables.js (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/js/fixedHeader.dataTables.min.js (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/js/fixedHeader.foundation.js (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/js/fixedHeader.foundation.min.js (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/js/fixedHeader.jqueryui.js (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/js/fixedHeader.jqueryui.min.js (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/js/fixedHeader.semanticui.js (100%) rename app/static/DataTables/{FixedHeader-3.2.1 => FixedHeader-3.2.2}/js/fixedHeader.semanticui.min.js (100%) create mode 100644 app/static/DataTables/JSZip-2.5.0/jszip.js create mode 100644 app/static/DataTables/JSZip-2.5.0/jszip.min.js create mode 100644 app/static/DataTables/RowGroup-1.1.4/css/rowGroup.bootstrap.css create mode 100644 app/static/DataTables/RowGroup-1.1.4/css/rowGroup.bootstrap.min.css create mode 100644 app/static/DataTables/RowGroup-1.1.4/css/rowGroup.bootstrap4.css create mode 100644 app/static/DataTables/RowGroup-1.1.4/css/rowGroup.bootstrap4.min.css create mode 100644 app/static/DataTables/RowGroup-1.1.4/css/rowGroup.bootstrap5.css create mode 100644 app/static/DataTables/RowGroup-1.1.4/css/rowGroup.bootstrap5.min.css create mode 100644 app/static/DataTables/RowGroup-1.1.4/css/rowGroup.bulma.css create mode 100644 app/static/DataTables/RowGroup-1.1.4/css/rowGroup.bulma.min.css create mode 100644 app/static/DataTables/RowGroup-1.1.4/css/rowGroup.dataTables.css create mode 100644 app/static/DataTables/RowGroup-1.1.4/css/rowGroup.dataTables.min.css create mode 100644 app/static/DataTables/RowGroup-1.1.4/css/rowGroup.foundation.css create mode 100644 app/static/DataTables/RowGroup-1.1.4/css/rowGroup.foundation.min.css create mode 100644 app/static/DataTables/RowGroup-1.1.4/css/rowGroup.jqueryui.css create mode 100644 app/static/DataTables/RowGroup-1.1.4/css/rowGroup.jqueryui.min.css create mode 100644 app/static/DataTables/RowGroup-1.1.4/css/rowGroup.semanticui.css create mode 100644 app/static/DataTables/RowGroup-1.1.4/css/rowGroup.semanticui.min.css create mode 100644 app/static/DataTables/RowGroup-1.1.4/js/dataTables.rowGroup.js create mode 100644 app/static/DataTables/RowGroup-1.1.4/js/dataTables.rowGroup.min.js create mode 100644 app/static/DataTables/RowGroup-1.1.4/js/rowGroup.bootstrap.js create mode 100644 app/static/DataTables/RowGroup-1.1.4/js/rowGroup.bootstrap.min.js create mode 100644 app/static/DataTables/RowGroup-1.1.4/js/rowGroup.bootstrap4.js create mode 100644 app/static/DataTables/RowGroup-1.1.4/js/rowGroup.bootstrap4.min.js create mode 100644 app/static/DataTables/RowGroup-1.1.4/js/rowGroup.bootstrap5.js create mode 100644 app/static/DataTables/RowGroup-1.1.4/js/rowGroup.bootstrap5.min.js create mode 100644 app/static/DataTables/RowGroup-1.1.4/js/rowGroup.bulma.js create mode 100644 app/static/DataTables/RowGroup-1.1.4/js/rowGroup.bulma.min.js create mode 100644 app/static/DataTables/RowGroup-1.1.4/js/rowGroup.dataTables.js create mode 100644 app/static/DataTables/RowGroup-1.1.4/js/rowGroup.dataTables.min.js create mode 100644 app/static/DataTables/RowGroup-1.1.4/js/rowGroup.foundation.js create mode 100644 app/static/DataTables/RowGroup-1.1.4/js/rowGroup.foundation.min.js create mode 100644 app/static/DataTables/RowGroup-1.1.4/js/rowGroup.jqueryui.js create mode 100644 app/static/DataTables/RowGroup-1.1.4/js/rowGroup.jqueryui.min.js create mode 100644 app/static/DataTables/RowGroup-1.1.4/js/rowGroup.semanticui.js create mode 100644 app/static/DataTables/RowGroup-1.1.4/js/rowGroup.semanticui.min.js create mode 100644 app/static/DataTables/RowReorder-1.2.8/css/rowReorder.bootstrap.css create mode 100644 app/static/DataTables/RowReorder-1.2.8/css/rowReorder.bootstrap.min.css create mode 100644 app/static/DataTables/RowReorder-1.2.8/css/rowReorder.bootstrap4.css create mode 100644 app/static/DataTables/RowReorder-1.2.8/css/rowReorder.bootstrap4.min.css create mode 100644 app/static/DataTables/RowReorder-1.2.8/css/rowReorder.bootstrap5.css create mode 100644 app/static/DataTables/RowReorder-1.2.8/css/rowReorder.bootstrap5.min.css create mode 100644 app/static/DataTables/RowReorder-1.2.8/css/rowReorder.bulma.css create mode 100644 app/static/DataTables/RowReorder-1.2.8/css/rowReorder.bulma.min.css create mode 100644 app/static/DataTables/RowReorder-1.2.8/css/rowReorder.dataTables.css create mode 100644 app/static/DataTables/RowReorder-1.2.8/css/rowReorder.dataTables.min.css create mode 100644 app/static/DataTables/RowReorder-1.2.8/css/rowReorder.foundation.css create mode 100644 app/static/DataTables/RowReorder-1.2.8/css/rowReorder.foundation.min.css create mode 100644 app/static/DataTables/RowReorder-1.2.8/css/rowReorder.jqueryui.css create mode 100644 app/static/DataTables/RowReorder-1.2.8/css/rowReorder.jqueryui.min.css create mode 100644 app/static/DataTables/RowReorder-1.2.8/css/rowReorder.semanticui.css create mode 100644 app/static/DataTables/RowReorder-1.2.8/css/rowReorder.semanticui.min.css create mode 100644 app/static/DataTables/RowReorder-1.2.8/js/dataTables.rowReorder.js create mode 100644 app/static/DataTables/RowReorder-1.2.8/js/dataTables.rowReorder.min.js create mode 100644 app/static/DataTables/RowReorder-1.2.8/js/rowReorder.bootstrap.js create mode 100644 app/static/DataTables/RowReorder-1.2.8/js/rowReorder.bootstrap.min.js create mode 100644 app/static/DataTables/RowReorder-1.2.8/js/rowReorder.bootstrap4.js create mode 100644 app/static/DataTables/RowReorder-1.2.8/js/rowReorder.bootstrap4.min.js create mode 100644 app/static/DataTables/RowReorder-1.2.8/js/rowReorder.bootstrap5.js create mode 100644 app/static/DataTables/RowReorder-1.2.8/js/rowReorder.bootstrap5.min.js create mode 100644 app/static/DataTables/RowReorder-1.2.8/js/rowReorder.bulma.js create mode 100644 app/static/DataTables/RowReorder-1.2.8/js/rowReorder.bulma.min.js create mode 100644 app/static/DataTables/RowReorder-1.2.8/js/rowReorder.dataTables.js create mode 100644 app/static/DataTables/RowReorder-1.2.8/js/rowReorder.dataTables.min.js create mode 100644 app/static/DataTables/RowReorder-1.2.8/js/rowReorder.foundation.js create mode 100644 app/static/DataTables/RowReorder-1.2.8/js/rowReorder.foundation.min.js create mode 100644 app/static/DataTables/RowReorder-1.2.8/js/rowReorder.jqueryui.js create mode 100644 app/static/DataTables/RowReorder-1.2.8/js/rowReorder.jqueryui.min.js create mode 100644 app/static/DataTables/RowReorder-1.2.8/js/rowReorder.semanticui.js create mode 100644 app/static/DataTables/RowReorder-1.2.8/js/rowReorder.semanticui.min.js delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/css/searchBuilder.bootstrap.css delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/css/searchBuilder.bootstrap.min.css delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/css/searchBuilder.bootstrap4.css delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/css/searchBuilder.bootstrap4.min.css delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/css/searchBuilder.bootstrap5.css delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/css/searchBuilder.bootstrap5.min.css delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/css/searchBuilder.bulma.css delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/css/searchBuilder.bulma.min.css delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/css/searchBuilder.dataTables.css delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/css/searchBuilder.dataTables.min.css delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/css/searchBuilder.foundation.css delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/css/searchBuilder.foundation.min.css delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/css/searchBuilder.jqueryui.css delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/css/searchBuilder.jqueryui.min.css delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/css/searchBuilder.semanticui.css delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/css/searchBuilder.semanticui.min.css delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/js/dataTables.searchBuilder.js delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/js/dataTables.searchBuilder.min.js delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/js/searchBuilder.bootstrap.js delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/js/searchBuilder.bootstrap.min.js delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/js/searchBuilder.bootstrap4.min.js delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/js/searchBuilder.bootstrap5.js delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/js/searchBuilder.bootstrap5.min.js delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/js/searchBuilder.bulma.js delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/js/searchBuilder.bulma.min.js delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/js/searchBuilder.dataTables.min.js delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/js/searchBuilder.foundation.js delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/js/searchBuilder.foundation.min.js delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/js/searchBuilder.jqueryui.js delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/js/searchBuilder.jqueryui.min.js delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/js/searchBuilder.semanticui.js delete mode 100644 app/static/DataTables/SearchBuilder-1.3.1/js/searchBuilder.semanticui.min.js create mode 100644 app/static/DataTables/Select-1.3.4/css/select.bootstrap.css create mode 100644 app/static/DataTables/Select-1.3.4/css/select.bootstrap.min.css create mode 100644 app/static/DataTables/Select-1.3.4/css/select.bootstrap4.css create mode 100644 app/static/DataTables/Select-1.3.4/css/select.bootstrap4.min.css create mode 100644 app/static/DataTables/Select-1.3.4/css/select.bootstrap5.css create mode 100644 app/static/DataTables/Select-1.3.4/css/select.bootstrap5.min.css create mode 100644 app/static/DataTables/Select-1.3.4/css/select.bulma.css create mode 100644 app/static/DataTables/Select-1.3.4/css/select.bulma.min.css create mode 100644 app/static/DataTables/Select-1.3.4/css/select.dataTables.css create mode 100644 app/static/DataTables/Select-1.3.4/css/select.dataTables.min.css create mode 100644 app/static/DataTables/Select-1.3.4/css/select.foundation.css create mode 100644 app/static/DataTables/Select-1.3.4/css/select.foundation.min.css create mode 100644 app/static/DataTables/Select-1.3.4/css/select.jqueryui.css create mode 100644 app/static/DataTables/Select-1.3.4/css/select.jqueryui.min.css create mode 100644 app/static/DataTables/Select-1.3.4/css/select.semanticui.css create mode 100644 app/static/DataTables/Select-1.3.4/css/select.semanticui.min.css create mode 100644 app/static/DataTables/Select-1.3.4/js/dataTables.select.js create mode 100644 app/static/DataTables/Select-1.3.4/js/dataTables.select.min.js create mode 100644 app/static/DataTables/Select-1.3.4/js/select.bootstrap.js create mode 100644 app/static/DataTables/Select-1.3.4/js/select.bootstrap.min.js create mode 100644 app/static/DataTables/Select-1.3.4/js/select.bootstrap4.js create mode 100644 app/static/DataTables/Select-1.3.4/js/select.bootstrap4.min.js create mode 100644 app/static/DataTables/Select-1.3.4/js/select.bootstrap5.js create mode 100644 app/static/DataTables/Select-1.3.4/js/select.bootstrap5.min.js create mode 100644 app/static/DataTables/Select-1.3.4/js/select.bulma.js create mode 100644 app/static/DataTables/Select-1.3.4/js/select.bulma.min.js create mode 100644 app/static/DataTables/Select-1.3.4/js/select.dataTables.js create mode 100644 app/static/DataTables/Select-1.3.4/js/select.dataTables.min.js create mode 100644 app/static/DataTables/Select-1.3.4/js/select.foundation.js create mode 100644 app/static/DataTables/Select-1.3.4/js/select.foundation.min.js create mode 100644 app/static/DataTables/Select-1.3.4/js/select.jqueryui.js create mode 100644 app/static/DataTables/Select-1.3.4/js/select.jqueryui.min.js create mode 100644 app/static/DataTables/Select-1.3.4/js/select.semanticui.js create mode 100644 app/static/DataTables/Select-1.3.4/js/select.semanticui.min.js create mode 100644 app/static/DataTables/pdfmake-0.1.36/pdfmake.js create mode 100644 app/static/DataTables/pdfmake-0.1.36/pdfmake.min.js create mode 100644 app/static/DataTables/pdfmake-0.1.36/vfs_fonts.js diff --git a/app/static/DataTables/Buttons-2.2.2/css/buttons.bootstrap.css b/app/static/DataTables/Buttons-2.2.2/css/buttons.bootstrap.css new file mode 100644 index 000000000..92485409e --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/css/buttons.bootstrap.css @@ -0,0 +1,380 @@ +@keyframes dtb-spinner { + 100% { + transform: rotate(360deg); + } +} +@-o-keyframes dtb-spinner { + 100% { + -o-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-ms-keyframes dtb-spinner { + 100% { + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-webkit-keyframes dtb-spinner { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-moz-keyframes dtb-spinner { + 100% { + -moz-transform: rotate(360deg); + transform: rotate(360deg); + } +} +div.dataTables_wrapper { + position: relative; +} + +div.dt-buttons { + position: initial; +} + +div.dt-button-info { + position: fixed; + top: 50%; + left: 50%; + width: 400px; + margin-top: -100px; + margin-left: -200px; + background-color: white; + border: 2px solid #111; + box-shadow: 3px 4px 10px 1px rgba(0, 0, 0, 0.3); + border-radius: 3px; + text-align: center; + z-index: 21; +} +div.dt-button-info h2 { + padding: 0.5em; + margin: 0; + font-weight: normal; + border-bottom: 1px solid #ddd; + background-color: #f3f3f3; +} +div.dt-button-info > div { + padding: 1em; +} + +div.dtb-popover-close { + position: absolute; + top: 10px; + right: 10px; + width: 22px; + height: 22px; + border: 1px solid #eaeaea; + background-color: #f9f9f9; + text-align: center; + border-radius: 3px; + cursor: pointer; + z-index: 12; +} + +button.dtb-hide-drop { + display: none !important; +} + +div.dt-button-collection-title { + text-align: center; + padding: 0.3em 0 0.5em; + margin-left: 0.5em; + margin-right: 0.5em; + font-size: 0.9em; +} + +div.dt-button-collection-title:empty { + display: none; +} + +span.dt-button-spacer { + display: inline-block; + margin: 0.5em; + white-space: nowrap; +} +span.dt-button-spacer.bar { + border-left: 1px solid rgba(0, 0, 0, 0.3); + vertical-align: middle; + padding-left: 0.5em; +} +span.dt-button-spacer.bar:empty { + height: 1em; + width: 1px; + padding-left: 0; +} + +div.dt-button-collection span.dt-button-spacer { + width: 100%; + font-size: 0.9em; + text-align: center; + margin: 0.5em 0; +} +div.dt-button-collection span.dt-button-spacer:empty { + height: 0; + width: 100%; +} +div.dt-button-collection span.dt-button-spacer.bar { + border-left: none; + border-bottom: 1px solid rgba(0, 0, 0, 0.3); + padding-left: 0; +} + +div.dt-button-collection { + position: absolute; + z-index: 2001; + background-color: white; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 4px; + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + padding: 0.5rem 0; + min-width: 200px; +} +div.dt-button-collection ul.dropdown-menu { + position: relative; + display: block; + z-index: 2002; + min-width: 100%; + background-color: transparent; + border: none; + box-shadow: none; + padding: 0; + border-radius: 0; +} +div.dt-button-collection div.dt-btn-split-wrapper { + width: 100%; + display: inline-flex; + padding-left: 5px; + padding-right: 5px; +} +div.dt-button-collection button.dt-btn-split-drop-button { + width: 100%; + border: none; + border-radius: 0px; + margin-left: 0px !important; +} +div.dt-button-collection button.dt-btn-split-drop-button:focus { + border: none; + border-radius: 0px; + outline: none; +} +div.dt-button-collection.fixed { + position: fixed; + display: block; + top: 50%; + left: 50%; + margin-left: -75px; + border-radius: 5px; + background-color: white; +} +div.dt-button-collection.fixed.two-column { + margin-left: -200px; +} +div.dt-button-collection.fixed.three-column { + margin-left: -225px; +} +div.dt-button-collection.fixed.four-column { + margin-left: -300px; +} +div.dt-button-collection.fixed.columns { + margin-left: -409px; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.fixed.columns { + margin-left: -308px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.fixed.columns { + margin-left: -203px; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.fixed.columns { + margin-left: -100px; + } +} +div.dt-button-collection.fixed > :last-child { + max-height: 100vh; + overflow: auto; +} +div.dt-button-collection.two-column > :last-child, div.dt-button-collection.three-column > :last-child, div.dt-button-collection.four-column > :last-child { + display: block !important; + -webkit-column-gap: 8px; + -moz-column-gap: 8px; + -ms-column-gap: 8px; + -o-column-gap: 8px; + column-gap: 8px; +} +div.dt-button-collection.two-column > :last-child > *, div.dt-button-collection.three-column > :last-child > *, div.dt-button-collection.four-column > :last-child > * { + -webkit-column-break-inside: avoid; + break-inside: avoid; +} +div.dt-button-collection.two-column { + width: 400px; +} +div.dt-button-collection.two-column > :last-child { + padding-bottom: 1px; + column-count: 2; +} +div.dt-button-collection.three-column { + width: 450px; +} +div.dt-button-collection.three-column > :last-child { + padding-bottom: 1px; + column-count: 3; +} +div.dt-button-collection.four-column { + width: 600px; +} +div.dt-button-collection.four-column > :last-child { + padding-bottom: 1px; + column-count: 4; +} +div.dt-button-collection .dt-button { + border-radius: 0; +} +div.dt-button-collection.columns { + width: auto; +} +div.dt-button-collection.columns > :last-child { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; + gap: 6px; + width: 818px; + padding-bottom: 1px; +} +div.dt-button-collection.columns > :last-child .dt-button { + min-width: 200px; + flex: 0 1; + margin: 0; +} +div.dt-button-collection.columns.dtb-b3 > :last-child, div.dt-button-collection.columns.dtb-b2 > :last-child, div.dt-button-collection.columns.dtb-b1 > :last-child { + justify-content: space-between; +} +div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 1 1 32%; +} +div.dt-button-collection.columns.dtb-b2 .dt-button { + flex: 1 1 48%; +} +div.dt-button-collection.columns.dtb-b1 .dt-button { + flex: 1 1 100%; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.columns > :last-child { + width: 612px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.columns > :last-child { + width: 406px; + } + div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 0 1 32%; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.columns > :last-child { + width: 200px; + } +} +div.dt-button-collection .dt-button { + min-width: 200px; +} + +div.dt-button-background { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 2001; +} + +@media screen and (max-width: 767px) { + div.dt-buttons { + float: none; + width: 100%; + text-align: center; + margin-bottom: 0.5em; + } + div.dt-buttons a.btn { + float: none; + } +} +div.dt-buttons button.btn.processing, +div.dt-buttons div.btn.processing, +div.dt-buttons a.btn.processing { + color: rgba(0, 0, 0, 0.2); +} +div.dt-buttons button.btn.processing:after, +div.dt-buttons div.btn.processing:after, +div.dt-buttons a.btn.processing:after { + position: absolute; + top: 50%; + left: 50%; + width: 16px; + height: 16px; + margin: -8px 0 0 -8px; + box-sizing: border-box; + display: block; + content: " "; + border: 2px solid #282828; + border-radius: 50%; + border-left-color: transparent; + border-right-color: transparent; + animation: dtb-spinner 1500ms infinite linear; + -o-animation: dtb-spinner 1500ms infinite linear; + -ms-animation: dtb-spinner 1500ms infinite linear; + -webkit-animation: dtb-spinner 1500ms infinite linear; + -moz-animation: dtb-spinner 1500ms infinite linear; +} + +div.dt-btn-split-wrapper button.dt-btn-split-drop { + border-top-right-radius: 4px !important; + border-bottom-right-radius: 4px !important; +} +div.dt-btn-split-wrapper:active:not(.disabled) button, div.dt-btn-split-wrapper.active:not(.disabled) button { + background-color: #e6e6e6; + border-color: #adadad; +} +div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop, div.dt-btn-split-wrapper.active:not(.disabled) button.dt-btn-split-drop { + box-shadow: none; + background-color: #fff; + border-color: #adadad; +} +div.dt-btn-split-wrapper:active:not(.disabled) button:hover, div.dt-btn-split-wrapper.active:not(.disabled) button:hover { + background-color: #e6e6e6; + border-color: #adadad; +} + +span.dt-down-arrow { + color: rgba(70, 70, 70, 0.9); + font-size: 10px; + padding-left: 10px; +} + +div.dataTables_wrapper div.dt-buttons.btn-group button.btn:last-of-type:first-of-type { + border-radius: 4px !important; +} + +span.dt-down-arrow { + display: none; +} + +span.dt-button-spacer { + float: left; +} +span.dt-button-spacer.bar:empty { + height: inherit; +} + +div.dt-button-collection span.dt-button-spacer { + padding-left: 1rem !important; + text-align: left; +} diff --git a/app/static/DataTables/Buttons-2.2.2/css/buttons.bootstrap.min.css b/app/static/DataTables/Buttons-2.2.2/css/buttons.bootstrap.min.css new file mode 100644 index 000000000..0c7adb426 --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/css/buttons.bootstrap.min.css @@ -0,0 +1 @@ +@keyframes dtb-spinner{100%{transform:rotate(360deg)}}@-o-keyframes dtb-spinner{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes dtb-spinner{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dtb-spinner{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes dtb-spinner{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}div.dataTables_wrapper{position:relative}div.dt-buttons{position:initial}div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 4px 10px 1px rgba(0, 0, 0, 0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}div.dtb-popover-close{position:absolute;top:10px;right:10px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:12}button.dtb-hide-drop{display:none !important}div.dt-button-collection-title{text-align:center;padding:.3em 0 .5em;margin-left:.5em;margin-right:.5em;font-size:.9em}div.dt-button-collection-title:empty{display:none}span.dt-button-spacer{display:inline-block;margin:.5em;white-space:nowrap}span.dt-button-spacer.bar{border-left:1px solid rgba(0, 0, 0, 0.3);vertical-align:middle;padding-left:.5em}span.dt-button-spacer.bar:empty{height:1em;width:1px;padding-left:0}div.dt-button-collection span.dt-button-spacer{width:100%;font-size:.9em;text-align:center;margin:.5em 0}div.dt-button-collection span.dt-button-spacer:empty{height:0;width:100%}div.dt-button-collection span.dt-button-spacer.bar{border-left:none;border-bottom:1px solid rgba(0, 0, 0, 0.3);padding-left:0}div.dt-button-collection{position:absolute;z-index:2001;background-color:white;border:1px solid rgba(0, 0, 0, 0.15);border-radius:4px;box-shadow:0 6px 12px rgba(0, 0, 0, 0.175);padding:.5rem 0;min-width:200px}div.dt-button-collection ul.dropdown-menu{position:relative;display:block;z-index:2002;min-width:100%;background-color:transparent;border:none;box-shadow:none;padding:0;border-radius:0}div.dt-button-collection div.dt-btn-split-wrapper{width:100%;display:inline-flex;padding-left:5px;padding-right:5px}div.dt-button-collection button.dt-btn-split-drop-button{width:100%;border:none;border-radius:0px;margin-left:0px !important}div.dt-button-collection button.dt-btn-split-drop-button:focus{border:none;border-radius:0px;outline:none}div.dt-button-collection.fixed{position:fixed;display:block;top:50%;left:50%;margin-left:-75px;border-radius:5px;background-color:white}div.dt-button-collection.fixed.two-column{margin-left:-200px}div.dt-button-collection.fixed.three-column{margin-left:-225px}div.dt-button-collection.fixed.four-column{margin-left:-300px}div.dt-button-collection.fixed.columns{margin-left:-409px}@media screen and (max-width: 1024px){div.dt-button-collection.fixed.columns{margin-left:-308px}}@media screen and (max-width: 640px){div.dt-button-collection.fixed.columns{margin-left:-203px}}@media screen and (max-width: 460px){div.dt-button-collection.fixed.columns{margin-left:-100px}}div.dt-button-collection.fixed>:last-child{max-height:100vh;overflow:auto}div.dt-button-collection.two-column>:last-child,div.dt-button-collection.three-column>:last-child,div.dt-button-collection.four-column>:last-child{display:block !important;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}div.dt-button-collection.two-column>:last-child>*,div.dt-button-collection.three-column>:last-child>*,div.dt-button-collection.four-column>:last-child>*{-webkit-column-break-inside:avoid;break-inside:avoid}div.dt-button-collection.two-column{width:400px}div.dt-button-collection.two-column>:last-child{padding-bottom:1px;column-count:2}div.dt-button-collection.three-column{width:450px}div.dt-button-collection.three-column>:last-child{padding-bottom:1px;column-count:3}div.dt-button-collection.four-column{width:600px}div.dt-button-collection.four-column>:last-child{padding-bottom:1px;column-count:4}div.dt-button-collection .dt-button{border-radius:0}div.dt-button-collection.columns{width:auto}div.dt-button-collection.columns>:last-child{display:flex;flex-wrap:wrap;justify-content:flex-start;align-items:center;gap:6px;width:818px;padding-bottom:1px}div.dt-button-collection.columns>:last-child .dt-button{min-width:200px;flex:0 1;margin:0}div.dt-button-collection.columns.dtb-b3>:last-child,div.dt-button-collection.columns.dtb-b2>:last-child,div.dt-button-collection.columns.dtb-b1>:last-child{justify-content:space-between}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:1 1 32%}div.dt-button-collection.columns.dtb-b2 .dt-button{flex:1 1 48%}div.dt-button-collection.columns.dtb-b1 .dt-button{flex:1 1 100%}@media screen and (max-width: 1024px){div.dt-button-collection.columns>:last-child{width:612px}}@media screen and (max-width: 640px){div.dt-button-collection.columns>:last-child{width:406px}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:0 1 32%}}@media screen and (max-width: 460px){div.dt-button-collection.columns>:last-child{width:200px}}div.dt-button-collection .dt-button{min-width:200px}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;z-index:2001}@media screen and (max-width: 767px){div.dt-buttons{float:none;width:100%;text-align:center;margin-bottom:.5em}div.dt-buttons a.btn{float:none}}div.dt-buttons button.btn.processing,div.dt-buttons div.btn.processing,div.dt-buttons a.btn.processing{color:rgba(0, 0, 0, 0.2)}div.dt-buttons button.btn.processing:after,div.dt-buttons div.btn.processing:after,div.dt-buttons a.btn.processing:after{position:absolute;top:50%;left:50%;width:16px;height:16px;margin:-8px 0 0 -8px;box-sizing:border-box;display:block;content:" ";border:2px solid #282828;border-radius:50%;border-left-color:transparent;border-right-color:transparent;animation:dtb-spinner 1500ms infinite linear;-o-animation:dtb-spinner 1500ms infinite linear;-ms-animation:dtb-spinner 1500ms infinite linear;-webkit-animation:dtb-spinner 1500ms infinite linear;-moz-animation:dtb-spinner 1500ms infinite linear}div.dt-btn-split-wrapper button.dt-btn-split-drop{border-top-right-radius:4px !important;border-bottom-right-radius:4px !important}div.dt-btn-split-wrapper:active:not(.disabled) button,div.dt-btn-split-wrapper.active:not(.disabled) button{background-color:#e6e6e6;border-color:#adadad}div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop,div.dt-btn-split-wrapper.active:not(.disabled) button.dt-btn-split-drop{box-shadow:none;background-color:#fff;border-color:#adadad}div.dt-btn-split-wrapper:active:not(.disabled) button:hover,div.dt-btn-split-wrapper.active:not(.disabled) button:hover{background-color:#e6e6e6;border-color:#adadad}span.dt-down-arrow{color:rgba(70, 70, 70, 0.9);font-size:10px;padding-left:10px}div.dataTables_wrapper div.dt-buttons.btn-group button.btn:last-of-type:first-of-type{border-radius:4px !important}span.dt-down-arrow{display:none}span.dt-button-spacer{float:left}span.dt-button-spacer.bar:empty{height:inherit}div.dt-button-collection span.dt-button-spacer{padding-left:1rem !important;text-align:left} diff --git a/app/static/DataTables/Buttons-2.2.2/css/buttons.bootstrap4.css b/app/static/DataTables/Buttons-2.2.2/css/buttons.bootstrap4.css new file mode 100644 index 000000000..45d37f50e --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/css/buttons.bootstrap4.css @@ -0,0 +1,426 @@ +@keyframes dtb-spinner { + 100% { + transform: rotate(360deg); + } +} +@-o-keyframes dtb-spinner { + 100% { + -o-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-ms-keyframes dtb-spinner { + 100% { + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-webkit-keyframes dtb-spinner { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-moz-keyframes dtb-spinner { + 100% { + -moz-transform: rotate(360deg); + transform: rotate(360deg); + } +} +div.dataTables_wrapper { + position: relative; +} + +div.dt-buttons { + position: initial; +} + +div.dt-button-info { + position: fixed; + top: 50%; + left: 50%; + width: 400px; + margin-top: -100px; + margin-left: -200px; + background-color: white; + border: 2px solid #111; + box-shadow: 3px 4px 10px 1px rgba(0, 0, 0, 0.3); + border-radius: 3px; + text-align: center; + z-index: 21; +} +div.dt-button-info h2 { + padding: 0.5em; + margin: 0; + font-weight: normal; + border-bottom: 1px solid #ddd; + background-color: #f3f3f3; +} +div.dt-button-info > div { + padding: 1em; +} + +div.dtb-popover-close { + position: absolute; + top: 10px; + right: 10px; + width: 22px; + height: 22px; + border: 1px solid #eaeaea; + background-color: #f9f9f9; + text-align: center; + border-radius: 3px; + cursor: pointer; + z-index: 12; +} + +button.dtb-hide-drop { + display: none !important; +} + +div.dt-button-collection-title { + text-align: center; + padding: 0.3em 0 0.5em; + margin-left: 0.5em; + margin-right: 0.5em; + font-size: 0.9em; +} + +div.dt-button-collection-title:empty { + display: none; +} + +span.dt-button-spacer { + display: inline-block; + margin: 0.5em; + white-space: nowrap; +} +span.dt-button-spacer.bar { + border-left: 1px solid rgba(0, 0, 0, 0.3); + vertical-align: middle; + padding-left: 0.5em; +} +span.dt-button-spacer.bar:empty { + height: 1em; + width: 1px; + padding-left: 0; +} + +div.dt-button-collection span.dt-button-spacer { + width: 100%; + font-size: 0.9em; + text-align: center; + margin: 0.5em 0; +} +div.dt-button-collection span.dt-button-spacer:empty { + height: 0; + width: 100%; +} +div.dt-button-collection span.dt-button-spacer.bar { + border-left: none; + border-bottom: 1px solid rgba(0, 0, 0, 0.3); + padding-left: 0; +} + +div.dt-button-collection { + position: absolute; + z-index: 2001; + background-color: white; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 4px; + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + padding: 0.5rem 0; + width: 200px; +} +div.dt-button-collection div.dropdown-menu { + position: relative; + display: block; + z-index: 2002; + min-width: 100%; + background-color: transparent; + border: none; + box-shadow: none; + padding: 0; + border-radius: 0; +} +div.dt-button-collection.fixed { + position: fixed; + display: block; + top: 50%; + left: 50%; + margin-left: -75px; + border-radius: 5px; + background-color: white; +} +div.dt-button-collection.fixed.two-column { + margin-left: -200px; +} +div.dt-button-collection.fixed.three-column { + margin-left: -225px; +} +div.dt-button-collection.fixed.four-column { + margin-left: -300px; +} +div.dt-button-collection.fixed.columns { + margin-left: -409px; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.fixed.columns { + margin-left: -308px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.fixed.columns { + margin-left: -203px; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.fixed.columns { + margin-left: -100px; + } +} +div.dt-button-collection.fixed > :last-child { + max-height: 100vh; + overflow: auto; +} +div.dt-button-collection.two-column > :last-child, div.dt-button-collection.three-column > :last-child, div.dt-button-collection.four-column > :last-child { + display: block !important; + -webkit-column-gap: 8px; + -moz-column-gap: 8px; + -ms-column-gap: 8px; + -o-column-gap: 8px; + column-gap: 8px; +} +div.dt-button-collection.two-column > :last-child > *, div.dt-button-collection.three-column > :last-child > *, div.dt-button-collection.four-column > :last-child > * { + -webkit-column-break-inside: avoid; + break-inside: avoid; +} +div.dt-button-collection.two-column { + width: 400px; +} +div.dt-button-collection.two-column > :last-child { + padding-bottom: 1px; + column-count: 2; +} +div.dt-button-collection.three-column { + width: 450px; +} +div.dt-button-collection.three-column > :last-child { + padding-bottom: 1px; + column-count: 3; +} +div.dt-button-collection.four-column { + width: 600px; +} +div.dt-button-collection.four-column > :last-child { + padding-bottom: 1px; + column-count: 4; +} +div.dt-button-collection .dt-button { + border-radius: 0; +} +div.dt-button-collection.columns { + width: auto; +} +div.dt-button-collection.columns > :last-child { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; + gap: 6px; + width: 818px; + padding-bottom: 1px; +} +div.dt-button-collection.columns > :last-child .dt-button { + min-width: 200px; + flex: 0 1; + margin: 0; +} +div.dt-button-collection.columns.dtb-b3 > :last-child, div.dt-button-collection.columns.dtb-b2 > :last-child, div.dt-button-collection.columns.dtb-b1 > :last-child { + justify-content: space-between; +} +div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 1 1 32%; +} +div.dt-button-collection.columns.dtb-b2 .dt-button { + flex: 1 1 48%; +} +div.dt-button-collection.columns.dtb-b1 .dt-button { + flex: 1 1 100%; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.columns > :last-child { + width: 612px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.columns > :last-child { + width: 406px; + } + div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 0 1 32%; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.columns > :last-child { + width: 200px; + } +} +div.dt-button-collection.fixed:before, div.dt-button-collection.fixed:after { + display: none; +} +div.dt-button-collection .btn-group { + flex: 1 1 auto; +} +div.dt-button-collection .dt-button { + min-width: 200px; +} +div.dt-button-collection div.dt-btn-split-wrapper { + width: 100%; + padding-left: 5px; + padding-right: 5px; +} +div.dt-button-collection button.dt-btn-split-drop-button { + width: 100%; + color: #212529; + border: none; + background-color: white; + border-radius: 0px; + margin-left: 0px !important; +} +div.dt-button-collection button.dt-btn-split-drop-button:focus { + border: none; + border-radius: 0px; + outline: none; +} +div.dt-button-collection button.dt-btn-split-drop-button:hover { + background-color: #e9ecef; +} +div.dt-button-collection button.dt-btn-split-drop-button:active { + background-color: #007bff !important; +} + +div.dt-button-background { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 999; +} + +@media screen and (max-width: 767px) { + div.dt-buttons { + float: none; + width: 100%; + text-align: center; + margin-bottom: 0.5em; + } + div.dt-buttons a.btn { + float: none; + } +} +div.dt-buttons button.btn.processing, +div.dt-buttons div.btn.processing, +div.dt-buttons a.btn.processing { + color: rgba(0, 0, 0, 0.2); +} +div.dt-buttons button.btn.processing:after, +div.dt-buttons div.btn.processing:after, +div.dt-buttons a.btn.processing:after { + position: absolute; + top: 50%; + left: 50%; + width: 16px; + height: 16px; + margin: -8px 0 0 -8px; + box-sizing: border-box; + display: block; + content: " "; + border: 2px solid #282828; + border-radius: 50%; + border-left-color: transparent; + border-right-color: transparent; + animation: dtb-spinner 1500ms infinite linear; + -o-animation: dtb-spinner 1500ms infinite linear; + -ms-animation: dtb-spinner 1500ms infinite linear; + -webkit-animation: dtb-spinner 1500ms infinite linear; + -moz-animation: dtb-spinner 1500ms infinite linear; +} +div.dt-buttons div.btn-group { + position: initial; +} + +div.dt-btn-split-wrapper:active:not(.disabled) button, div.dt-btn-split-wrapper.active:not(.disabled) button { + background-color: #5a6268; + border-color: #545b62; +} +div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop, div.dt-btn-split-wrapper.active:not(.disabled) button.dt-btn-split-drop { + box-shadow: none; + background-color: #6c757d; + border-color: #6c757d; +} +div.dt-btn-split-wrapper:active:not(.disabled) button:hover, div.dt-btn-split-wrapper.active:not(.disabled) button:hover { + background-color: #5a6268; + border-color: #545b62; +} + +div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group { + border-radius: 4px !important; +} +div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group:last-child { + border-top-left-radius: 0px !important; + border-bottom-left-radius: 0px !important; +} +div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group:first-child { + border-top-right-radius: 0px !important; + border-bottom-right-radius: 0px !important; +} +div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group:last-child:first-child { + border-top-left-radius: 4px !important; + border-bottom-left-radius: 4px !important; + border-top-right-radius: 4px !important; + border-bottom-right-radius: 4px !important; +} +div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group button.dt-btn-split-drop:last-child { + border: 1px solid #6c757d; +} +div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group div.dt-btn-split-wrapper { + border: none; +} + +div.dt-button-collection div.btn-group { + border-radius: 4px !important; +} +div.dt-button-collection div.btn-group button { + border-radius: 4px; +} +div.dt-button-collection div.btn-group button:last-child { + border-top-left-radius: 0px !important; + border-bottom-left-radius: 0px !important; +} +div.dt-button-collection div.btn-group button:first-child { + border-top-right-radius: 0px !important; + border-bottom-right-radius: 0px !important; +} +div.dt-button-collection div.btn-group button:last-child:first-child { + border-top-left-radius: 4px !important; + border-bottom-left-radius: 4px !important; + border-top-right-radius: 4px !important; + border-bottom-right-radius: 4px !important; +} +div.dt-button-collection div.btn-group button.dt-btn-split-drop:last-child { + border: 1px solid #6c757d; +} +div.dt-button-collection div.btn-group div.dt-btn-split-wrapper { + border: none; +} + +span.dt-button-spacer.bar:empty { + height: inherit; +} + +div.dt-button-collection span.dt-button-spacer { + padding-left: 1rem !important; + text-align: left; +} diff --git a/app/static/DataTables/Buttons-2.2.2/css/buttons.bootstrap4.min.css b/app/static/DataTables/Buttons-2.2.2/css/buttons.bootstrap4.min.css new file mode 100644 index 000000000..d688b82e0 --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/css/buttons.bootstrap4.min.css @@ -0,0 +1 @@ +@keyframes dtb-spinner{100%{transform:rotate(360deg)}}@-o-keyframes dtb-spinner{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes dtb-spinner{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dtb-spinner{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes dtb-spinner{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}div.dataTables_wrapper{position:relative}div.dt-buttons{position:initial}div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 4px 10px 1px rgba(0, 0, 0, 0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}div.dtb-popover-close{position:absolute;top:10px;right:10px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:12}button.dtb-hide-drop{display:none !important}div.dt-button-collection-title{text-align:center;padding:.3em 0 .5em;margin-left:.5em;margin-right:.5em;font-size:.9em}div.dt-button-collection-title:empty{display:none}span.dt-button-spacer{display:inline-block;margin:.5em;white-space:nowrap}span.dt-button-spacer.bar{border-left:1px solid rgba(0, 0, 0, 0.3);vertical-align:middle;padding-left:.5em}span.dt-button-spacer.bar:empty{height:1em;width:1px;padding-left:0}div.dt-button-collection span.dt-button-spacer{width:100%;font-size:.9em;text-align:center;margin:.5em 0}div.dt-button-collection span.dt-button-spacer:empty{height:0;width:100%}div.dt-button-collection span.dt-button-spacer.bar{border-left:none;border-bottom:1px solid rgba(0, 0, 0, 0.3);padding-left:0}div.dt-button-collection{position:absolute;z-index:2001;background-color:white;border:1px solid rgba(0, 0, 0, 0.15);border-radius:4px;box-shadow:0 6px 12px rgba(0, 0, 0, 0.175);padding:.5rem 0;width:200px}div.dt-button-collection div.dropdown-menu{position:relative;display:block;z-index:2002;min-width:100%;background-color:transparent;border:none;box-shadow:none;padding:0;border-radius:0}div.dt-button-collection.fixed{position:fixed;display:block;top:50%;left:50%;margin-left:-75px;border-radius:5px;background-color:white}div.dt-button-collection.fixed.two-column{margin-left:-200px}div.dt-button-collection.fixed.three-column{margin-left:-225px}div.dt-button-collection.fixed.four-column{margin-left:-300px}div.dt-button-collection.fixed.columns{margin-left:-409px}@media screen and (max-width: 1024px){div.dt-button-collection.fixed.columns{margin-left:-308px}}@media screen and (max-width: 640px){div.dt-button-collection.fixed.columns{margin-left:-203px}}@media screen and (max-width: 460px){div.dt-button-collection.fixed.columns{margin-left:-100px}}div.dt-button-collection.fixed>:last-child{max-height:100vh;overflow:auto}div.dt-button-collection.two-column>:last-child,div.dt-button-collection.three-column>:last-child,div.dt-button-collection.four-column>:last-child{display:block !important;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}div.dt-button-collection.two-column>:last-child>*,div.dt-button-collection.three-column>:last-child>*,div.dt-button-collection.four-column>:last-child>*{-webkit-column-break-inside:avoid;break-inside:avoid}div.dt-button-collection.two-column{width:400px}div.dt-button-collection.two-column>:last-child{padding-bottom:1px;column-count:2}div.dt-button-collection.three-column{width:450px}div.dt-button-collection.three-column>:last-child{padding-bottom:1px;column-count:3}div.dt-button-collection.four-column{width:600px}div.dt-button-collection.four-column>:last-child{padding-bottom:1px;column-count:4}div.dt-button-collection .dt-button{border-radius:0}div.dt-button-collection.columns{width:auto}div.dt-button-collection.columns>:last-child{display:flex;flex-wrap:wrap;justify-content:flex-start;align-items:center;gap:6px;width:818px;padding-bottom:1px}div.dt-button-collection.columns>:last-child .dt-button{min-width:200px;flex:0 1;margin:0}div.dt-button-collection.columns.dtb-b3>:last-child,div.dt-button-collection.columns.dtb-b2>:last-child,div.dt-button-collection.columns.dtb-b1>:last-child{justify-content:space-between}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:1 1 32%}div.dt-button-collection.columns.dtb-b2 .dt-button{flex:1 1 48%}div.dt-button-collection.columns.dtb-b1 .dt-button{flex:1 1 100%}@media screen and (max-width: 1024px){div.dt-button-collection.columns>:last-child{width:612px}}@media screen and (max-width: 640px){div.dt-button-collection.columns>:last-child{width:406px}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:0 1 32%}}@media screen and (max-width: 460px){div.dt-button-collection.columns>:last-child{width:200px}}div.dt-button-collection.fixed:before,div.dt-button-collection.fixed:after{display:none}div.dt-button-collection .btn-group{flex:1 1 auto}div.dt-button-collection .dt-button{min-width:200px}div.dt-button-collection div.dt-btn-split-wrapper{width:100%;padding-left:5px;padding-right:5px}div.dt-button-collection button.dt-btn-split-drop-button{width:100%;color:#212529;border:none;background-color:white;border-radius:0px;margin-left:0px !important}div.dt-button-collection button.dt-btn-split-drop-button:focus{border:none;border-radius:0px;outline:none}div.dt-button-collection button.dt-btn-split-drop-button:hover{background-color:#e9ecef}div.dt-button-collection button.dt-btn-split-drop-button:active{background-color:#007bff !important}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;z-index:999}@media screen and (max-width: 767px){div.dt-buttons{float:none;width:100%;text-align:center;margin-bottom:.5em}div.dt-buttons a.btn{float:none}}div.dt-buttons button.btn.processing,div.dt-buttons div.btn.processing,div.dt-buttons a.btn.processing{color:rgba(0, 0, 0, 0.2)}div.dt-buttons button.btn.processing:after,div.dt-buttons div.btn.processing:after,div.dt-buttons a.btn.processing:after{position:absolute;top:50%;left:50%;width:16px;height:16px;margin:-8px 0 0 -8px;box-sizing:border-box;display:block;content:" ";border:2px solid #282828;border-radius:50%;border-left-color:transparent;border-right-color:transparent;animation:dtb-spinner 1500ms infinite linear;-o-animation:dtb-spinner 1500ms infinite linear;-ms-animation:dtb-spinner 1500ms infinite linear;-webkit-animation:dtb-spinner 1500ms infinite linear;-moz-animation:dtb-spinner 1500ms infinite linear}div.dt-buttons div.btn-group{position:initial}div.dt-btn-split-wrapper:active:not(.disabled) button,div.dt-btn-split-wrapper.active:not(.disabled) button{background-color:#5a6268;border-color:#545b62}div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop,div.dt-btn-split-wrapper.active:not(.disabled) button.dt-btn-split-drop{box-shadow:none;background-color:#6c757d;border-color:#6c757d}div.dt-btn-split-wrapper:active:not(.disabled) button:hover,div.dt-btn-split-wrapper.active:not(.disabled) button:hover{background-color:#5a6268;border-color:#545b62}div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group{border-radius:4px !important}div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group:last-child{border-top-left-radius:0px !important;border-bottom-left-radius:0px !important}div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group:first-child{border-top-right-radius:0px !important;border-bottom-right-radius:0px !important}div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group:last-child:first-child{border-top-left-radius:4px !important;border-bottom-left-radius:4px !important;border-top-right-radius:4px !important;border-bottom-right-radius:4px !important}div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group button.dt-btn-split-drop:last-child{border:1px solid #6c757d}div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group div.dt-btn-split-wrapper{border:none}div.dt-button-collection div.btn-group{border-radius:4px !important}div.dt-button-collection div.btn-group button{border-radius:4px}div.dt-button-collection div.btn-group button:last-child{border-top-left-radius:0px !important;border-bottom-left-radius:0px !important}div.dt-button-collection div.btn-group button:first-child{border-top-right-radius:0px !important;border-bottom-right-radius:0px !important}div.dt-button-collection div.btn-group button:last-child:first-child{border-top-left-radius:4px !important;border-bottom-left-radius:4px !important;border-top-right-radius:4px !important;border-bottom-right-radius:4px !important}div.dt-button-collection div.btn-group button.dt-btn-split-drop:last-child{border:1px solid #6c757d}div.dt-button-collection div.btn-group div.dt-btn-split-wrapper{border:none}span.dt-button-spacer.bar:empty{height:inherit}div.dt-button-collection span.dt-button-spacer{padding-left:1rem !important;text-align:left} diff --git a/app/static/DataTables/Buttons-2.2.2/css/buttons.bootstrap5.css b/app/static/DataTables/Buttons-2.2.2/css/buttons.bootstrap5.css new file mode 100644 index 000000000..40ccc2e02 --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/css/buttons.bootstrap5.css @@ -0,0 +1,428 @@ +@keyframes dtb-spinner { + 100% { + transform: rotate(360deg); + } +} +@-o-keyframes dtb-spinner { + 100% { + -o-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-ms-keyframes dtb-spinner { + 100% { + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-webkit-keyframes dtb-spinner { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-moz-keyframes dtb-spinner { + 100% { + -moz-transform: rotate(360deg); + transform: rotate(360deg); + } +} +div.dataTables_wrapper { + position: relative; +} + +div.dt-buttons { + position: initial; +} + +div.dt-button-info { + position: fixed; + top: 50%; + left: 50%; + width: 400px; + margin-top: -100px; + margin-left: -200px; + background-color: white; + border: 2px solid #111; + box-shadow: 3px 4px 10px 1px rgba(0, 0, 0, 0.3); + border-radius: 3px; + text-align: center; + z-index: 21; +} +div.dt-button-info h2 { + padding: 0.5em; + margin: 0; + font-weight: normal; + border-bottom: 1px solid #ddd; + background-color: #f3f3f3; +} +div.dt-button-info > div { + padding: 1em; +} + +div.dtb-popover-close { + position: absolute; + top: 10px; + right: 10px; + width: 22px; + height: 22px; + border: 1px solid #eaeaea; + background-color: #f9f9f9; + text-align: center; + border-radius: 3px; + cursor: pointer; + z-index: 12; +} + +button.dtb-hide-drop { + display: none !important; +} + +div.dt-button-collection-title { + text-align: center; + padding: 0.3em 0 0.5em; + margin-left: 0.5em; + margin-right: 0.5em; + font-size: 0.9em; +} + +div.dt-button-collection-title:empty { + display: none; +} + +span.dt-button-spacer { + display: inline-block; + margin: 0.5em; + white-space: nowrap; +} +span.dt-button-spacer.bar { + border-left: 1px solid rgba(0, 0, 0, 0.3); + vertical-align: middle; + padding-left: 0.5em; +} +span.dt-button-spacer.bar:empty { + height: 1em; + width: 1px; + padding-left: 0; +} + +div.dt-button-collection span.dt-button-spacer { + width: 100%; + font-size: 0.9em; + text-align: center; + margin: 0.5em 0; +} +div.dt-button-collection span.dt-button-spacer:empty { + height: 0; + width: 100%; +} +div.dt-button-collection span.dt-button-spacer.bar { + border-left: none; + border-bottom: 1px solid rgba(0, 0, 0, 0.3); + padding-left: 0; +} + +div.dt-button-collection { + position: absolute; + z-index: 2001; + background-color: white; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 4px; + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + padding: 0.5rem 0; + width: 200px; +} +div.dt-button-collection div.dropdown-menu { + position: relative; + display: block; + background-color: transparent; + border: none; + box-shadow: none; + padding: 0; + border-radius: 0; + z-index: 2002; + min-width: 100%; +} +div.dt-button-collection.fixed { + position: fixed; + display: block; + top: 50%; + left: 50%; + margin-left: -75px; + border-radius: 5px; + background-color: white; +} +div.dt-button-collection.fixed.two-column { + margin-left: -200px; +} +div.dt-button-collection.fixed.three-column { + margin-left: -225px; +} +div.dt-button-collection.fixed.four-column { + margin-left: -300px; +} +div.dt-button-collection.fixed.columns { + margin-left: -409px; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.fixed.columns { + margin-left: -308px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.fixed.columns { + margin-left: -203px; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.fixed.columns { + margin-left: -100px; + } +} +div.dt-button-collection.fixed > :last-child { + max-height: 100vh; + overflow: auto; +} +div.dt-button-collection.two-column > :last-child, div.dt-button-collection.three-column > :last-child, div.dt-button-collection.four-column > :last-child { + display: block !important; + -webkit-column-gap: 8px; + -moz-column-gap: 8px; + -ms-column-gap: 8px; + -o-column-gap: 8px; + column-gap: 8px; +} +div.dt-button-collection.two-column > :last-child > *, div.dt-button-collection.three-column > :last-child > *, div.dt-button-collection.four-column > :last-child > * { + -webkit-column-break-inside: avoid; + break-inside: avoid; +} +div.dt-button-collection.two-column { + width: 400px; +} +div.dt-button-collection.two-column > :last-child { + padding-bottom: 1px; + column-count: 2; +} +div.dt-button-collection.three-column { + width: 450px; +} +div.dt-button-collection.three-column > :last-child { + padding-bottom: 1px; + column-count: 3; +} +div.dt-button-collection.four-column { + width: 600px; +} +div.dt-button-collection.four-column > :last-child { + padding-bottom: 1px; + column-count: 4; +} +div.dt-button-collection .dt-button { + border-radius: 0; +} +div.dt-button-collection.columns { + width: auto; +} +div.dt-button-collection.columns > :last-child { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; + gap: 6px; + width: 818px; + padding-bottom: 1px; +} +div.dt-button-collection.columns > :last-child .dt-button { + min-width: 200px; + flex: 0 1; + margin: 0; +} +div.dt-button-collection.columns.dtb-b3 > :last-child, div.dt-button-collection.columns.dtb-b2 > :last-child, div.dt-button-collection.columns.dtb-b1 > :last-child { + justify-content: space-between; +} +div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 1 1 32%; +} +div.dt-button-collection.columns.dtb-b2 .dt-button { + flex: 1 1 48%; +} +div.dt-button-collection.columns.dtb-b1 .dt-button { + flex: 1 1 100%; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.columns > :last-child { + width: 612px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.columns > :last-child { + width: 406px; + } + div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 0 1 32%; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.columns > :last-child { + width: 200px; + } +} +div.dt-button-collection.fixed:before, div.dt-button-collection.fixed:after { + display: none; +} +div.dt-button-collection .btn-group { + flex: 1 1 auto; +} +div.dt-button-collection .dt-button { + min-width: 200px; +} +div.dt-button-collection div.dt-btn-split-wrapper { + width: 100%; +} +div.dt-button-collection button.dt-btn-split-drop-button { + width: 100%; + color: #212529; + border: none; + background-color: white; + border-radius: 0px; + margin-left: 0px !important; +} +div.dt-button-collection button.dt-btn-split-drop-button:focus { + border: none; + border-radius: 0px; + outline: none; +} +div.dt-button-collection button.dt-btn-split-drop-button:hover { + background-color: #e9ecef; +} +div.dt-button-collection button.dt-btn-split-drop-button:active { + background-color: #007bff !important; +} + +div.dt-button-background { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 999; +} + +@media screen and (max-width: 767px) { + div.dt-buttons { + float: none; + width: 100%; + text-align: center; + margin-bottom: 0.5em; + } + div.dt-buttons a.btn { + float: none; + } +} +div.dt-buttons button.btn.processing, +div.dt-buttons div.btn.processing, +div.dt-buttons a.btn.processing { + color: rgba(0, 0, 0, 0.2); +} +div.dt-buttons button.btn.processing:after, +div.dt-buttons div.btn.processing:after, +div.dt-buttons a.btn.processing:after { + position: absolute; + top: 50%; + left: 50%; + width: 16px; + height: 16px; + margin: -8px 0 0 -8px; + box-sizing: border-box; + display: block; + content: " "; + border: 2px solid #282828; + border-radius: 50%; + border-left-color: transparent; + border-right-color: transparent; + animation: dtb-spinner 1500ms infinite linear; + -o-animation: dtb-spinner 1500ms infinite linear; + -ms-animation: dtb-spinner 1500ms infinite linear; + -webkit-animation: dtb-spinner 1500ms infinite linear; + -moz-animation: dtb-spinner 1500ms infinite linear; +} +div.dt-buttons div.btn-group { + position: initial; +} + +div.dt-btn-split-wrapper button.dt-btn-split-drop { + border-top-right-radius: 0.25rem !important; + border-bottom-right-radius: 0.25rem !important; +} +div.dt-btn-split-wrapper:active:not(.disabled) button, div.dt-btn-split-wrapper.active:not(.disabled) button { + background-color: #5a6268; + border-color: #545b62; +} +div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop, div.dt-btn-split-wrapper.active:not(.disabled) button.dt-btn-split-drop { + box-shadow: none; + background-color: #6c757d; + border-color: #6c757d; +} +div.dt-btn-split-wrapper:active:not(.disabled) button:hover, div.dt-btn-split-wrapper.active:not(.disabled) button:hover { + background-color: #5a6268; + border-color: #545b62; +} + +div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group { + border-radius: 4px !important; +} +div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group:last-child { + border-top-left-radius: 0px !important; + border-bottom-left-radius: 0px !important; +} +div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group:first-child { + border-top-right-radius: 0px !important; + border-bottom-right-radius: 0px !important; +} +div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group:last-child:first-child { + border-top-left-radius: 4px !important; + border-bottom-left-radius: 4px !important; + border-top-right-radius: 4px !important; + border-bottom-right-radius: 4px !important; +} +div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group button.dt-btn-split-drop:last-child { + border: 1px solid #6c757d; +} +div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group div.dt-btn-split-wrapper { + border: none; +} + +div.dt-button-collection div.btn-group { + border-radius: 4px !important; +} +div.dt-button-collection div.btn-group button { + border-radius: 4px; +} +div.dt-button-collection div.btn-group button:last-child { + border-top-left-radius: 0px !important; + border-bottom-left-radius: 0px !important; +} +div.dt-button-collection div.btn-group button:first-child { + border-top-right-radius: 0px !important; + border-bottom-right-radius: 0px !important; +} +div.dt-button-collection div.btn-group button:last-child:first-child { + border-top-left-radius: 4px !important; + border-bottom-left-radius: 4px !important; + border-top-right-radius: 4px !important; + border-bottom-right-radius: 4px !important; +} +div.dt-button-collection div.btn-group button.dt-btn-split-drop:last-child { + border: 1px solid #6c757d; +} +div.dt-button-collection div.btn-group div.dt-btn-split-wrapper { + border: none; +} + +span.dt-button-spacer.bar:empty { + height: inherit; +} + +div.dt-button-collection span.dt-button-spacer { + padding-left: 1rem !important; + text-align: left; +} diff --git a/app/static/DataTables/Buttons-2.2.2/css/buttons.bootstrap5.min.css b/app/static/DataTables/Buttons-2.2.2/css/buttons.bootstrap5.min.css new file mode 100644 index 000000000..52d830322 --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/css/buttons.bootstrap5.min.css @@ -0,0 +1 @@ +@keyframes dtb-spinner{100%{transform:rotate(360deg)}}@-o-keyframes dtb-spinner{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes dtb-spinner{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dtb-spinner{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes dtb-spinner{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}div.dataTables_wrapper{position:relative}div.dt-buttons{position:initial}div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 4px 10px 1px rgba(0, 0, 0, 0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}div.dtb-popover-close{position:absolute;top:10px;right:10px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:12}button.dtb-hide-drop{display:none !important}div.dt-button-collection-title{text-align:center;padding:.3em 0 .5em;margin-left:.5em;margin-right:.5em;font-size:.9em}div.dt-button-collection-title:empty{display:none}span.dt-button-spacer{display:inline-block;margin:.5em;white-space:nowrap}span.dt-button-spacer.bar{border-left:1px solid rgba(0, 0, 0, 0.3);vertical-align:middle;padding-left:.5em}span.dt-button-spacer.bar:empty{height:1em;width:1px;padding-left:0}div.dt-button-collection span.dt-button-spacer{width:100%;font-size:.9em;text-align:center;margin:.5em 0}div.dt-button-collection span.dt-button-spacer:empty{height:0;width:100%}div.dt-button-collection span.dt-button-spacer.bar{border-left:none;border-bottom:1px solid rgba(0, 0, 0, 0.3);padding-left:0}div.dt-button-collection{position:absolute;z-index:2001;background-color:white;border:1px solid rgba(0, 0, 0, 0.15);border-radius:4px;box-shadow:0 6px 12px rgba(0, 0, 0, 0.175);padding:.5rem 0;width:200px}div.dt-button-collection div.dropdown-menu{position:relative;display:block;background-color:transparent;border:none;box-shadow:none;padding:0;border-radius:0;z-index:2002;min-width:100%}div.dt-button-collection.fixed{position:fixed;display:block;top:50%;left:50%;margin-left:-75px;border-radius:5px;background-color:white}div.dt-button-collection.fixed.two-column{margin-left:-200px}div.dt-button-collection.fixed.three-column{margin-left:-225px}div.dt-button-collection.fixed.four-column{margin-left:-300px}div.dt-button-collection.fixed.columns{margin-left:-409px}@media screen and (max-width: 1024px){div.dt-button-collection.fixed.columns{margin-left:-308px}}@media screen and (max-width: 640px){div.dt-button-collection.fixed.columns{margin-left:-203px}}@media screen and (max-width: 460px){div.dt-button-collection.fixed.columns{margin-left:-100px}}div.dt-button-collection.fixed>:last-child{max-height:100vh;overflow:auto}div.dt-button-collection.two-column>:last-child,div.dt-button-collection.three-column>:last-child,div.dt-button-collection.four-column>:last-child{display:block !important;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}div.dt-button-collection.two-column>:last-child>*,div.dt-button-collection.three-column>:last-child>*,div.dt-button-collection.four-column>:last-child>*{-webkit-column-break-inside:avoid;break-inside:avoid}div.dt-button-collection.two-column{width:400px}div.dt-button-collection.two-column>:last-child{padding-bottom:1px;column-count:2}div.dt-button-collection.three-column{width:450px}div.dt-button-collection.three-column>:last-child{padding-bottom:1px;column-count:3}div.dt-button-collection.four-column{width:600px}div.dt-button-collection.four-column>:last-child{padding-bottom:1px;column-count:4}div.dt-button-collection .dt-button{border-radius:0}div.dt-button-collection.columns{width:auto}div.dt-button-collection.columns>:last-child{display:flex;flex-wrap:wrap;justify-content:flex-start;align-items:center;gap:6px;width:818px;padding-bottom:1px}div.dt-button-collection.columns>:last-child .dt-button{min-width:200px;flex:0 1;margin:0}div.dt-button-collection.columns.dtb-b3>:last-child,div.dt-button-collection.columns.dtb-b2>:last-child,div.dt-button-collection.columns.dtb-b1>:last-child{justify-content:space-between}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:1 1 32%}div.dt-button-collection.columns.dtb-b2 .dt-button{flex:1 1 48%}div.dt-button-collection.columns.dtb-b1 .dt-button{flex:1 1 100%}@media screen and (max-width: 1024px){div.dt-button-collection.columns>:last-child{width:612px}}@media screen and (max-width: 640px){div.dt-button-collection.columns>:last-child{width:406px}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:0 1 32%}}@media screen and (max-width: 460px){div.dt-button-collection.columns>:last-child{width:200px}}div.dt-button-collection.fixed:before,div.dt-button-collection.fixed:after{display:none}div.dt-button-collection .btn-group{flex:1 1 auto}div.dt-button-collection .dt-button{min-width:200px}div.dt-button-collection div.dt-btn-split-wrapper{width:100%}div.dt-button-collection button.dt-btn-split-drop-button{width:100%;color:#212529;border:none;background-color:white;border-radius:0px;margin-left:0px !important}div.dt-button-collection button.dt-btn-split-drop-button:focus{border:none;border-radius:0px;outline:none}div.dt-button-collection button.dt-btn-split-drop-button:hover{background-color:#e9ecef}div.dt-button-collection button.dt-btn-split-drop-button:active{background-color:#007bff !important}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;z-index:999}@media screen and (max-width: 767px){div.dt-buttons{float:none;width:100%;text-align:center;margin-bottom:.5em}div.dt-buttons a.btn{float:none}}div.dt-buttons button.btn.processing,div.dt-buttons div.btn.processing,div.dt-buttons a.btn.processing{color:rgba(0, 0, 0, 0.2)}div.dt-buttons button.btn.processing:after,div.dt-buttons div.btn.processing:after,div.dt-buttons a.btn.processing:after{position:absolute;top:50%;left:50%;width:16px;height:16px;margin:-8px 0 0 -8px;box-sizing:border-box;display:block;content:" ";border:2px solid #282828;border-radius:50%;border-left-color:transparent;border-right-color:transparent;animation:dtb-spinner 1500ms infinite linear;-o-animation:dtb-spinner 1500ms infinite linear;-ms-animation:dtb-spinner 1500ms infinite linear;-webkit-animation:dtb-spinner 1500ms infinite linear;-moz-animation:dtb-spinner 1500ms infinite linear}div.dt-buttons div.btn-group{position:initial}div.dt-btn-split-wrapper button.dt-btn-split-drop{border-top-right-radius:.25rem !important;border-bottom-right-radius:.25rem !important}div.dt-btn-split-wrapper:active:not(.disabled) button,div.dt-btn-split-wrapper.active:not(.disabled) button{background-color:#5a6268;border-color:#545b62}div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop,div.dt-btn-split-wrapper.active:not(.disabled) button.dt-btn-split-drop{box-shadow:none;background-color:#6c757d;border-color:#6c757d}div.dt-btn-split-wrapper:active:not(.disabled) button:hover,div.dt-btn-split-wrapper.active:not(.disabled) button:hover{background-color:#5a6268;border-color:#545b62}div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group{border-radius:4px !important}div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group:last-child{border-top-left-radius:0px !important;border-bottom-left-radius:0px !important}div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group:first-child{border-top-right-radius:0px !important;border-bottom-right-radius:0px !important}div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group:last-child:first-child{border-top-left-radius:4px !important;border-bottom-left-radius:4px !important;border-top-right-radius:4px !important;border-bottom-right-radius:4px !important}div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group button.dt-btn-split-drop:last-child{border:1px solid #6c757d}div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group div.dt-btn-split-wrapper{border:none}div.dt-button-collection div.btn-group{border-radius:4px !important}div.dt-button-collection div.btn-group button{border-radius:4px}div.dt-button-collection div.btn-group button:last-child{border-top-left-radius:0px !important;border-bottom-left-radius:0px !important}div.dt-button-collection div.btn-group button:first-child{border-top-right-radius:0px !important;border-bottom-right-radius:0px !important}div.dt-button-collection div.btn-group button:last-child:first-child{border-top-left-radius:4px !important;border-bottom-left-radius:4px !important;border-top-right-radius:4px !important;border-bottom-right-radius:4px !important}div.dt-button-collection div.btn-group button.dt-btn-split-drop:last-child{border:1px solid #6c757d}div.dt-button-collection div.btn-group div.dt-btn-split-wrapper{border:none}span.dt-button-spacer.bar:empty{height:inherit}div.dt-button-collection span.dt-button-spacer{padding-left:1rem !important;text-align:left} diff --git a/app/static/DataTables/Buttons-2.2.2/css/buttons.bulma.css b/app/static/DataTables/Buttons-2.2.2/css/buttons.bulma.css new file mode 100644 index 000000000..6ac1424c5 --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/css/buttons.bulma.css @@ -0,0 +1,425 @@ +@keyframes dtb-spinner { + 100% { + transform: rotate(360deg); + } +} +@-o-keyframes dtb-spinner { + 100% { + -o-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-ms-keyframes dtb-spinner { + 100% { + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-webkit-keyframes dtb-spinner { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-moz-keyframes dtb-spinner { + 100% { + -moz-transform: rotate(360deg); + transform: rotate(360deg); + } +} +div.dataTables_wrapper { + position: relative; +} + +div.dt-buttons { + position: initial; +} + +div.dt-button-info { + position: fixed; + top: 50%; + left: 50%; + width: 400px; + margin-top: -100px; + margin-left: -200px; + background-color: white; + border: 2px solid #111; + box-shadow: 3px 4px 10px 1px rgba(0, 0, 0, 0.3); + border-radius: 3px; + text-align: center; + z-index: 21; +} +div.dt-button-info h2 { + padding: 0.5em; + margin: 0; + font-weight: normal; + border-bottom: 1px solid #ddd; + background-color: #f3f3f3; +} +div.dt-button-info > div { + padding: 1em; +} + +div.dtb-popover-close { + position: absolute; + top: 10px; + right: 10px; + width: 22px; + height: 22px; + border: 1px solid #eaeaea; + background-color: #f9f9f9; + text-align: center; + border-radius: 3px; + cursor: pointer; + z-index: 12; +} + +button.dtb-hide-drop { + display: none !important; +} + +div.dt-button-collection-title { + text-align: center; + padding: 0.3em 0 0.5em; + margin-left: 0.5em; + margin-right: 0.5em; + font-size: 0.9em; +} + +div.dt-button-collection-title:empty { + display: none; +} + +span.dt-button-spacer { + display: inline-block; + margin: 0.5em; + white-space: nowrap; +} +span.dt-button-spacer.bar { + border-left: 1px solid rgba(0, 0, 0, 0.3); + vertical-align: middle; + padding-left: 0.5em; +} +span.dt-button-spacer.bar:empty { + height: 1em; + width: 1px; + padding-left: 0; +} + +div.dt-button-collection span.dt-button-spacer { + width: 100%; + font-size: 0.9em; + text-align: center; + margin: 0.5em 0; +} +div.dt-button-collection span.dt-button-spacer:empty { + height: 0; + width: 100%; +} +div.dt-button-collection span.dt-button-spacer.bar { + border-left: none; + border-bottom: 1px solid rgba(0, 0, 0, 0.3); + padding-left: 0; +} + +div.dt-button-collection { + position: absolute; + z-index: 2001; + min-width: 200px; + background: white; + max-width: none; + display: block; + box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.02); + border-radius: 4; + padding-top: 0.5rem; +} +div.dt-button-collection div.dropdown-menu { + display: block; + z-index: 2002; + min-width: 100%; +} +div.dt-button-collection div.dt-btn-split-wrapper { + width: 100%; + padding-left: 5px; + padding-right: 5px; + margin-bottom: 0px; + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: flex-start; + align-content: flex-start; + align-items: stretch; +} +div.dt-button-collection div.dt-btn-split-wrapper button { + margin-right: 0px; + display: inline-block; + width: 0; + flex-grow: 1; + flex-shrink: 0; + flex-basis: 50px; + margin-top: 0px; + border-bottom-left-radius: 3px; + border-top-left-radius: 3px; + border-top-right-radius: 0px; + border-bottom-right-radius: 0px; + overflow: hidden; + text-overflow: ellipsis; +} +div.dt-button-collection div.dt-btn-split-wrapper button.dt-button { + min-width: 30px; + margin-left: -1px; + flex-grow: 0; + flex-shrink: 0; + flex-basis: 0; + border-bottom-left-radius: 0px; + border-top-left-radius: 0px; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; + padding: 0px; +} +div.dt-button-collection.fixed { + position: fixed; + display: block; + top: 50%; + left: 50%; + margin-left: -75px; + border-radius: 5px; + background-color: white; +} +div.dt-button-collection.fixed.two-column { + margin-left: -200px; +} +div.dt-button-collection.fixed.three-column { + margin-left: -225px; +} +div.dt-button-collection.fixed.four-column { + margin-left: -300px; +} +div.dt-button-collection.fixed.columns { + margin-left: -409px; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.fixed.columns { + margin-left: -308px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.fixed.columns { + margin-left: -203px; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.fixed.columns { + margin-left: -100px; + } +} +div.dt-button-collection.fixed > :last-child { + max-height: 100vh; + overflow: auto; +} +div.dt-button-collection.two-column > :last-child, div.dt-button-collection.three-column > :last-child, div.dt-button-collection.four-column > :last-child { + display: block !important; + -webkit-column-gap: 8px; + -moz-column-gap: 8px; + -ms-column-gap: 8px; + -o-column-gap: 8px; + column-gap: 8px; +} +div.dt-button-collection.two-column > :last-child > *, div.dt-button-collection.three-column > :last-child > *, div.dt-button-collection.four-column > :last-child > * { + -webkit-column-break-inside: avoid; + break-inside: avoid; +} +div.dt-button-collection.two-column { + width: 400px; +} +div.dt-button-collection.two-column > :last-child { + padding-bottom: 1px; + column-count: 2; +} +div.dt-button-collection.three-column { + width: 450px; +} +div.dt-button-collection.three-column > :last-child { + padding-bottom: 1px; + column-count: 3; +} +div.dt-button-collection.four-column { + width: 600px; +} +div.dt-button-collection.four-column > :last-child { + padding-bottom: 1px; + column-count: 4; +} +div.dt-button-collection .dt-button { + border-radius: 0; +} +div.dt-button-collection.columns { + width: auto; +} +div.dt-button-collection.columns > :last-child { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; + gap: 6px; + width: 818px; + padding-bottom: 1px; +} +div.dt-button-collection.columns > :last-child .dt-button { + min-width: 200px; + flex: 0 1; + margin: 0; +} +div.dt-button-collection.columns.dtb-b3 > :last-child, div.dt-button-collection.columns.dtb-b2 > :last-child, div.dt-button-collection.columns.dtb-b1 > :last-child { + justify-content: space-between; +} +div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 1 1 32%; +} +div.dt-button-collection.columns.dtb-b2 .dt-button { + flex: 1 1 48%; +} +div.dt-button-collection.columns.dtb-b1 .dt-button { + flex: 1 1 100%; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.columns > :last-child { + width: 612px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.columns > :last-child { + width: 406px; + } + div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 0 1 32%; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.columns > :last-child { + width: 200px; + } +} +div.dt-button-collection .dropdown-content { + box-shadow: none; + padding-top: 0; + border-radius: 0; +} +div.dt-button-collection.fixed:before, div.dt-button-collection.fixed:after { + display: none; +} + +div.dt-button-background { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 999; +} + +@media screen and (max-width: 767px) { + div.dt-buttons { + float: none; + width: 100%; + text-align: center; + margin-bottom: 0.5em; + } + div.dt-buttons a.btn { + float: none; + } +} +div.dt-buttons button.btn.processing, +div.dt-buttons div.btn.processing, +div.dt-buttons a.btn.processing { + color: rgba(0, 0, 0, 0.2); +} +div.dt-buttons button.btn.processing:after, +div.dt-buttons div.btn.processing:after, +div.dt-buttons a.btn.processing:after { + position: absolute; + top: 50%; + left: 50%; + width: 16px; + height: 16px; + margin: -8px 0 0 -8px; + box-sizing: border-box; + display: block; + content: " "; + border: 2px solid #282828; + border-radius: 50%; + border-left-color: transparent; + border-right-color: transparent; + animation: dtb-spinner 1500ms infinite linear; + -o-animation: dtb-spinner 1500ms infinite linear; + -ms-animation: dtb-spinner 1500ms infinite linear; + -webkit-animation: dtb-spinner 1500ms infinite linear; + -moz-animation: dtb-spinner 1500ms infinite linear; +} +div.dt-buttons button.button { + margin-left: 5px; +} +div.dt-buttons button.button:first-child { + margin-left: 0px; +} + +span.dt-down-arrow { + display: none; +} + +span.dt-button-spacer { + display: inline-flex; + margin: 0.5em; + white-space: nowrap; + align-items: center; + font-size: 1rem; +} +span.dt-button-spacer.bar:empty { + height: inherit; +} + +div.dt-button-collection span.dt-button-spacer { + text-align: left; + font-size: 0.875rem; + padding-left: 1rem !important; +} + +div.dt-btn-split-wrapper { + padding-left: 5px; + padding-right: 5px; + margin-bottom: 0px; + margin-bottom: 0px !important; +} +div.dt-btn-split-wrapper button { + margin-right: 0px; + display: inline-block; + margin-top: 0px; + border-bottom-left-radius: 3px; + border-top-left-radius: 3px; + border-top-right-radius: 0px; + border-bottom-right-radius: 0px; + overflow: hidden; + text-overflow: ellipsis; +} +div.dt-btn-split-wrapper button.dt-button { + min-width: 30px; + margin-left: -1px; + border-bottom-left-radius: 0px; + border-top-left-radius: 0px; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; + padding: 0px; +} +div.dt-btn-split-wrapper:active:not(.disabled) button, div.dt-btn-split-wrapper.active:not(.disabled) button, div.dt-btn-split-wrapper.is-active:not(.disabled) button { + background-color: #eee; + border-color: transparent; +} +div.dt-btn-split-wrapper:active:not(.disabled) button.dt-button, div.dt-btn-split-wrapper.active:not(.disabled) button.dt-button, div.dt-btn-split-wrapper.is-active:not(.disabled) button.dt-button { + box-shadow: none; + background-color: whitesmoke; + border-color: transparent; +} +div.dt-btn-split-wrapper:active:not(.disabled) button:hover, div.dt-btn-split-wrapper.active:not(.disabled) button:hover, div.dt-btn-split-wrapper.is-active:not(.disabled) button:hover { + background-color: #eee; + border-color: transparent; +} diff --git a/app/static/DataTables/Buttons-2.2.2/css/buttons.bulma.min.css b/app/static/DataTables/Buttons-2.2.2/css/buttons.bulma.min.css new file mode 100644 index 000000000..99ee3ac88 --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/css/buttons.bulma.min.css @@ -0,0 +1 @@ +@keyframes dtb-spinner{100%{transform:rotate(360deg)}}@-o-keyframes dtb-spinner{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes dtb-spinner{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dtb-spinner{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes dtb-spinner{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}div.dataTables_wrapper{position:relative}div.dt-buttons{position:initial}div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 4px 10px 1px rgba(0, 0, 0, 0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}div.dtb-popover-close{position:absolute;top:10px;right:10px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:12}button.dtb-hide-drop{display:none !important}div.dt-button-collection-title{text-align:center;padding:.3em 0 .5em;margin-left:.5em;margin-right:.5em;font-size:.9em}div.dt-button-collection-title:empty{display:none}span.dt-button-spacer{display:inline-block;margin:.5em;white-space:nowrap}span.dt-button-spacer.bar{border-left:1px solid rgba(0, 0, 0, 0.3);vertical-align:middle;padding-left:.5em}span.dt-button-spacer.bar:empty{height:1em;width:1px;padding-left:0}div.dt-button-collection span.dt-button-spacer{width:100%;font-size:.9em;text-align:center;margin:.5em 0}div.dt-button-collection span.dt-button-spacer:empty{height:0;width:100%}div.dt-button-collection span.dt-button-spacer.bar{border-left:none;border-bottom:1px solid rgba(0, 0, 0, 0.3);padding-left:0}div.dt-button-collection{position:absolute;z-index:2001;min-width:200px;background:white;max-width:none;display:block;box-shadow:0 .5em 1em -0.125em rgba(10, 10, 10, 0.1),0 0 0 1px rgba(10, 10, 10, 0.02);border-radius:4;padding-top:.5rem}div.dt-button-collection div.dropdown-menu{display:block;z-index:2002;min-width:100%}div.dt-button-collection div.dt-btn-split-wrapper{width:100%;padding-left:5px;padding-right:5px;margin-bottom:0px;display:flex;flex-direction:row;flex-wrap:wrap;justify-content:flex-start;align-content:flex-start;align-items:stretch}div.dt-button-collection div.dt-btn-split-wrapper button{margin-right:0px;display:inline-block;width:0;flex-grow:1;flex-shrink:0;flex-basis:50px;margin-top:0px;border-bottom-left-radius:3px;border-top-left-radius:3px;border-top-right-radius:0px;border-bottom-right-radius:0px;overflow:hidden;text-overflow:ellipsis}div.dt-button-collection div.dt-btn-split-wrapper button.dt-button{min-width:30px;margin-left:-1px;flex-grow:0;flex-shrink:0;flex-basis:0;border-bottom-left-radius:0px;border-top-left-radius:0px;border-top-right-radius:3px;border-bottom-right-radius:3px;padding:0px}div.dt-button-collection.fixed{position:fixed;display:block;top:50%;left:50%;margin-left:-75px;border-radius:5px;background-color:white}div.dt-button-collection.fixed.two-column{margin-left:-200px}div.dt-button-collection.fixed.three-column{margin-left:-225px}div.dt-button-collection.fixed.four-column{margin-left:-300px}div.dt-button-collection.fixed.columns{margin-left:-409px}@media screen and (max-width: 1024px){div.dt-button-collection.fixed.columns{margin-left:-308px}}@media screen and (max-width: 640px){div.dt-button-collection.fixed.columns{margin-left:-203px}}@media screen and (max-width: 460px){div.dt-button-collection.fixed.columns{margin-left:-100px}}div.dt-button-collection.fixed>:last-child{max-height:100vh;overflow:auto}div.dt-button-collection.two-column>:last-child,div.dt-button-collection.three-column>:last-child,div.dt-button-collection.four-column>:last-child{display:block !important;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}div.dt-button-collection.two-column>:last-child>*,div.dt-button-collection.three-column>:last-child>*,div.dt-button-collection.four-column>:last-child>*{-webkit-column-break-inside:avoid;break-inside:avoid}div.dt-button-collection.two-column{width:400px}div.dt-button-collection.two-column>:last-child{padding-bottom:1px;column-count:2}div.dt-button-collection.three-column{width:450px}div.dt-button-collection.three-column>:last-child{padding-bottom:1px;column-count:3}div.dt-button-collection.four-column{width:600px}div.dt-button-collection.four-column>:last-child{padding-bottom:1px;column-count:4}div.dt-button-collection .dt-button{border-radius:0}div.dt-button-collection.columns{width:auto}div.dt-button-collection.columns>:last-child{display:flex;flex-wrap:wrap;justify-content:flex-start;align-items:center;gap:6px;width:818px;padding-bottom:1px}div.dt-button-collection.columns>:last-child .dt-button{min-width:200px;flex:0 1;margin:0}div.dt-button-collection.columns.dtb-b3>:last-child,div.dt-button-collection.columns.dtb-b2>:last-child,div.dt-button-collection.columns.dtb-b1>:last-child{justify-content:space-between}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:1 1 32%}div.dt-button-collection.columns.dtb-b2 .dt-button{flex:1 1 48%}div.dt-button-collection.columns.dtb-b1 .dt-button{flex:1 1 100%}@media screen and (max-width: 1024px){div.dt-button-collection.columns>:last-child{width:612px}}@media screen and (max-width: 640px){div.dt-button-collection.columns>:last-child{width:406px}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:0 1 32%}}@media screen and (max-width: 460px){div.dt-button-collection.columns>:last-child{width:200px}}div.dt-button-collection .dropdown-content{box-shadow:none;padding-top:0;border-radius:0}div.dt-button-collection.fixed:before,div.dt-button-collection.fixed:after{display:none}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;z-index:999}@media screen and (max-width: 767px){div.dt-buttons{float:none;width:100%;text-align:center;margin-bottom:.5em}div.dt-buttons a.btn{float:none}}div.dt-buttons button.btn.processing,div.dt-buttons div.btn.processing,div.dt-buttons a.btn.processing{color:rgba(0, 0, 0, 0.2)}div.dt-buttons button.btn.processing:after,div.dt-buttons div.btn.processing:after,div.dt-buttons a.btn.processing:after{position:absolute;top:50%;left:50%;width:16px;height:16px;margin:-8px 0 0 -8px;box-sizing:border-box;display:block;content:" ";border:2px solid #282828;border-radius:50%;border-left-color:transparent;border-right-color:transparent;animation:dtb-spinner 1500ms infinite linear;-o-animation:dtb-spinner 1500ms infinite linear;-ms-animation:dtb-spinner 1500ms infinite linear;-webkit-animation:dtb-spinner 1500ms infinite linear;-moz-animation:dtb-spinner 1500ms infinite linear}div.dt-buttons button.button{margin-left:5px}div.dt-buttons button.button:first-child{margin-left:0px}span.dt-down-arrow{display:none}span.dt-button-spacer{display:inline-flex;margin:.5em;white-space:nowrap;align-items:center;font-size:1rem}span.dt-button-spacer.bar:empty{height:inherit}div.dt-button-collection span.dt-button-spacer{text-align:left;font-size:.875rem;padding-left:1rem !important}div.dt-btn-split-wrapper{padding-left:5px;padding-right:5px;margin-bottom:0px;margin-bottom:0px !important}div.dt-btn-split-wrapper button{margin-right:0px;display:inline-block;margin-top:0px;border-bottom-left-radius:3px;border-top-left-radius:3px;border-top-right-radius:0px;border-bottom-right-radius:0px;overflow:hidden;text-overflow:ellipsis}div.dt-btn-split-wrapper button.dt-button{min-width:30px;margin-left:-1px;border-bottom-left-radius:0px;border-top-left-radius:0px;border-top-right-radius:3px;border-bottom-right-radius:3px;padding:0px}div.dt-btn-split-wrapper:active:not(.disabled) button,div.dt-btn-split-wrapper.active:not(.disabled) button,div.dt-btn-split-wrapper.is-active:not(.disabled) button{background-color:#eee;border-color:transparent}div.dt-btn-split-wrapper:active:not(.disabled) button.dt-button,div.dt-btn-split-wrapper.active:not(.disabled) button.dt-button,div.dt-btn-split-wrapper.is-active:not(.disabled) button.dt-button{box-shadow:none;background-color:whitesmoke;border-color:transparent}div.dt-btn-split-wrapper:active:not(.disabled) button:hover,div.dt-btn-split-wrapper.active:not(.disabled) button:hover,div.dt-btn-split-wrapper.is-active:not(.disabled) button:hover{background-color:#eee;border-color:transparent} diff --git a/app/static/DataTables/Buttons-2.2.2/css/buttons.dataTables.css b/app/static/DataTables/Buttons-2.2.2/css/buttons.dataTables.css new file mode 100644 index 000000000..ce33a3c96 --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/css/buttons.dataTables.css @@ -0,0 +1,631 @@ +@keyframes dtb-spinner { + 100% { + transform: rotate(360deg); + } +} +@-o-keyframes dtb-spinner { + 100% { + -o-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-ms-keyframes dtb-spinner { + 100% { + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-webkit-keyframes dtb-spinner { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-moz-keyframes dtb-spinner { + 100% { + -moz-transform: rotate(360deg); + transform: rotate(360deg); + } +} +div.dataTables_wrapper { + position: relative; +} + +div.dt-buttons { + position: initial; +} + +div.dt-button-info { + position: fixed; + top: 50%; + left: 50%; + width: 400px; + margin-top: -100px; + margin-left: -200px; + background-color: white; + border: 2px solid #111; + box-shadow: 3px 4px 10px 1px rgba(0, 0, 0, 0.3); + border-radius: 3px; + text-align: center; + z-index: 21; +} +div.dt-button-info h2 { + padding: 0.5em; + margin: 0; + font-weight: normal; + border-bottom: 1px solid #ddd; + background-color: #f3f3f3; +} +div.dt-button-info > div { + padding: 1em; +} + +div.dtb-popover-close { + position: absolute; + top: 10px; + right: 10px; + width: 22px; + height: 22px; + border: 1px solid #eaeaea; + background-color: #f9f9f9; + text-align: center; + border-radius: 3px; + cursor: pointer; + z-index: 12; +} + +button.dtb-hide-drop { + display: none !important; +} + +div.dt-button-collection-title { + text-align: center; + padding: 0.3em 0 0.5em; + margin-left: 0.5em; + margin-right: 0.5em; + font-size: 0.9em; +} + +div.dt-button-collection-title:empty { + display: none; +} + +span.dt-button-spacer { + display: inline-block; + margin: 0.5em; + white-space: nowrap; +} +span.dt-button-spacer.bar { + border-left: 1px solid rgba(0, 0, 0, 0.3); + vertical-align: middle; + padding-left: 0.5em; +} +span.dt-button-spacer.bar:empty { + height: 1em; + width: 1px; + padding-left: 0; +} + +div.dt-button-collection span.dt-button-spacer { + width: 100%; + font-size: 0.9em; + text-align: center; + margin: 0.5em 0; +} +div.dt-button-collection span.dt-button-spacer:empty { + height: 0; + width: 100%; +} +div.dt-button-collection span.dt-button-spacer.bar { + border-left: none; + border-bottom: 1px solid rgba(0, 0, 0, 0.3); + padding-left: 0; +} + +button.dt-button, +div.dt-button, +a.dt-button, +input.dt-button { + position: relative; + display: inline-block; + box-sizing: border-box; + margin-left: 0.167em; + margin-right: 0.167em; + margin-bottom: 0.333em; + padding: 0.5em 1em; + border: 1px solid rgba(0, 0, 0, 0.3); + border-radius: 2px; + cursor: pointer; + font-size: 0.88em; + line-height: 1.6em; + color: black; + white-space: nowrap; + overflow: hidden; + background-color: rgba(0, 0, 0, 0.1); + /* Fallback */ + background: -webkit-linear-gradient(top, rgba(230, 230, 230, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%); + /* Chrome 10+, Saf5.1+, iOS 5+ */ + background: -moz-linear-gradient(top, rgba(230, 230, 230, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%); + /* FF3.6 */ + background: -ms-linear-gradient(top, rgba(230, 230, 230, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%); + /* IE10 */ + background: -o-linear-gradient(top, rgba(230, 230, 230, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%); + /* Opera 11.10+ */ + background: linear-gradient(to bottom, rgba(230, 230, 230, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="rgba(230, 230, 230, 0.1)", EndColorStr="rgba(0, 0, 0, 0.1)"); + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + text-decoration: none; + outline: none; + text-overflow: ellipsis; +} +button.dt-button:first-child, +div.dt-button:first-child, +a.dt-button:first-child, +input.dt-button:first-child { + margin-left: 0; +} +button.dt-button.disabled, +div.dt-button.disabled, +a.dt-button.disabled, +input.dt-button.disabled { + cursor: default; + opacity: 0.4; +} +button.dt-button:active:not(.disabled), button.dt-button.active:not(.disabled), +div.dt-button:active:not(.disabled), +div.dt-button.active:not(.disabled), +a.dt-button:active:not(.disabled), +a.dt-button.active:not(.disabled), +input.dt-button:active:not(.disabled), +input.dt-button.active:not(.disabled) { + background-color: rgba(0, 0, 0, 0.1); + /* Fallback */ + background: -webkit-linear-gradient(top, rgba(179, 179, 179, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%); + /* Chrome 10+, Saf5.1+, iOS 5+ */ + background: -moz-linear-gradient(top, rgba(179, 179, 179, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%); + /* FF3.6 */ + background: -ms-linear-gradient(top, rgba(179, 179, 179, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%); + /* IE10 */ + background: -o-linear-gradient(top, rgba(179, 179, 179, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%); + /* Opera 11.10+ */ + background: linear-gradient(to bottom, rgba(179, 179, 179, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="rgba(179, 179, 179, 0.1)", EndColorStr="rgba(0, 0, 0, 0.1)"); + box-shadow: inset 1px 1px 3px #999999; +} +button.dt-button:active:not(.disabled):hover:not(.disabled), button.dt-button.active:not(.disabled):hover:not(.disabled), +div.dt-button:active:not(.disabled):hover:not(.disabled), +div.dt-button.active:not(.disabled):hover:not(.disabled), +a.dt-button:active:not(.disabled):hover:not(.disabled), +a.dt-button.active:not(.disabled):hover:not(.disabled), +input.dt-button:active:not(.disabled):hover:not(.disabled), +input.dt-button.active:not(.disabled):hover:not(.disabled) { + box-shadow: inset 1px 1px 3px #999999; + background-color: rgba(0, 0, 0, 0.1); + /* Fallback */ + background: -webkit-linear-gradient(top, rgba(128, 128, 128, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%); + /* Chrome 10+, Saf5.1+, iOS 5+ */ + background: -moz-linear-gradient(top, rgba(128, 128, 128, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%); + /* FF3.6 */ + background: -ms-linear-gradient(top, rgba(128, 128, 128, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%); + /* IE10 */ + background: -o-linear-gradient(top, rgba(128, 128, 128, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%); + /* Opera 11.10+ */ + background: linear-gradient(to bottom, rgba(128, 128, 128, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="rgba(128, 128, 128, 0.1)", EndColorStr="rgba(0, 0, 0, 0.1)"); +} +button.dt-button:hover, +div.dt-button:hover, +a.dt-button:hover, +input.dt-button:hover { + text-decoration: none; +} +button.dt-button:hover:not(.disabled), +div.dt-button:hover:not(.disabled), +a.dt-button:hover:not(.disabled), +input.dt-button:hover:not(.disabled) { + border: 1px solid #666; + background-color: rgba(0, 0, 0, 0.1); + /* Fallback */ + background: -webkit-linear-gradient(top, rgba(153, 153, 153, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%); + /* Chrome 10+, Saf5.1+, iOS 5+ */ + background: -moz-linear-gradient(top, rgba(153, 153, 153, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%); + /* FF3.6 */ + background: -ms-linear-gradient(top, rgba(153, 153, 153, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%); + /* IE10 */ + background: -o-linear-gradient(top, rgba(153, 153, 153, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%); + /* Opera 11.10+ */ + background: linear-gradient(to bottom, rgba(153, 153, 153, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="rgba(153, 153, 153, 0.1)", EndColorStr="rgba(0, 0, 0, 0.1)"); +} +button.dt-button:focus:not(.disabled), +div.dt-button:focus:not(.disabled), +a.dt-button:focus:not(.disabled), +input.dt-button:focus:not(.disabled) { + border: 1px solid #426c9e; + text-shadow: 0 1px 0 #c4def1; + outline: none; + background-color: #79ace9; + /* Fallback */ + background: -webkit-linear-gradient(top, #d1e2f7 0%, #79ace9 100%); + /* Chrome 10+, Saf5.1+, iOS 5+ */ + background: -moz-linear-gradient(top, #d1e2f7 0%, #79ace9 100%); + /* FF3.6 */ + background: -ms-linear-gradient(top, #d1e2f7 0%, #79ace9 100%); + /* IE10 */ + background: -o-linear-gradient(top, #d1e2f7 0%, #79ace9 100%); + /* Opera 11.10+ */ + background: linear-gradient(to bottom, #d1e2f7 0%, #79ace9 100%); + filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="#d1e2f7", EndColorStr="#79ace9"); +} +button.dt-button span.dt-down-arrow, +div.dt-button span.dt-down-arrow, +a.dt-button span.dt-down-arrow, +input.dt-button span.dt-down-arrow { + position: relative; + top: -2px; + color: rgba(70, 70, 70, 0.75); + font-size: 8px; + padding-left: 10px; + line-height: 1em; +} + +.dt-button embed { + outline: none; +} + +div.dt-buttons { + float: left; +} +div.dt-buttons.buttons-right { + float: right; +} + +div.dataTables_layout_cell div.dt-buttons { + float: none; +} +div.dataTables_layout_cell div.dt-buttons.buttons-right { + float: none; +} + +div.dt-btn-split-wrapper { + display: inline-block; +} + +div.dt-button-collection { + position: absolute; + top: 0; + left: 0; + width: 200px; + margin-top: 3px; + margin-bottom: 3px; + padding: 4px 4px 2px 4px; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.4); + background-color: white; + overflow: hidden; + z-index: 2002; + border-radius: 5px; + box-shadow: 3px 4px 10px 1px rgba(0, 0, 0, 0.3); + box-sizing: border-box; +} +div.dt-button-collection button.dt-button, +div.dt-button-collection div.dt-button, +div.dt-button-collection a.dt-button { + position: relative; + left: 0; + right: 0; + width: 100%; + display: block; + float: none; + margin: 4px 0 2px 0; +} +div.dt-button-collection button.dt-button:active:not(.disabled), div.dt-button-collection button.dt-button.active:not(.disabled), +div.dt-button-collection div.dt-button:active:not(.disabled), +div.dt-button-collection div.dt-button.active:not(.disabled), +div.dt-button-collection a.dt-button:active:not(.disabled), +div.dt-button-collection a.dt-button.active:not(.disabled) { + background-color: #dadada; + /* Fallback */ + background: -webkit-linear-gradient(top, #f0f0f0 0%, #dadada 100%); + /* Chrome 10+, Saf5.1+, iOS 5+ */ + background: -moz-linear-gradient(top, #f0f0f0 0%, #dadada 100%); + /* FF3.6 */ + background: -ms-linear-gradient(top, #f0f0f0 0%, #dadada 100%); + /* IE10 */ + background: -o-linear-gradient(top, #f0f0f0 0%, #dadada 100%); + /* Opera 11.10+ */ + background: linear-gradient(to bottom, #f0f0f0 0%, #dadada 100%); + filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="#f0f0f0", EndColorStr="#dadada"); + box-shadow: inset 1px 1px 3px #666; +} +div.dt-button-collection button.dt-button:first-child, +div.dt-button-collection div.dt-button:first-child, +div.dt-button-collection a.dt-button:first-child { + margin-top: 0; + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} +div.dt-button-collection button.dt-button:last-child, +div.dt-button-collection div.dt-button:last-child, +div.dt-button-collection a.dt-button:last-child { + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; +} +div.dt-button-collection div.dt-btn-split-wrapper { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: flex-start; + align-content: flex-start; + align-items: stretch; + margin: 4px 0 2px 0; +} +div.dt-button-collection div.dt-btn-split-wrapper button.dt-button { + margin: 0; + display: inline-block; + width: 0; + flex-grow: 1; + flex-shrink: 0; + flex-basis: 50px; + border-radius: 0; +} +div.dt-button-collection div.dt-btn-split-wrapper button.dt-btn-split-drop { + min-width: 20px; + flex-grow: 0; + flex-shrink: 0; + flex-basis: 0; +} +div.dt-button-collection div.dt-btn-split-wrapper:first-child { + margin-top: 0; +} +div.dt-button-collection div.dt-btn-split-wrapper:first-child button.dt-button { + border-top-left-radius: 3px; +} +div.dt-button-collection div.dt-btn-split-wrapper:first-child button.dt-btn-split-drop { + border-top-right-radius: 3px; +} +div.dt-button-collection div.dt-btn-split-wrapper:last-child button.dt-button { + border-bottom-left-radius: 3px; +} +div.dt-button-collection div.dt-btn-split-wrapper:last-child button.dt-btn-split-drop { + border-bottom-right-radius: 3px; +} +div.dt-button-collection div.dt-btn-split-wrapper:active:not(.disabled) button.dt-button, div.dt-button-collection div.dt-btn-split-wrapper.active:not(.disabled) button.dt-button { + background-color: #dadada; + /* Fallback */ + background: -webkit-linear-gradient(top, #f0f0f0 0%, #dadada 100%); + /* Chrome 10+, Saf5.1+, iOS 5+ */ + background: -moz-linear-gradient(top, #f0f0f0 0%, #dadada 100%); + /* FF3.6 */ + background: -ms-linear-gradient(top, #f0f0f0 0%, #dadada 100%); + /* IE10 */ + background: -o-linear-gradient(top, #f0f0f0 0%, #dadada 100%); + /* Opera 11.10+ */ + background: linear-gradient(to bottom, #f0f0f0 0%, #dadada 100%); + filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="#f0f0f0", EndColorStr="#dadada"); + box-shadow: inset 0px 0px 4px #666; +} +div.dt-button-collection div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop, div.dt-button-collection div.dt-btn-split-wrapper.active:not(.disabled) button.dt-btn-split-drop { + box-shadow: none; +} +div.dt-button-collection.fixed .dt-button:first-child { + margin-top: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; +} +div.dt-button-collection.fixed .dt-button:last-child { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} +div.dt-button-collection.fixed { + position: fixed; + display: block; + top: 50%; + left: 50%; + margin-left: -75px; + border-radius: 5px; + background-color: white; +} +div.dt-button-collection.fixed.two-column { + margin-left: -200px; +} +div.dt-button-collection.fixed.three-column { + margin-left: -225px; +} +div.dt-button-collection.fixed.four-column { + margin-left: -300px; +} +div.dt-button-collection.fixed.columns { + margin-left: -409px; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.fixed.columns { + margin-left: -308px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.fixed.columns { + margin-left: -203px; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.fixed.columns { + margin-left: -100px; + } +} +div.dt-button-collection.fixed > :last-child { + max-height: 100vh; + overflow: auto; +} +div.dt-button-collection.two-column > :last-child, div.dt-button-collection.three-column > :last-child, div.dt-button-collection.four-column > :last-child { + display: block !important; + -webkit-column-gap: 8px; + -moz-column-gap: 8px; + -ms-column-gap: 8px; + -o-column-gap: 8px; + column-gap: 8px; +} +div.dt-button-collection.two-column > :last-child > *, div.dt-button-collection.three-column > :last-child > *, div.dt-button-collection.four-column > :last-child > * { + -webkit-column-break-inside: avoid; + break-inside: avoid; +} +div.dt-button-collection.two-column { + width: 400px; +} +div.dt-button-collection.two-column > :last-child { + padding-bottom: 1px; + column-count: 2; +} +div.dt-button-collection.three-column { + width: 450px; +} +div.dt-button-collection.three-column > :last-child { + padding-bottom: 1px; + column-count: 3; +} +div.dt-button-collection.four-column { + width: 600px; +} +div.dt-button-collection.four-column > :last-child { + padding-bottom: 1px; + column-count: 4; +} +div.dt-button-collection .dt-button { + border-radius: 0; +} +div.dt-button-collection.columns { + width: auto; +} +div.dt-button-collection.columns > :last-child { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; + gap: 6px; + width: 818px; + padding-bottom: 1px; +} +div.dt-button-collection.columns > :last-child .dt-button { + min-width: 200px; + flex: 0 1; + margin: 0; +} +div.dt-button-collection.columns.dtb-b3 > :last-child, div.dt-button-collection.columns.dtb-b2 > :last-child, div.dt-button-collection.columns.dtb-b1 > :last-child { + justify-content: space-between; +} +div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 1 1 32%; +} +div.dt-button-collection.columns.dtb-b2 .dt-button { + flex: 1 1 48%; +} +div.dt-button-collection.columns.dtb-b1 .dt-button { + flex: 1 1 100%; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.columns > :last-child { + width: 612px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.columns > :last-child { + width: 406px; + } + div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 0 1 32%; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.columns > :last-child { + width: 200px; + } +} + +div.dt-button-background { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.7); + /* Fallback */ + background: -ms-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%); + /* IE10 Consumer Preview */ + background: -moz-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%); + /* Firefox */ + background: -o-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%); + /* Opera */ + background: -webkit-gradient(radial, center center, 0, center center, 497, color-stop(0, rgba(0, 0, 0, 0.3)), color-stop(1, rgba(0, 0, 0, 0.7))); + /* Webkit (Safari/Chrome 10) */ + background: -webkit-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%); + /* Webkit (Chrome 11+) */ + background: radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%); + /* W3C Markup, IE10 Release Preview */ + z-index: 2001; +} + +@media screen and (max-width: 640px) { + div.dt-buttons { + float: none !important; + text-align: center; + } +} +button.dt-button.processing, +div.dt-button.processing, +a.dt-button.processing { + color: rgba(0, 0, 0, 0.2); +} +button.dt-button.processing:after, +div.dt-button.processing:after, +a.dt-button.processing:after { + position: absolute; + top: 50%; + left: 50%; + width: 16px; + height: 16px; + margin: -8px 0 0 -8px; + box-sizing: border-box; + display: block; + content: " "; + border: 2px solid #282828; + border-radius: 50%; + border-left-color: transparent; + border-right-color: transparent; + animation: dtb-spinner 1500ms infinite linear; + -o-animation: dtb-spinner 1500ms infinite linear; + -ms-animation: dtb-spinner 1500ms infinite linear; + -webkit-animation: dtb-spinner 1500ms infinite linear; + -moz-animation: dtb-spinner 1500ms infinite linear; +} + +button.dt-btn-split-drop { + margin-left: calc(-1px - 0.333em); + padding-bottom: calc(0.5em - 1px); + border-radius: 0px 1px 1px 0px; + color: rgba(70, 70, 70, 0.9); + border-left: none; +} +button.dt-btn-split-drop span.dt-btn-split-drop-arrow { + position: relative; + top: -1px; + left: -2px; + font-size: 8px; +} +button.dt-btn-split-drop:hover { + z-index: 2; +} + +button.buttons-split { + border-right: 1px solid rgba(70, 70, 70, 0); + border-radius: 1px 0px 0px 1px; +} + +button.dt-btn-split-drop-button { + background-color: white; +} +button.dt-btn-split-drop-button:hover { + background-color: white; +} diff --git a/app/static/DataTables/Buttons-2.2.2/css/buttons.dataTables.min.css b/app/static/DataTables/Buttons-2.2.2/css/buttons.dataTables.min.css new file mode 100644 index 000000000..fd38c86a7 --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/css/buttons.dataTables.min.css @@ -0,0 +1 @@ +@keyframes dtb-spinner{100%{transform:rotate(360deg)}}@-o-keyframes dtb-spinner{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes dtb-spinner{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dtb-spinner{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes dtb-spinner{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}div.dataTables_wrapper{position:relative}div.dt-buttons{position:initial}div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 4px 10px 1px rgba(0, 0, 0, 0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}div.dtb-popover-close{position:absolute;top:10px;right:10px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:12}button.dtb-hide-drop{display:none !important}div.dt-button-collection-title{text-align:center;padding:.3em 0 .5em;margin-left:.5em;margin-right:.5em;font-size:.9em}div.dt-button-collection-title:empty{display:none}span.dt-button-spacer{display:inline-block;margin:.5em;white-space:nowrap}span.dt-button-spacer.bar{border-left:1px solid rgba(0, 0, 0, 0.3);vertical-align:middle;padding-left:.5em}span.dt-button-spacer.bar:empty{height:1em;width:1px;padding-left:0}div.dt-button-collection span.dt-button-spacer{width:100%;font-size:.9em;text-align:center;margin:.5em 0}div.dt-button-collection span.dt-button-spacer:empty{height:0;width:100%}div.dt-button-collection span.dt-button-spacer.bar{border-left:none;border-bottom:1px solid rgba(0, 0, 0, 0.3);padding-left:0}button.dt-button,div.dt-button,a.dt-button,input.dt-button{position:relative;display:inline-block;box-sizing:border-box;margin-left:.167em;margin-right:.167em;margin-bottom:.333em;padding:.5em 1em;border:1px solid rgba(0, 0, 0, 0.3);border-radius:2px;cursor:pointer;font-size:.88em;line-height:1.6em;color:black;white-space:nowrap;overflow:hidden;background-color:rgba(0, 0, 0, 0.1);background:-webkit-linear-gradient(top, rgba(230, 230, 230, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-moz-linear-gradient(top, rgba(230, 230, 230, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-ms-linear-gradient(top, rgba(230, 230, 230, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-o-linear-gradient(top, rgba(230, 230, 230, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:linear-gradient(to bottom, rgba(230, 230, 230, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="rgba(230, 230, 230, 0.1)", EndColorStr="rgba(0, 0, 0, 0.1)");-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-decoration:none;outline:none;text-overflow:ellipsis}button.dt-button:first-child,div.dt-button:first-child,a.dt-button:first-child,input.dt-button:first-child{margin-left:0}button.dt-button.disabled,div.dt-button.disabled,a.dt-button.disabled,input.dt-button.disabled{cursor:default;opacity:.4}button.dt-button:active:not(.disabled),button.dt-button.active:not(.disabled),div.dt-button:active:not(.disabled),div.dt-button.active:not(.disabled),a.dt-button:active:not(.disabled),a.dt-button.active:not(.disabled),input.dt-button:active:not(.disabled),input.dt-button.active:not(.disabled){background-color:rgba(0, 0, 0, 0.1);background:-webkit-linear-gradient(top, rgba(179, 179, 179, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-moz-linear-gradient(top, rgba(179, 179, 179, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-ms-linear-gradient(top, rgba(179, 179, 179, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-o-linear-gradient(top, rgba(179, 179, 179, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:linear-gradient(to bottom, rgba(179, 179, 179, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="rgba(179, 179, 179, 0.1)", EndColorStr="rgba(0, 0, 0, 0.1)");box-shadow:inset 1px 1px 3px #999}button.dt-button:active:not(.disabled):hover:not(.disabled),button.dt-button.active:not(.disabled):hover:not(.disabled),div.dt-button:active:not(.disabled):hover:not(.disabled),div.dt-button.active:not(.disabled):hover:not(.disabled),a.dt-button:active:not(.disabled):hover:not(.disabled),a.dt-button.active:not(.disabled):hover:not(.disabled),input.dt-button:active:not(.disabled):hover:not(.disabled),input.dt-button.active:not(.disabled):hover:not(.disabled){box-shadow:inset 1px 1px 3px #999;background-color:rgba(0, 0, 0, 0.1);background:-webkit-linear-gradient(top, rgba(128, 128, 128, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-moz-linear-gradient(top, rgba(128, 128, 128, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-ms-linear-gradient(top, rgba(128, 128, 128, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-o-linear-gradient(top, rgba(128, 128, 128, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:linear-gradient(to bottom, rgba(128, 128, 128, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="rgba(128, 128, 128, 0.1)", EndColorStr="rgba(0, 0, 0, 0.1)")}button.dt-button:hover,div.dt-button:hover,a.dt-button:hover,input.dt-button:hover{text-decoration:none}button.dt-button:hover:not(.disabled),div.dt-button:hover:not(.disabled),a.dt-button:hover:not(.disabled),input.dt-button:hover:not(.disabled){border:1px solid #666;background-color:rgba(0, 0, 0, 0.1);background:-webkit-linear-gradient(top, rgba(153, 153, 153, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-moz-linear-gradient(top, rgba(153, 153, 153, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-ms-linear-gradient(top, rgba(153, 153, 153, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:-o-linear-gradient(top, rgba(153, 153, 153, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);background:linear-gradient(to bottom, rgba(153, 153, 153, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="rgba(153, 153, 153, 0.1)", EndColorStr="rgba(0, 0, 0, 0.1)")}button.dt-button:focus:not(.disabled),div.dt-button:focus:not(.disabled),a.dt-button:focus:not(.disabled),input.dt-button:focus:not(.disabled){border:1px solid #426c9e;text-shadow:0 1px 0 #c4def1;outline:none;background-color:#79ace9;background:-webkit-linear-gradient(top, #d1e2f7 0%, #79ace9 100%);background:-moz-linear-gradient(top, #d1e2f7 0%, #79ace9 100%);background:-ms-linear-gradient(top, #d1e2f7 0%, #79ace9 100%);background:-o-linear-gradient(top, #d1e2f7 0%, #79ace9 100%);background:linear-gradient(to bottom, #d1e2f7 0%, #79ace9 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="#d1e2f7", EndColorStr="#79ace9")}button.dt-button span.dt-down-arrow,div.dt-button span.dt-down-arrow,a.dt-button span.dt-down-arrow,input.dt-button span.dt-down-arrow{position:relative;top:-2px;color:rgba(70, 70, 70, 0.75);font-size:8px;padding-left:10px;line-height:1em}.dt-button embed{outline:none}div.dt-buttons{float:left}div.dt-buttons.buttons-right{float:right}div.dataTables_layout_cell div.dt-buttons{float:none}div.dataTables_layout_cell div.dt-buttons.buttons-right{float:none}div.dt-btn-split-wrapper{display:inline-block}div.dt-button-collection{position:absolute;top:0;left:0;width:200px;margin-top:3px;margin-bottom:3px;padding:4px 4px 2px 4px;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.4);background-color:white;overflow:hidden;z-index:2002;border-radius:5px;box-shadow:3px 4px 10px 1px rgba(0, 0, 0, 0.3);box-sizing:border-box}div.dt-button-collection button.dt-button,div.dt-button-collection div.dt-button,div.dt-button-collection a.dt-button{position:relative;left:0;right:0;width:100%;display:block;float:none;margin:4px 0 2px 0}div.dt-button-collection button.dt-button:active:not(.disabled),div.dt-button-collection button.dt-button.active:not(.disabled),div.dt-button-collection div.dt-button:active:not(.disabled),div.dt-button-collection div.dt-button.active:not(.disabled),div.dt-button-collection a.dt-button:active:not(.disabled),div.dt-button-collection a.dt-button.active:not(.disabled){background-color:#dadada;background:-webkit-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background:-moz-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background:-ms-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background:-o-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background:linear-gradient(to bottom, #f0f0f0 0%, #dadada 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="#f0f0f0", EndColorStr="#dadada");box-shadow:inset 1px 1px 3px #666}div.dt-button-collection button.dt-button:first-child,div.dt-button-collection div.dt-button:first-child,div.dt-button-collection a.dt-button:first-child{margin-top:0;border-top-left-radius:3px;border-top-right-radius:3px}div.dt-button-collection button.dt-button:last-child,div.dt-button-collection div.dt-button:last-child,div.dt-button-collection a.dt-button:last-child{border-bottom-left-radius:3px;border-bottom-right-radius:3px}div.dt-button-collection div.dt-btn-split-wrapper{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:flex-start;align-content:flex-start;align-items:stretch;margin:4px 0 2px 0}div.dt-button-collection div.dt-btn-split-wrapper button.dt-button{margin:0;display:inline-block;width:0;flex-grow:1;flex-shrink:0;flex-basis:50px;border-radius:0}div.dt-button-collection div.dt-btn-split-wrapper button.dt-btn-split-drop{min-width:20px;flex-grow:0;flex-shrink:0;flex-basis:0}div.dt-button-collection div.dt-btn-split-wrapper:first-child{margin-top:0}div.dt-button-collection div.dt-btn-split-wrapper:first-child button.dt-button{border-top-left-radius:3px}div.dt-button-collection div.dt-btn-split-wrapper:first-child button.dt-btn-split-drop{border-top-right-radius:3px}div.dt-button-collection div.dt-btn-split-wrapper:last-child button.dt-button{border-bottom-left-radius:3px}div.dt-button-collection div.dt-btn-split-wrapper:last-child button.dt-btn-split-drop{border-bottom-right-radius:3px}div.dt-button-collection div.dt-btn-split-wrapper:active:not(.disabled) button.dt-button,div.dt-button-collection div.dt-btn-split-wrapper.active:not(.disabled) button.dt-button{background-color:#dadada;background:-webkit-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background:-moz-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background:-ms-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background:-o-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background:linear-gradient(to bottom, #f0f0f0 0%, #dadada 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="#f0f0f0", EndColorStr="#dadada");box-shadow:inset 0px 0px 4px #666}div.dt-button-collection div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop,div.dt-button-collection div.dt-btn-split-wrapper.active:not(.disabled) button.dt-btn-split-drop{box-shadow:none}div.dt-button-collection.fixed .dt-button:first-child{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}div.dt-button-collection.fixed .dt-button:last-child{border-bottom-left-radius:0;border-bottom-right-radius:0}div.dt-button-collection.fixed{position:fixed;display:block;top:50%;left:50%;margin-left:-75px;border-radius:5px;background-color:white}div.dt-button-collection.fixed.two-column{margin-left:-200px}div.dt-button-collection.fixed.three-column{margin-left:-225px}div.dt-button-collection.fixed.four-column{margin-left:-300px}div.dt-button-collection.fixed.columns{margin-left:-409px}@media screen and (max-width: 1024px){div.dt-button-collection.fixed.columns{margin-left:-308px}}@media screen and (max-width: 640px){div.dt-button-collection.fixed.columns{margin-left:-203px}}@media screen and (max-width: 460px){div.dt-button-collection.fixed.columns{margin-left:-100px}}div.dt-button-collection.fixed>:last-child{max-height:100vh;overflow:auto}div.dt-button-collection.two-column>:last-child,div.dt-button-collection.three-column>:last-child,div.dt-button-collection.four-column>:last-child{display:block !important;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}div.dt-button-collection.two-column>:last-child>*,div.dt-button-collection.three-column>:last-child>*,div.dt-button-collection.four-column>:last-child>*{-webkit-column-break-inside:avoid;break-inside:avoid}div.dt-button-collection.two-column{width:400px}div.dt-button-collection.two-column>:last-child{padding-bottom:1px;column-count:2}div.dt-button-collection.three-column{width:450px}div.dt-button-collection.three-column>:last-child{padding-bottom:1px;column-count:3}div.dt-button-collection.four-column{width:600px}div.dt-button-collection.four-column>:last-child{padding-bottom:1px;column-count:4}div.dt-button-collection .dt-button{border-radius:0}div.dt-button-collection.columns{width:auto}div.dt-button-collection.columns>:last-child{display:flex;flex-wrap:wrap;justify-content:flex-start;align-items:center;gap:6px;width:818px;padding-bottom:1px}div.dt-button-collection.columns>:last-child .dt-button{min-width:200px;flex:0 1;margin:0}div.dt-button-collection.columns.dtb-b3>:last-child,div.dt-button-collection.columns.dtb-b2>:last-child,div.dt-button-collection.columns.dtb-b1>:last-child{justify-content:space-between}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:1 1 32%}div.dt-button-collection.columns.dtb-b2 .dt-button{flex:1 1 48%}div.dt-button-collection.columns.dtb-b1 .dt-button{flex:1 1 100%}@media screen and (max-width: 1024px){div.dt-button-collection.columns>:last-child{width:612px}}@media screen and (max-width: 640px){div.dt-button-collection.columns>:last-child{width:406px}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:0 1 32%}}@media screen and (max-width: 460px){div.dt-button-collection.columns>:last-child{width:200px}}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0, 0, 0, 0.7);background:-ms-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);background:-moz-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);background:-o-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);background:-webkit-gradient(radial, center center, 0, center center, 497, color-stop(0, rgba(0, 0, 0, 0.3)), color-stop(1, rgba(0, 0, 0, 0.7)));background:-webkit-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);background:radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);z-index:2001}@media screen and (max-width: 640px){div.dt-buttons{float:none !important;text-align:center}}button.dt-button.processing,div.dt-button.processing,a.dt-button.processing{color:rgba(0, 0, 0, 0.2)}button.dt-button.processing:after,div.dt-button.processing:after,a.dt-button.processing:after{position:absolute;top:50%;left:50%;width:16px;height:16px;margin:-8px 0 0 -8px;box-sizing:border-box;display:block;content:" ";border:2px solid #282828;border-radius:50%;border-left-color:transparent;border-right-color:transparent;animation:dtb-spinner 1500ms infinite linear;-o-animation:dtb-spinner 1500ms infinite linear;-ms-animation:dtb-spinner 1500ms infinite linear;-webkit-animation:dtb-spinner 1500ms infinite linear;-moz-animation:dtb-spinner 1500ms infinite linear}button.dt-btn-split-drop{margin-left:calc(-1px - .333em);padding-bottom:calc(.5em - 1px);border-radius:0px 1px 1px 0px;color:rgba(70, 70, 70, 0.9);border-left:none}button.dt-btn-split-drop span.dt-btn-split-drop-arrow{position:relative;top:-1px;left:-2px;font-size:8px}button.dt-btn-split-drop:hover{z-index:2}button.buttons-split{border-right:1px solid rgba(70, 70, 70, 0);border-radius:1px 0px 0px 1px}button.dt-btn-split-drop-button{background-color:white}button.dt-btn-split-drop-button:hover{background-color:white} diff --git a/app/static/DataTables/Buttons-2.2.2/css/buttons.foundation.css b/app/static/DataTables/Buttons-2.2.2/css/buttons.foundation.css new file mode 100644 index 000000000..f697d843d --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/css/buttons.foundation.css @@ -0,0 +1,367 @@ +@keyframes dtb-spinner { + 100% { + transform: rotate(360deg); + } +} +@-o-keyframes dtb-spinner { + 100% { + -o-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-ms-keyframes dtb-spinner { + 100% { + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-webkit-keyframes dtb-spinner { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-moz-keyframes dtb-spinner { + 100% { + -moz-transform: rotate(360deg); + transform: rotate(360deg); + } +} +div.dataTables_wrapper { + position: relative; +} + +div.dt-buttons { + position: initial; +} + +div.dt-button-info { + position: fixed; + top: 50%; + left: 50%; + width: 400px; + margin-top: -100px; + margin-left: -200px; + background-color: white; + border: 2px solid #111; + box-shadow: 3px 4px 10px 1px rgba(0, 0, 0, 0.3); + border-radius: 3px; + text-align: center; + z-index: 21; +} +div.dt-button-info h2 { + padding: 0.5em; + margin: 0; + font-weight: normal; + border-bottom: 1px solid #ddd; + background-color: #f3f3f3; +} +div.dt-button-info > div { + padding: 1em; +} + +div.dtb-popover-close { + position: absolute; + top: 10px; + right: 10px; + width: 22px; + height: 22px; + border: 1px solid #eaeaea; + background-color: #f9f9f9; + text-align: center; + border-radius: 3px; + cursor: pointer; + z-index: 12; +} + +button.dtb-hide-drop { + display: none !important; +} + +div.dt-button-collection-title { + text-align: center; + padding: 0.3em 0 0.5em; + margin-left: 0.5em; + margin-right: 0.5em; + font-size: 0.9em; +} + +div.dt-button-collection-title:empty { + display: none; +} + +span.dt-button-spacer { + display: inline-block; + margin: 0.5em; + white-space: nowrap; +} +span.dt-button-spacer.bar { + border-left: 1px solid rgba(0, 0, 0, 0.3); + vertical-align: middle; + padding-left: 0.5em; +} +span.dt-button-spacer.bar:empty { + height: 1em; + width: 1px; + padding-left: 0; +} + +div.dt-button-collection span.dt-button-spacer { + width: 100%; + font-size: 0.9em; + text-align: center; + margin: 0.5em 0; +} +div.dt-button-collection span.dt-button-spacer:empty { + height: 0; + width: 100%; +} +div.dt-button-collection span.dt-button-spacer.bar { + border-left: none; + border-bottom: 1px solid rgba(0, 0, 0, 0.3); + padding-left: 0; +} + +ul.dt-buttons li { + margin: 0; +} +ul.dt-buttons li.active a { + box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.6); +} + +ul.dt-buttons.button-group a { + margin-bottom: 0; +} + +div.dt-button-collection { + position: absolute; + z-index: 2002; + max-width: none; + border: 1px solid #cacaca; + padding: 0.5rem; + background-color: white; +} +div.dt-button-collection.fixed { + position: fixed; + display: block; + top: 50%; + left: 50%; + margin-left: -75px; + border-radius: 5px; + background-color: white; +} +div.dt-button-collection.fixed.two-column { + margin-left: -200px; +} +div.dt-button-collection.fixed.three-column { + margin-left: -225px; +} +div.dt-button-collection.fixed.four-column { + margin-left: -300px; +} +div.dt-button-collection.fixed.columns { + margin-left: -409px; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.fixed.columns { + margin-left: -308px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.fixed.columns { + margin-left: -203px; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.fixed.columns { + margin-left: -100px; + } +} +div.dt-button-collection.fixed > :last-child { + max-height: 100vh; + overflow: auto; +} +div.dt-button-collection.two-column > :last-child, div.dt-button-collection.three-column > :last-child, div.dt-button-collection.four-column > :last-child { + display: block !important; + -webkit-column-gap: 8px; + -moz-column-gap: 8px; + -ms-column-gap: 8px; + -o-column-gap: 8px; + column-gap: 8px; +} +div.dt-button-collection.two-column > :last-child > *, div.dt-button-collection.three-column > :last-child > *, div.dt-button-collection.four-column > :last-child > * { + -webkit-column-break-inside: avoid; + break-inside: avoid; +} +div.dt-button-collection.two-column { + width: 400px; +} +div.dt-button-collection.two-column > :last-child { + padding-bottom: 1px; + column-count: 2; +} +div.dt-button-collection.three-column { + width: 450px; +} +div.dt-button-collection.three-column > :last-child { + padding-bottom: 1px; + column-count: 3; +} +div.dt-button-collection.four-column { + width: 600px; +} +div.dt-button-collection.four-column > :last-child { + padding-bottom: 1px; + column-count: 4; +} +div.dt-button-collection .dt-button { + border-radius: 0; +} +div.dt-button-collection.columns { + width: auto; +} +div.dt-button-collection.columns > :last-child { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; + gap: 6px; + width: 818px; + padding-bottom: 1px; +} +div.dt-button-collection.columns > :last-child .dt-button { + min-width: 200px; + flex: 0 1; + margin: 0; +} +div.dt-button-collection.columns.dtb-b3 > :last-child, div.dt-button-collection.columns.dtb-b2 > :last-child, div.dt-button-collection.columns.dtb-b1 > :last-child { + justify-content: space-between; +} +div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 1 1 32%; +} +div.dt-button-collection.columns.dtb-b2 .dt-button { + flex: 1 1 48%; +} +div.dt-button-collection.columns.dtb-b1 .dt-button { + flex: 1 1 100%; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.columns > :last-child { + width: 612px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.columns > :last-child { + width: 406px; + } + div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 0 1 32%; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.columns > :last-child { + width: 200px; + } +} +div.dt-button-collection .button-group.stacked { + position: relative; + border: none; + padding: 0; + margin: 0; +} +div.dt-button-collection.columns .button-group.stacked { + flex-direction: row; + padding: 0; +} +div.dt-button-collection.columns .dt-button { + flex-basis: 200px; +} +div.dt-button-collection div.dt-btn-split-wrapper a.button { + flex-grow: 1; +} +div.dt-button-collection div.dt-btn-split-wrapper a.button, +div.dt-button-collection div.dt-btn-split-wrapper button.button { + display: inline-block !important; + white-space: nowrap; + height: 40px; + flex-basis: auto; + overflow: hidden; + text-overflow: ellipsis; +} + +div.dt-button-background { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 88; +} + +@media screen and (max-width: 767px) { + ul.dt-buttons { + float: none; + width: 100%; + text-align: center; + margin-bottom: 0.5rem; + } + ul.dt-buttons li { + float: none; + } +} +div.button-group.stacked.dropdown-pane { + margin-top: 2px; + padding: 1px; + z-index: 89; +} +div.button-group.stacked.dropdown-pane a.button { + display: block; + margin-bottom: 1px; + border-right: none; +} +div.button-group.stacked.dropdown-pane a.button:last-child { + margin-bottom: 0; + margin-right: 1px; +} + +div.dt-buttons button.button.processing, +div.dt-buttons div.button.processing, +div.dt-buttons a.button.processing { + color: rgba(0, 0, 0, 0.2); + color: rgba(255, 255, 255, 0.2); + border-top-color: white; + border-bottom-color: white; +} +div.dt-buttons button.button.processing:after, +div.dt-buttons div.button.processing:after, +div.dt-buttons a.button.processing:after { + position: absolute; + top: 50%; + left: 50%; + width: 16px; + height: 16px; + margin: -8px 0 0 -8px; + box-sizing: border-box; + display: block; + content: " "; + border: 2px solid #282828; + border-radius: 50%; + border-left-color: transparent; + border-right-color: transparent; + animation: dtb-spinner 1500ms infinite linear; + -o-animation: dtb-spinner 1500ms infinite linear; + -ms-animation: dtb-spinner 1500ms infinite linear; + -webkit-animation: dtb-spinner 1500ms infinite linear; + -moz-animation: dtb-spinner 1500ms infinite linear; +} + +div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop, div.dt-btn-split-wrapper.secondary:not(.disabled) button.dt-btn-split-drop { + box-shadow: none; + background-color: #1779ba; + border-color: transparent; +} +div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop:hover, div.dt-btn-split-wrapper.secondary:not(.disabled) button.dt-btn-split-drop:hover { + background-color: #14679e; + border-color: transparent; +} diff --git a/app/static/DataTables/Buttons-2.2.2/css/buttons.foundation.min.css b/app/static/DataTables/Buttons-2.2.2/css/buttons.foundation.min.css new file mode 100644 index 000000000..f4d4a69cd --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/css/buttons.foundation.min.css @@ -0,0 +1 @@ +@keyframes dtb-spinner{100%{transform:rotate(360deg)}}@-o-keyframes dtb-spinner{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes dtb-spinner{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dtb-spinner{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes dtb-spinner{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}div.dataTables_wrapper{position:relative}div.dt-buttons{position:initial}div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 4px 10px 1px rgba(0, 0, 0, 0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}div.dtb-popover-close{position:absolute;top:10px;right:10px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:12}button.dtb-hide-drop{display:none !important}div.dt-button-collection-title{text-align:center;padding:.3em 0 .5em;margin-left:.5em;margin-right:.5em;font-size:.9em}div.dt-button-collection-title:empty{display:none}span.dt-button-spacer{display:inline-block;margin:.5em;white-space:nowrap}span.dt-button-spacer.bar{border-left:1px solid rgba(0, 0, 0, 0.3);vertical-align:middle;padding-left:.5em}span.dt-button-spacer.bar:empty{height:1em;width:1px;padding-left:0}div.dt-button-collection span.dt-button-spacer{width:100%;font-size:.9em;text-align:center;margin:.5em 0}div.dt-button-collection span.dt-button-spacer:empty{height:0;width:100%}div.dt-button-collection span.dt-button-spacer.bar{border-left:none;border-bottom:1px solid rgba(0, 0, 0, 0.3);padding-left:0}ul.dt-buttons li{margin:0}ul.dt-buttons li.active a{box-shadow:inset 0 0 10px rgba(0, 0, 0, 0.6)}ul.dt-buttons.button-group a{margin-bottom:0}div.dt-button-collection{position:absolute;z-index:2002;max-width:none;border:1px solid #cacaca;padding:.5rem;background-color:white}div.dt-button-collection.fixed{position:fixed;display:block;top:50%;left:50%;margin-left:-75px;border-radius:5px;background-color:white}div.dt-button-collection.fixed.two-column{margin-left:-200px}div.dt-button-collection.fixed.three-column{margin-left:-225px}div.dt-button-collection.fixed.four-column{margin-left:-300px}div.dt-button-collection.fixed.columns{margin-left:-409px}@media screen and (max-width: 1024px){div.dt-button-collection.fixed.columns{margin-left:-308px}}@media screen and (max-width: 640px){div.dt-button-collection.fixed.columns{margin-left:-203px}}@media screen and (max-width: 460px){div.dt-button-collection.fixed.columns{margin-left:-100px}}div.dt-button-collection.fixed>:last-child{max-height:100vh;overflow:auto}div.dt-button-collection.two-column>:last-child,div.dt-button-collection.three-column>:last-child,div.dt-button-collection.four-column>:last-child{display:block !important;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}div.dt-button-collection.two-column>:last-child>*,div.dt-button-collection.three-column>:last-child>*,div.dt-button-collection.four-column>:last-child>*{-webkit-column-break-inside:avoid;break-inside:avoid}div.dt-button-collection.two-column{width:400px}div.dt-button-collection.two-column>:last-child{padding-bottom:1px;column-count:2}div.dt-button-collection.three-column{width:450px}div.dt-button-collection.three-column>:last-child{padding-bottom:1px;column-count:3}div.dt-button-collection.four-column{width:600px}div.dt-button-collection.four-column>:last-child{padding-bottom:1px;column-count:4}div.dt-button-collection .dt-button{border-radius:0}div.dt-button-collection.columns{width:auto}div.dt-button-collection.columns>:last-child{display:flex;flex-wrap:wrap;justify-content:flex-start;align-items:center;gap:6px;width:818px;padding-bottom:1px}div.dt-button-collection.columns>:last-child .dt-button{min-width:200px;flex:0 1;margin:0}div.dt-button-collection.columns.dtb-b3>:last-child,div.dt-button-collection.columns.dtb-b2>:last-child,div.dt-button-collection.columns.dtb-b1>:last-child{justify-content:space-between}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:1 1 32%}div.dt-button-collection.columns.dtb-b2 .dt-button{flex:1 1 48%}div.dt-button-collection.columns.dtb-b1 .dt-button{flex:1 1 100%}@media screen and (max-width: 1024px){div.dt-button-collection.columns>:last-child{width:612px}}@media screen and (max-width: 640px){div.dt-button-collection.columns>:last-child{width:406px}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:0 1 32%}}@media screen and (max-width: 460px){div.dt-button-collection.columns>:last-child{width:200px}}div.dt-button-collection .button-group.stacked{position:relative;border:none;padding:0;margin:0}div.dt-button-collection.columns .button-group.stacked{flex-direction:row;padding:0}div.dt-button-collection.columns .dt-button{flex-basis:200px}div.dt-button-collection div.dt-btn-split-wrapper a.button{flex-grow:1}div.dt-button-collection div.dt-btn-split-wrapper a.button,div.dt-button-collection div.dt-btn-split-wrapper button.button{display:inline-block !important;white-space:nowrap;height:40px;flex-basis:auto;overflow:hidden;text-overflow:ellipsis}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;z-index:88}@media screen and (max-width: 767px){ul.dt-buttons{float:none;width:100%;text-align:center;margin-bottom:.5rem}ul.dt-buttons li{float:none}}div.button-group.stacked.dropdown-pane{margin-top:2px;padding:1px;z-index:89}div.button-group.stacked.dropdown-pane a.button{display:block;margin-bottom:1px;border-right:none}div.button-group.stacked.dropdown-pane a.button:last-child{margin-bottom:0;margin-right:1px}div.dt-buttons button.button.processing,div.dt-buttons div.button.processing,div.dt-buttons a.button.processing{color:rgba(0, 0, 0, 0.2);color:rgba(255, 255, 255, 0.2);border-top-color:white;border-bottom-color:white}div.dt-buttons button.button.processing:after,div.dt-buttons div.button.processing:after,div.dt-buttons a.button.processing:after{position:absolute;top:50%;left:50%;width:16px;height:16px;margin:-8px 0 0 -8px;box-sizing:border-box;display:block;content:" ";border:2px solid #282828;border-radius:50%;border-left-color:transparent;border-right-color:transparent;animation:dtb-spinner 1500ms infinite linear;-o-animation:dtb-spinner 1500ms infinite linear;-ms-animation:dtb-spinner 1500ms infinite linear;-webkit-animation:dtb-spinner 1500ms infinite linear;-moz-animation:dtb-spinner 1500ms infinite linear}div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop,div.dt-btn-split-wrapper.secondary:not(.disabled) button.dt-btn-split-drop{box-shadow:none;background-color:#1779ba;border-color:transparent}div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop:hover,div.dt-btn-split-wrapper.secondary:not(.disabled) button.dt-btn-split-drop:hover{background-color:#14679e;border-color:transparent} diff --git a/app/static/DataTables/Buttons-2.2.2/css/buttons.jqueryui.css b/app/static/DataTables/Buttons-2.2.2/css/buttons.jqueryui.css new file mode 100644 index 000000000..857470d07 --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/css/buttons.jqueryui.css @@ -0,0 +1,395 @@ +@keyframes dtb-spinner { + 100% { + transform: rotate(360deg); + } +} +@-o-keyframes dtb-spinner { + 100% { + -o-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-ms-keyframes dtb-spinner { + 100% { + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-webkit-keyframes dtb-spinner { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-moz-keyframes dtb-spinner { + 100% { + -moz-transform: rotate(360deg); + transform: rotate(360deg); + } +} +div.dataTables_wrapper { + position: relative; +} + +div.dt-buttons { + position: initial; +} + +div.dt-button-info { + position: fixed; + top: 50%; + left: 50%; + width: 400px; + margin-top: -100px; + margin-left: -200px; + background-color: white; + border: 2px solid #111; + box-shadow: 3px 4px 10px 1px rgba(0, 0, 0, 0.3); + border-radius: 3px; + text-align: center; + z-index: 21; +} +div.dt-button-info h2 { + padding: 0.5em; + margin: 0; + font-weight: normal; + border-bottom: 1px solid #ddd; + background-color: #f3f3f3; +} +div.dt-button-info > div { + padding: 1em; +} + +div.dtb-popover-close { + position: absolute; + top: 10px; + right: 10px; + width: 22px; + height: 22px; + border: 1px solid #eaeaea; + background-color: #f9f9f9; + text-align: center; + border-radius: 3px; + cursor: pointer; + z-index: 12; +} + +button.dtb-hide-drop { + display: none !important; +} + +div.dt-button-collection-title { + text-align: center; + padding: 0.3em 0 0.5em; + margin-left: 0.5em; + margin-right: 0.5em; + font-size: 0.9em; +} + +div.dt-button-collection-title:empty { + display: none; +} + +span.dt-button-spacer { + display: inline-block; + margin: 0.5em; + white-space: nowrap; +} +span.dt-button-spacer.bar { + border-left: 1px solid rgba(0, 0, 0, 0.3); + vertical-align: middle; + padding-left: 0.5em; +} +span.dt-button-spacer.bar:empty { + height: 1em; + width: 1px; + padding-left: 0; +} + +div.dt-button-collection span.dt-button-spacer { + width: 100%; + font-size: 0.9em; + text-align: center; + margin: 0.5em 0; +} +div.dt-button-collection span.dt-button-spacer:empty { + height: 0; + width: 100%; +} +div.dt-button-collection span.dt-button-spacer.bar { + border-left: none; + border-bottom: 1px solid rgba(0, 0, 0, 0.3); + padding-left: 0; +} + +div.dt-buttons { + position: relative; + float: left; +} +div.dt-buttons .dt-button { + margin-right: 0; +} +div.dt-buttons .dt-button span.ui-icon { + display: inline-block; + vertical-align: middle; + margin-top: -2px; +} +div.dt-buttons .dt-button:active { + outline: none; +} +div.dt-buttons .dt-button:hover > span { + background-color: rgba(0, 0, 0, 0.05); +} + +div.dt-button-collection { + position: absolute; + top: 0; + left: 0; + width: 150px; + margin-top: 3px; + padding: 8px 8px 4px 8px; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.4); + background-color: #f3f3f3; + overflow: hidden; + z-index: 2002; + border-radius: 5px; + box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.3); + z-index: 2002; + -webkit-column-gap: 0; + -moz-column-gap: 0; + -ms-column-gap: 0; + -o-column-gap: 0; + column-gap: 0; +} +div.dt-button-collection .dt-button { + position: relative; + left: 0; + right: 0; + width: 100%; + box-sizing: border-box; + display: block; + float: none; + margin-right: 0; + margin-bottom: 4px; +} +div.dt-button-collection .dt-button:hover > span { + background-color: rgba(0, 0, 0, 0.05); +} +div.dt-button-collection.fixed { + position: fixed; + display: block; + top: 50%; + left: 50%; + margin-left: -75px; + border-radius: 5px; + background-color: white; +} +div.dt-button-collection.fixed.two-column { + margin-left: -200px; +} +div.dt-button-collection.fixed.three-column { + margin-left: -225px; +} +div.dt-button-collection.fixed.four-column { + margin-left: -300px; +} +div.dt-button-collection.fixed.columns { + margin-left: -409px; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.fixed.columns { + margin-left: -308px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.fixed.columns { + margin-left: -203px; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.fixed.columns { + margin-left: -100px; + } +} +div.dt-button-collection.fixed > :last-child { + max-height: 100vh; + overflow: auto; +} +div.dt-button-collection.two-column > :last-child, div.dt-button-collection.three-column > :last-child, div.dt-button-collection.four-column > :last-child { + display: block !important; + -webkit-column-gap: 8px; + -moz-column-gap: 8px; + -ms-column-gap: 8px; + -o-column-gap: 8px; + column-gap: 8px; +} +div.dt-button-collection.two-column > :last-child > *, div.dt-button-collection.three-column > :last-child > *, div.dt-button-collection.four-column > :last-child > * { + -webkit-column-break-inside: avoid; + break-inside: avoid; +} +div.dt-button-collection.two-column { + width: 400px; +} +div.dt-button-collection.two-column > :last-child { + padding-bottom: 1px; + column-count: 2; +} +div.dt-button-collection.three-column { + width: 450px; +} +div.dt-button-collection.three-column > :last-child { + padding-bottom: 1px; + column-count: 3; +} +div.dt-button-collection.four-column { + width: 600px; +} +div.dt-button-collection.four-column > :last-child { + padding-bottom: 1px; + column-count: 4; +} +div.dt-button-collection .dt-button { + border-radius: 0; +} +div.dt-button-collection.columns { + width: auto; +} +div.dt-button-collection.columns > :last-child { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; + gap: 6px; + width: 818px; + padding-bottom: 1px; +} +div.dt-button-collection.columns > :last-child .dt-button { + min-width: 200px; + flex: 0 1; + margin: 0; +} +div.dt-button-collection.columns.dtb-b3 > :last-child, div.dt-button-collection.columns.dtb-b2 > :last-child, div.dt-button-collection.columns.dtb-b1 > :last-child { + justify-content: space-between; +} +div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 1 1 32%; +} +div.dt-button-collection.columns.dtb-b2 .dt-button { + flex: 1 1 48%; +} +div.dt-button-collection.columns.dtb-b1 .dt-button { + flex: 1 1 100%; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.columns > :last-child { + width: 612px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.columns > :last-child { + width: 406px; + } + div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 0 1 32%; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.columns > :last-child { + width: 200px; + } +} + +div.dt-btn-split-wrapper { + padding: 0px !important; + background-color: transparent !important; + display: flex; + border: none !important; + margin: 0px; +} +div.dt-btn-split-wrapper:hover { + border: none; +} +div.dt-btn-split-wrapper button.dt-btn-split-drop { + width: 24px; + padding-left: 6px; + padding-right: 6px; + font-size: 10px; + height: 29.5px; + border-radius: 0px; + margin-left: -1px; +} +div.dt-btn-split-wrapper:active:not(.disabled) button.dt-button, div.dt-btn-split-wrapper.ui-state-active:not(.disabled) button.dt-button, div.dt-btn-split-wrapper.is-active:not(.disabled) button.dt-button { + background-color: #007fff; + border-color: #003eff; +} +div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop, div.dt-btn-split-wrapper.ui-state-active:not(.disabled) button.dt-btn-split-drop, div.dt-btn-split-wrapper.is-active:not(.disabled) button.dt-btn-split-drop { + box-shadow: none; + background-color: #f6f6f6; + border-color: #c5c5c5; +} +div.dt-btn-split-wrapper:active:not(.disabled) button:hover, div.dt-btn-split-wrapper.ui-state-active:not(.disabled) button:hover, div.dt-btn-split-wrapper.is-active:not(.disabled) button:hover { + background-color: #ededed; + border-color: #cccccc; +} + +div.dt-button-background { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.7); + /* Fallback */ + background: -ms-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%); + /* IE10 Consumer Preview */ + background: -moz-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%); + /* Firefox */ + background: -o-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%); + /* Opera */ + background: -webkit-gradient(radial, center center, 0, center center, 497, color-stop(0, rgba(0, 0, 0, 0.3)), color-stop(1, rgba(0, 0, 0, 0.7))); + /* Webkit (Safari/Chrome 10) */ + background: -webkit-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%); + /* Webkit (Chrome 11+) */ + background: radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%); + /* W3C Markup, IE10 Release Preview */ + z-index: 2001; +} + +@media screen and (max-width: 640px) { + div.dt-buttons { + float: none !important; + text-align: center; + } +} +button.dt-button.processing, +div.dt-button.processing, +a.dt-button.processing { + color: rgba(0, 0, 0, 0.2); +} +button.dt-button.processing:after, +div.dt-button.processing:after, +a.dt-button.processing:after { + position: absolute; + top: 50%; + left: 50%; + width: 16px; + height: 16px; + margin: -8px 0 0 -8px; + box-sizing: border-box; + display: block; + content: " "; + border: 2px solid #282828; + border-radius: 50%; + border-left-color: transparent; + border-right-color: transparent; + animation: dtb-spinner 1500ms infinite linear; + -o-animation: dtb-spinner 1500ms infinite linear; + -ms-animation: dtb-spinner 1500ms infinite linear; + -webkit-animation: dtb-spinner 1500ms infinite linear; + -moz-animation: dtb-spinner 1500ms infinite linear; +} + +span.dt-down-arrow { + display: none; +} diff --git a/app/static/DataTables/Buttons-2.2.2/css/buttons.jqueryui.min.css b/app/static/DataTables/Buttons-2.2.2/css/buttons.jqueryui.min.css new file mode 100644 index 000000000..5c2f9d82f --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/css/buttons.jqueryui.min.css @@ -0,0 +1 @@ +@keyframes dtb-spinner{100%{transform:rotate(360deg)}}@-o-keyframes dtb-spinner{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes dtb-spinner{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dtb-spinner{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes dtb-spinner{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}div.dataTables_wrapper{position:relative}div.dt-buttons{position:initial}div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 4px 10px 1px rgba(0, 0, 0, 0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}div.dtb-popover-close{position:absolute;top:10px;right:10px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:12}button.dtb-hide-drop{display:none !important}div.dt-button-collection-title{text-align:center;padding:.3em 0 .5em;margin-left:.5em;margin-right:.5em;font-size:.9em}div.dt-button-collection-title:empty{display:none}span.dt-button-spacer{display:inline-block;margin:.5em;white-space:nowrap}span.dt-button-spacer.bar{border-left:1px solid rgba(0, 0, 0, 0.3);vertical-align:middle;padding-left:.5em}span.dt-button-spacer.bar:empty{height:1em;width:1px;padding-left:0}div.dt-button-collection span.dt-button-spacer{width:100%;font-size:.9em;text-align:center;margin:.5em 0}div.dt-button-collection span.dt-button-spacer:empty{height:0;width:100%}div.dt-button-collection span.dt-button-spacer.bar{border-left:none;border-bottom:1px solid rgba(0, 0, 0, 0.3);padding-left:0}div.dt-buttons{position:relative;float:left}div.dt-buttons .dt-button{margin-right:0}div.dt-buttons .dt-button span.ui-icon{display:inline-block;vertical-align:middle;margin-top:-2px}div.dt-buttons .dt-button:active{outline:none}div.dt-buttons .dt-button:hover>span{background-color:rgba(0, 0, 0, 0.05)}div.dt-button-collection{position:absolute;top:0;left:0;width:150px;margin-top:3px;padding:8px 8px 4px 8px;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.4);background-color:#f3f3f3;overflow:hidden;z-index:2002;border-radius:5px;box-shadow:3px 3px 5px rgba(0, 0, 0, 0.3);z-index:2002;-webkit-column-gap:0;-moz-column-gap:0;-ms-column-gap:0;-o-column-gap:0;column-gap:0}div.dt-button-collection .dt-button{position:relative;left:0;right:0;width:100%;box-sizing:border-box;display:block;float:none;margin-right:0;margin-bottom:4px}div.dt-button-collection .dt-button:hover>span{background-color:rgba(0, 0, 0, 0.05)}div.dt-button-collection.fixed{position:fixed;display:block;top:50%;left:50%;margin-left:-75px;border-radius:5px;background-color:white}div.dt-button-collection.fixed.two-column{margin-left:-200px}div.dt-button-collection.fixed.three-column{margin-left:-225px}div.dt-button-collection.fixed.four-column{margin-left:-300px}div.dt-button-collection.fixed.columns{margin-left:-409px}@media screen and (max-width: 1024px){div.dt-button-collection.fixed.columns{margin-left:-308px}}@media screen and (max-width: 640px){div.dt-button-collection.fixed.columns{margin-left:-203px}}@media screen and (max-width: 460px){div.dt-button-collection.fixed.columns{margin-left:-100px}}div.dt-button-collection.fixed>:last-child{max-height:100vh;overflow:auto}div.dt-button-collection.two-column>:last-child,div.dt-button-collection.three-column>:last-child,div.dt-button-collection.four-column>:last-child{display:block !important;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}div.dt-button-collection.two-column>:last-child>*,div.dt-button-collection.three-column>:last-child>*,div.dt-button-collection.four-column>:last-child>*{-webkit-column-break-inside:avoid;break-inside:avoid}div.dt-button-collection.two-column{width:400px}div.dt-button-collection.two-column>:last-child{padding-bottom:1px;column-count:2}div.dt-button-collection.three-column{width:450px}div.dt-button-collection.three-column>:last-child{padding-bottom:1px;column-count:3}div.dt-button-collection.four-column{width:600px}div.dt-button-collection.four-column>:last-child{padding-bottom:1px;column-count:4}div.dt-button-collection .dt-button{border-radius:0}div.dt-button-collection.columns{width:auto}div.dt-button-collection.columns>:last-child{display:flex;flex-wrap:wrap;justify-content:flex-start;align-items:center;gap:6px;width:818px;padding-bottom:1px}div.dt-button-collection.columns>:last-child .dt-button{min-width:200px;flex:0 1;margin:0}div.dt-button-collection.columns.dtb-b3>:last-child,div.dt-button-collection.columns.dtb-b2>:last-child,div.dt-button-collection.columns.dtb-b1>:last-child{justify-content:space-between}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:1 1 32%}div.dt-button-collection.columns.dtb-b2 .dt-button{flex:1 1 48%}div.dt-button-collection.columns.dtb-b1 .dt-button{flex:1 1 100%}@media screen and (max-width: 1024px){div.dt-button-collection.columns>:last-child{width:612px}}@media screen and (max-width: 640px){div.dt-button-collection.columns>:last-child{width:406px}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:0 1 32%}}@media screen and (max-width: 460px){div.dt-button-collection.columns>:last-child{width:200px}}div.dt-btn-split-wrapper{padding:0px !important;background-color:transparent !important;display:flex;border:none !important;margin:0px}div.dt-btn-split-wrapper:hover{border:none}div.dt-btn-split-wrapper button.dt-btn-split-drop{width:24px;padding-left:6px;padding-right:6px;font-size:10px;height:29.5px;border-radius:0px;margin-left:-1px}div.dt-btn-split-wrapper:active:not(.disabled) button.dt-button,div.dt-btn-split-wrapper.ui-state-active:not(.disabled) button.dt-button,div.dt-btn-split-wrapper.is-active:not(.disabled) button.dt-button{background-color:#007fff;border-color:#003eff}div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop,div.dt-btn-split-wrapper.ui-state-active:not(.disabled) button.dt-btn-split-drop,div.dt-btn-split-wrapper.is-active:not(.disabled) button.dt-btn-split-drop{box-shadow:none;background-color:#f6f6f6;border-color:#c5c5c5}div.dt-btn-split-wrapper:active:not(.disabled) button:hover,div.dt-btn-split-wrapper.ui-state-active:not(.disabled) button:hover,div.dt-btn-split-wrapper.is-active:not(.disabled) button:hover{background-color:#ededed;border-color:#ccc}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0, 0, 0, 0.7);background:-ms-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);background:-moz-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);background:-o-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);background:-webkit-gradient(radial, center center, 0, center center, 497, color-stop(0, rgba(0, 0, 0, 0.3)), color-stop(1, rgba(0, 0, 0, 0.7)));background:-webkit-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);background:radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);z-index:2001}@media screen and (max-width: 640px){div.dt-buttons{float:none !important;text-align:center}}button.dt-button.processing,div.dt-button.processing,a.dt-button.processing{color:rgba(0, 0, 0, 0.2)}button.dt-button.processing:after,div.dt-button.processing:after,a.dt-button.processing:after{position:absolute;top:50%;left:50%;width:16px;height:16px;margin:-8px 0 0 -8px;box-sizing:border-box;display:block;content:" ";border:2px solid #282828;border-radius:50%;border-left-color:transparent;border-right-color:transparent;animation:dtb-spinner 1500ms infinite linear;-o-animation:dtb-spinner 1500ms infinite linear;-ms-animation:dtb-spinner 1500ms infinite linear;-webkit-animation:dtb-spinner 1500ms infinite linear;-moz-animation:dtb-spinner 1500ms infinite linear}span.dt-down-arrow{display:none} diff --git a/app/static/DataTables/Buttons-2.2.2/css/buttons.semanticui.css b/app/static/DataTables/Buttons-2.2.2/css/buttons.semanticui.css new file mode 100644 index 000000000..901251e88 --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/css/buttons.semanticui.css @@ -0,0 +1,397 @@ +@keyframes dtb-spinner { + 100% { + transform: rotate(360deg); + } +} +@-o-keyframes dtb-spinner { + 100% { + -o-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-ms-keyframes dtb-spinner { + 100% { + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-webkit-keyframes dtb-spinner { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-moz-keyframes dtb-spinner { + 100% { + -moz-transform: rotate(360deg); + transform: rotate(360deg); + } +} +div.dataTables_wrapper { + position: relative; +} + +div.dt-buttons { + position: initial; +} + +div.dt-button-info { + position: fixed; + top: 50%; + left: 50%; + width: 400px; + margin-top: -100px; + margin-left: -200px; + background-color: white; + border: 2px solid #111; + box-shadow: 3px 4px 10px 1px rgba(0, 0, 0, 0.3); + border-radius: 3px; + text-align: center; + z-index: 21; +} +div.dt-button-info h2 { + padding: 0.5em; + margin: 0; + font-weight: normal; + border-bottom: 1px solid #ddd; + background-color: #f3f3f3; +} +div.dt-button-info > div { + padding: 1em; +} + +div.dtb-popover-close { + position: absolute; + top: 10px; + right: 10px; + width: 22px; + height: 22px; + border: 1px solid #eaeaea; + background-color: #f9f9f9; + text-align: center; + border-radius: 3px; + cursor: pointer; + z-index: 12; +} + +button.dtb-hide-drop { + display: none !important; +} + +div.dt-button-collection-title { + text-align: center; + padding: 0.3em 0 0.5em; + margin-left: 0.5em; + margin-right: 0.5em; + font-size: 0.9em; +} + +div.dt-button-collection-title:empty { + display: none; +} + +span.dt-button-spacer { + display: inline-block; + margin: 0.5em; + white-space: nowrap; +} +span.dt-button-spacer.bar { + border-left: 1px solid rgba(0, 0, 0, 0.3); + vertical-align: middle; + padding-left: 0.5em; +} +span.dt-button-spacer.bar:empty { + height: 1em; + width: 1px; + padding-left: 0; +} + +div.dt-button-collection span.dt-button-spacer { + width: 100%; + font-size: 0.9em; + text-align: center; + margin: 0.5em 0; +} +div.dt-button-collection span.dt-button-spacer:empty { + height: 0; + width: 100%; +} +div.dt-button-collection span.dt-button-spacer.bar { + border-left: none; + border-bottom: 1px solid rgba(0, 0, 0, 0.3); + padding-left: 0; +} + +div.dt-button-collection { + position: absolute; + top: 0; + left: 0; + min-width: 200px; + margin-top: 3px !important; + margin-bottom: 3px !important; + z-index: 2002; + background: white; + border: 1px solid rgba(34, 36, 38, 0.15); + font-size: 1em; + padding: 0.5rem; +} +div.dt-button-collection.fixed { + position: fixed; + display: block; + top: 50%; + left: 50%; + margin-left: -75px; + border-radius: 5px; + background-color: white; +} +div.dt-button-collection.fixed.two-column { + margin-left: -200px; +} +div.dt-button-collection.fixed.three-column { + margin-left: -225px; +} +div.dt-button-collection.fixed.four-column { + margin-left: -300px; +} +div.dt-button-collection.fixed.columns { + margin-left: -409px; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.fixed.columns { + margin-left: -308px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.fixed.columns { + margin-left: -203px; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.fixed.columns { + margin-left: -100px; + } +} +div.dt-button-collection.fixed > :last-child { + max-height: 100vh; + overflow: auto; +} +div.dt-button-collection.two-column > :last-child, div.dt-button-collection.three-column > :last-child, div.dt-button-collection.four-column > :last-child { + display: block !important; + -webkit-column-gap: 8px; + -moz-column-gap: 8px; + -ms-column-gap: 8px; + -o-column-gap: 8px; + column-gap: 8px; +} +div.dt-button-collection.two-column > :last-child > *, div.dt-button-collection.three-column > :last-child > *, div.dt-button-collection.four-column > :last-child > * { + -webkit-column-break-inside: avoid; + break-inside: avoid; +} +div.dt-button-collection.two-column { + width: 400px; +} +div.dt-button-collection.two-column > :last-child { + padding-bottom: 1px; + column-count: 2; +} +div.dt-button-collection.three-column { + width: 450px; +} +div.dt-button-collection.three-column > :last-child { + padding-bottom: 1px; + column-count: 3; +} +div.dt-button-collection.four-column { + width: 600px; +} +div.dt-button-collection.four-column > :last-child { + padding-bottom: 1px; + column-count: 4; +} +div.dt-button-collection .dt-button { + border-radius: 0; +} +div.dt-button-collection.columns { + width: auto; +} +div.dt-button-collection.columns > :last-child { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; + gap: 6px; + width: 818px; + padding-bottom: 1px; +} +div.dt-button-collection.columns > :last-child .dt-button { + min-width: 200px; + flex: 0 1; + margin: 0; +} +div.dt-button-collection.columns.dtb-b3 > :last-child, div.dt-button-collection.columns.dtb-b2 > :last-child, div.dt-button-collection.columns.dtb-b1 > :last-child { + justify-content: space-between; +} +div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 1 1 32%; +} +div.dt-button-collection.columns.dtb-b2 .dt-button { + flex: 1 1 48%; +} +div.dt-button-collection.columns.dtb-b1 .dt-button { + flex: 1 1 100%; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.columns > :last-child { + width: 612px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.columns > :last-child { + width: 406px; + } + div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 0 1 32%; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.columns > :last-child { + width: 200px; + } +} +div.dt-button-collection div.dt-button-collection-title { + font-size: 1rem; +} +div.dt-button-collection:not(.columns) .ui.vertical.buttons { + width: 100%; + border: none; +} +div.dt-button-collection.columns .ui.vertical.buttons { + flex-direction: row; + border: none; +} +div.dt-button-collection button.dt-button { + border: 1px solid rgba(34, 36, 38, 0.15) !important; +} +div.dt-button-collection div.dt-btn-split-wrapper { + display: flex; +} +div.dt-button-collection div.dt-btn-split-wrapper button { + flex-grow: 1 !important; + flex-basis: auto !important; + width: auto !important; + border-top-right-radius: 0px !important; +} +div.dt-button-collection div.dt-btn-split-wrapper button.dt-btn-split-drop { + flex-grow: 0 !important; + flex-basis: auto !important; + border-bottom-left-radius: 0px !important; + border-bottom-right-radius: 0px !important; + border-top-right-radius: 4px !important; +} + +button.buttons-collection.ui.button span:after { + display: inline-block; + content: "▾"; + padding-left: 0.5em; +} + +div.dt-button-background { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 2001; +} + +@media screen and (max-width: 767px) { + div.dt-buttons { + float: none; + width: 100%; + text-align: center; + margin-bottom: 0.5em; + } + div.dt-buttons a.btn { + float: none; + } +} +div.dt-buttons button.button.processing, +div.dt-buttons div.button.processing, +div.dt-buttons a.button.processing { + position: relative; + color: rgba(0, 0, 0, 0.2); +} +div.dt-buttons button.button.processing:after, +div.dt-buttons div.button.processing:after, +div.dt-buttons a.button.processing:after { + position: absolute; + top: 50%; + left: 50%; + width: 16px; + height: 16px; + margin: -8px 0 0 -8px; + box-sizing: border-box; + display: block; + content: " "; + border: 2px solid #282828; + border-radius: 50%; + border-left-color: transparent; + border-right-color: transparent; + animation: dtb-spinner 1500ms infinite linear; + -o-animation: dtb-spinner 1500ms infinite linear; + -ms-animation: dtb-spinner 1500ms infinite linear; + -webkit-animation: dtb-spinner 1500ms infinite linear; + -moz-animation: dtb-spinner 1500ms infinite linear; +} +div.dt-buttons.ui.buttons { + flex-wrap: wrap; +} +div.dt-buttons.ui.basic.buttons .ui.button { + border-bottom: 1px solid rgba(34, 36, 38, 0.15); + margin-bottom: -1px; +} +div.dt-buttons.ui.basic.buttons .ui.button:hover { + background: transparent !important; +} + +span.dt-down-arrow { + display: none; +} + +span.dt-button-spacer { + cursor: inherit; +} +span.dt-button-spacer.bar { + padding-left: 1.5em; +} +span.dt-button-spacer.bar:empty { + height: inherit; +} + +div.dt-button-collection span.dt-button-spacer { + border-top: 1px solid rgba(34, 36, 38, 0.15); +} +div.dt-button-collection span.dt-button-spacer.bar { + border-bottom: none; + padding-left: 1.5em; +} + +div.dt-buttons.ui.basic.buttons .button.dt-button-spacer { + background: rgba(34, 36, 38, 0.05) !important; + box-shadow: none; + cursor: initial; +} +div.dt-buttons.ui.basic.buttons .button.dt-button-spacer:hover { + background-color: rgba(34, 36, 38, 0.05) !important; +} + +div.dt-btn-split-wrapper:active:not(.disabled) button.button, div.dt-btn-split-wrapper.active:not(.disabled) button.button { + background-color: #f8f8f8 !important; +} +div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop, div.dt-btn-split-wrapper.active:not(.disabled) button.dt-btn-split-drop { + box-shadow: none; + background-color: transparent !important; +} +div.dt-btn-split-wrapper:active:not(.disabled) button.button:hover, div.dt-btn-split-wrapper.active:not(.disabled) button.button:hover { + background-color: transparent !important; +} diff --git a/app/static/DataTables/Buttons-2.2.2/css/buttons.semanticui.min.css b/app/static/DataTables/Buttons-2.2.2/css/buttons.semanticui.min.css new file mode 100644 index 000000000..3bdfbc4a2 --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/css/buttons.semanticui.min.css @@ -0,0 +1 @@ +@keyframes dtb-spinner{100%{transform:rotate(360deg)}}@-o-keyframes dtb-spinner{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes dtb-spinner{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dtb-spinner{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes dtb-spinner{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}div.dataTables_wrapper{position:relative}div.dt-buttons{position:initial}div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 4px 10px 1px rgba(0, 0, 0, 0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}div.dtb-popover-close{position:absolute;top:10px;right:10px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:12}button.dtb-hide-drop{display:none !important}div.dt-button-collection-title{text-align:center;padding:.3em 0 .5em;margin-left:.5em;margin-right:.5em;font-size:.9em}div.dt-button-collection-title:empty{display:none}span.dt-button-spacer{display:inline-block;margin:.5em;white-space:nowrap}span.dt-button-spacer.bar{border-left:1px solid rgba(0, 0, 0, 0.3);vertical-align:middle;padding-left:.5em}span.dt-button-spacer.bar:empty{height:1em;width:1px;padding-left:0}div.dt-button-collection span.dt-button-spacer{width:100%;font-size:.9em;text-align:center;margin:.5em 0}div.dt-button-collection span.dt-button-spacer:empty{height:0;width:100%}div.dt-button-collection span.dt-button-spacer.bar{border-left:none;border-bottom:1px solid rgba(0, 0, 0, 0.3);padding-left:0}div.dt-button-collection{position:absolute;top:0;left:0;min-width:200px;margin-top:3px !important;margin-bottom:3px !important;z-index:2002;background:white;border:1px solid rgba(34, 36, 38, 0.15);font-size:1em;padding:.5rem}div.dt-button-collection.fixed{position:fixed;display:block;top:50%;left:50%;margin-left:-75px;border-radius:5px;background-color:white}div.dt-button-collection.fixed.two-column{margin-left:-200px}div.dt-button-collection.fixed.three-column{margin-left:-225px}div.dt-button-collection.fixed.four-column{margin-left:-300px}div.dt-button-collection.fixed.columns{margin-left:-409px}@media screen and (max-width: 1024px){div.dt-button-collection.fixed.columns{margin-left:-308px}}@media screen and (max-width: 640px){div.dt-button-collection.fixed.columns{margin-left:-203px}}@media screen and (max-width: 460px){div.dt-button-collection.fixed.columns{margin-left:-100px}}div.dt-button-collection.fixed>:last-child{max-height:100vh;overflow:auto}div.dt-button-collection.two-column>:last-child,div.dt-button-collection.three-column>:last-child,div.dt-button-collection.four-column>:last-child{display:block !important;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}div.dt-button-collection.two-column>:last-child>*,div.dt-button-collection.three-column>:last-child>*,div.dt-button-collection.four-column>:last-child>*{-webkit-column-break-inside:avoid;break-inside:avoid}div.dt-button-collection.two-column{width:400px}div.dt-button-collection.two-column>:last-child{padding-bottom:1px;column-count:2}div.dt-button-collection.three-column{width:450px}div.dt-button-collection.three-column>:last-child{padding-bottom:1px;column-count:3}div.dt-button-collection.four-column{width:600px}div.dt-button-collection.four-column>:last-child{padding-bottom:1px;column-count:4}div.dt-button-collection .dt-button{border-radius:0}div.dt-button-collection.columns{width:auto}div.dt-button-collection.columns>:last-child{display:flex;flex-wrap:wrap;justify-content:flex-start;align-items:center;gap:6px;width:818px;padding-bottom:1px}div.dt-button-collection.columns>:last-child .dt-button{min-width:200px;flex:0 1;margin:0}div.dt-button-collection.columns.dtb-b3>:last-child,div.dt-button-collection.columns.dtb-b2>:last-child,div.dt-button-collection.columns.dtb-b1>:last-child{justify-content:space-between}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:1 1 32%}div.dt-button-collection.columns.dtb-b2 .dt-button{flex:1 1 48%}div.dt-button-collection.columns.dtb-b1 .dt-button{flex:1 1 100%}@media screen and (max-width: 1024px){div.dt-button-collection.columns>:last-child{width:612px}}@media screen and (max-width: 640px){div.dt-button-collection.columns>:last-child{width:406px}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:0 1 32%}}@media screen and (max-width: 460px){div.dt-button-collection.columns>:last-child{width:200px}}div.dt-button-collection div.dt-button-collection-title{font-size:1rem}div.dt-button-collection:not(.columns) .ui.vertical.buttons{width:100%;border:none}div.dt-button-collection.columns .ui.vertical.buttons{flex-direction:row;border:none}div.dt-button-collection button.dt-button{border:1px solid rgba(34, 36, 38, 0.15) !important}div.dt-button-collection div.dt-btn-split-wrapper{display:flex}div.dt-button-collection div.dt-btn-split-wrapper button{flex-grow:1 !important;flex-basis:auto !important;width:auto !important;border-top-right-radius:0px !important}div.dt-button-collection div.dt-btn-split-wrapper button.dt-btn-split-drop{flex-grow:0 !important;flex-basis:auto !important;border-bottom-left-radius:0px !important;border-bottom-right-radius:0px !important;border-top-right-radius:4px !important}button.buttons-collection.ui.button span:after{display:inline-block;content:"▾";padding-left:.5em}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;z-index:2001}@media screen and (max-width: 767px){div.dt-buttons{float:none;width:100%;text-align:center;margin-bottom:.5em}div.dt-buttons a.btn{float:none}}div.dt-buttons button.button.processing,div.dt-buttons div.button.processing,div.dt-buttons a.button.processing{position:relative;color:rgba(0, 0, 0, 0.2)}div.dt-buttons button.button.processing:after,div.dt-buttons div.button.processing:after,div.dt-buttons a.button.processing:after{position:absolute;top:50%;left:50%;width:16px;height:16px;margin:-8px 0 0 -8px;box-sizing:border-box;display:block;content:" ";border:2px solid #282828;border-radius:50%;border-left-color:transparent;border-right-color:transparent;animation:dtb-spinner 1500ms infinite linear;-o-animation:dtb-spinner 1500ms infinite linear;-ms-animation:dtb-spinner 1500ms infinite linear;-webkit-animation:dtb-spinner 1500ms infinite linear;-moz-animation:dtb-spinner 1500ms infinite linear}div.dt-buttons.ui.buttons{flex-wrap:wrap}div.dt-buttons.ui.basic.buttons .ui.button{border-bottom:1px solid rgba(34, 36, 38, 0.15);margin-bottom:-1px}div.dt-buttons.ui.basic.buttons .ui.button:hover{background:transparent !important}span.dt-down-arrow{display:none}span.dt-button-spacer{cursor:inherit}span.dt-button-spacer.bar{padding-left:1.5em}span.dt-button-spacer.bar:empty{height:inherit}div.dt-button-collection span.dt-button-spacer{border-top:1px solid rgba(34, 36, 38, 0.15)}div.dt-button-collection span.dt-button-spacer.bar{border-bottom:none;padding-left:1.5em}div.dt-buttons.ui.basic.buttons .button.dt-button-spacer{background:rgba(34, 36, 38, 0.05) !important;box-shadow:none;cursor:initial}div.dt-buttons.ui.basic.buttons .button.dt-button-spacer:hover{background-color:rgba(34, 36, 38, 0.05) !important}div.dt-btn-split-wrapper:active:not(.disabled) button.button,div.dt-btn-split-wrapper.active:not(.disabled) button.button{background-color:#f8f8f8 !important}div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop,div.dt-btn-split-wrapper.active:not(.disabled) button.dt-btn-split-drop{box-shadow:none;background-color:transparent !important}div.dt-btn-split-wrapper:active:not(.disabled) button.button:hover,div.dt-btn-split-wrapper.active:not(.disabled) button.button:hover{background-color:transparent !important} diff --git a/app/static/DataTables/Buttons-2.2.2/css/common.scss b/app/static/DataTables/Buttons-2.2.2/css/common.scss new file mode 100644 index 000000000..3535d9d23 --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/css/common.scss @@ -0,0 +1,101 @@ + +div.dataTables_wrapper { + position: relative; +} + +div.dt-buttons { + position: initial; +} + +div.dt-button-info { + position: fixed; + top: 50%; + left: 50%; + width: 400px; + margin-top: -100px; + margin-left: -200px; + background-color: white; + border: 2px solid #111; + box-shadow: 3px 4px 10px 1px rgba(0, 0, 0, 0.3); + border-radius: 3px; + text-align: center; + z-index: 21; + + h2 { + padding: 0.5em; + margin: 0; + font-weight: normal; + border-bottom: 1px solid #ddd; + background-color: #f3f3f3; + } + + > div { + padding: 1em; + } +} + +div.dtb-popover-close { + position: absolute; + top: 10px; + right: 10px; + width: 22px; + height: 22px; + border: 1px solid #eaeaea; + background-color: #f9f9f9; + text-align: center; + border-radius: 3px; + cursor: pointer; + z-index: 12; +} + +button.dtb-hide-drop { + display: none !important; +} + +div.dt-button-collection-title { + text-align: center; + padding: 0.3em 0 0.5em; + margin-left: 0.5em; + margin-right: 0.5em; + font-size: 0.9em; +} + +div.dt-button-collection-title:empty { + display: none; +} + +span.dt-button-spacer { + display: inline-block; + margin: 0.5em; + white-space: nowrap; + + &.bar { + border-left: 1px solid rgba(0, 0, 0, 0.3); + vertical-align: middle; + padding-left: 0.5em; + + &:empty { + height: 1em; + width: 1px; + padding-left: 0; + } + } +} + +div.dt-button-collection span.dt-button-spacer { + width: 100%; + font-size: 0.9em; + text-align: center; + margin: 0.5em 0; + + &:empty { + height: 0; + width: 100%; + } + + &.bar { + border-left: none; + border-bottom: 1px solid rgba(0, 0, 0, 0.3); + padding-left: 0; + } +} diff --git a/app/static/DataTables/Buttons-2.2.2/css/mixins.scss b/app/static/DataTables/Buttons-2.2.2/css/mixins.scss new file mode 100644 index 000000000..b50a0a4c0 --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/css/mixins.scss @@ -0,0 +1,237 @@ + +@function dtb-tint( $color, $percent ) { + @return mix(white, $color, $percent); +} + +@function dtb-shade( $color, $percent ) { + @return mix(black, $color, $percent); +} + +@mixin dtb-two-stop-gradient($fromColor, $toColor) { + background-color: $toColor; /* Fallback */ + background: -webkit-linear-gradient(top, $fromColor 0%, $toColor 100%); /* Chrome 10+, Saf5.1+, iOS 5+ */ + background: -moz-linear-gradient(top, $fromColor 0%, $toColor 100%); /* FF3.6 */ + background: -ms-linear-gradient(top, $fromColor 0%, $toColor 100%); /* IE10 */ + background: -o-linear-gradient(top, $fromColor 0%, $toColor 100%); /* Opera 11.10+ */ + background: linear-gradient(to bottom, $fromColor 0%, $toColor 100%); + filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#{nth( $fromColor, 1 )}', EndColorStr='#{nth( $toColor, 1 )}'); +} + +@mixin dtb-radial-gradient ($fromColor, $toColor ) { + background: $toColor; /* Fallback */ + background: -ms-radial-gradient(center, ellipse farthest-corner, $fromColor 0%, $toColor 100%); /* IE10 Consumer Preview */ + background: -moz-radial-gradient(center, ellipse farthest-corner, $fromColor 0%, $toColor 100%); /* Firefox */ + background: -o-radial-gradient(center, ellipse farthest-corner, $fromColor 0%, $toColor 100%); /* Opera */ + background: -webkit-gradient(radial, center center, 0, center center, 497, color-stop(0, $fromColor), color-stop(1, $toColor)); /* Webkit (Safari/Chrome 10) */ + background: -webkit-radial-gradient(center, ellipse farthest-corner, $fromColor 0%, $toColor 100%); /* Webkit (Chrome 11+) */ + background: radial-gradient(ellipse farthest-corner at center, $fromColor 0%, $toColor 100%); /* W3C Markup, IE10 Release Preview */ +} + + +@mixin dtb-fixed-collection { + // Fixed positioning feature + &.fixed { + position: fixed; + display: block; + top: 50%; + left: 50%; + margin-left: -75px; + border-radius: 5px; + background-color: white; + + &.two-column { + margin-left: -200px; + } + + &.three-column { + margin-left: -225px; + } + + &.four-column { + margin-left: -300px; + } + + &.columns { + // Four column + margin-left: -409px; + + @media screen and (max-width: 1024px) { + margin-left: -308px; + } + + @media screen and (max-width: 640px) { + margin-left: -203px; + } + + @media screen and (max-width: 460px) { + margin-left: -100px; + } + } + + > :last-child { + max-height: 100vh; + overflow: auto; + } + } + + &.two-column > :last-child, + &.three-column > :last-child, + &.four-column > :last-child { + > * { + -webkit-column-break-inside: avoid; + break-inside: avoid; + } + + // Multi-column layout feature + display: block !important; + -webkit-column-gap: 8px; + -moz-column-gap: 8px; + -ms-column-gap: 8px; + -o-column-gap: 8px; + column-gap: 8px; + } + + &.two-column { + width: 400px; + + > :last-child { + padding-bottom: 1px; + column-count: 2; + } + } + + &.three-column { + width: 450px; + + > :last-child { + padding-bottom: 1px; + column-count: 3; + } + } + + &.four-column { + width: 600px; + + > :last-child { + padding-bottom: 1px; + column-count: 4; + } + } + + // Chrome fix - 531528 + .dt-button { + border-radius: 0; + } + + &.columns { + // Four column layout + width: auto; + + > :last-child { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; + gap: 6px; + + width: 818px; + padding-bottom: 1px; + + .dt-button { + min-width: 200px; + flex: 0 1; + margin: 0; + } + } + + &.dtb-b3, + &.dtb-b2, + &.dtb-b1 { + > :last-child { + justify-content: space-between; + } + } + + &.dtb-b3 .dt-button { + flex: 1 1 32%; + } + &.dtb-b2 .dt-button { + flex: 1 1 48%; + } + &.dtb-b1 .dt-button { + flex: 1 1 100%; + } + + @media screen and (max-width: 1024px) { + // Three column layout + > :last-child { + width: 612px; + } + } + + @media screen and (max-width: 640px) { + // Two column layout + > :last-child { + width: 406px; + } + + &.dtb-b3 .dt-button { + flex: 0 1 32%; + } + } + + @media screen and (max-width: 460px) { + // Single column + > :last-child { + width: 200px; + } + } + } +} + + +@mixin dtb-processing { + color: rgba(0, 0, 0, 0.2); + + &:after { + position: absolute; + top: 50%; + left: 50%; + width: 16px; + height: 16px; + margin: -8px 0 0 -8px; + box-sizing: border-box; + + display: block; + content: ' '; + border: 2px solid rgb(40,40,40); + border-radius: 50%; + border-left-color: transparent; + border-right-color: transparent; + animation: dtb-spinner 1500ms infinite linear; + -o-animation: dtb-spinner 1500ms infinite linear; + -ms-animation: dtb-spinner 1500ms infinite linear; + -webkit-animation: dtb-spinner 1500ms infinite linear; + -moz-animation: dtb-spinner 1500ms infinite linear; + } +} + +@keyframes dtb-spinner { + 100%{ transform: rotate(360deg); } +} + +@-o-keyframes dtb-spinner { + 100%{ -o-transform: rotate(360deg); transform: rotate(360deg); } +} + +@-ms-keyframes dtb-spinner { + 100%{ -ms-transform: rotate(360deg); transform: rotate(360deg); } +} + +@-webkit-keyframes dtb-spinner { + 100%{ -webkit-transform: rotate(360deg); transform: rotate(360deg); } +} + +@-moz-keyframes dtb-spinner { + 100%{ -moz-transform: rotate(360deg); transform: rotate(360deg); } +} diff --git a/app/static/DataTables/Buttons-2.2.2/js/buttons.bootstrap.js b/app/static/DataTables/Buttons-2.2.2/js/buttons.bootstrap.js new file mode 100644 index 000000000..0644cd67f --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/js/buttons.bootstrap.js @@ -0,0 +1,89 @@ +/*! Bootstrap integration for DataTables' Buttons + * ©2016 SpryMedia Ltd - datatables.net/license + */ + +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net-bs', 'datatables.net-buttons'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + module.exports = function (root, $) { + if ( ! root ) { + root = window; + } + + if ( ! $ || ! $.fn.dataTable ) { + $ = require('datatables.net-bs')(root, $).$; + } + + if ( ! $.fn.dataTable.Buttons ) { + require('datatables.net-buttons')(root, $); + } + + return factory( $, root, root.document ); + }; + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; + + +$.extend( true, DataTable.Buttons.defaults, { + dom: { + container: { + className: 'dt-buttons btn-group' + }, + button: { + className: 'btn btn-default' + }, + collection: { + tag: 'ul', + className: 'dropdown-menu', + closeButton: false, + button: { + tag: 'li', + className: 'dt-button', + active: 'active', + disabled: 'disabled' + }, + buttonLiner: { + tag: 'a', + className: '' + } + }, + splitWrapper: { + tag: 'div', + className: 'dt-btn-split-wrapper btn-group', + closeButton: false, + }, + splitDropdown: { + tag: 'button', + text: '▼', + className: 'btn btn-default dt-btn-split-drop dropdown-toggle', + closeButton: false, + align: 'split-left', + splitAlignClass: 'dt-button-split-left' + }, + splitDropdownButton: { + tag: 'button', + className: 'dt-btn-split-drop-button btn btn-default', + closeButton: false + } + } +} ); + +DataTable.ext.buttons.collection.text = function ( dt ) { + return dt.i18n('buttons.collection', 'Collection '); +}; + + +return DataTable.Buttons; +})); diff --git a/app/static/DataTables/Buttons-2.2.2/js/buttons.bootstrap.min.js b/app/static/DataTables/Buttons-2.2.2/js/buttons.bootstrap.min.js new file mode 100644 index 000000000..88c40f917 --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/js/buttons.bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + Bootstrap integration for DataTables' Buttons + ©2016 SpryMedia Ltd - datatables.net/license +*/ +(function(c){"function"===typeof define&&define.amd?define(["jquery","datatables.net-bs","datatables.net-buttons"],function(a){return c(a,window,document)}):"object"===typeof exports?module.exports=function(a,b){a||(a=window);b&&b.fn.dataTable||(b=require("datatables.net-bs")(a,b).$);b.fn.dataTable.Buttons||require("datatables.net-buttons")(a,b);return c(b,a,a.document)}:c(jQuery,window,document)})(function(c,a,b,e){a=c.fn.dataTable;c.extend(!0,a.Buttons.defaults,{dom:{container:{className:"dt-buttons btn-group"}, +button:{className:"btn btn-default"},collection:{tag:"ul",className:"dropdown-menu",closeButton:!1,button:{tag:"li",className:"dt-button",active:"active",disabled:"disabled"},buttonLiner:{tag:"a",className:""}},splitWrapper:{tag:"div",className:"dt-btn-split-wrapper btn-group",closeButton:!1},splitDropdown:{tag:"button",text:"▼",className:"btn btn-default dt-btn-split-drop dropdown-toggle",closeButton:!1,align:"split-left",splitAlignClass:"dt-button-split-left"},splitDropdownButton:{tag:"button", +className:"dt-btn-split-drop-button btn btn-default",closeButton:!1}}});a.ext.buttons.collection.text=function(d){return d.i18n("buttons.collection",'Collection ')};return a.Buttons}); diff --git a/app/static/DataTables/Buttons-2.2.2/js/buttons.bootstrap4.js b/app/static/DataTables/Buttons-2.2.2/js/buttons.bootstrap4.js new file mode 100644 index 000000000..599b836b7 --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/js/buttons.bootstrap4.js @@ -0,0 +1,87 @@ +/*! Bootstrap integration for DataTables' Buttons + * ©2016 SpryMedia Ltd - datatables.net/license + */ + +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net-bs4', 'datatables.net-buttons'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + module.exports = function (root, $) { + if ( ! root ) { + root = window; + } + + if ( ! $ || ! $.fn.dataTable ) { + $ = require('datatables.net-bs4')(root, $).$; + } + + if ( ! $.fn.dataTable.Buttons ) { + require('datatables.net-buttons')(root, $); + } + + return factory( $, root, root.document ); + }; + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; + +$.extend( true, DataTable.Buttons.defaults, { + dom: { + container: { + className: 'dt-buttons btn-group flex-wrap' + }, + button: { + className: 'btn btn-secondary' + }, + collection: { + tag: 'div', + className: 'dropdown-menu', + closeButton: false, + button: { + tag: 'a', + className: 'dt-button dropdown-item', + active: 'active', + disabled: 'disabled' + } + }, + splitWrapper: { + tag: 'div', + className: 'dt-btn-split-wrapper btn-group', + closeButton: false, + }, + splitDropdown: { + tag: 'button', + text: '', + className: 'btn btn-secondary dt-btn-split-drop dropdown-toggle dropdown-toggle-split', + closeButton: false, + align: 'split-left', + splitAlignClass: 'dt-button-split-left' + }, + splitDropdownButton: { + tag: 'button', + className: 'dt-btn-split-drop-button btn btn-secondary', + closeButton: false + } + }, + buttonCreated: function ( config, button ) { + return config.buttons ? + $('
    ').append(button) : + button; + } +} ); + +DataTable.ext.buttons.collection.className += ' dropdown-toggle'; +DataTable.ext.buttons.collection.rightAlignClassName = 'dropdown-menu-right'; + +return DataTable.Buttons; +})); diff --git a/app/static/DataTables/Buttons-2.2.2/js/buttons.bootstrap4.min.js b/app/static/DataTables/Buttons-2.2.2/js/buttons.bootstrap4.min.js new file mode 100644 index 000000000..3d3d41c83 --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/js/buttons.bootstrap4.min.js @@ -0,0 +1,7 @@ +/*! + Bootstrap integration for DataTables' Buttons + ©2016 SpryMedia Ltd - datatables.net/license +*/ +(function(c){"function"===typeof define&&define.amd?define(["jquery","datatables.net-bs4","datatables.net-buttons"],function(a){return c(a,window,document)}):"object"===typeof exports?module.exports=function(a,b){a||(a=window);b&&b.fn.dataTable||(b=require("datatables.net-bs4")(a,b).$);b.fn.dataTable.Buttons||require("datatables.net-buttons")(a,b);return c(b,a,a.document)}:c(jQuery,window,document)})(function(c,a,b,f){a=c.fn.dataTable;c.extend(!0,a.Buttons.defaults,{dom:{container:{className:"dt-buttons btn-group flex-wrap"}, +button:{className:"btn btn-secondary"},collection:{tag:"div",className:"dropdown-menu",closeButton:!1,button:{tag:"a",className:"dt-button dropdown-item",active:"active",disabled:"disabled"}},splitWrapper:{tag:"div",className:"dt-btn-split-wrapper btn-group",closeButton:!1},splitDropdown:{tag:"button",text:"",className:"btn btn-secondary dt-btn-split-drop dropdown-toggle dropdown-toggle-split",closeButton:!1,align:"split-left",splitAlignClass:"dt-button-split-left"},splitDropdownButton:{tag:"button", +className:"dt-btn-split-drop-button btn btn-secondary",closeButton:!1}},buttonCreated:function(e,d){return e.buttons?c('
    ').append(d):d}});a.ext.buttons.collection.className+=" dropdown-toggle";a.ext.buttons.collection.rightAlignClassName="dropdown-menu-right";return a.Buttons}); diff --git a/app/static/DataTables/Buttons-2.2.2/js/buttons.bootstrap5.js b/app/static/DataTables/Buttons-2.2.2/js/buttons.bootstrap5.js new file mode 100644 index 000000000..69c5da638 --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/js/buttons.bootstrap5.js @@ -0,0 +1,87 @@ +/*! Bootstrap integration for DataTables' Buttons + * ©2016 SpryMedia Ltd - datatables.net/license + */ + +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net-bs5', 'datatables.net-buttons'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + module.exports = function (root, $) { + if ( ! root ) { + root = window; + } + + if ( ! $ || ! $.fn.dataTable ) { + $ = require('datatables.net-bs5')(root, $).$; + } + + if ( ! $.fn.dataTable.Buttons ) { + require('datatables.net-buttons')(root, $); + } + + return factory( $, root, root.document ); + }; + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; + +$.extend( true, DataTable.Buttons.defaults, { + dom: { + container: { + className: 'dt-buttons btn-group flex-wrap' + }, + button: { + className: 'btn btn-secondary' + }, + collection: { + tag: 'div', + className: 'dropdown-menu', + closeButton: false, + button: { + tag: 'a', + className: 'dt-button dropdown-item', + active: 'active', + disabled: 'disabled' + } + }, + splitWrapper: { + tag: 'div', + className: 'dt-btn-split-wrapper btn-group', + closeButton: false, + }, + splitDropdown: { + tag: 'button', + text: '', + className: 'btn btn-secondary dt-btn-split-drop dropdown-toggle dropdown-toggle-split', + closeButton: false, + align: 'split-left', + splitAlignClass: 'dt-button-split-left' + }, + splitDropdownButton: { + tag: 'button', + className: 'dt-btn-split-drop-button btn btn-secondary', + closeButton: false + } + }, + buttonCreated: function ( config, button ) { + return config.buttons ? + $('
    ').append(button) : + button; + } +} ); + +DataTable.ext.buttons.collection.className += ' dropdown-toggle'; +DataTable.ext.buttons.collection.rightAlignClassName = 'dropdown-menu-right'; + +return DataTable.Buttons; +})); diff --git a/app/static/DataTables/Buttons-2.2.2/js/buttons.bootstrap5.min.js b/app/static/DataTables/Buttons-2.2.2/js/buttons.bootstrap5.min.js new file mode 100644 index 000000000..b05ff7a68 --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/js/buttons.bootstrap5.min.js @@ -0,0 +1,7 @@ +/*! + Bootstrap integration for DataTables' Buttons + ©2016 SpryMedia Ltd - datatables.net/license +*/ +(function(c){"function"===typeof define&&define.amd?define(["jquery","datatables.net-bs5","datatables.net-buttons"],function(a){return c(a,window,document)}):"object"===typeof exports?module.exports=function(a,b){a||(a=window);b&&b.fn.dataTable||(b=require("datatables.net-bs5")(a,b).$);b.fn.dataTable.Buttons||require("datatables.net-buttons")(a,b);return c(b,a,a.document)}:c(jQuery,window,document)})(function(c,a,b,f){a=c.fn.dataTable;c.extend(!0,a.Buttons.defaults,{dom:{container:{className:"dt-buttons btn-group flex-wrap"}, +button:{className:"btn btn-secondary"},collection:{tag:"div",className:"dropdown-menu",closeButton:!1,button:{tag:"a",className:"dt-button dropdown-item",active:"active",disabled:"disabled"}},splitWrapper:{tag:"div",className:"dt-btn-split-wrapper btn-group",closeButton:!1},splitDropdown:{tag:"button",text:"",className:"btn btn-secondary dt-btn-split-drop dropdown-toggle dropdown-toggle-split",closeButton:!1,align:"split-left",splitAlignClass:"dt-button-split-left"},splitDropdownButton:{tag:"button", +className:"dt-btn-split-drop-button btn btn-secondary",closeButton:!1}},buttonCreated:function(e,d){return e.buttons?c('
    ').append(d):d}});a.ext.buttons.collection.className+=" dropdown-toggle";a.ext.buttons.collection.rightAlignClassName="dropdown-menu-right";return a.Buttons}); diff --git a/app/static/DataTables/Buttons-2.2.2/js/buttons.bulma.js b/app/static/DataTables/Buttons-2.2.2/js/buttons.bulma.js new file mode 100644 index 000000000..08d743a11 --- /dev/null +++ b/app/static/DataTables/Buttons-2.2.2/js/buttons.bulma.js @@ -0,0 +1,98 @@ +/*! Bulma integration for DataTables' Buttons + * ©2021 SpryMedia Ltd - datatables.net/license + */ + +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net-bm', 'datatables.net-buttons'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + module.exports = function (root, $) { + if ( ! root ) { + root = window; + } + + if ( ! $ || ! $.fn.dataTable ) { + $ = require('datatables.net-bm')(root, $).$; + } + + if ( ! $.fn.dataTable.Buttons ) { + require('datatables.net-buttons')(root, $); + } + + return factory( $, root, root.document ); + }; + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; + +$.extend( true, DataTable.Buttons.defaults, { + dom: { + container: { + className: 'dt-buttons field is-grouped' + }, + button: { + className: 'button is-light', + active: 'is-active', + disabled: 'is-disabled' + }, + collection: { + tag: 'div', + closeButton: false, + className: 'dropdown-content', + button: { + tag: 'a', + className: 'dt-button dropdown-item', + active: 'is-active', + disabled: 'is-disabled' + } + }, + splitWrapper: { + tag: 'div', + className: 'dt-btn-split-wrapper dropdown-trigger buttons has-addons', + closeButton: false + }, + splitDropdownButton: { + tag: 'button', + className: 'dt-btn-split-drop-button button is-light', + closeButton: false + }, + splitDropdown: { + tag: 'button', + text: '▼', + className: 'button is-light', + closeButton: false, + align: 'split-left', + splitAlignClass: 'dt-button-split-left' + } + }, + buttonCreated: function ( config, button ) { + // For collections + if (config.buttons) { + // Wrap the dropdown content in a menu element + config._collection = $('