diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 17:14:58 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 17:14:58 +0700 |
| commit | 1ca3b3df3421961caec3b747a364071c80f5c7da (patch) | |
| tree | 6778a1f0f3f9b4c6e26d6d87ccde16e24da6c9d6 /hr_organizational_chart/static | |
| parent | b57188be371d36d96caac4b8d65a40745c0e972c (diff) | |
initial commit
Diffstat (limited to 'hr_organizational_chart/static')
45 files changed, 2415 insertions, 0 deletions
diff --git a/hr_organizational_chart/static/description/assets/icons/chevron.png b/hr_organizational_chart/static/description/assets/icons/chevron.png Binary files differnew file mode 100644 index 0000000..2089293 --- /dev/null +++ b/hr_organizational_chart/static/description/assets/icons/chevron.png diff --git a/hr_organizational_chart/static/description/assets/icons/cogs.png b/hr_organizational_chart/static/description/assets/icons/cogs.png Binary files differnew file mode 100644 index 0000000..95d0bad --- /dev/null +++ b/hr_organizational_chart/static/description/assets/icons/cogs.png diff --git a/hr_organizational_chart/static/description/assets/icons/consultation.png b/hr_organizational_chart/static/description/assets/icons/consultation.png Binary files differnew file mode 100644 index 0000000..8319d4b --- /dev/null +++ b/hr_organizational_chart/static/description/assets/icons/consultation.png diff --git a/hr_organizational_chart/static/description/assets/icons/ecom-black.png b/hr_organizational_chart/static/description/assets/icons/ecom-black.png Binary files differnew file mode 100644 index 0000000..a9385ff --- /dev/null +++ b/hr_organizational_chart/static/description/assets/icons/ecom-black.png diff --git a/hr_organizational_chart/static/description/assets/icons/education-black.png b/hr_organizational_chart/static/description/assets/icons/education-black.png Binary files differnew file mode 100644 index 0000000..3eb09b2 --- /dev/null +++ b/hr_organizational_chart/static/description/assets/icons/education-black.png diff --git a/hr_organizational_chart/static/description/assets/icons/hotel-black.png b/hr_organizational_chart/static/description/assets/icons/hotel-black.png Binary files differnew file mode 100644 index 0000000..130f613 --- /dev/null +++ b/hr_organizational_chart/static/description/assets/icons/hotel-black.png diff --git a/hr_organizational_chart/static/description/assets/icons/license.png b/hr_organizational_chart/static/description/assets/icons/license.png Binary files differnew file mode 100644 index 0000000..a586979 --- /dev/null +++ b/hr_organizational_chart/static/description/assets/icons/license.png diff --git a/hr_organizational_chart/static/description/assets/icons/lifebuoy.png b/hr_organizational_chart/static/description/assets/icons/lifebuoy.png Binary files differnew file mode 100644 index 0000000..658d56c --- /dev/null +++ b/hr_organizational_chart/static/description/assets/icons/lifebuoy.png diff --git a/hr_organizational_chart/static/description/assets/icons/manufacturing-black.png b/hr_organizational_chart/static/description/assets/icons/manufacturing-black.png Binary files differnew file mode 100644 index 0000000..697eb0e --- /dev/null +++ b/hr_organizational_chart/static/description/assets/icons/manufacturing-black.png diff --git a/hr_organizational_chart/static/description/assets/icons/pos-black.png b/hr_organizational_chart/static/description/assets/icons/pos-black.png Binary files differnew file mode 100644 index 0000000..97c0f90 --- /dev/null +++ b/hr_organizational_chart/static/description/assets/icons/pos-black.png diff --git a/hr_organizational_chart/static/description/assets/icons/puzzle.png b/hr_organizational_chart/static/description/assets/icons/puzzle.png Binary files differnew file mode 100644 index 0000000..65cf854 --- /dev/null +++ b/hr_organizational_chart/static/description/assets/icons/puzzle.png diff --git a/hr_organizational_chart/static/description/assets/icons/restaurant-black.png b/hr_organizational_chart/static/description/assets/icons/restaurant-black.png Binary files differnew file mode 100644 index 0000000..4a35eb9 --- /dev/null +++ b/hr_organizational_chart/static/description/assets/icons/restaurant-black.png diff --git a/hr_organizational_chart/static/description/assets/icons/service-black.png b/hr_organizational_chart/static/description/assets/icons/service-black.png Binary files differnew file mode 100644 index 0000000..301ab51 --- /dev/null +++ b/hr_organizational_chart/static/description/assets/icons/service-black.png diff --git a/hr_organizational_chart/static/description/assets/icons/trading-black.png b/hr_organizational_chart/static/description/assets/icons/trading-black.png Binary files differnew file mode 100644 index 0000000..9398ba2 --- /dev/null +++ b/hr_organizational_chart/static/description/assets/icons/trading-black.png diff --git a/hr_organizational_chart/static/description/assets/icons/training.png b/hr_organizational_chart/static/description/assets/icons/training.png Binary files differnew file mode 100644 index 0000000..884ca02 --- /dev/null +++ b/hr_organizational_chart/static/description/assets/icons/training.png diff --git a/hr_organizational_chart/static/description/assets/icons/update.png b/hr_organizational_chart/static/description/assets/icons/update.png Binary files differnew file mode 100644 index 0000000..ecbc5a0 --- /dev/null +++ b/hr_organizational_chart/static/description/assets/icons/update.png diff --git a/hr_organizational_chart/static/description/assets/icons/user.png b/hr_organizational_chart/static/description/assets/icons/user.png Binary files differnew file mode 100644 index 0000000..6ffb23d --- /dev/null +++ b/hr_organizational_chart/static/description/assets/icons/user.png diff --git a/hr_organizational_chart/static/description/assets/icons/wrench.png b/hr_organizational_chart/static/description/assets/icons/wrench.png Binary files differnew file mode 100644 index 0000000..6c04dea --- /dev/null +++ b/hr_organizational_chart/static/description/assets/icons/wrench.png diff --git a/hr_organizational_chart/static/description/banner.png b/hr_organizational_chart/static/description/banner.png Binary files differnew file mode 100644 index 0000000..8416aa6 --- /dev/null +++ b/hr_organizational_chart/static/description/banner.png diff --git a/hr_organizational_chart/static/description/icon.png b/hr_organizational_chart/static/description/icon.png Binary files differnew file mode 100644 index 0000000..4967efd --- /dev/null +++ b/hr_organizational_chart/static/description/icon.png diff --git a/hr_organizational_chart/static/description/images/bio_image.png b/hr_organizational_chart/static/description/images/bio_image.png Binary files differnew file mode 100644 index 0000000..acc34b2 --- /dev/null +++ b/hr_organizational_chart/static/description/images/bio_image.png diff --git a/hr_organizational_chart/static/description/images/chart_expand.png b/hr_organizational_chart/static/description/images/chart_expand.png Binary files differnew file mode 100644 index 0000000..3250a95 --- /dev/null +++ b/hr_organizational_chart/static/description/images/chart_expand.png diff --git a/hr_organizational_chart/static/description/images/chart_shrink.png b/hr_organizational_chart/static/description/images/chart_shrink.png Binary files differnew file mode 100644 index 0000000..1a995e1 --- /dev/null +++ b/hr_organizational_chart/static/description/images/chart_shrink.png diff --git a/hr_organizational_chart/static/description/images/chart_view.png b/hr_organizational_chart/static/description/images/chart_view.png Binary files differnew file mode 100644 index 0000000..5bfb5d2 --- /dev/null +++ b/hr_organizational_chart/static/description/images/chart_view.png diff --git a/hr_organizational_chart/static/description/images/checked.png b/hr_organizational_chart/static/description/images/checked.png Binary files differnew file mode 100644 index 0000000..c8e371f --- /dev/null +++ b/hr_organizational_chart/static/description/images/checked.png diff --git a/hr_organizational_chart/static/description/images/core_image.gif b/hr_organizational_chart/static/description/images/core_image.gif Binary files differnew file mode 100644 index 0000000..e303923 --- /dev/null +++ b/hr_organizational_chart/static/description/images/core_image.gif diff --git a/hr_organizational_chart/static/description/images/custody_image.png b/hr_organizational_chart/static/description/images/custody_image.png Binary files differnew file mode 100644 index 0000000..439a5ef --- /dev/null +++ b/hr_organizational_chart/static/description/images/custody_image.png diff --git a/hr_organizational_chart/static/description/images/dash_image.gif b/hr_organizational_chart/static/description/images/dash_image.gif Binary files differnew file mode 100644 index 0000000..f5cac4e --- /dev/null +++ b/hr_organizational_chart/static/description/images/dash_image.gif diff --git a/hr_organizational_chart/static/description/images/hero.png b/hr_organizational_chart/static/description/images/hero.png Binary files differnew file mode 100644 index 0000000..87b52bc --- /dev/null +++ b/hr_organizational_chart/static/description/images/hero.png diff --git a/hr_organizational_chart/static/description/images/loan_image.png b/hr_organizational_chart/static/description/images/loan_image.png Binary files differnew file mode 100644 index 0000000..76c7ce5 --- /dev/null +++ b/hr_organizational_chart/static/description/images/loan_image.png diff --git a/hr_organizational_chart/static/description/images/menu_item_click.png b/hr_organizational_chart/static/description/images/menu_item_click.png Binary files differnew file mode 100644 index 0000000..0b5712e --- /dev/null +++ b/hr_organizational_chart/static/description/images/menu_item_click.png diff --git a/hr_organizational_chart/static/description/images/openhrms.png b/hr_organizational_chart/static/description/images/openhrms.png Binary files differnew file mode 100644 index 0000000..a462223 --- /dev/null +++ b/hr_organizational_chart/static/description/images/openhrms.png diff --git a/hr_organizational_chart/static/description/images/org_chart.gif b/hr_organizational_chart/static/description/images/org_chart.gif Binary files differnew file mode 100644 index 0000000..4d0b9e6 --- /dev/null +++ b/hr_organizational_chart/static/description/images/org_chart.gif diff --git a/hr_organizational_chart/static/description/images/profile_view.png b/hr_organizational_chart/static/description/images/profile_view.png Binary files differnew file mode 100644 index 0000000..728a868 --- /dev/null +++ b/hr_organizational_chart/static/description/images/profile_view.png diff --git a/hr_organizational_chart/static/description/images/salary_image.png b/hr_organizational_chart/static/description/images/salary_image.png Binary files differnew file mode 100644 index 0000000..127ea73 --- /dev/null +++ b/hr_organizational_chart/static/description/images/salary_image.png diff --git a/hr_organizational_chart/static/description/index.html b/hr_organizational_chart/static/description/index.html new file mode 100644 index 0000000..c8b2d9c --- /dev/null +++ b/hr_organizational_chart/static/description/index.html @@ -0,0 +1,550 @@ +<div style="padding: 3.5rem 1.5rem !important; background-color: #ffffff !important;">
+ <div class="container">
+ <!-- HERO -->
+ <div class="row">
+ <div class="col-lg-12 d-flex flex-column justify-content-center"
+ style="text-align: center; padding: 1rem !important;">
+ <h1 class="text-center" style="color: #00438B !important; font-size: 3rem !important;"><span
+ style="font-weight: 700 !important;">OpenHRMS</span><span style="font-weight: 300 !important;">
+ HR ORGANIZATIONAL CHART</span></h1>
+ <p class="text-center"
+ style="color: #212529 !important; font-size: 1.5rem !important; letter-spacing: 2px !important;">
+ Company Hierarchy At A Glance</p>
+ <img src="./images/hero.png" class="img-responsive">
+ </div>
+ </div>
+ <!-- END OF HERO -->
+
+ <!-- OVERVIEW -->
+ <div class="row">
+ <div class="col-lg-12 d-flex flex-column justify-content-center"
+ style="text-align: center; padding: 2.5rem 1rem !important;">
+ <h2 style="color: #212529 !important;">Overview</h2>
+ <hr
+ style="border: 3px solid #00438B !important; background-color: #00438B !important; width: 80px !important; margin-bottom: 2rem !important;" />
+ <p class="text-center" style="color: #212529 !important; font-size: 1.5rem !important;">
+ This module give the overall department based HR Organizational Chart.
+ </p>
+ </div>
+ </div>
+ <!-- END OF OVERVIEW -->
+
+
+ <!-- KEY FEATURES -->
+ <div class="row">
+ <div class="col-lg-12 d-flex flex-column justify-content-center" style="padding: 2.5rem 1rem !important;">
+ <h2 class="text-center" style="color: #212529 !important;">Key Features</h2>
+ <hr
+ style="border: 3px solid #00438B !important; background-color: #00438B !important; width: 80px !important; margin-bottom: 2rem !important;" />
+ <div class="row">
+ <div class="col-lg-6">
+
+ <div class="d-flex deep-2"
+ style="height: 60px !important; padding: 1rem 1.5rem !important; border-radius: 0 !important; margin: 1.5rem 0">
+ <img src="./images/checked.png" style="height: 24px !important; width: 24px !important;"
+ class="mt-1 mr-2" height="24px" width="24px">
+ <p style="color: #212529 !important; font-size: 1.3rem !important;">
+ View overall hierarchy of the HR department.
+ </p>
+ </div>
+
+ <div class="d-flex deep-2"
+ style="height: 60px !important; padding: 1rem 1.5rem !important; border-radius: 0 !important; margin: 1.5rem 0">
+ <img src="./images/checked.png" style="height: 24px !important; width: 24px !important;"
+ class="mt-1 mr-2" height="24px" width="24px">
+ <p style="color: #212529 !important; font-size: 1.3rem !important;">
+ Easly get employee form by a click
+ </p>
+ </div>
+ </div>
+ <div class="col-lg-6">
+ <div class="d-flex deep-2"
+ style="height: 60px !important; padding: 1rem 1.5rem !important; border-radius: 0 !important; margin: 1.5rem 0">
+ <img src="./images/checked.png" style="height: 24px !important; width: 24px !important;"
+ class="mt-1 mr-2" height="24px" width="24px">
+ <p style="color: #212529 !important; font-size: 1.3rem !important;">
+ Get child hierarchy by click on image
+ </p>
+ </div>
+
+ <div class="d-flex deep-2"
+ style="height: 60px !important; padding: 1rem 1.5rem !important; border-radius: 0 !important; margin: 1.5rem 0">
+ <img src="./images/checked.png" style="height: 24px !important; width: 24px !important;"
+ class="mt-1 mr-2" height="24px" width="24px">
+ <p style="color: #212529 !important; font-size: 1.3rem !important;">
+ Department included Profile view in this chart
+ </p>
+ </div>
+
+ </div>
+
+
+ </div>
+
+ </div>
+ </div>
+
+ <!-- END OF KEY FEATURES -->
+
+ <!-- SCREENSHOTS -->
+ <div class="row">
+ <div class="col-lg-12 d-flex flex-column justify-content-center" style="padding: 2.5rem 1rem !important;">
+ <h2 style="text-align: center; color: #212529 !important;">Screenshots</h2>
+ <hr
+ style="border: 3px solid #00438B !important; background-color: #00438B !important; width: 80px !important; margin-bottom: 2rem !important;" />
+
+ <!-- img -->
+ <div class="d-flex m-0">
+ <div class="mr-3">
+ <h3
+ style="font-size: 2rem !important; font-weight: 800 !important; color: #ffffff !important; background-color: #00438B !important; padding: 1rem !important; width: 70px !important; height: 80px !important;">
+ 01</h3>
+ </div>
+ <div>
+ <h3 style="font-size: 1.7rem !important; font-weight: 600 !important;"> Chart view in menu item
+ click.
+ </h3>
+ </div>
+ </div>
+ <img src="./images/menu_item_click.png" class="img-responsive"
+ style="margin-top: -15px !important; border-top: 5px solid #00438B !important; margin-bottom: 4rem !important;">
+ <!-- endo of img -->
+
+ <!-- img -->
+ <div class="d-flex m-0">
+ <div class="mr-3">
+ <h3
+ style="font-size: 2rem !important; font-weight: 800 !important; color: #ffffff !important; background-color: #00438B !important; padding: 1rem !important; width: 70px !important; height: 80px !important;">
+ 02</h3>
+ </div>
+ <div>
+ <h3 style="font-size: 1.7rem !important; font-weight: 600 !important;">Easily expandable chart
+ </h3>
+
+ </div>
+ </div>
+ <img src="./images/chart_expand.png" class="img-responsive"
+ style="margin-top: -15px !important; border-top: 5px solid #00438B !important; margin-bottom: 4rem !important;">
+ <!-- endo of img -->
+
+ <!-- img -->
+ <div class="d-flex m-0">
+ <div class="mr-3">
+ <h3
+ style="font-size: 2rem !important; font-weight: 800 !important; color: #ffffff !important; background-color: #00438B !important; padding: 1rem !important; width: 70px !important; height: 80px !important;">
+ 03</h3>
+ </div>
+ <div>
+ <h3 style="font-size: 1.7rem !important; font-weight: 600 !important;">Easily shrinkable chart
+ </h3>
+ </div>
+ </div>
+ <img src="./images/chart_shrink.png" class="img-responsive"
+ style="margin-top: -15px !important; border-top: 5px solid #00438B !important; margin-bottom: 4rem !important;">
+ <!-- endo of img -->
+
+ <!-- img -->
+ <div class="d-flex m-0">
+ <div class="mr-3">
+ <h3
+ style="font-size: 2rem !important; font-weight: 800 !important; color: #ffffff !important; background-color: #00438B !important; padding: 1rem !important; width: 70px !important; height: 80px !important;">
+ 04</h3>
+ </div>
+ <div>
+ <h3 style="font-size: 1.7rem !important; font-weight: 600 !important;">Complete chart view
+ </h3>
+ </div>
+ </div>
+ <img src="./images/chart_view.png" class="img-responsive"
+ style="margin-top: -15px !important; border-top: 5px solid #00438B !important; margin-bottom: 4rem !important;">
+ <!-- endo of img -->
+ </div>
+ </div>
+ <!-- END OF SCREENSHOTS -->
+
+
+ <!-- SUGGESTED PRODUCTS -->
+ <div class="row">
+ <div class="col-lg-12 d-flex flex-column justify-content-center"
+ style="text-align: center; padding: 2.5rem 1rem !important;">
+ <h2 style="color: #212529 !important;">Suggested Products</h2>
+ <hr
+ style="border: 3px solid #00438B !important; background-color: #00438B !important; width: 80px !important; margin-bottom: 2rem !important;" />
+
+ <div id="demo1" class="row carousel slide" data-ride="carousel">
+ <!-- The slideshow -->
+ <div class="carousel-inner">
+ <div class="carousel-item active" style="min-height:0px">
+ <div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
+ <a href="https://apps.odoo.com/apps/modules/14.0/ohrms_core/" target="_blank">
+ <div style="border-radius:10px">
+ <img class="img img-responsive center-block"
+ style="border-top-left-radius:10px; border-top-right-radius:10px"
+ src="./images/core_image.gif">
+ </div>
+ </a>
+ </div>
+ <div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
+ <a href="https://apps.odoo.com/apps/modules/14.0/ohrms_salary_advance/" target="_blank">
+ <div style="border-radius:10px">
+ <img class="img img-responsive center-block"
+ style="border-top-left-radius:10px; border-top-right-radius:10px"
+ src="./images/advance_image.png">
+ </div>
+ </a>
+ </div>
+ <div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
+ <a href="https://apps.odoo.com/apps/modules/13.0/oh_hr_zk_attendance/" target="_blank">
+ <div style="border-radius:10px">
+ <img class="img img-responsive center-block"
+ style="border-top-left-radius:10px; border-top-right-radius:10px"
+ src="./images/bio_image.png">
+ </div>
+ </a>
+ </div>
+ </div>
+ <div class="carousel-item" style="min-height:0px">
+ <div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
+ <a href="https://apps.odoo.com/apps/modules/14.0/ohrms_loan/" target="_blank">
+ <div style="border-radius:10px">
+ <img class="img img-responsive center-block"
+ style="border-top-left-radius:10px; border-top-right-radius:10px"
+ src="./images/loan_image.png">
+ </div>
+ </a>
+ </div>
+ <div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
+ <a href="https://apps.odoo.com/apps/modules/14.0/hr_custody/" target="_blank">
+ <div style="border-radius:10px">
+ <img class="img img-responsive center-block"
+ style="border-top-left-radius:10px; border-top-right-radius:10px"
+ src="./images/custody_image.png">
+ </div>
+ </a>
+ </div>
+ <div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
+ <a href="https://apps.odoo.com/apps/modules/13.0/ohrms_salary_advance/" target="_blank">
+ <div style="border-radius:10px">
+ <img class="img img-responsive center-block"
+ style="border-top-left-radius:10px; border-top-right-radius:10px"
+ src="./images/salary_image.png">
+ </div>
+ </a>
+ </div>
+ </div>
+ </div>
+ <!-- Left and right controls -->
+ <a class="carousel-control-prev" href="#demo1" data-slide="prev"
+ style="left:-25px;width: 35px;color: #000;"> <span class="carousel-control-prev-icon"><i
+ class="fa fa-chevron-left" style="font-size:24px"></i></span> </a> <a
+ class="carousel-control-next" href="#demo1" data-slide="next"
+ style="right:-25px;width: 35px;color: #000;">
+ <span class="carousel-control-next-icon"><i class="fa fa-chevron-right"
+ style="font-size:24px"></i></span>
+ </a>
+ </div>
+ </div>
+ </div>
+ <!-- END OF SUGGESTED PRODUCTS -->
+
+ <!-- OUR SERVICES -->
+ <section class="container" style="margin-top: 6rem !important;">
+ <div class="row">
+ <div class="col-lg-12 d-flex flex-column justify-content-center align-items-center">
+ <h2 style="color: #212529 !important;">Our Services</h2>
+ <hr
+ style="border: 3px solid #00438B !important; background-color: #00438B !important; width: 80px !important; margin-bottom: 2rem !important;" />
+ </div>
+
+ <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
+ <div class="d-flex justify-content-center align-items-center mx-3 my-3"
+ style="background-color: #1dd1a1 !important; border-radius: 15px !important; height: 80px; width: 80px;">
+ <img src="assets/icons/cogs.png" class="img-responsive" height="48px" width="48px">
+ </div>
+ <h6 class="text-center"
+ style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">Odoo
+ Customization</h6>
+ </div>
+
+ <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
+ <div class="d-flex justify-content-center align-items-center mx-3 my-3"
+ style="background-color: #ff6b6b !important; border-radius: 15px !important; height: 80px; width: 80px;">
+ <img src="assets/icons/wrench.png" class="img-responsive" height="48px" width="48px">
+ </div>
+ <h6 class="text-center"
+ style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">Odoo
+ Implementation</h6>
+ </div>
+
+ <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
+ <div class="d-flex justify-content-center align-items-center mx-3 my-3"
+ style="background-color: #6462CD !important; border-radius: 15px !important; height: 80px; width: 80px;">
+ <img src="assets/icons/lifebuoy.png" class="img-responsive" height="48px" width="48px">
+ </div>
+ <h6 class="text-center"
+ style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">Odoo
+ Support</h6>
+ </div>
+
+
+ <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
+ <div class="d-flex justify-content-center align-items-center mx-3 my-3"
+ style="background-color: #ffa801 !important; border-radius: 15px !important; height: 80px; width: 80px;">
+ <img src="assets/icons/user.png" class="img-responsive" height="48px" width="48px">
+ </div>
+ <h6 class="text-center"
+ style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">Hire
+ Odoo
+ Developer</h6>
+ </div>
+
+ <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
+ <div class="d-flex justify-content-center align-items-center mx-3 my-3"
+ style="background-color: #54a0ff !important; border-radius: 15px !important; height: 80px; width: 80px;">
+ <img src="assets/icons/puzzle.png" class="img-responsive" height="48px" width="48px">
+ </div>
+ <h6 class="text-center"
+ style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">Odoo
+ Integration</h6>
+ </div>
+
+ <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
+ <div class="d-flex justify-content-center align-items-center mx-3 my-3"
+ style="background-color: #6d7680 !important; border-radius: 15px !important; height: 80px; width: 80px;">
+ <img src="assets/icons/update.png" class="img-responsive" height="48px" width="48px">
+ </div>
+ <h6 class="text-center"
+ style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">Odoo
+ Migration</h6>
+ </div>
+
+
+ <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
+ <div class="d-flex justify-content-center align-items-center mx-3 my-3"
+ style="background-color: #786fa6 !important; border-radius: 15px !important; height: 80px; width: 80px;">
+ <img src="assets/icons/consultation.png" class="img-responsive" height="48px" width="48px">
+ </div>
+ <h6 class="text-center"
+ style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">Odoo
+ Consultancy</h6>
+ </div>
+
+ <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
+ <div class="d-flex justify-content-center align-items-center mx-3 my-3"
+ style="background-color: #f8a5c2 !important; border-radius: 15px !important; height: 80px; width: 80px;">
+ <img src="assets/icons/training.png" class="img-responsive" height="48px" width="48px">
+ </div>
+ <h6 class="text-center"
+ style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">Odoo
+ Implementation</h6>
+ </div>
+
+ <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
+ <div class="d-flex justify-content-center align-items-center mx-3 my-3"
+ style="background-color: #e6be26 !important; border-radius: 15px !important; height: 80px; width: 80px;">
+ <img src="assets/icons/license.png" class="img-responsive" height="48px" width="48px">
+ </div>
+ <h6 class="text-center"
+ style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">Odoo
+ Licensing Consultancy</h6>
+ </div>
+ </div>
+ </section>
+ <!-- END OF END OF OUR SERVICES -->
+
+ <!-- OUR INDUSTRIES -->
+ <section class="container" style="margin-top: 6rem !important;">
+ <div class="row">
+ <div class="col-lg-12 d-flex flex-column justify-content-center align-items-center">
+ <h2 style="color: #212529 !important;">Our Industries</h2>
+ <hr
+ style="border: 3px solid #00438B !important; background-color: #00438B !important; width: 80px !important; margin-bottom: 2rem !important;" />
+ </div>
+
+ <div class="col-lg-3">
+ <div class="my-4 d-flex flex-column justify-content-center"
+ style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;">
+ <img src="./assets/icons/trading-black.png" class="img-responsive mb-3" height="48px"
+ width="48px">
+ <h5
+ style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
+ Trading
+ </h5>
+ <p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
+ Easily procure
+ and
+ sell your products</p>
+ </div>
+ </div>
+
+ <div class="col-lg-3">
+ <div class="my-4 d-flex flex-column justify-content-center"
+ style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;">
+ <img src="./assets/icons/pos-black.png" class="img-responsive mb-3" height="48px" width="48px">
+ <h5
+ style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
+ POS
+ </h5>
+ <p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
+ Easy
+ configuration
+ and convivial experience</p>
+ </div>
+ </div>
+
+ <div class="col-lg-3">
+ <div class="my-4 d-flex flex-column justify-content-center"
+ style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;">
+ <img src="./assets/icons/education-black.png" class="img-responsive mb-3" height="48px"
+ width="48px">
+ <h5
+ style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
+ Education
+ </h5>
+ <p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
+ A platform for
+ educational management</p>
+ </div>
+ </div>
+
+ <div class="col-lg-3">
+ <div class="my-4 d-flex flex-column justify-content-center"
+ style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;">
+ <img src="./assets/icons/manufacturing-black.png" class="img-responsive mb-3" height="48px"
+ width="48px">
+ <h5
+ style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
+ Manufacturing
+ </h5>
+ <p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
+ Plan, track and
+ schedule your operations</p>
+ </div>
+ </div>
+
+ <div class="col-lg-3">
+ <div class="my-4 d-flex flex-column justify-content-center"
+ style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;">
+ <img src="./assets/icons/ecom-black.png" class="img-responsive mb-3" height="48px" width="48px">
+ <h5
+ style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
+ E-commerce & Website
+ </h5>
+ <p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
+ Mobile
+ friendly,
+ awe-inspiring product pages</p>
+ </div>
+ </div>
+
+ <div class="col-lg-3">
+ <div class="my-4 d-flex flex-column justify-content-center"
+ style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;">
+ <img src="./assets/icons/service-black.png" class="img-responsive mb-3" height="48px"
+ width="48px">
+ <h5
+ style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
+ Service Management
+ </h5>
+ <p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
+ Keep track of
+ services and invoice</p>
+ </div>
+ </div>
+
+ <div class="col-lg-3">
+ <div class="my-4 d-flex flex-column justify-content-center"
+ style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;">
+ <img src="./assets/icons/restaurant-black.png" class="img-responsive mb-3" height="48px"
+ width="48px">
+ <h5
+ style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
+ Restaurant
+ </h5>
+ <p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
+ Run your bar or
+ restaurant methodically</p>
+ </div>
+ </div>
+
+ <div class="col-lg-3">
+ <div class="my-4 d-flex flex-column justify-content-center"
+ style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;">
+ <img src="./assets/icons/hotel-black.png" class="img-responsive mb-3" height="48px"
+ width="48px">
+ <h5
+ style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
+ Hotel Management
+ </h5>
+ <p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
+ An
+ all-inclusive
+ hotel management application</p>
+ </div>
+ </div>
+
+ </div>
+ </section>
+
+ <!-- END OF END OF OUR INDUSTRIES -->
+
+ <!-- FOOTER -->
+ <!-- Footer Section -->
+ <section class="container" style="margin: 5rem auto 2rem;">
+ <div class="row" style="max-width:1540px;">
+ <div class="col-lg-12 d-flex flex-column justify-content-center align-items-center">
+ <h2 style="color: #212529 !important;">Need Help?</h2>
+ <hr
+ style="border: 3px solid #00438B !important; background-color: #00438B !important; width: 80px !important; margin-bottom: 2rem !important;" />
+ </div>
+ </div>
+
+ <!-- Contact Cards -->
+ <div class="row d-flex justify-content-center align-items-center"
+ style="max-width:1540px; margin: 0 auto 2rem auto;">
+
+ <div class="col-lg-12" style="padding: 0rem 3rem 2rem; border-radius: 10px; margin-right: 3rem; ">
+
+ <div class="row mt-4">
+ <div class="col-lg-4">
+ <a href="mailto:odoo@cybrosys.com" target="_blank" class="btn btn-block mb-2 deep_hover"
+ style="text-decoration: none; background-color: #4d4d4d; color: #FFF; border-radius: 4px;"><i
+ class="fa fa-envelope mr-2"></i>odoo@cybrosys.com</a>
+ </div>
+ <div class="col-lg-4">
+ <a href="https://api.whatsapp.com/send?phone=918606827707" target="_blank"
+ class="btn btn-block mb-2 deep_hover"
+ style="text-decoration: none; background-color: #25D366; color: #FFF; border-radius: 4px;"><i
+ class="fa fa-whatsapp mr-2"></i>WhatsApp</a>
+ </div>
+ <div class="col-lg-4">
+ <a href="mailto:info@cybrosys.com" target="_blank" class="btn btn-block deep_hover"
+ style="text-decoration: none; background-color: #4d4d4d; color: #FFF; border-radius: 4px;"><i
+ class="fa fa-envelope mr-2"></i>info@cybrosys.com</a>
+ </div>
+ </div>
+ </div>
+
+ </div>
+ <!-- End of Contact Cards -->
+ </section>
+ <!-- Footer -->
+ <section class="oe_container" style="padding: 2rem 3rem 1rem;">
+ <div class="row" style="max-width:1540px; margin: 0 auto; margin-right: 3rem; ">
+ <!-- Logo -->
+ <div class="col-lg-12 d-flex justify-content-center align-items-center" style="margin-top: 3rem;">
+ <img src="https://www.cybrosys.com/images/logo.png" width="200px" height="auto" />
+ </div>
+ <!-- End of Logo -->
+ <div class="col-lg-12">
+ <hr
+ style="margin-top: 3rem;background: linear-gradient(90deg, rgba(2,0,36,0) 0%, rgba(229,229,229,1) 33%, rgba(229,229,229,1) 58%, rgba(0,212,255,0) 100%); height: 2px; border-style: none;">
+ <!-- End of Footer Section -->
+ </div>
+ </div>
+ </section>
+ <!-- END OF FOOTER -->
+
+
+ </div>
+</div>
\ No newline at end of file diff --git a/hr_organizational_chart/static/js/hr_org_chart.js b/hr_organizational_chart/static/js/hr_org_chart.js new file mode 100644 index 0000000..58bc15a --- /dev/null +++ b/hr_organizational_chart/static/js/hr_org_chart.js @@ -0,0 +1,89 @@ +var employee_data = []; + +var nodeTemplate = function(data) { + return ` + <span class="office">${data.office}</span> + <div class="title">${data.name}</div> + <div class="content">${data.title}</div> + `; + }; + +odoo.define("hr_org_chart_employee.hr_org_chart", function (require) { + "use strict"; + + var core = require('web.core'); + var session = require('web.session'); + var ajax = require('web.ajax'); + var Widget = require('web.Widget'); + var QWeb = core.qweb; + var _t = core._t; + var AbstractAction = require('web.AbstractAction'); + var _lt = core._lt; + + var OrgChartDepartment = AbstractAction.extend({ + events: { + 'click .nodes,.node': 'view_employee', + }, + init: function(parent, context){ + this._super(parent, context); + var self = this; + if (context.tag == 'employee_organization_chart') { + this._rpc({ + route: '/get/employees', + }).then(function (result) { + self._rpc({ + model: 'hr.organizational.chart', + method: 'get_employee_data', + args: [result], + }, []).then(function(values){ + employee_data = values; + self.render(); + self.href = window.location.href; + }); + }); + } + }, + willStart: function() { + return $.when(ajax.loadLibs(this), this._super()); + }, + start: function() { + var self = this; + return this._super(); + }, + render: function() { + var super_render = this._super; + var self = this; + var org_chart = QWeb.render('hr_organizational_chart.org_chart_template', { + widget: self, + }); + $(".o_control_panel").addClass("o_hidden"); + $(org_chart).prependTo(self.$el); + return org_chart; + }, + reload: function () { + window.location.href = this.href; + }, + view_employee: function(ev){ + if (ev.target.attributes[1]){ + var id = parseInt(ev.target.attributes[1].nodeValue) + this.do_action({ + name: _t("Employee"), + type: 'ir.actions.act_window', + res_model: 'hr.employee', + res_id: id, + view_mode: 'form', + views: [[false, 'form']], + }) + } + }, + }); + + + + core.action_registry.add('employee_organization_chart', OrgChartDepartment); + window.reload() + + return OrgChartDepartment; + + +});
\ No newline at end of file diff --git a/hr_organizational_chart/static/js/jquery_hr_orgchart.js b/hr_organizational_chart/static/js/jquery_hr_orgchart.js new file mode 100644 index 0000000..f074951 --- /dev/null +++ b/hr_organizational_chart/static/js/jquery_hr_orgchart.js @@ -0,0 +1,1047 @@ +/* + * jQuery OrgChart Plugin + * https://github.com/dabeng/OrgChart + * + * Copyright 2016, dabeng + * https://github.com/dabeng + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ +'use strict'; + +(function (factory) { + if (typeof module === 'object' && typeof module.exports === 'object') { + factory(require('jquery'), window, document); + } else { + factory(jQuery, window, document); + } +}(function ($, window, document, undefined) { + var OrgChart = function (elem, opts) { + this.$chartContainer = $(elem); + this.opts = opts; + this.defaultOptions = { + 'nodeTitle': 'name', + 'nodeId': 'id', + 'toggleSiblingsResp': false, + 'visibleLevel': 999, + 'chartClass': '', + 'exportButton': false, + 'exportFilename': 'OrgChart', + 'exportFileextension': 'png', + 'draggable': false, + 'direction': 't2b', + 'pan': false, + 'zoom': false, + 'zoominLimit': 7, + 'zoomoutLimit': 0.5 + }; + }; + // + OrgChart.prototype = { + // + init: function (opts) { + var that = this; + this.options = $.extend({}, this.defaultOptions, this.opts, opts); + // build the org-chart + var $chartContainer = this.$chartContainer; + if (this.$chart) { + this.$chart.remove(); + } + var data = this.options.data; + var $chart = this.$chart = $('<div>', { + 'data': { 'options': this.options }, + 'class': 'orgchart' + (this.options.chartClass !== '' ? ' ' + this.options.chartClass : '') + (this.options.direction !== 't2b' ? ' ' + this.options.direction : ''), + }); + if (typeof MutationObserver !== 'undefined') { + this.triggerInitEvent(); + } + if ($.type(data) === 'object') { + if (data instanceof $) { // ul datasource + this.buildHierarchy($chart, this.buildJsonDS(data.children()), 0, this.options); + } else { // local json datasource + this.buildHierarchy($chart, this.options.ajaxURL ? data : this.attachRel(data, '00')); + } + } else { + $chart.append('<i class="fa fa-circle-o-notch fa-spin spinner"></i>'); + $.ajax({ + 'url': data, + 'dataType': 'json' + }) + .done(function(data, textStatus, jqXHR) { + that.buildHierarchy($chart, that.options.ajaxURL ? data : that.attachRel(data, '00'), 0, that.options); + }) + .fail(function(jqXHR, textStatus, errorThrown) { + console.log(errorThrown); + }) + .always(function() { + $chart.children('.spinner').remove(); + }); + } + $chartContainer.append($chart); + + if (this.options.pan) { + this.bindPan(); + } + + if (this.options.zoom) { + this.bindZoom(); + } + + return this; + }, + // + triggerInitEvent: function () { + var that = this; + var mo = new MutationObserver(function (mutations) { + mo.disconnect(); + initTime: + for (var i = 0; i < mutations.length; i++) { + for (var j = 0; j < mutations[i].addedNodes.length; j++) { + if (mutations[i].addedNodes[j].classList.contains('orgchart')) { + if (that.options.initCompleted && typeof that.options.initCompleted === 'function') { + that.options.initCompleted(that.$chart); + var initEvent = $.Event('init.orgchart'); + that.$chart.trigger(initEvent); + break initTime; + } + } + } + } + }); + mo.observe(this.$chartContainer[0], { childList: true }); + }, + // + panStartHandler: function (e) { + var $chart = $(e.delegateTarget); + if ($(e.target).closest('.node').length || (e.touches && e.touches.length > 1)) { + $chart.data('panning', false); + return; + } else { + $chart.css('cursor', 'move').data('panning', true); + } + var lastX = 0; + var lastY = 0; + var lastTf = $chart.css('transform'); + if (lastTf !== 'none') { + var temp = lastTf.split(','); + if (lastTf.indexOf('3d') === -1) { + lastX = parseInt(temp[4]); + lastY = parseInt(temp[5]); + } else { + lastX = parseInt(temp[12]); + lastY = parseInt(temp[13]); + } + } + var startX = 0; + var startY = 0; + if (!e.targetTouches) { // pand on desktop + startX = e.pageX - lastX; + startY = e.pageY - lastY; + } else if (e.targetTouches.length === 1) { // pan on mobile device + startX = e.targetTouches[0].pageX - lastX; + startY = e.targetTouches[0].pageY - lastY; + } else if (e.targetTouches.length > 1) { + return; + } + $chart.on('mousemove touchmove',function(e) { + if (!$chart.data('panning')) { + return; + } + var newX = 0; + var newY = 0; + if (!e.targetTouches) { // pand on desktop + newX = e.pageX - startX; + newY = e.pageY - startY; + } else if (e.targetTouches.length === 1) { // pan on mobile device + newX = e.targetTouches[0].pageX - startX; + newY = e.targetTouches[0].pageY - startY; + } else if (e.targetTouches.length > 1) { + return; + } + var lastTf = $chart.css('transform'); + if (lastTf === 'none') { + if (lastTf.indexOf('3d') === -1) { + $chart.css('transform', 'matrix(1, 0, 0, 1, ' + newX + ', ' + newY + ')'); + } else { + $chart.css('transform', 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, ' + newX + ', ' + newY + ', 0, 1)'); + } + } else { + var matrix = lastTf.split(','); + if (lastTf.indexOf('3d') === -1) { + matrix[4] = ' ' + newX; + matrix[5] = ' ' + newY + ')'; + } else { + matrix[12] = ' ' + newX; + matrix[13] = ' ' + newY; + } + $chart.css('transform', matrix.join(',')); + } + }); + }, + // + panEndHandler: function (e) { + if (e.data.chart.data('panning')) { + e.data.chart.data('panning', false).css('cursor', 'default').off('mousemove'); + } + }, + // + bindPan: function () { + this.$chartContainer.css('overflow', 'hidden'); + this.$chart.on('mousedown touchstart', this.panStartHandler); + $(document).on('mouseup touchend', { 'chart': this.$chart }, this.panEndHandler); + }, + // + unbindPan: function () { + this.$chartContainer.css('overflow', 'auto'); + this.$chart.off('mousedown touchstart', this.panStartHandler); + $(document).off('mouseup touchend', this.panEndHandler); + }, + // + zoomWheelHandler: function (e) { + var oc = e.data.oc; + e.preventDefault(); + var newScale = 1 + (e.originalEvent.deltaY > 0 ? -0.2 : 0.2); + oc.setChartScale(oc.$chart, newScale); + }, + // + zoomStartHandler: function (e) { + if(e.touches && e.touches.length === 2) { + var oc = e.data.oc; + oc.$chart.data('pinching', true); + var dist = oc.getPinchDist(e); + oc.$chart.data('pinchDistStart', dist); + } + }, + zoomingHandler: function (e) { + var oc = e.data.oc; + if(oc.$chart.data('pinching')) { + var dist = oc.getPinchDist(e); + oc.$chart.data('pinchDistEnd', dist); + } + }, + zoomEndHandler: function (e) { + var oc = e.data.oc; + if(oc.$chart.data('pinching')) { + oc.$chart.data('pinching', false); + var diff = oc.$chart.data('pinchDistEnd') - oc.$chart.data('pinchDistStart'); + if (diff > 0) { + oc.setChartScale(oc.$chart, 1.2); + } else if (diff < 0) { + oc.setChartScale(oc.$chart, 0.8); + } + } + }, + // + bindZoom: function () { + this.$chartContainer.on('wheel', { 'oc': this }, this.zoomWheelHandler); + this.$chartContainer.on('touchstart', { 'oc': this }, this.zoomStartHandler); + $(document).on('touchmove', { 'oc': this }, this.zoomingHandler); + $(document).on('touchend', { 'oc': this }, this.zoomEndHandler); + }, + unbindZoom: function () { + this.$chartContainer.off('wheel', this.zoomWheelHandler); + this.$chartContainer.off('touchstart', this.zoomStartHandler); + $(document).off('touchmove', this.zoomingHandler); + $(document).off('touchend', this.zoomEndHandler); + }, + // + getPinchDist: function (e) { + return Math.sqrt((e.touches[0].clientX - e.touches[1].clientX) * (e.touches[0].clientX - e.touches[1].clientX) + + (e.touches[0].clientY - e.touches[1].clientY) * (e.touches[0].clientY - e.touches[1].clientY)); + }, + // + setChartScale: function ($chart, newScale) { + var opts = $chart.data('options'); + var lastTf = $chart.css('transform'); + var matrix = ''; + var targetScale = 1; + if (lastTf === 'none') { + $chart.css('transform', 'scale(' + newScale + ',' + newScale + ')'); + } else { + matrix = lastTf.split(','); + if (lastTf.indexOf('3d') === -1) { + targetScale = Math.abs(window.parseFloat(matrix[3]) * newScale); + if (targetScale > opts.zoomoutLimit && targetScale < opts.zoominLimit) { + $chart.css('transform', lastTf + ' scale(' + newScale + ',' + newScale + ')'); + } + } else { + targetScale = Math.abs(window.parseFloat(matrix[1]) * newScale); + if (targetScale > opts.zoomoutLimit && targetScale < opts.zoominLimit) { + $chart.css('transform', lastTf + ' scale3d(' + newScale + ',' + newScale + ', 1)'); + } + } + } + }, + // + buildJsonDS: function ($li) { + var that = this; + var subObj = { + 'name': $li.contents().eq(0).text().trim(), + 'relationship': ($li.parent().parent().is('li') ? '1': '0') + ($li.siblings('li').length ? 1: 0) + ($li.children('ul').length ? 1 : 0) + }; + $.each($li.data(), function(key, value) { + subObj[key] = value; + }); + $li.children('ul').children().each(function() { + if (!subObj.children) { subObj.children = []; } + subObj.children.push(that.buildJsonDS($(this))); + }); + return subObj; + }, + // + attachRel: function (data, flags) { + var that = this; + data.relationship = flags + (data.children && data.children.length > 0 ? 1 : 0); + if (data.children) { + data.children.forEach(function(item) { + that.attachRel(item, '1' + (data.children.length > 1 ? 1 : 0)); + }); + } + return data; + }, + // + loopChart: function ($chart) { + var that = this; + var $tr = $chart.find('tr:first'); + var subObj = { 'id': $tr.find('.node')[0].id }; + $tr.siblings(':last').children().each(function() { + if (!subObj.children) { subObj.children = []; } + subObj.children.push(that.loopChart($(this))); + }); + return subObj; + }, + // + getHierarchy: function () { + if (typeof this.$chart === 'undefined') { + return 'Error: orgchart does not exist' + } else { + if (!this.$chart.find('.node').length) { + return 'Error: nodes do not exist' + } else { + var valid = true; + this.$chart.find('.node').each(function () { + if (!this.id) { + valid = false; + return false; + } + }); + if (!valid) { + return 'Error: All nodes of orghcart to be exported must have data-id attribute!'; + } + } + } + return this.loopChart(this.$chart); + }, + // detect the exist/display state of related node + getNodeState: function ($node, relation) { + var $target = {}; + var relation = relation || 'self'; + if (relation === 'parent') { + $target = $node.closest('.nodes').siblings(':first'); + if ($target.length) { + if ($target.is('.hidden') || (!$target.is('.hidden') && $target.closest('.nodes').is('.hidden'))) { + return { 'exist': true, 'visible': false }; + } + return { 'exist': true, 'visible': true }; + } + } else if (relation === 'children') { + $target = $node.closest('tr').siblings(':last'); + if ($target.length) { + if (!$target.is('.hidden')) { + return { 'exist': true, 'visible': true }; + } + return { 'exist': true, 'visible': false }; + } + } else if (relation === 'siblings') { + $target = $node.closest('table').parent().siblings(); + if ($target.length) { + if (!$target.is('.hidden') && !$target.parent().is('.hidden')) { + return { 'exist': true, 'visible': true }; + } + return { 'exist': true, 'visible': false }; + } + } else { + $target = $node; + if ($target.length) { + if (!(($target.closest('.nodes').length && $target.closest('.nodes').is('.hidden')) || + ($target.closest('table').parent().length && $target.closest('table').parent().is('.hidden')) || + ($target.parent().is('li') && ($target.closest('ul').is('.hidden') || $target.closest('verticalNodes').is('.hidden'))) + )) { + return { 'exist': true, 'visible': true }; + } + return { 'exist': true, 'visible': false }; + } + } + return { 'exist': false, 'visible': false }; + }, + // find the related nodes + getRelatedNodes: function ($node, relation) { + if (!$node || !($node instanceof $) || !$node.is('.node')) { + return $(); + } + if (relation === 'parent') { + return $node.closest('.nodes').parent().children(':first').find('.node'); + } else if (relation === 'children') { + return $node.closest('tr').siblings('.nodes').children().find('.node:first'); + } else if (relation === 'siblings') { + return $node.closest('table').parent().siblings().find('.node:first'); + } else { + return $(); + } + }, + // show the parent node of the specified node + showParent: function ($node) { + // just show only one superior level + var $upperLevel = $node.closest('.nodes').siblings().removeClass('hidden'); + // just show only one line + $upperLevel.eq(2).children().slice(1, -1).addClass('hidden'); + // show parent node with animation + var $parent = $upperLevel.eq(0).find('.node'); + this.repaint($parent[0]); + $parent.addClass('sliding').removeClass('slide-down').one('transitionend', { 'node': $node }, this.showParentEnd.bind(this)); + }, + stopAjax: function ($nodeLevel) { + if ($nodeLevel.find('.spinner').length) { + $nodeLevel.closest('.orgchart').data('inAjax', false); + } + }, + isVisibleNode: function (index, elem) { + return this.getNodeState($(elem)).visible; + }, + // + // start up loading status for requesting new nodes + startLoading: function ($edge) { + var $chart = this.$chart; + if (typeof $chart.data('inAjax') !== 'undefined' && $chart.data('inAjax') === true) { + return false; + } + + $edge.addClass('hidden'); + $edge.parent().append('<i class="fa fa-circle-o-notch fa-spin spinner"></i>') + .children().not('.spinner').css('opacity', 0.2); + $chart.data('inAjax', true); + $('.oc-export-btn' + (this.options.chartClass !== '' ? '.' + this.options.chartClass : '')).prop('disabled', true); + return true; + }, + // terminate loading status for requesting new nodes + endLoading: function ($edge) { + var $node = $edge.parent(); + $edge.removeClass('hidden'); + $node.find('.spinner').remove(); + $node.children().removeAttr('style'); + this.$chart.data('inAjax', false); + $('.oc-export-btn' + (this.options.chartClass !== '' ? '.' + this.options.chartClass : '')).prop('disabled', false); + }, + // whether the cursor is hovering over the node + isInAction: function ($node) { + return $node.children('.edge').attr('class').indexOf('fa-') > -1 ? true : false; + }, + // + switchVerticalArrow: function ($arrow) { + $arrow.toggleClass('fa-chevron-up').toggleClass('fa-chevron-down'); + }, + // + switchHorizontalArrow: function ($node) { + var opts = this.options; + if (opts.toggleSiblingsResp && (typeof opts.ajaxURL === 'undefined' || $node.closest('.nodes').data('siblingsLoaded'))) { + var $prevSib = $node.closest('table').parent().prev(); + if ($prevSib.length) { + if ($prevSib.is('.hidden')) { + $node.children('.leftEdge').addClass('fa-chevron-left').removeClass('fa-chevron-right'); + } else { + $node.children('.leftEdge').addClass('fa-chevron-right').removeClass('fa-chevron-left'); + } + } + var $nextSib = $node.closest('table').parent().next(); + if ($nextSib.length) { + if ($nextSib.is('.hidden')) { + $node.children('.rightEdge').addClass('fa-chevron-right').removeClass('fa-chevron-left'); + } else { + $node.children('.rightEdge').addClass('fa-chevron-left').removeClass('fa-chevron-right'); + } + } + } else { + var $sibs = $node.closest('table').parent().siblings(); + var sibsVisible = $sibs.length ? !$sibs.is('.hidden') : false; + $node.children('.leftEdge').toggleClass('fa-chevron-right', sibsVisible).toggleClass('fa-chevron-left', !sibsVisible); + $node.children('.rightEdge').toggleClass('fa-chevron-left', sibsVisible).toggleClass('fa-chevron-right', !sibsVisible); + } + }, + // + repaint: function (node) { + if (node) { + node.style.offsetWidth = node.offsetWidth; + } + }, + // load new nodes by ajax + loadNodes: function (rel, url, $edge) { + var that = this; + var opts = this.options; + $.ajax({ 'url': url, 'dataType': 'json' }) + .done(function (data) { + if (that.$chart.data('inAjax')) { + if (rel === 'parent') { + if (!$.isEmptyObject(data)) { + that.addParent($edge.parent(), data); + } + } else if (rel === 'children') { + if (data.children.length) { + that.addChildren($edge.parent(), data[rel]); + } + } else { + that.addSiblings($edge.parent(), data.siblings ? data.siblings : data); + } + } + }) + .fail(function () { + console.log('Failed to get ' + rel + ' data'); + }) + .always(function () { + that.endLoading($edge); + }); + }, + // + HideFirstParentEnd: function (event) { + var $topEdge = event.data.topEdge; + var $node = $topEdge.parent(); + if (this.isInAction($node)) { + this.switchVerticalArrow($topEdge); + this.switchHorizontalArrow($node); + } + }, + // + expandVNodesEnd: function (event) { + event.data.vNodes.removeClass('sliding'); + }, + // + collapseVNodesEnd: function (event) { + event.data.vNodes.removeClass('sliding').closest('ul').addClass('hidden'); + }, + // + createGhostNode: function (event) { + var $nodeDiv = $(event.target); + var opts = this.options; + var origEvent = event.originalEvent; + var isFirefox = /firefox/.test(window.navigator.userAgent.toLowerCase()); + var ghostNode, nodeCover; + if (!document.querySelector('.ghost-node')) { + ghostNode = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + ghostNode.classList.add('ghost-node'); + nodeCover = document.createElementNS('http://www.w3.org/2000/svg','rect'); + ghostNode.appendChild(nodeCover); + $nodeDiv.closest('.orgchart').append(ghostNode); + } else { + ghostNode = $nodeDiv.closest('.orgchart').children('.ghost-node').get(0); + nodeCover = $(ghostNode).children().get(0); + } + var transValues = $nodeDiv.closest('.orgchart').css('transform').split(','); + var isHorizontal = opts.direction === 't2b' || opts.direction === 'b2t'; + var scale = Math.abs(window.parseFloat(isHorizontal ? transValues[0].slice(transValues[0].indexOf('(') + 1) : transValues[1])); + ghostNode.setAttribute('width', isHorizontal ? $nodeDiv.outerWidth(false) : $nodeDiv.outerHeight(false)); + ghostNode.setAttribute('height', isHorizontal ? $nodeDiv.outerHeight(false) : $nodeDiv.outerWidth(false)); + nodeCover.setAttribute('x',5 * scale); + nodeCover.setAttribute('y',5 * scale); + nodeCover.setAttribute('width', 120 * scale); + nodeCover.setAttribute('height', 40 * scale); + nodeCover.setAttribute('rx', 4 * scale); + nodeCover.setAttribute('ry', 4 * scale); + nodeCover.setAttribute('stroke-width', 1 * scale); + var xOffset = origEvent.offsetX * scale; + var yOffset = origEvent.offsetY * scale; + if (opts.direction === 'l2r') { + xOffset = origEvent.offsetY * scale; + yOffset = origEvent.offsetX * scale; + } else if (opts.direction === 'r2l') { + xOffset = $nodeDiv.outerWidth(false) - origEvent.offsetY * scale; + yOffset = origEvent.offsetX * scale; + } else if (opts.direction === 'b2t') { + xOffset = $nodeDiv.outerWidth(false) - origEvent.offsetX * scale; + yOffset = $nodeDiv.outerHeight(false) - origEvent.offsetY * scale; + } + if (isFirefox) { // hack for old version of Firefox(< 48.0) + nodeCover.setAttribute('fill', 'rgb(255, 255, 255)'); + nodeCover.setAttribute('stroke', 'rgb(191, 0, 0)'); + var ghostNodeWrapper = document.createElement('img'); + ghostNodeWrapper.src = 'data:image/svg+xml;utf8,' + (new XMLSerializer()).serializeToString(ghostNode); + origEvent.dataTransfer.setDragImage(ghostNodeWrapper, xOffset, yOffset); + } else { + origEvent.dataTransfer.setDragImage(ghostNode, xOffset, yOffset); + } + }, + // + filterAllowedDropNodes: function ($dragged) { + var opts = this.options; + var $dragZone = $dragged.closest('.nodes').siblings().eq(0).find('.node:first'); + var $dragHier = $dragged.closest('table').find('.node'); + this.$chart.data('dragged', $dragged) + .find('.node').each(function (index, node) { + if ($dragHier.index(node) === -1) { + if (opts.dropCriteria) { + if (opts.dropCriteria($dragged, $dragZone, $(node))) { + $(node).addClass('allowedDrop'); + } + } else { + $(node).addClass('allowedDrop'); + } + } + }); + }, + // + dragstartHandler: function (event) { + event.originalEvent.dataTransfer.setData('text/html', 'hack for firefox'); + // if users enable zoom or direction options + if (this.$chart.css('transform') !== 'none') { + this.createGhostNode(event); + } + this.filterAllowedDropNodes($(event.target)); + }, + // + dragoverHandler: function (event) { + event.preventDefault(); + if (!$(event.delegateTarget).is('.allowedDrop')) { + event.originalEvent.dataTransfer.dropEffect = 'none'; + } + }, + // + dragendHandler: function (event) { + this.$chart.find('.allowedDrop').removeClass('allowedDrop'); + }, + // + dropHandler: function (event) { + var $dropZone = $(event.delegateTarget); + var $dragged = this.$chart.data('dragged'); + var $dragZone = $dragged.closest('.nodes').siblings().eq(0).children(); + var dropEvent = $.Event('nodedrop.orgchart'); + this.$chart.trigger(dropEvent, { 'draggedNode': $dragged, 'dragZone': $dragZone.children(), 'dropZone': $dropZone }); + if (dropEvent.isDefaultPrevented()) { + return; + } + // firstly, deal with the hierarchy of drop zone + if (!$dropZone.closest('tr').siblings().length) { // if the drop zone is a leaf node + $dropZone.append('<i class="edge verticalEdge bottomEdge fa"></i>') + .parent().attr('colspan', 2) + .parent().after('<tr class="lines"><td colspan="2"><div class="lineDown"></div></td></tr>' + + '<tr class="lines"><td class="lineRight"></td><td class="lineLeft"></td></tr>' + + '<tr class="nodes"></tr>') + .siblings(':last').append($dragged.find('.horizontalEdge').remove().end().closest('table').parent()); + } else { + var dropColspan = parseInt($dropZone.parent().attr('colspan')) + 2; + var horizontalEdges = '<i class="edge horizontalEdge rightEdge fa"></i><i class="edge horizontalEdge leftEdge fa"></i>'; + $dropZone.closest('tr').next().addBack().children().attr('colspan', dropColspan); + if (!$dragged.find('.horizontalEdge').length) { + $dragged.append(horizontalEdges); + } + $dropZone.closest('tr').siblings().eq(1).children(':last').before('<td class="lineLeft lineTop"></td><td class="lineRight lineTop"></td>') + .end().next().append($dragged.closest('table').parent()); + var $dropSibs = $dragged.closest('table').parent().siblings().find('.node:first'); + if ($dropSibs.length === 1) { + $dropSibs.append(horizontalEdges); + } + } + // secondly, deal with the hierarchy of dragged node + var dragColspan = parseInt($dragZone.attr('colspan')); + if (dragColspan > 2) { + $dragZone.attr('colspan', dragColspan - 2) + .parent().next().children().attr('colspan', dragColspan - 2) + .end().next().children().slice(1, 3).remove(); + var $dragSibs = $dragZone.parent().siblings('.nodes').children().find('.node:first'); + if ($dragSibs.length ===1) { + $dragSibs.find('.horizontalEdge').remove(); + } + } else { + $dragZone.removeAttr('colspan') + .find('.bottomEdge').remove() + .end().end().siblings().remove(); + } + }, + // + touchstartHandler: function (event) { + console.log("orgChart: touchstart 1: touchHandled=" + this.touchHandled + ", touchMoved=" + this.touchMoved + ", target=" + event.target.innerText); + if (this.touchHandled) + return; + this.touchHandled = true; + this.touchMoved = false; // this is so we can work out later if this was a 'press' or a 'drag' touch + event.preventDefault(); + }, + // + touchmoveHandler: function (event) { + if (!this.touchHandled) + return; + event.preventDefault(); + if (!this.touchMoved) { + var nodeIsSelected = $(this).hasClass('focused'); + console.log("orgChart: touchmove 1: " + event.touches.length + " touches, we have not moved, so simulate a drag start", event.touches); + // TODO: visualise the start of the drag (as would happen on desktop) + this.simulateMouseEvent(event, 'dragstart'); + } + this.touchMoved = true; + var $touching = $(document.elementFromPoint(event.touches[0].clientX, event.touches[0].clientY)); + var $touchingNode = $touching.closest('div.node'); + + if ($touchingNode.length > 0) { + var touchingNodeElement = $touchingNode[0]; + // TODO: simulate the dragover visualisation + if ($touchingNode.is('.allowedDrop')) { + console.log("orgChart: touchmove 2: this node (" + touchingNodeElement.id + ") is allowed to be a drop target"); + this.touchTargetNode = touchingNodeElement; + } else { + console.log("orgChart: touchmove 3: this node (" + touchingNodeElement.id + ") is NOT allowed to be a drop target"); + this.touchTargetNode = null; + } + } else { + console.log("orgchart: touchmove 4: not touching a node"); + this.touchTargetNode = null; + } + }, + // + touchendHandler: function (event) { + console.log("orgChart: touchend 1: touchHandled=" + this.touchHandled + ", touchMoved=" + this.touchMoved + ", " + event.target.innerText + " "); + if (!this.touchHandled) { + console.log("orgChart: touchend 2: not handled by us, so aborting"); + return; + } + if (this.touchMoved) { + // we've had movement, so this was a 'drag' touch + if (this.touchTargetNode) { + console.log("orgChart: touchend 3: moved to a node, so simulating drop"); + var fakeEventForDropHandler = { delegateTarget: this.touchTargetNode }; + this.dropHandler(fakeEventForDropHandler); + this.touchTargetNode = null; + } + console.log("orgChart: touchend 4: simulating dragend"); + this.simulateMouseEvent(event, 'dragend'); + } + else { + // we did not move, so assume this was a 'press' touch + console.log("orgChart: touchend 5: moved, so simulating click"); + this.simulateMouseEvent(event, 'click'); + } + this.touchHandled = false; + }, + // simulate a mouse event (so we can fake them on a touch device) + simulateMouseEvent: function (event, simulatedType) { + // Ignore multi-touch events + if (event.originalEvent.touches.length > 1) { + return; + } + var touch = event.originalEvent.changedTouches[0]; + var simulatedEvent = document.createEvent('MouseEvents'); + simulatedEvent.initMouseEvent( + simulatedType, // type + true, // bubbles + true, // cancelable + window, // view + 1, // detail + touch.screenX, // screenX + touch.screenY, // screenY + touch.clientX, // clientX + touch.clientY, // clientY + false, // ctrlKey + false, // altKey + false, // shiftKey + false, // metaKey + 0, // button + null // relatedTarget + ); + // Dispatch the simulated event to the target element + event.target.dispatchEvent(simulatedEvent); + }, + // + bindDragDrop: function ($node) { + $node.on('dragstart', this.dragstartHandler.bind(this)) + .on('dragover', this.dragoverHandler.bind(this)) + .on('dragend', this.dragendHandler.bind(this)) + .on('drop', this.dropHandler.bind(this)) + .on('touchstart', this.touchstartHandler.bind(this)) + .on('touchmove', this.touchmoveHandler.bind(this)) + .on('touchend', this.touchendHandler.bind(this)); + }, + // create node + createNode: function (data) { + var that = this; + var opts = this.options; + var level = data.level; + if (data.children) { + $.each(data.children, function (index, child) { + child.parentId = data.id; + }); + } + // construct the content of node + var $nodeDiv = $('<div' + (opts.draggable ? ' draggable="true"' : '') + (data[opts.nodeId] ? ' id="' + data[opts.nodeId] + '"' : '') + (data.parentId ? ' data-parent="' + data.parentId + '"' : '') + '>') + .addClass('node ' + (data.className || '') + (level > opts.visibleLevel ? ' slide-up' : '')); + if (opts.nodeTemplate) { + $nodeDiv.append(opts.nodeTemplate(data)); + } else { + $nodeDiv.append('<div class="title">' + data[opts.nodeTitle] + '</div>') + .append(typeof opts.nodeContent !== 'undefined' ? '<div class="content">' + (data[opts.nodeContent] || '') + '</div>' : ''); + } + // + var nodeData = $.extend({}, data); + delete nodeData.children; + $nodeDiv.data('nodeData', nodeData); + // append 4 direction arrows or expand/collapse buttons + var flags = data.relationship || ''; + if (opts.verticalLevel && level >= opts.verticalLevel) { + if ((level + 1) > opts.verticalLevel && Number(flags.substr(2,1))) { + var icon = level + 1 > opts.visibleLevel ? 'plus' : 'minus'; + $nodeDiv.append('<i class="toggleBtn fa fa-' + icon + '-square"></i>'); + } + } else { + if (Number(flags.substr(0,1))) { + $nodeDiv.append('<i class="edge verticalEdge topEdge fa"></i>'); + } + if(Number(flags.substr(1,1))) { + $nodeDiv.append('<i class="edge horizontalEdge rightEdge fa"></i>' + + '<i class="edge horizontalEdge leftEdge fa"></i>'); + } + if(Number(flags.substr(2,1))) { + $nodeDiv.append('<i class="edge verticalEdge bottomEdge fa"></i>') + .children('.title').prepend('<i class="fa '+ opts.parentNodeSymbol + ' symbol"></i>'); + } + } + + if (opts.draggable) { + this.bindDragDrop($nodeDiv); + this.touchHandled = false; + this.touchMoved = false; + this.touchTargetNode = null; + } + // allow user to append dom modification after finishing node create of orgchart + if (opts.createNode) { + opts.createNode($nodeDiv, data); + } + + return $nodeDiv; + }, + // recursively build the tree + buildHierarchy: function ($appendTo, data) { + var that = this; + var opts = this.options; + var level = 0; + if (data.level) { + level = data.level; + } else { + level = data.level = $appendTo.parentsUntil('.orgchart', '.nodes').length + 1; + } + // Construct the node + var childrenData = data.children; + var hasChildren = childrenData ? childrenData.length : false; + var $nodeWrapper; + if (Object.keys(data).length > 2) { + var $nodeDiv = this.createNode(data); + if (opts.verticalLevel && level >= opts.verticalLevel) { + $appendTo.append($nodeDiv); + }else { + $nodeWrapper = $('<table>'); + $appendTo.append($nodeWrapper.append($('<tr/>').append($('<td' + (hasChildren ? ' colspan="' + childrenData.length * 2 + '"' : '') + '></td>').append($nodeDiv)))); + } + } + // Construct the lower level(two "connectiong lines" rows and "inferior nodes" row) + if (hasChildren) { + var isHidden = (level + 1 > opts.visibleLevel || data.collapsed) ? ' hidden' : ''; + var isVerticalLayer = (opts.verticalLevel && (level + 1) >= opts.verticalLevel) ? true : false; + var $nodesLayer; + if (isVerticalLayer) { + $nodesLayer = $('<ul>'); + if (isHidden && level + 1 > opts.verticalLevel) { + $nodesLayer.addClass(isHidden); + } + if (level + 1 === opts.verticalLevel) { + $appendTo.children('table').append('<tr class="verticalNodes' + isHidden + '"><td></td></tr>') + .find('.verticalNodes').children().append($nodesLayer); + } else { + $appendTo.append($nodesLayer); + } + } else { + var $upperLines = $('<tr class="lines' + isHidden + '"><td colspan="' + childrenData.length * 2 + '"><div class="lineDown"></div></td></tr>'); + var lowerLines = '<tr class="lines' + isHidden + '"><td class="lineRight"></td>'; + for (var i=1; i<childrenData.length; i++) { + lowerLines += '<td class="lineLeft lineTop"></td><td class="lineRight lineTop"></td>'; + } + lowerLines += '<td class="lineLeft"></td></tr>'; + $nodesLayer = $('<tr class="nodes' + isHidden + '">'); + if (Object.keys(data).length === 2) { + $appendTo.append($upperLines).append(lowerLines).append($nodesLayer); + } else { + $nodeWrapper.append($upperLines).append(lowerLines).append($nodesLayer); + } + } + // recurse through children nodes + $.each(childrenData, function () { + var $nodeCell = isVerticalLayer ? $('<li>') : $('<td colspan="2">'); + $nodesLayer.append($nodeCell); + this.level = level + 1; + that.buildHierarchy($nodeCell, this); + }); + } + }, + // build the child nodes of specific node + buildChildNode: function ($appendTo, data) { + $appendTo.find('td:first').attr('colspan', data.length * 2); + this.buildHierarchy($appendTo, { 'children': data }); + }, + // exposed method + addChildren: function ($node, data) { + this.buildChildNode($node.closest('table'), data); + if (!$node.children('.bottomEdge').length) { + $node.append('<i class="edge verticalEdge bottomEdge fa"></i>'); + } + if (!$node.find('.symbol').length) { + $node.children('.title').prepend('<i class="fa '+ this.options.parentNodeSymbol + ' symbol"></i>'); + } + if (this.isInAction($node)) { + this.switchVerticalArrow($node.children('.bottomEdge')); + } + }, + // build the parent node of specific node + buildParentNode: function ($currentRoot, data) { + data.relationship = data.relationship || '001'; + var $table = $('<table>') + .append($('<tr>').append($('<td colspan="2">').append(this.createNode(data)))) + .append('<tr class="lines"><td colspan="2"><div class="lineDown"></div></td></tr>') + .append('<tr class="lines"><td class="lineRight"></td><td class="lineLeft"></td></tr>'); + this.$chart.prepend($table) + .children('table:first').append('<tr class="nodes"><td colspan="2"></td></tr>') + .children('tr:last').children().append(this.$chart.children('table').last()); + }, + // exposed method + addParent: function ($currentRoot, data) { + this.buildParentNode($currentRoot, data); + if (!$currentRoot.children('.topEdge').length) { + $currentRoot.children('.title').after('<i class="edge verticalEdge topEdge fa"></i>'); + } + if (this.isInAction($currentRoot)) { + this.switchVerticalArrow($currentRoot.children('.topEdge')); + } + }, + // subsequent processing of build sibling nodes + complementLine: function ($oneSibling, siblingCount, existingSibligCount) { + var lines = ''; + for (var i = 0; i < existingSibligCount; i++) { + lines += '<td class="lineLeft lineTop"></td><td class="lineRight lineTop"></td>'; + } + $oneSibling.parent().prevAll('tr:gt(0)').children().attr('colspan', siblingCount * 2) + .end().next().children(':first').after(lines); + }, + // build the sibling nodes of specific node + buildSiblingNode: function ($nodeChart, data) { + var newSiblingCount = $.isArray(data) ? data.length : data.children.length; + var existingSibligCount = $nodeChart.parent().is('td') ? $nodeChart.closest('tr').children().length : 1; + var siblingCount = existingSibligCount + newSiblingCount; + var insertPostion = (siblingCount > 1) ? Math.floor(siblingCount/2 - 1) : 0; + // just build the sibling nodes for the specific node + if ($nodeChart.parent().is('td')) { + var $parent = $nodeChart.closest('tr').prevAll('tr:last'); + $nodeChart.closest('tr').prevAll('tr:lt(2)').remove(); + this.buildChildNode($nodeChart.parent().closest('table'), data); + var $siblingTds = $nodeChart.parent().closest('table').children('tr:last').children('td'); + if (existingSibligCount > 1) { + this.complementLine($siblingTds.eq(0).before($nodeChart.closest('td').siblings().addBack().unwrap()), siblingCount, existingSibligCount); + } else { + this.complementLine($siblingTds.eq(insertPostion).after($nodeChart.closest('td').unwrap()), siblingCount, 1); + } + } else { // build the sibling nodes and parent node for the specific ndoe + this.buildHierarchy($nodeChart.closest('.orgchart'), data); + this.complementLine($nodeChart.next().children('tr:last').children().eq(insertPostion).after($('<td colspan="2">').append($nodeChart)), + siblingCount, 1); + } + }, + // + addSiblings: function ($node, data) { + this.buildSiblingNode($node.closest('table'), data); + $node.closest('.nodes').data('siblingsLoaded', true); + if (!$node.children('.leftEdge').length) { + $node.children('.topEdge').after('<i class="edge horizontalEdge rightEdge fa"></i><i class="edge horizontalEdge leftEdge fa"></i>'); + } + if (this.isInAction($node)) { + this.switchHorizontalArrow($node); + $node.children('.topEdge').removeClass('fa-chevron-up').addClass('fa-chevron-down'); + } + }, + // + removeNodes: function ($node) { + var $parent = $node.closest('table').parent(); + var $sibs = $parent.parent().siblings(); + if ($parent.is('td')) { + if (this.getNodeState($node, 'siblings').exist) { + $sibs.eq(2).children('.lineTop:lt(2)').remove(); + $sibs.slice(0, 2).children().attr('colspan', $sibs.eq(2).children().length); + $parent.remove(); + } else { + $sibs.eq(0).children().removeAttr('colspan') + .find('.bottomEdge').remove() + .end().end().siblings().remove(); + } + } else { + $parent.add($parent.siblings()).remove(); + } + }, + // + export: function (exportFilename, exportFileextension) { + var that = this; + exportFilename = (typeof exportFilename !== 'undefined') ? exportFilename : this.options.exportFilename; + exportFileextension = (typeof exportFileextension !== 'undefined') ? exportFileextension : this.options.exportFileextension; + if ($(this).children('.spinner').length) { + return false; + } + var $chartContainer = this.$chartContainer; + var $mask = $chartContainer.find('.mask'); + if (!$mask.length) { + $chartContainer.append('<div class="mask"><i class="fa fa-circle-o-notch fa-spin spinner"></i></div>'); + } else { + $mask.removeClass('hidden'); + } + var sourceChart = $chartContainer.addClass('canvasContainer').find('.orgchart:not(".hidden")').get(0); + var flag = that.options.direction === 'l2r' || that.options.direction === 'r2l'; + html2canvas(sourceChart, { + 'width': flag ? sourceChart.clientHeight : sourceChart.clientWidth, + 'height': flag ? sourceChart.clientWidth : sourceChart.clientHeight, + 'onclone': function (cloneDoc) { + $(cloneDoc).find('.canvasContainer').css('overflow', 'visible') + .find('.orgchart:not(".hidden"):first').css('transform', ''); + }, + 'onrendered': function (canvas) { + $chartContainer.find('.mask').addClass('hidden'); + if (exportFileextension.toLowerCase() === 'pdf') { + var doc = {}; + var docWidth = Math.floor(canvas.width * 0.2646); + var docHeight = Math.floor(canvas.height * 0.2646); + if (docWidth > docHeight) { + doc = new jsPDF('l', 'mm', [docWidth, docHeight]); + } else { + doc = new jsPDF('p', 'mm', [docHeight, docWidth]); + } + doc.addImage(canvas.toDataURL(), 'png', 0, 0); + doc.save(exportFilename + '.pdf'); + } else { + var isWebkit = 'WebkitAppearance' in document.documentElement.style; + var isFf = !!window.sidebar; + var isEdge = navigator.appName === 'Microsoft Internet Explorer' || (navigator.appName === "Netscape" && navigator.appVersion.indexOf('Edge') > -1); + + if ((!isWebkit && !isFf) || isEdge) { + window.navigator.msSaveBlob(canvas.msToBlob(), exportFilename + '.png'); + } else { + var selector = '.oc-download-btn' + (that.options.chartClass !== '' ? '.' + that.options.chartClass : ''); + if (!$chartContainer.find(selector).length) { + $chartContainer.append('<a class="oc-download-btn' + (that.options.chartClass !== '' ? ' ' + that.options.chartClass : '') + '"' + + ' download="' + exportFilename + '.png"></a>'); + } + $chartContainer.find(selector).attr('href', canvas.toDataURL())[0].click(); + } + } + } + }) + .then(function () { + $chartContainer.removeClass('canvasContainer'); + }, function () { + $chartContainer.removeClass('canvasContainer'); + }); + } + }; + + $.fn.orgchart = function (opts) { + return new OrgChart(this, opts).init(); + }; + +})); diff --git a/hr_organizational_chart/static/src/css/hr_orgchart.css b/hr_organizational_chart/static/src/css/hr_orgchart.css new file mode 100644 index 0000000..58815b8 --- /dev/null +++ b/hr_organizational_chart/static/src/css/hr_orgchart.css @@ -0,0 +1,474 @@ +/* + * jQuery OrgChart Plugin + * https://github.com/dabeng/OrgChart + * + * Copyright 2016, dabeng + * https://github.com/dabeng + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +.orgchart { + box-sizing: border-box; + display: inline-block; + min-height: 202px; + min-width: 202px; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-size: 10px 10px; + border: 1px dashed rgba(0,0,0,0); + padding: 20px; +} + +.orgchart .hidden, .orgchart~.hidden { + display: none; +} + +.orgchart.b2t { + transform: rotate(180deg); +} + +.orgchart.l2r { + position: absolute; + transform: rotate(-90deg) rotateY(180deg); + transform-origin: left top; +} + +.orgchart .verticalNodes ul { + list-style: none; + margin: 0; + padding-left: 18px; + text-align: left; +} +.orgchart .verticalNodes ul:first-child { + margin-top: 2px; +} +.orgchart .verticalNodes>td::before { + content: ''; + border: 1px solid rgba(217, 83, 79, 0.8); +} +.orgchart .verticalNodes>td>ul>li:first-child::before { + box-sizing: border-box; + top: -4px; + height: 30px; + width: calc(50% - 2px); + border-width: 2px 0 0 2px; +} +.orgchart .verticalNodes ul>li { + position: relative; +} +.orgchart .verticalNodes ul>li::before, +.orgchart .verticalNodes ul>li::after { + box-sizing: border-box; + content: ''; + position: absolute; + left: -6px; + border-color: rgba(217, 83, 79, 0.8); + border-style: solid; + border-width: 0 0 2px 2px; +} +.orgchart .verticalNodes ul>li::before { + top: -4px; + height: 30px; + width: 11px; +} +.orgchart .verticalNodes ul>li::after { + top: 1px; + height: 100%; +} +.orgchart .verticalNodes ul>li:first-child::after { + box-sizing: border-box; + top: 24px; + width: 11px; + border-width: 2px 0 0 2px; +} +.orgchart .verticalNodes ul>li:last-child::after { + box-sizing: border-box; + border-width: 2px 0 0; +} + +.orgchart.r2l { + position: absolute; + transform: rotate(90deg); + transform-origin: left top; +} + +.orgchart>.spinner { + font-size: 100px; + margin-top: 30px; + color: rgba(68, 157, 68, 0.8); +} + +.orgchart table { + border-spacing: 0; + border-collapse: separate; +} + +.orgchart>table:first-child{ + margin: 20px auto; +} + +.orgchart td { + text-align: center; + vertical-align: top; + padding: 0; +} + +.orgchart .lines:nth-child(3) td { + box-sizing: border-box; + height: 20px; +} + +.orgchart .lines .lineTop { + border-top: 2px solid #acacac; +} + +.orgchart .lines .lineRight { + border-right: 1px solid #acacac; + float: none; + border-radius: 0; +} + +.orgchart .lines .lineLeft { + border-left: 1px solid #acacac; + float: none; + border-radius: 0; +} + +.orgchart .lines .lineDown { + background-color: #acacac; + margin: 0 auto; + height: 20px; + width: 2px; + float: none; +} + +/* node styling */ +.orgchart .node { + box-sizing: border-box; + display: inline-block; + position: relative; + margin: 0; + padding: 3px; + border: 2px dashed transparent; + text-align: center; + width: 160px; +} + +.orgchart.l2r .node, .orgchart.r2l .node { + width: 50px; + height: 130px; +} + +.orgchart .node>.spinner { + position: absolute; + top: calc(50% - 15px); + left: calc(50% - 15px); + vertical-align: middle; + font-size: 30px; + color: rgba(68, 157, 68, 0.8); +} + +.orgchart .node:hover { + transition: .5s; + cursor: default; + z-index: 20; +} + +.orgchart .node.focused { + background-color: rgba(238, 217, 54, 0.5); +} + +.orgchart .ghost-node { + position: fixed; + left: -10000px; + top: -10000px; +} + +.orgchart .ghost-node rect { + fill: #ffffff; + stroke: #bf0000; +} + +.orgchart .node.allowedDrop { + border-color: rgba(68, 157, 68, 0.9); +} + +.orgchart .node .title { + text-align: center; + font-size: 10px; + font-weight: bold; + height: 20px; + line-height: 20px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + background-color: #e3e3e3; + color: #fff; + border-radius:0; +} + +.orgchart.b2t .node .title { + transform: rotate(-180deg); + transform-origin: center bottom; +} + +.orgchart.l2r .node .title { + transform: rotate(-90deg) translate(-40px, -40px) rotateY(180deg); + transform-origin: bottom center; + width: 120px; +} + +.orgchart.r2l .node .title { + transform: rotate(-90deg) translate(-40px, -40px); + transform-origin: bottom center; + width: 120px; +} + +.orgchart .node .title .symbol { + float: left; + margin-top: 4px; + margin-left: 2px; +} + + +.orgchart.b2t .node .content { + transform: rotate(180deg); + transform-origin: center top; +} + +.orgchart.l2r .node .content { + transform: rotate(-90deg) translate(-40px, -40px) rotateY(180deg); + transform-origin: top center; + width: 120px; +} + +.orgchart.r2l .node .content { + transform: rotate(-90deg) translate(-40px, -40px); + transform-origin: top center; + width: 120px; +} + +.orgchart .node .edge { + font-size: 15px; + position: absolute; + color: rgba(68, 157, 68, 0.5); + cursor: default; + transition: .2s; +} + +.orgchart.noncollapsable .node .edge { + display: none; +} + +.orgchart .edge:hover { + color: #449d44; + cursor: pointer; +} + +.orgchart .node .verticalEdge { + width: calc(100% - 10px); + width: -webkit-calc(100% - 10px); + width: -moz-calc(100% - 10px); + left: 5px; +} + +.orgchart .node .topEdge { + top: -4px; +} + +.orgchart .node .bottomEdge { + bottom: -4px; +} + +.orgchart .node .horizontalEdge { + width: 15px; + height: calc(100% - 10px); + height: -webkit-calc(100% - 10px); + height: -moz-calc(100% - 10px); + top: 5px; +} + +.orgchart .node .rightEdge { + right: -4px; +} + +.orgchart .node .leftEdge { + left: -4px; +} + +.orgchart .node .horizontalEdge::before { + position: absolute; + top: calc(50% - 7px); +} + +.orgchart .node .rightEdge::before { + right: 3px; +} + +.orgchart .node .leftEdge::before { + left: 3px; +} + +.orgchart .node .toggleBtn { + position: absolute; + left: 5px; + bottom: -2px; + color: rgba(68, 157, 68, 0.6); +} + +.orgchart .node .toggleBtn:hover { + color: rgba(68, 157, 68, 0.8); +} + +.oc-export-btn { + display: inline-block; + position: absolute; + right: 5px; + top: 5px; + padding: 6px 12px; + margin-bottom: 0; + font-size: 14px; + font-weight: 400; + line-height: 1.42857143; + text-align: center; + white-space: nowrap; + vertical-align: middle; + touch-action: manipulation; + cursor: pointer; + user-select: none; + color: #fff; + background-color: #5cb85c; + border: 1px solid transparent; + border-color: #4cae4c; + border-radius: 4px; +} + +.oc-export-btn[disabled] { + cursor: not-allowed; + box-shadow: none; + opacity: 0.3; +} + +.oc-export-btn:hover,.oc-export-btn:focus,.oc-export-btn:active { + background-color: #449d44; + border-color: #347a34; +} + +.orgchart~.mask { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 999; + text-align: center; + background-color: rgba(0,0,0,0.3); +} + +.orgchart~.mask .spinner { + position: absolute; + top: calc(50% - 54px); + left: calc(50% - 54px); + color: rgba(255,255,255,0.8); + font-size: 108px; +} + +.orgchart .node { + transition: transform 0.3s, opacity 0.3s; +} + +.orgchart .slide-down { + opacity: 0; + transform: translateY(40px); +} + +.orgchart.l2r .node.slide-down, .orgchart.r2l .node.slide-down { + transform: translateY(130px); +} + +.orgchart .slide-up { + opacity: 0; + transform: translateY(-40px); +} + +.orgchart.l2r .node.slide-up, .orgchart.r2l .node.slide-up { + transform: translateY(-130px); +} + +.orgchart .slide-right { + opacity: 0; + transform: translateX(130px); +} + +.orgchart.l2r .node.slide-right, .orgchart.r2l .node.slide-right { + transform: translateX(40px); +} + +.orgchart .slide-left { + opacity: 0; + transform: translateX(-130px); +} + +.orgchart.l2r .node.slide-left, .orgchart.r2l .node.slide-left { + transform: translateX(-40px); +} +.orgchart .middle-level .title { + + background-color: #e3e3e3; + +} +.orgchart .middle-level .content { + + border-color: #e3e3e3; + +} +.orgchart .node .content { + + box-sizing: border-box; + width: 100%; + height: 20px; + font-size: 9px; + line-height: 18px; + + border-radius: 0; + text-align: center; + background-color: #e3e3e3; + color: #333; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + padding: 0 9px 24px; + +} +.orgchart .node .title { + + text-align: center; + font-size: 11px; + font-weight: bold; + height: 16px; + line-height: 24px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + background-color: #e3e3e3; + color: #353535; + border-radius: 0px; + +} +.office > img { + + width: 50px; + height: 50px; + border-radius: 50%; + margin-bottom: 4px; + +} +#chart-container ~ .o_content { +display: none; +}
\ No newline at end of file diff --git a/hr_organizational_chart/static/src/css/style.css b/hr_organizational_chart/static/src/css/style.css new file mode 100644 index 0000000..05d3a35 --- /dev/null +++ b/hr_organizational_chart/static/src/css/style.css @@ -0,0 +1,42 @@ +html,body { + width: 100%; + height: 100%; + margin: 0; + padding: 0; +} + +body { + line-height: 1.428571429; + color: #333333; +} + +#chart-container { + display: inline-block; + text-align: center; + height: 100vh; + width: 100%; + overflow: auto; + +} +.o_org_chart_title.mb16.mt0 { + + color: #4661ae; + border-block-color: blue; + margin-top: 39px !important; + font-size: 22px; + +} + + +.orgchart td.left, .orgchart td.right, .orgchart td.top { border-color: #aaa; } +.orgchart td>.down { background-color: #aaa; } +.orgchart .middle-level .title { background-color: #e3e3e3; } +.orgchart .middle-level .content { border-color: #e3e3e3; } +.orgchart .product-dept .title { background-color: #e3e3e3; } +.orgchart .product-dept .content { border-color: #e3e3e3; } +.orgchart .rd-dept .title { background-color: #e3e3e3; } +.orgchart .rd-dept .content { border-color: #e3e3e3; } +.orgchart .pipeline1 .title { background-color: #e3e3e3; } +.orgchart .pipeline1 .content { border-color: #e3e3e3; } +.orgchart .frontend1 .title { background-color: #e3e3e3; } +.orgchart .frontend1 .content { border-color: #e3e3e3; } diff --git a/hr_organizational_chart/static/src/img/default_image.png b/hr_organizational_chart/static/src/img/default_image.png Binary files differnew file mode 100644 index 0000000..6557e68 --- /dev/null +++ b/hr_organizational_chart/static/src/img/default_image.png diff --git a/hr_organizational_chart/static/src/js/organizational_view.js b/hr_organizational_chart/static/src/js/organizational_view.js new file mode 100644 index 0000000..a0942a3 --- /dev/null +++ b/hr_organizational_chart/static/src/js/organizational_view.js @@ -0,0 +1,100 @@ +odoo.define('hr_organizational_chart.view_chart', function (require){ +"use strict"; +var AbstractAction = require('web.AbstractAction'); +var ajax = require('web.ajax'); +var core = require('web.core'); +var rpc = require('web.rpc'); +var ActionManager = require('web.ActionManager'); +var _t = core._t; + + +var EmployeeOrganizationalChart = AbstractAction.extend({ + + contentTemplate: 'OrganizationalEmployeeChart', + events: { + 'click img': '_getChild_data', + 'click .employee_name': 'view_employee', + }, + + init: function(parent, context) { + this._super(parent, context); + this.renderEmployeeDetails(); + }, + renderEmployeeDetails: function (){ + var employee_id = 1 + var self = this; + this._rpc({ + route: '/get/parent/employee', + }).then(function (result) { + self.parent_len = result[1]; + $.ajax({ + url: '/get/parent/child', + type: 'POST', + data: JSON.stringify(result[0]), + success: function (value) { + $('#o_parent_employee').append(value); + }, + }); + + }); + + }, + _getChild_data: function(events){ + console.log(events) + if(events.target.parentElement.className){ + var self = this + this.id = events.target.parentElement.id; + this.check_child = $( "#"+this.id+".o_level_1" ); + if (this.check_child[0]){ + this.colspan_td = this.check_child[0].parentElement.parentElement + this.tbody_child = this.colspan_td.parentElement.parentElement + var child_length = this.tbody_child.children.length + if (child_length == 1){ + this._rpc({ + route: '/get/parent/colspan', + params: { + emp_id: parseInt(this.id), + }, + }).then(function (col_val){ + if (col_val){ + self.colspan_td.colSpan = col_val; + } + }); + this._rpc({ + route: '/get/child/data', + params: { + click_id: parseInt(this.id), + }, + }).then(function (result){ + if (result){ + $(result).appendTo(self.tbody_child); + } + }); + } + else{ + for(var i = 0;i < 3; i++){ + this.tbody_child.children[1].remove(); + } + self.colspan_td.colSpan = 2; + } + + } + } + }, + view_employee: function(ev){ + if (ev.target.parentElement.className){ + var id = parseInt(ev.target.parentElement.parentElement.children[0].id) + this.do_action({ + name: _t("Employee"), + type: 'ir.actions.act_window', + res_model: 'hr.employee', + res_id: id, + view_mode: 'form', + views: [[false, 'form']], + }) + } + }, +}); + core.action_registry.add('organization_dashboard', EmployeeOrganizationalChart); + +}); diff --git a/hr_organizational_chart/static/src/scss/chart_view.scss b/hr_organizational_chart/static/src/scss/chart_view.scss new file mode 100644 index 0000000..3fd82f2 --- /dev/null +++ b/hr_organizational_chart/static/src/scss/chart_view.scss @@ -0,0 +1,73 @@ +.o_chart_head { + text-align: center; +} +.o_chart_head img { + width: 68px; + border: 3px solid #777; + border-radius: 100%; +} +.o_child_container { + display: flex; + justify-content: center; + text-align: center; + margin-top: 4rem; +} +.o_level_1 img { + width: 68px; + border: 3px solid #777; + border-radius: 100%; +} +.o_level_1 { + margin: 15px; + min-width: 100px; +} + +.empchart table { + border-spacing: 0; + border-collapse: separate; +} + +.empchart td { + text-align: center; + padding: 0; + vertical-align: top; +} + +.empchart .lines:nth-child(3) td { + height: 20px; + box-sizing: border-box; +} + +.empchart .lines .leftLine { + border-left: 1px solid rgb(89, 87, 87); + float: none; + border-radius: 0; +} + +.empchart .lines .topLine { + border-top: 2px solid rgb(89, 87, 87); +} + +.empchart .lines .downLine { + background-color: rgb(89, 87, 87); + float: none; + margin: 0 auto; + width: 2px; + height: 20px; +} + +.empchart .lines .rightLine { + border-right: 1px solid rgb(89, 87, 87); + float: none; + border-radius: 0; +} + +.employee_name p:nth-child(1) { + font-weight: 600; + margin-bottom: -2px; + margin-top: 7px; +} +#o_organizational_chart .o_org_chart_title.mb16.mt0 { + background-color: darkgray; + padding: 17px; +}
\ No newline at end of file diff --git a/hr_organizational_chart/static/src/xml/chart_view.xml b/hr_organizational_chart/static/src/xml/chart_view.xml new file mode 100644 index 0000000..ebdfbb9 --- /dev/null +++ b/hr_organizational_chart/static/src/xml/chart_view.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<templates id="template" xml:space="preserve"> + + <t t-name="OrganizationalEmployeeChart"> + <div id="o_organizational_chart"> + <h4 class="o_org_chart_title mb16 mt0" align="center">Organization Chart</h4> + <center> + <div id="o_parent_employee" class="empchart"> + + </div> + </center> + </div> + + + + + </t> + + </templates> + diff --git a/hr_organizational_chart/static/src/xml/hr_org_chart_template.xml b/hr_organizational_chart/static/src/xml/hr_org_chart_template.xml new file mode 100644 index 0000000..71ad1a0 --- /dev/null +++ b/hr_organizational_chart/static/src/xml/hr_org_chart_template.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<templates xml:space="preserve"> + <t t-name="hr_organizational_chart.org_chart_template"> + <h4 class="o_org_chart_title mb16 mt0" align="center">Organization Chart</h4> + <div id="chart-container"></div> + <script type="text/javascript"> + $(function() { + <!-- Get Employee Data --> + var datascource = employee_data.values; + + var oc = $('#chart-container').orgchart({ + 'data' : datascource, + 'nodeTemplate': nodeTemplate, + 'toggleSiblingsResp': true + }); + + }); + </script> + </t> +</templates> |
