Nested Pages - Version 1.0

Version Description

  • Nested Pages

=

Download this release

Release Info

Developer kylephillips
Plugin Icon 128x128 Nested Pages
Version 1.0
Comparing to
See all releases

Version 1.0

Files changed (48) hide show
  1. assets/css/fonts/nestedpages.eot +0 -0
  2. assets/css/fonts/nestedpages.svg +23 -0
  3. assets/css/fonts/nestedpages.ttf +0 -0
  4. assets/css/fonts/nestedpages.woff +0 -0
  5. assets/css/nestedpages.css +1 -0
  6. assets/images/border.png +0 -0
  7. assets/images/loading-white.gif +0 -0
  8. assets/images/loading.gif +0 -0
  9. assets/js/lib/jquery.mjs.nestedSortable.js +664 -0
  10. assets/js/lib/jquery.ui.touch-punch.min.js +11 -0
  11. assets/js/lib/nestedpages.js +578 -0
  12. assets/js/nestedpages.min.js +1 -0
  13. assets/screenshot-1.png +0 -0
  14. assets/screenshot-2.png +0 -0
  15. assets/screenshot-3.gif +0 -0
  16. assets/screenshot-4.gif +0 -0
  17. assets/scss/_alerts.scss +11 -0
  18. assets/scss/_buttons.scss +51 -0
  19. assets/scss/_expand-handle.scss +28 -0
  20. assets/scss/_icons.scss +63 -0
  21. assets/scss/_mixins.scss +27 -0
  22. assets/scss/_page-listing.scss +309 -0
  23. assets/scss/_quick-edit.scss +143 -0
  24. assets/scss/_toggle-all.scss +29 -0
  25. assets/scss/_top-tools.scss +10 -0
  26. assets/scss/_variables.scss +12 -0
  27. assets/scss/nestedpages.scss +15 -0
  28. includes/class-nestedpages.php +63 -0
  29. includes/class-np-activate.php +89 -0
  30. includes/class-np-dependencies.php +79 -0
  31. includes/class-np-handler-base.php +108 -0
  32. includes/class-np-handler-quickedit.php +53 -0
  33. includes/class-np-handler-sort.php +43 -0
  34. includes/class-np-handler-syncmenu.php +39 -0
  35. includes/class-np-navmenu.php +112 -0
  36. includes/class-np-newpage.php +58 -0
  37. includes/class-np-pagelisting.php +220 -0
  38. includes/class-np-pagemeta.php +72 -0
  39. includes/class-np-postrepository.php +164 -0
  40. includes/class-np-validation.php +70 -0
  41. languages/index.php +2 -0
  42. languages/nestedpages.mo +0 -0
  43. languages/nestedpages.pot +179 -0
  44. nestedpages.php +32 -0
  45. readme.txt +109 -0
  46. views/pages.php +39 -0
  47. views/quickedit.php +137 -0
  48. views/row.php +92 -0
assets/css/fonts/nestedpages.eot ADDED
Binary file
assets/css/fonts/nestedpages.svg ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
3
+ <svg xmlns="http://www.w3.org/2000/svg">
4
+ <metadata>Generated by IcoMoon</metadata>
5
+ <defs>
6
+ <font id="nestedpages" horiz-adv-x="512">
7
+ <font-face units-per-em="512" ascent="480" descent="-32" />
8
+ <missing-glyph horiz-adv-x="512" />
9
+ <glyph unicode="&#x20;" d="" horiz-adv-x="256" />
10
+ <glyph unicode="&#xe600;" d="M102.4 198.4h230.4v76.8l128-102.4-128-102.4v76.8h-281.6v230.4h51.2v-179.2z" />
11
+ <glyph unicode="&#xe601;" d="M398.080 129.28l-56.064-52.736-87.552 93.44-93.184-87.808-52.736 55.808 93.184 87.808-87.552 93.184 55.808 52.736 87.808-93.184 93.184 87.552 52.48-55.808-93.184-87.808z" />
12
+ <glyph unicode="&#xe602;" d="M368.384 339.2l34.304-24.064-137.472-190.72h-34.304l-77.312 102.656 34.304 32 60.16-47.872z" />
13
+ <glyph unicode="&#xe603;" d="M435.2 300.8v51.2h-358.4v-51.2h358.4zM435.2 198.4v51.2h-358.4v-51.2h358.4zM435.2 96v51.2h-358.4v-51.2h358.4z" />
14
+ <glyph unicode="&#xe604;" d="M384 275.2l-103.168-153.6-101.632 153.6h204.8z" />
15
+ <glyph unicode="&#xe605;" d="M204.8 326.4l153.6-103.168-153.6-101.632v204.8z" />
16
+ <glyph unicode="&#xe606;" d="M32 384h448v-96h-448zM32 256h448v-96h-448zM32 128h448v-96h-448z" />
17
+ <glyph unicode="&#xe607;" d="M256 448c141.385 0 256-93.125 256-208s-114.615-208-256-208c-13.578 0-26.905 0.867-39.912 2.522-54.989-54.989-120.625-64.85-184.088-66.298v13.458c34.268 16.789 64 47.37 64 82.318 0 4.877-0.379 9.665-1.082 14.348-57.898 38.132-94.918 96.377-94.918 161.652 0 114.875 114.615 208 256 208z" />
18
+ <glyph unicode="&#xe608;" d="M432 480c44.182 0 80-35.817 80-80 0-18.010-5.955-34.629-16-48l-32-32-112 112 32 32c13.371 10.045 29.989 16 48 16zM32 112l-32-144 144 32 296 296-112 112-296-296zM357.789 298.211l-224-224-27.578 27.578 224 224 27.578-27.578z" />
19
+ <glyph unicode="&#xe609;" d="M296 256h-8v96c0 52.935-43.065 96-96 96h-64c-52.935 0-96-43.065-96-96v-96h-8c-13.2 0-24-10.8-24-24v-240c0-13.2 10.8-24 24-24h272c13.2 0 24 10.8 24 24v240c0 13.2-10.8 24-24 24zM192 32h-64l13.92 69.6c-8.404 5.766-13.92 15.437-13.92 26.4 0 17.673 14.327 32 32 32s32-14.327 32-32c0-10.963-5.516-20.634-13.92-26.4l13.92-69.6zM224 256h-128v96c0 17.645 14.355 32 32 32h64c17.645 0 32-14.355 32-32v-96z" />
20
+ <glyph unicode="&#xe60a;" d="M400 416h-288c-26.51 0-48-21.49-48-48v-16h384v16c0 26.51-21.49 48-48 48zM316.16 448l7.058-50.5h-134.436l7.057 50.5h120.321zM320 480h-128c-13.2 0-25.495-10.696-27.321-23.769l-9.357-66.962c-1.827-13.073 7.478-23.769 20.678-23.769h160c13.2 0 22.505 10.696 20.679 23.769l-9.357 66.962c-1.827 13.073-14.122 23.769-27.322 23.769v0zM408 320h-304c-17.6 0-30.696-14.341-29.103-31.869l26.206-288.263c1.593-17.527 17.297-31.868 34.897-31.868h240c17.6 0 33.304 14.341 34.897 31.868l26.205 288.263c1.594 17.528-11.502 31.869-29.102 31.869zM192 32h-48l-16 224h64v-224zM288 32h-64v224h64v-224zM368 32h-48v224h64l-16-224z" />
21
+ <glyph unicode="&#xe60b;" d="M256 384c-111.659 0-208.441-65.021-256-160 47.559-94.979 144.341-160 256-160 111.657 0 208.439 65.021 256 160-47.558 94.979-144.343 160-256 160zM382.225 299.148c30.081-19.187 55.571-44.887 74.717-75.148-19.146-30.261-44.637-55.961-74.718-75.149-37.797-24.108-81.445-36.851-126.224-36.851-44.78 0-88.428 12.743-126.225 36.852-30.080 19.186-55.57 44.886-74.717 75.148 19.146 30.262 44.637 55.962 74.717 75.148 1.959 1.25 3.938 2.461 5.929 3.65-4.979-13.664-7.704-28.411-7.704-43.798 0-70.692 57.308-128 128-128s128 57.308 128 128c0 15.387-2.725 30.134-7.704 43.799 1.99-1.189 3.969-2.401 5.929-3.651zM256 275c0-26.51-21.49-48-48-48s-48 21.49-48 48 21.49 48 48 48 48-21.49 48-48z" />
22
+ <glyph unicode="&#xe60c;" d="M419.661 331.792c38.822-27.515 70.685-64.546 92.339-107.792-47.561-94.979-144.343-160-256-160-31.283 0-61.396 5.106-89.589 14.542l38.978 38.978c16.529-3.65 33.486-5.52 50.611-5.52 44.779 0 88.427 12.743 126.223 36.852 30.081 19.188 55.572 44.888 74.718 75.149-18.526 29.283-43.007 54.275-71.825 73.247l34.545 34.544zM256 131c-11.362 0-22.376 1.488-32.864 4.267l156.593 156.592c2.781-10.486 4.271-21.497 4.271-32.859 0-70.692-57.308-128-128-128zM480 480h-26.869l-109.806-109.806c-27.538 8.962-56.877 13.806-87.325 13.806-111.659 0-208.441-65.021-256-160 21.329-42.596 52.564-79.154 90.597-106.534l-90.597-90.597v-26.869h26.869l453.131 453.131v26.869zM208 323c24.022 0 43.923-17.647 47.446-40.685l-54.762-54.762c-23.037 3.524-40.684 23.425-40.684 47.447 0 26.51 21.49 48 48 48zM55.058 224c19.146 30.262 44.637 55.962 74.717 75.148 1.959 1.25 3.938 2.461 5.929 3.65-4.979-13.664-7.704-28.411-7.704-43.798 0-29.262 9.825-56.224 26.349-77.781l-29.275-29.275c-28.036 18.821-51.877 43.386-70.016 72.056z" />
23
+ </font></defs></svg>
assets/css/fonts/nestedpages.ttf ADDED
Binary file
assets/css/fonts/nestedpages.woff ADDED
Binary file
assets/css/nestedpages.css ADDED
@@ -0,0 +1 @@
 
1
+ @font-face{font-family:'nestedpages';src:url('fonts/nestedpages.eot?-cjbqo6');src:url('fonts/nestedpages.eot?#iefix-cjbqo6') format('embedded-opentype'),url('fonts/nestedpages.woff?-cjbqo6') format('woff'),url('fonts/nestedpages.ttf?-cjbqo6') format('truetype'),url('fonts/nestedpages.svg?-cjbqo6#nestedpages') format('svg');font-weight:normal;font-style:normal;}[class^="np-icon-"],[class*=" np-icon-"]{font-family:'nestedpages';speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;}.np-icon-no:before{content:"\e601";}.np-icon-yes:before{content:"\e602";}.np-icon-menu:before{content:"\e603";}.np-icon-arrow-down:before{content:"\e604";}.np-icon-arrow-right:before{content:"\e605";}.np-icon-sub-menu:before{content:"\e600";}.np-icon-pencil:before{content:"\e608";}.np-icon-bubble:before{content:"\e607";}.np-icon-lock:before{content:"\e609";}.np-icon-remove:before{content:"\e60a";}.np-icon-menu2:before{content:"\e606";}.np-icon-eye:before{content:"\e60b";}.np-icon-eye-blocked:before{content:"\e60c";}.np-btn,.np-toggle-edit{text-decoration:none;color:#555;display:inline-block;background-color:#f7f7f7;border:1px solid #e1e1e1;padding:3px 8px;-webkit-box-shadow:inset 0 1px 0 #fff,0 1px 0 rgba(0, 0, 0, 0.08);box-shadow:inset 0 1px 0 #fff,0 1px 0 rgba(0, 0, 0, 0.08);-webkit-transition:all 200ms ease;-o-transition:all 200ms ease;transition:all 200ms ease;}.np-btn:hover,.np-toggle-edit:hover{background-color:#0074a2;color:#ffffff;-webkit-transition:all 200ms ease;-o-transition:all 200ms ease;transition:all 200ms ease;-webkit-box-shadow:0 1px 0 rgba(0, 0, 0, 0.08);box-shadow:0 1px 0 rgba(0, 0, 0, 0.08);}.np-btn-trash{background-color:#e14d43;border-color:#e14d43;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.3),0 1px 0 rgba(0, 0, 0, 0.08);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.3),0 1px 0 rgba(0, 0, 0, 0.08);color:#ffffff;}.np-btn-trash:hover{background-color:#ba251e;border-color:#ba251e;}.np-toggle-edit{display:none;float:right;margin-right:10px;}.np-toggle-edit.active{background-color:#0074a2;color:#ffffff;-webkit-box-shadow:none;box-shadow:none;border-color:#0074a2;}@media (max-width: 767px){.np-toggle-edit{display:inline-block;}}.np-quickedit-error{border-left:4px solid #dd3d36;padding:4px 0 4px 8px;margin-bottom:10px;background-color:#f9f9f9;}.nestedpages-toggleall{float:right;margin-top:-30px;}.np-toggle-publish{color:#999999;}.np-toggle-publish.active{color:#333;font-weight:bold;}.np-sync-menu-cont{float:right;margin:-27px 15px 0px 0px;}#nested-loading{display:none;float:right;width:30px;margin:-31px 120px 0 0;}.wppages-top-tools{margin-bottom:20px;padding-top:10px;}.wppages-top-tools a{text-decoration:none;}.wppages-handle-expand{float:left;background-color:#f2f2f2;font-size:18px;width:46px;height:46px;margin-right:5px;text-align:center;border-right:1px solid #e1e1e1;}.wppages-handle-expand div{background-color:#ffffff;border:1px solid #e1e1e1;width:24px;height:24px;line-height:24px;-webkit-border-radius:15px;border-radius:15px;margin-top:9px;cursor:pointer;-webkit-transition:all 200ms ease;-o-transition:all 200ms ease;transition:all 200ms ease;}.wppages-handle-expand div:hover{background-color:#0074a2;border-color:#0074a2;color:#ffffff;-webkit-transition:all 200ms ease;-o-transition:all 200ms ease;transition:all 200ms ease;}.nestedpages{clear:both;-webkit-border-radius:4px;border-radius:4px;}.nestedpages .ui-sortable-placeholder{display:block !important;position:relative;min-height:46px;border:0;border:1px dashed #0074a2 !important;background-color:#effaff;margin:0;}.nestedpages .ui-sortable-helper{opacity:0.8;-webkit-box-shadow:2px 2px 3px 0px rgba(0, 0, 0, 0.5);box-shadow:2px 2px 3px 0px rgba(0, 0, 0, 0.5);}.nestedpages ol{list-style-type:none;clear:both;margin:0;-webkit-box-shadow:0 1px 1px rgba(0, 0, 0, 0.06);box-shadow:0 1px 1px rgba(0, 0, 0, 0.06);border:1px solid #e5e5e5;-webkit-border-radius:3px;border-radius:3px;}.nestedpages ol a{text-decoration:none;}.nestedpages ol .page-link{line-height:26px;}.nestedpages ol .page-link .edit-indicator{margin-left:10px;display:none;}.nestedpages ol .page-link .edit-indicator i{font-size:12px;margin-right:3px;}.nestedpages ol .page-link:hover .edit-indicator{display:inline-block;}.nestedpages ol .locked{color:#333;margin-left:20px;}.nestedpages ol .locked em{font-style:normal;}.nestedpages ol .status{color:#999999;margin:0px 10px;}.nestedpages ol .np-icon-eye-blocked{color:#999999;}.nestedpages ol .nav-status{color:#b3b3b3;}.nestedpages ol .np-hide{display:none;}.nestedpages ol .np-seo-indicator{display:block;float:right;width:12px;height:12px;-webkit-border-radius:8px;border-radius:8px;background-color:#999999;margin:6px 10px 0 0;}.nestedpages ol .np-seo-indicator.good{background-color:#7ad03a;}.nestedpages ol .np-seo-indicator.ok{background-color:#ffba00;}.nestedpages ol .np-seo-indicator.poor{background-color:#ee7c1b;}.nestedpages ol .np-seo-indicator.bad{background-color:#dd3d36;}.nestedpages ol .np-seo-indicator.warn{background-color:maroon;}.nestedpages ol .np-seo-indicator.wrong{background-color:red;}.nestedpages ol li{margin:0;border-top:1px solid #e1e1e1;background-color:#0074a2;}.nestedpages ol li.first{border:0;}.nestedpages ol li:first-child{border:0;}.nestedpages ol li.no-border{border:0;}.nestedpages ol ol{display:none;-webkit-border-radius:0;border-radius:0;list-style-type:none;border:0;-webkit-box-shadow:none;box-shadow:none;border-top:1px solid #e1e1e1;}.nestedpages .child-toggle{float:left;margin:-10px 10px 0 0;width:46px;height:46px;background-color:#f0f0f0;text-align:center;}.nestedpages .child-toggle a{display:inline-block;margin-top:7px;width:28px;height:28px;background-color:#ffffff;border:1px solid #e1e1e1;-webkit-border-radius:20px;border-radius:20px;font-size:20px;line-height:30px;color:#333;-webkit-transition:all 200ms ease;-o-transition:all 200ms ease;transition:all 200ms ease;}.nestedpages .child-toggle a i{line-height:26px;}.nestedpages .child-toggle a:hover{background-color:#0074a2;color:#ffffff;border-color:#0074a2;}.nestedpages .handle{display:inline-block;cursor:move;font-size:20px;color:#b3b3b3;-webkit-transition:all 200ms ease;-o-transition:all 200ms ease;transition:all 200ms ease;position:relative;top:3px;}.nestedpages .handle:hover{-webkit-transition:all 200ms ease;-o-transition:all 200ms ease;transition:all 200ms ease;color:#0074a2;}.nestedpages .np-icon-sub-menu{display:none;color:#999999;position:relative;left:2px;}.nestedpages .handle,.nestedpages .np-icon-sub-menu{width:30px;height:46px;line-height:36px;margin-top:-10px;}.nestedpages li ol .row .np-icon-sub-menu{display:inline-block;}.nestedpages li ol .row .handle{display:none;}.nestedpages li ol .row:hover .np-icon-sub-menu{display:none;}.nestedpages li ol .row:hover .handle{display:inline-block;}.nestedpages .row{background-color:#ffffff;display:block;padding:10px 0px 0px 0px;height:36px;zoom:1;}.nestedpages .row:before,.nestedpages .row:after{content:" ";display:table;}.nestedpages .row:after{clear:both;}.nestedpages .row:hover{background-color:#f0f0f0;}.nestedpages .row.np-updated{background-color:#e9f7df;-webkit-transition:background-color 400ms ease;-o-transition:background-color 400ms ease;transition:background-color 400ms ease;}.nestedpages .row.np-updated-show{background-color:#ffffff;-webkit-transition:background-color 400ms ease;-o-transition:background-color 400ms ease;transition:background-color 400ms ease;}.nestedpages ol li ol .row-inner{padding-left:86px;}.nestedpages ol li ol li ol .row-inner{padding-left:116px;}.nestedpages ol li ol li ol li ol .row-inner{padding-left:156px;}.nestedpages .action-buttons{display:none;float:right;margin:0 10px 0 0;}.nestedpages .action-buttons a{margin-left:5px;}@media (min-width: 768px){.nestedpages .row:hover .action-buttons{display:block;}}@media (max-width: 767px){.nestedpages ol .page-link{line-height:24px;}.nestedpages ol .page-link:hover span{display:none;}.nestedpages ol .locked em{display:none;}.nestedpages .child-toggle{background:transparent;}.nestedpages .row{height:auto;}.nestedpages .action-buttons{display:none;background-color:#0074a2;float:none;margin:0;padding:8px;}.nestedpages .action-buttons a{margin-left:5px;}}.nestedpages .quick-edit{background-color:#ffffff;-webkit-border-radius:0;border-radius:0;}.nestedpages .quick-edit .form-interior{padding:10px;}.nestedpages .quick-edit h3{margin:0 0 8px 0;font-size:14px;}.nestedpages .quick-edit .fields{margin-bottom:10px;background:url('../images/border.png') repeat-y;background-position:center;zoom:1;}.nestedpages .quick-edit .fields:before,.nestedpages .quick-edit .fields:after{content:" ";display:table;}.nestedpages .quick-edit .fields:after{clear:both;}.nestedpages .quick-edit .left{float:left;width:48%;}.nestedpages .quick-edit .right{float:right;width:48%;}.nestedpages .quick-edit label{font-style:oblique;}.nestedpages .quick-edit .buttons{clear:both;zoom:1;background-color:#404040;padding:8px;}.nestedpages .quick-edit .buttons:before,.nestedpages .quick-edit .buttons:after{content:" ";display:table;}.nestedpages .quick-edit .buttons:after{clear:both;}.nestedpages .quick-edit .form-control{clear:both;zoom:1;margin-bottom:5px;}.nestedpages .quick-edit .form-control:before,.nestedpages .quick-edit .form-control:after{content:" ";display:table;}.nestedpages .quick-edit .form-control:after{clear:both;}.nestedpages .quick-edit .form-control input[type='text'],.nestedpages .quick-edit .form-control input[type='password'],.nestedpages .quick-edit .form-control select{float:right;width:75%;}.nestedpages .quick-edit .form-control label{float:left;width:20%;}.nestedpages .quick-edit .comments{float:right;width:75%;margin-bottom:10px;zoom:1;}.nestedpages .quick-edit .comments:before,.nestedpages .quick-edit .comments:after{content:" ";display:table;}.nestedpages .quick-edit .comments:after{clear:both;}.nestedpages .quick-edit .dates{float:right;width:75%;margin-bottom:6px;}.nestedpages .quick-edit .dates select{width:25%;}.nestedpages .quick-edit .dates input{width:12%;}.nestedpages .quick-edit .np-qe-loading{display:none;float:right;width:25px;height:25px;margin:2px 10px 0 0;background:url('../images/loading-white.gif') no-repeat;}.nestedpages .quick-edit .np-toggle-taxonomies{clear:both;float:right;width:71%;text-align:center;}.nestedpages .quick-edit .np-taxonomies{display:none;clear:both;background-color:#f9f9f9;padding:8px;zoom:1;}.nestedpages .quick-edit .np-taxonomies:before,.nestedpages .quick-edit .np-taxonomies:after{content:" ";display:table;}.nestedpages .quick-edit .np-taxonomies:after{clear:both;}.nestedpages .quick-edit .np-taxonomy{float:left;width:30%;margin-right:3.33%;}.nestedpages .quick-edit .np-taxonomy .title{font-weight:bold;margin-bottom:4px;display:block;}.nestedpages .quick-edit .np-taxonomy li{background-color:#ffffff;border:0;}@media (max-width: 767px){.nestedpages .quick-edit .fields{background:transparent;}.nestedpages .quick-edit .left,.nestedpages .quick-edit .right{float:none;width:100%;}.nestedpages .quick-edit .form-control{margin-bottom:10px;}.nestedpages .quick-edit .form-control input[type='text'],.nestedpages .quick-edit .form-control input[type='password'],.nestedpages .quick-edit .form-control select{float:none;width:100%;}.nestedpages .quick-edit .form-control label{display:block;float:none;width:100%;margin-bottom:4px;}.nestedpages .quick-edit .comments{float:none;width:100%;}.nestedpages .quick-edit .dates{float:none;width:100%;margin-bottom:6px;}}
assets/images/border.png ADDED
Binary file
assets/images/loading-white.gif ADDED
Binary file
assets/images/loading.gif ADDED
Binary file
assets/js/lib/jquery.mjs.nestedSortable.js ADDED
@@ -0,0 +1,664 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * jQuery UI Nested Sortable
3
+ * v 2.0 / 29 oct 2012
4
+ * http://mjsarfatti.com/sandbox/nestedSortable
5
+ *
6
+ * Depends on:
7
+ * jquery.ui.sortable.js 1.10+
8
+ *
9
+ * Copyright (c) 2010-2013 Manuele J Sarfatti
10
+ * Licensed under the MIT License
11
+ * http://www.opensource.org/licenses/mit-license.php
12
+ */
13
+ (function( factory ) {
14
+ if ( typeof define === "function" && define.amd ) {
15
+
16
+ // AMD. Register as an anonymous module.
17
+ define([
18
+ "jquery",
19
+ "jquery-ui/sortable"
20
+ ], factory );
21
+ } else {
22
+
23
+ // Browser globals
24
+ factory( jQuery );
25
+ }
26
+ }(function($) {
27
+
28
+ function isOverAxis( x, reference, size ) {
29
+ return ( x > reference ) && ( x < ( reference + size ) );
30
+ }
31
+
32
+ $.widget("mjs.nestedSortable", $.extend({}, $.ui.sortable.prototype, {
33
+
34
+ options: {
35
+ disableParentChange: false,
36
+ doNotClear: false,
37
+ expandOnHover: 700,
38
+ isAllowed: function(placeholder, placeholderParent, originalItem) { return true; },
39
+ isTree: false,
40
+ listType: 'ol',
41
+ maxLevels: 0,
42
+ protectRoot: false,
43
+ rootID: null,
44
+ rtl: false,
45
+ startCollapsed: false,
46
+ tabSize: 20,
47
+
48
+ branchClass: 'mjs-nestedSortable-branch',
49
+ collapsedClass: 'mjs-nestedSortable-collapsed',
50
+ disableNestingClass: 'mjs-nestedSortable-no-nesting',
51
+ errorClass: 'mjs-nestedSortable-error',
52
+ expandedClass: 'mjs-nestedSortable-expanded',
53
+ hoveringClass: 'mjs-nestedSortable-hovering',
54
+ leafClass: 'mjs-nestedSortable-leaf',
55
+ disabledClass: 'mjs-nestedSortable-disabled'
56
+ },
57
+
58
+ _create: function() {
59
+ this.element.data('ui-sortable', this.element.data('mjs-nestedSortable'));
60
+
61
+ // mjs - prevent browser from freezing if the HTML is not correct
62
+ if (!this.element.is(this.options.listType))
63
+ throw new Error('nestedSortable: Please check that the listType option is set to your actual list type');
64
+
65
+ // mjs - force 'intersect' tolerance method if we have a tree with expanding/collapsing functionality
66
+ if (this.options.isTree && this.options.expandOnHover) {
67
+ this.options.tolerance = 'intersect';
68
+ }
69
+
70
+ $.ui.sortable.prototype._create.apply(this, arguments);
71
+
72
+ // mjs - prepare the tree by applying the right classes (the CSS is responsible for actual hide/show functionality)
73
+ if (this.options.isTree) {
74
+ var self = this;
75
+ $(this.items).each(function() {
76
+ var $li = this.item;
77
+ if ($li.children(self.options.listType).length) {
78
+ $li.addClass(self.options.branchClass);
79
+ // expand/collapse class only if they have children
80
+ if ( ! $li.hasClass( self.options.collapsedClass ) && ( ! $li.hasClass( self.options.expandedClass ) ) ) {
81
+ if (self.options.startCollapsed) $li.addClass(self.options.collapsedClass);
82
+ else $li.addClass(self.options.expandedClass);
83
+ }
84
+ } else {
85
+ $li.addClass(self.options.leafClass);
86
+ }
87
+ });
88
+ }
89
+ },
90
+
91
+ _destroy: function() {
92
+ this.element
93
+ .removeData("mjs-nestedSortable")
94
+ .removeData("ui-sortable");
95
+ return $.ui.sortable.prototype._destroy.apply(this, arguments);
96
+ },
97
+
98
+ _mouseDrag: function(event) {
99
+ var i, item, itemElement, intersection,
100
+ o = this.options,
101
+ scrolled = false;
102
+
103
+ //Compute the helpers position
104
+ this.position = this._generatePosition(event);
105
+ this.positionAbs = this._convertPositionTo("absolute");
106
+
107
+ if (!this.lastPositionAbs) {
108
+ this.lastPositionAbs = this.positionAbs;
109
+ }
110
+
111
+ //Do scrolling
112
+ if(this.options.scroll) {
113
+ if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') {
114
+
115
+ if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
116
+ this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
117
+ } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
118
+ this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
119
+ }
120
+
121
+ if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
122
+ this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
123
+ } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
124
+ this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
125
+ }
126
+
127
+ } else {
128
+
129
+ if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
130
+ scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
131
+ } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
132
+ scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
133
+ }
134
+
135
+ if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
136
+ scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
137
+ } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
138
+ scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
139
+ }
140
+
141
+ }
142
+
143
+ if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
144
+ $.ui.ddmanager.prepareOffsets(this, event);
145
+ }
146
+
147
+ //Regenerate the absolute position used for position checks
148
+ this.positionAbs = this._convertPositionTo("absolute");
149
+
150
+ // mjs - find the top offset before rearrangement,
151
+ var previousTopOffset = this.placeholder.offset().top;
152
+
153
+ //Set the helper position
154
+ if(!this.options.axis || this.options.axis !== "y") {
155
+ this.helper[0].style.left = this.position.left+"px";
156
+ }
157
+ if(!this.options.axis || this.options.axis !== "x") {
158
+ this.helper[0].style.top = this.position.top+"px";
159
+ }
160
+
161
+ // mjs - check and reset hovering state at each cycle
162
+ this.hovering = this.hovering ? this.hovering : null;
163
+ this.mouseentered = this.mouseentered ? this.mouseentered : false;
164
+
165
+ // mjs - let's start caching some variables
166
+ var parentItem = (this.placeholder[0].parentNode.parentNode &&
167
+ $(this.placeholder[0].parentNode.parentNode).closest('.ui-sortable').length)
168
+ ? $(this.placeholder[0].parentNode.parentNode)
169
+ : null,
170
+ level = this._getLevel(this.placeholder),
171
+ childLevels = this._getChildLevels(this.helper);
172
+
173
+ var newList = document.createElement(o.listType);
174
+
175
+ //Rearrange
176
+ for (i = this.items.length - 1; i >= 0; i--) {
177
+
178
+ //Cache variables and intersection, continue if no intersection
179
+ item = this.items[i];
180
+ itemElement = item.item[0];
181
+ intersection = this._intersectsWithPointer(item);
182
+ if (!intersection) {
183
+ continue;
184
+ }
185
+
186
+ // Only put the placeholder inside the current Container, skip all
187
+ // items form other containers. This works because when moving
188
+ // an item from one container to another the
189
+ // currentContainer is switched before the placeholder is moved.
190
+ //
191
+ // Without this moving items in "sub-sortables" can cause the placeholder to jitter
192
+ // beetween the outer and inner container.
193
+ if (item.instance !== this.currentContainer) {
194
+ continue;
195
+ }
196
+
197
+ // No action if intersected item is disabled
198
+ // and the element above or below in the direction we're going is also disabled
199
+ if (itemElement.className.indexOf(o.disabledClass) !== -1) {
200
+ // Note: intersection hardcoded direction values from jquery.ui.sortable.js:_intersectsWithPointer
201
+ if (intersection === 2) {
202
+ // Going down
203
+ var itemAfter = this.items[i + 1];
204
+ if (itemAfter && itemAfter.item[0].className.indexOf(o.disabledClass) !== -1){
205
+ continue;
206
+ }
207
+
208
+ }
209
+ else if (intersection === 1) {
210
+ // Going up
211
+ var itemBefore = this.items[i - 1];
212
+ if (itemBefore && itemBefore.item[0].className.indexOf(o.disabledClass) !== -1){
213
+ continue;
214
+ }
215
+ }
216
+ }
217
+
218
+ // cannot intersect with itself
219
+ // no useless actions that have been done before
220
+ // no action if the item moved is the parent of the item checked
221
+ if (itemElement !== this.currentItem[0] &&
222
+ this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
223
+ !$.contains(this.placeholder[0], itemElement) &&
224
+ (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
225
+ ) {
226
+
227
+ // mjs - we are intersecting an element: trigger the mouseenter event and store this state
228
+ if (!this.mouseentered) {
229
+ $(itemElement).mouseenter();
230
+ this.mouseentered = true;
231
+ }
232
+
233
+ // mjs - if the element has children and they are hidden, show them after a delay (CSS responsible)
234
+ if (o.isTree && $(itemElement).hasClass(o.collapsedClass) && o.expandOnHover) {
235
+ if (!this.hovering) {
236
+ $(itemElement).addClass(o.hoveringClass);
237
+ var self = this;
238
+ this.hovering = window.setTimeout(function() {
239
+ $(itemElement).removeClass(o.collapsedClass).addClass(o.expandedClass);
240
+ self.refreshPositions();
241
+ self._trigger("expand", event, self._uiHash());
242
+ }, o.expandOnHover);
243
+ }
244
+ }
245
+
246
+ this.direction = intersection == 1 ? "down" : "up";
247
+
248
+ // mjs - rearrange the elements and reset timeouts and hovering state
249
+ if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) {
250
+ $(itemElement).mouseleave();
251
+ this.mouseentered = false;
252
+ $(itemElement).removeClass(o.hoveringClass);
253
+ this.hovering && window.clearTimeout(this.hovering);
254
+ this.hovering = null;
255
+
256
+ // mjs - do not switch container if it's a root item and 'protectRoot' is true
257
+ // or if it's not a root item but we are trying to make it root
258
+ if (o.protectRoot
259
+ && ! (this.currentItem[0].parentNode == this.element[0] // it's a root item
260
+ && itemElement.parentNode != this.element[0]) // it's intersecting a non-root item
261
+ ) {
262
+ if (this.currentItem[0].parentNode != this.element[0]
263
+ && itemElement.parentNode == this.element[0]
264
+ ) {
265
+
266
+ if ( ! $(itemElement).children(o.listType).length) {
267
+ itemElement.appendChild(newList);
268
+ o.isTree && $(itemElement).removeClass(o.leafClass).addClass(o.branchClass + ' ' + o.expandedClass);
269
+ }
270
+
271
+ var a = this.direction === "down" ? $(itemElement).prev().children(o.listType) : $(itemElement).children(o.listType);
272
+ if (a[0] !== undefined) {
273
+ this._rearrange(event, null, a);
274
+ }
275
+
276
+ } else {
277
+ this._rearrange(event, item);
278
+ }
279
+ } else if ( ! o.protectRoot) {
280
+ this._rearrange(event, item);
281
+ }
282
+ } else {
283
+ break;
284
+ }
285
+
286
+ // Clear emtpy ul's/ol's
287
+ this._clearEmpty(itemElement);
288
+
289
+ this._trigger("change", event, this._uiHash());
290
+ break;
291
+ }
292
+ }
293
+
294
+ // mjs - to find the previous sibling in the list, keep backtracking until we hit a valid list item.
295
+ var previousItem = this.placeholder[0].previousSibling ? $(this.placeholder[0].previousSibling) : null;
296
+ if (previousItem != null) {
297
+ while (previousItem[0].nodeName.toLowerCase() != 'li' || previousItem[0].className.indexOf(o.disabledClass) !== -1 || previousItem[0] == this.currentItem[0] || previousItem[0] == this.helper[0]) {
298
+ if (previousItem[0].previousSibling) {
299
+ previousItem = $(previousItem[0].previousSibling);
300
+ } else {
301
+ previousItem = null;
302
+ break;
303
+ }
304
+ }
305
+ }
306
+
307
+ // mjs - to find the next sibling in the list, keep stepping forward until we hit a valid list item.
308
+ var nextItem = this.placeholder[0].nextSibling ? $(this.placeholder[0].nextSibling) : null;
309
+ if (nextItem != null) {
310
+ while (nextItem[0].nodeName.toLowerCase() != 'li' || nextItem[0].className.indexOf(o.disabledClass) !== -1 || nextItem[0] == this.currentItem[0] || nextItem[0] == this.helper[0]) {
311
+ if (nextItem[0].nextSibling) {
312
+ nextItem = $(nextItem[0].nextSibling);
313
+ } else {
314
+ nextItem = null;
315
+ break;
316
+ }
317
+ }
318
+ }
319
+
320
+ this.beyondMaxLevels = 0;
321
+
322
+ // mjs - if the item is moved to the left, send it one level up but only if it's at the bottom of the list
323
+ if (parentItem != null
324
+ && nextItem == null
325
+ && ! (o.protectRoot && parentItem[0].parentNode == this.element[0])
326
+ &&
327
+ (o.rtl && (this.positionAbs.left + this.helper.outerWidth() > parentItem.offset().left + parentItem.outerWidth())
328
+ || ! o.rtl && (this.positionAbs.left < parentItem.offset().left))
329
+ ) {
330
+
331
+ parentItem.after(this.placeholder[0]);
332
+ if (o.isTree && parentItem.children(o.listItem).children('li:visible:not(.ui-sortable-helper)').length < 1) {
333
+ parentItem.removeClass(this.options.branchClass + ' ' + this.options.expandedClass)
334
+ .addClass(this.options.leafClass);
335
+ }
336
+ this._clearEmpty(parentItem[0]);
337
+ this._trigger("change", event, this._uiHash());
338
+ }
339
+ // mjs - if the item is below a sibling and is moved to the right, make it a child of that sibling
340
+ else if (previousItem != null
341
+ && ! previousItem.hasClass(o.disableNestingClass)
342
+ &&
343
+ (previousItem.children(o.listType).length && previousItem.children(o.listType).is(':visible')
344
+ || ! previousItem.children(o.listType).length)
345
+ && ! (o.protectRoot && this.currentItem[0].parentNode == this.element[0])
346
+ &&
347
+ (o.rtl && (this.positionAbs.left + this.helper.outerWidth() < previousItem.offset().left + previousItem.outerWidth() - o.tabSize)
348
+ || ! o.rtl && (this.positionAbs.left > previousItem.offset().left + o.tabSize))
349
+ ) {
350
+
351
+ this._isAllowed(previousItem, level, level+childLevels+1);
352
+
353
+ if (!previousItem.children(o.listType).length) {
354
+ previousItem[0].appendChild(newList);
355
+ o.isTree && previousItem.removeClass(o.leafClass).addClass(o.branchClass + ' ' + o.expandedClass);
356
+ }
357
+
358
+ // mjs - if this item is being moved from the top, add it to the top of the list.
359
+ if (previousTopOffset && (previousTopOffset <= previousItem.offset().top)) {
360
+ previousItem.children(o.listType).prepend(this.placeholder);
361
+ }
362
+ // mjs - otherwise, add it to the bottom of the list.
363
+ else {
364
+ previousItem.children(o.listType)[0].appendChild(this.placeholder[0]);
365
+ }
366
+
367
+ this._trigger("change", event, this._uiHash());
368
+ }
369
+ else {
370
+ this._isAllowed(parentItem, level, level+childLevels);
371
+ }
372
+
373
+ //Post events to containers
374
+ this._contactContainers(event);
375
+
376
+ //Interconnect with droppables
377
+ if($.ui.ddmanager) {
378
+ $.ui.ddmanager.drag(this, event);
379
+ }
380
+
381
+ //Call callbacks
382
+ this._trigger('sort', event, this._uiHash());
383
+
384
+ this.lastPositionAbs = this.positionAbs;
385
+ return false;
386
+
387
+ },
388
+
389
+ _mouseStop: function(event, noPropagation) {
390
+
391
+ // mjs - if the item is in a position not allowed, send it back
392
+ if (this.beyondMaxLevels) {
393
+
394
+ this.placeholder.removeClass(this.options.errorClass);
395
+
396
+ if (this.domPosition.prev) {
397
+ $(this.domPosition.prev).after(this.placeholder);
398
+ } else {
399
+ $(this.domPosition.parent).prepend(this.placeholder);
400
+ }
401
+
402
+ this._trigger("revert", event, this._uiHash());
403
+
404
+ }
405
+
406
+
407
+ // mjs - clear the hovering timeout, just to be sure
408
+ $('.'+this.options.hoveringClass).mouseleave().removeClass(this.options.hoveringClass);
409
+ this.mouseentered = false;
410
+ this.hovering && window.clearTimeout(this.hovering);
411
+ this.hovering = null;
412
+
413
+ $.ui.sortable.prototype._mouseStop.apply(this, arguments);
414
+
415
+ var pid = $(this.domPosition.parent).parent().attr("id");
416
+ var sort = this.domPosition.prev ? $(this.domPosition.prev).next().index() : 0;
417
+
418
+ if(!(pid == this._uiHash().item.parent().parent().attr("id") &&
419
+ sort == this._uiHash().item.index())) {
420
+ this._trigger("relocate", event, this._uiHash());
421
+ }
422
+
423
+ },
424
+
425
+ // mjs - this function is slightly modified to make it easier to hover over a collapsed element and have it expand
426
+ _intersectsWithSides: function(item) {
427
+
428
+ var half = this.options.isTree ? .8 : .5;
429
+
430
+ var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height*half), item.height),
431
+ isOverTopHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top - (item.height*half), item.height),
432
+ isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
433
+ verticalDirection = this._getDragVerticalDirection(),
434
+ horizontalDirection = this._getDragHorizontalDirection();
435
+
436
+ if (this.floating && horizontalDirection) {
437
+ return ((horizontalDirection == "right" && isOverRightHalf) || (horizontalDirection == "left" && !isOverRightHalf));
438
+ } else {
439
+ return verticalDirection && ((verticalDirection == "down" && isOverBottomHalf) || (verticalDirection == "up" && isOverTopHalf));
440
+ }
441
+
442
+ },
443
+
444
+ _contactContainers: function(event) {
445
+
446
+ if (this.options.protectRoot && this.currentItem[0].parentNode == this.element[0] ) {
447
+ return;
448
+ }
449
+
450
+ $.ui.sortable.prototype._contactContainers.apply(this, arguments);
451
+
452
+ },
453
+
454
+ _clear: function(event, noPropagation) {
455
+
456
+ $.ui.sortable.prototype._clear.apply(this, arguments);
457
+
458
+ // mjs - clean last empty ul/ol
459
+ for (var i = this.items.length - 1; i >= 0; i--) {
460
+ var item = this.items[i].item[0];
461
+ this._clearEmpty(item);
462
+ }
463
+
464
+ },
465
+
466
+ serialize: function(options) {
467
+
468
+ var o = $.extend({}, this.options, options),
469
+ items = this._getItemsAsjQuery(o && o.connected),
470
+ str = [];
471
+
472
+ $(items).each(function() {
473
+ var res = ($(o.item || this).attr(o.attribute || 'id') || '')
474
+ .match(o.expression || (/(.+)[-=_](.+)/)),
475
+ pid = ($(o.item || this).parent(o.listType)
476
+ .parent(o.items)
477
+ .attr(o.attribute || 'id') || '')
478
+ .match(o.expression || (/(.+)[-=_](.+)/));
479
+
480
+ if (res) {
481
+ str.push(((o.key || res[1]) + '[' + (o.key && o.expression ? res[1] : res[2]) + ']')
482
+ + '='
483
+ + (pid ? (o.key && o.expression ? pid[1] : pid[2]) : o.rootID));
484
+ }
485
+ });
486
+
487
+ if(!str.length && o.key) {
488
+ str.push(o.key + '=');
489
+ }
490
+
491
+ return str.join('&');
492
+
493
+ },
494
+
495
+ toHierarchy: function(options) {
496
+
497
+ var o = $.extend({}, this.options, options),
498
+ sDepth = o.startDepthCount || 0,
499
+ ret = [];
500
+
501
+ $(this.element).children(o.items).each(function () {
502
+ var level = _recursiveItems(this);
503
+ ret.push(level);
504
+ });
505
+
506
+ return ret;
507
+
508
+ function _recursiveItems(item) {
509
+ var id = ($(item).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
510
+ if (id) {
511
+ var currentItem = {"id" : id[2]};
512
+ if ($(item).children(o.listType).children(o.items).length > 0) {
513
+ currentItem.children = [];
514
+ $(item).children(o.listType).children(o.items).each(function() {
515
+ var level = _recursiveItems(this);
516
+ currentItem.children.push(level);
517
+ });
518
+ }
519
+ return currentItem;
520
+ }
521
+ }
522
+ },
523
+
524
+ toArray: function(options) {
525
+
526
+ var o = $.extend({}, this.options, options),
527
+ sDepth = o.startDepthCount || 0,
528
+ ret = [],
529
+ left = 1;
530
+
531
+ if (!o.excludeRoot) {
532
+ ret.push({
533
+ "item_id": o.rootID,
534
+ "parent_id": null,
535
+ "depth": sDepth,
536
+ "left": left,
537
+ "right": ($(o.items, this.element).length + 1) * 2
538
+ });
539
+ left++
540
+ }
541
+
542
+ $(this.element).children(o.items).each(function () {
543
+ left = _recursiveArray(this, sDepth + 1, left);
544
+ });
545
+
546
+ ret = ret.sort(function(a,b){ return (a.left - b.left); });
547
+
548
+ return ret;
549
+
550
+ function _recursiveArray(item, depth, left) {
551
+
552
+ var right = left + 1,
553
+ id,
554
+ pid;
555
+
556
+ if ($(item).children(o.listType).children(o.items).length > 0) {
557
+ depth ++;
558
+ $(item).children(o.listType).children(o.items).each(function () {
559
+ right = _recursiveArray($(this), depth, right);
560
+ });
561
+ depth --;
562
+ }
563
+
564
+ id = ($(item).attr(o.attribute || 'id')).match(o.expression || (/(.+)[-=_](.+)/));
565
+
566
+ if (depth === sDepth + 1) {
567
+ pid = o.rootID;
568
+ } else {
569
+ var parentItem = ($(item).parent(o.listType)
570
+ .parent(o.items)
571
+ .attr(o.attribute || 'id'))
572
+ .match(o.expression || (/(.+)[-=_](.+)/));
573
+ pid = parentItem[2];
574
+ }
575
+
576
+ if (id) {
577
+ ret.push({"item_id": id[2], "parent_id": pid, "depth": depth, "left": left, "right": right});
578
+ }
579
+
580
+ left = right + 1;
581
+ return left;
582
+ }
583
+
584
+ },
585
+
586
+ _clearEmpty: function(item) {
587
+ var o = this.options;
588
+
589
+ var emptyList = $(item).children(o.listType);
590
+
591
+ if (emptyList.length && !emptyList.children().length && !o.doNotClear) {
592
+ o.isTree && $(item).removeClass(o.branchClass + ' ' + o.expandedClass).addClass(o.leafClass);
593
+ emptyList.remove();
594
+ } else if (o.isTree && emptyList.length && emptyList.children().length && emptyList.is(':visible')) {
595
+ $(item).removeClass(o.leafClass).addClass(o.branchClass + ' ' + o.expandedClass);
596
+ } else if (o.isTree && emptyList.length && emptyList.children().length && !emptyList.is(':visible')) {
597
+ $(item).removeClass(o.leafClass).addClass(o.branchClass + ' ' + o.collapsedClass);
598
+ }
599
+
600
+ },
601
+
602
+ _getLevel: function(item) {
603
+
604
+ var level = 1;
605
+
606
+ if (this.options.listType) {
607
+ var list = item.closest(this.options.listType);
608
+ while (list && list.length > 0 &&
609
+ !list.is('.ui-sortable')) {
610
+ level++;
611
+ list = list.parent().closest(this.options.listType);
612
+ }
613
+ }
614
+
615
+ return level;
616
+ },
617
+
618
+ _getChildLevels: function(parent, depth) {
619
+ var self = this,
620
+ o = this.options,
621
+ result = 0;
622
+ depth = depth || 0;
623
+
624
+ $(parent).children(o.listType).children(o.items).each(function (index, child) {
625
+ result = Math.max(self._getChildLevels(child, depth + 1), result);
626
+ });
627
+
628
+ return depth ? result + 1 : result;
629
+ },
630
+
631
+ _isAllowed: function(parentItem, level, levels) {
632
+ var o = this.options,
633
+ maxLevels = this.placeholder.closest('.ui-sortable').nestedSortable('option', 'maxLevels'); // this takes into account the maxLevels set to the recipient list
634
+
635
+ // Check if the parent has changed to prevent it, when o.disableParentChange is true
636
+ var oldParent = this.currentItem.parent().parent();
637
+ var disabledByParentchange = o.disableParentChange && (
638
+ parentItem !== null && !oldParent.is(parentItem)//From somewhere to somewhere else, except the root
639
+ || parentItem === null && oldParent.is('li') //From somewhere to the root
640
+ );
641
+ // mjs - is the root protected?
642
+ // mjs - are we nesting too deep?
643
+ if (disabledByParentchange || ! o.isAllowed(this.placeholder, parentItem, this.currentItem)) {
644
+ this.placeholder.addClass(o.errorClass);
645
+ if (maxLevels < levels && maxLevels != 0) {
646
+ this.beyondMaxLevels = levels - maxLevels;
647
+ } else {
648
+ this.beyondMaxLevels = 1;
649
+ }
650
+ } else {
651
+ if (maxLevels < levels && maxLevels != 0) {
652
+ this.placeholder.addClass(o.errorClass);
653
+ this.beyondMaxLevels = levels - maxLevels;
654
+ } else {
655
+ this.placeholder.removeClass(o.errorClass);
656
+ this.beyondMaxLevels = 0;
657
+ }
658
+ }
659
+ }
660
+
661
+ }));
662
+
663
+ $.mjs.nestedSortable.prototype.options = $.extend({}, $.ui.sortable.prototype.options, $.mjs.nestedSortable.prototype.options);
664
+ }));
assets/js/lib/jquery.ui.touch-punch.min.js ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * jQuery UI Touch Punch 0.2.3
3
+ *
4
+ * Copyright 2011–2014, Dave Furfero
5
+ * Dual licensed under the MIT or GPL Version 2 licenses.
6
+ *
7
+ * Depends:
8
+ * jquery.ui.widget.js
9
+ * jquery.ui.mouse.js
10
+ */
11
+ !function(a){function f(a,b){if(!(a.originalEvent.touches.length>1)){a.preventDefault();var c=a.originalEvent.changedTouches[0],d=document.createEvent("MouseEvents");d.initMouseEvent(b,!0,!0,window,1,c.screenX,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,null),a.target.dispatchEvent(d)}}if(a.support.touch="ontouchend"in document,a.support.touch){var e,b=a.ui.mouse.prototype,c=b._mouseInit,d=b._mouseDestroy;b._touchStart=function(a){var b=this;!e&&b._mouseCapture(a.originalEvent.changedTouches[0])&&(e=!0,b._touchMoved=!1,f(a,"mouseover"),f(a,"mousemove"),f(a,"mousedown"))},b._touchMove=function(a){e&&(this._touchMoved=!0,f(a,"mousemove"))},b._touchEnd=function(a){e&&(f(a,"mouseup"),f(a,"mouseout"),this._touchMoved||f(a,"click"),e=!1)},b._mouseInit=function(){var b=this;b.element.bind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),c.call(b)},b._mouseDestroy=function(){var b=this;b.element.unbind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),d.call(b)}}}(jQuery);
assets/js/lib/nestedpages.js ADDED
@@ -0,0 +1,578 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * WP Pages Scripts Required by WP Pages Plugin
3
+ * @author Kyle Phillips
4
+ */
5
+ jQuery(function($){
6
+
7
+ /**
8
+ * ------------------------------------------------------------------------
9
+ * Sortable and Toggline
10
+ * ------------------------------------------------------------------------
11
+ **/
12
+
13
+
14
+ /**
15
+ * Add the Submenu Toggles (using JS to prevent additional DB Queries)
16
+ */
17
+ $(document).ready(function(){
18
+ add_remove_submenu_toggles();
19
+ np_set_borders();
20
+ });
21
+
22
+ /**
23
+ * Toggle the Submenus
24
+ */
25
+ $(document).on('click', '.child-toggle a', function(e){
26
+ e.preventDefault();
27
+ var submenu = $(this).parent('.child-toggle').parent('.row').siblings('ol');
28
+ $(this).find('i').toggleClass('np-icon-arrow-down').toggleClass('np-icon-arrow-right');
29
+ $(submenu).toggle();
30
+ np_set_borders();
31
+ });
32
+
33
+ /**
34
+ * Toggle all pages (Expand All)
35
+ */
36
+ $(document).on('click', '.nestedpages-toggleall a', function(e){
37
+ e.preventDefault();
38
+ if ( $(this).attr('data-toggle') == 'closed' )
39
+ {
40
+ $('.nestedpages ol li ol').show();
41
+ $(this).attr('data-toggle', 'opened');
42
+ $(this).text(nestedpages.collapse_text);
43
+ $('.child-toggle i').removeClass('np-icon-arrow-right').addClass('np-icon-arrow-down');
44
+ revert_quick_edit();
45
+ np_set_borders();
46
+ } else
47
+ {
48
+ $('.nestedpages ol li ol').hide();
49
+ $(this).attr('data-toggle', 'closed');
50
+ $(this).text(nestedpages.expand_text);
51
+ $('.child-toggle i').removeClass('np-icon-arrow-down').addClass('np-icon-arrow-right');
52
+ revert_quick_edit();
53
+ np_set_borders();
54
+ }
55
+ });
56
+
57
+ /**
58
+ * Toggle hidden pages
59
+ */
60
+ $(document).on('click', '.np-toggle-hidden', function(e){
61
+ e.preventDefault();
62
+ var action = $(this).attr('href');
63
+ if ( action === 'show' ){
64
+ $(this).attr('href', 'hide');
65
+ $(this).text('Show Hidden Pages');
66
+ $('.np-hide').removeClass('shown').hide();
67
+ np_set_borders();
68
+ } else {
69
+ $(this).attr('href', 'show');
70
+ $(this).text('Hide Hidden Pages');
71
+ $('.np-hide').addClass('shown').show();
72
+ np_set_borders();
73
+ }
74
+ });
75
+
76
+ /**
77
+ * Fix :visible :first css limitation when toggling various options
78
+ */
79
+ function np_set_borders()
80
+ {
81
+ var lists = $('.nplist');
82
+ $('.page-row').removeClass('no-border');
83
+ $.each(lists, function(){
84
+ $(this).find('.page-row:visible:first').addClass('no-border');
85
+ });
86
+ }
87
+
88
+ /**
89
+ * Toggle between showing published pages and all
90
+ */
91
+ $(document).on('click', '.np-toggle-publish', function(e){
92
+ e.preventDefault();
93
+ var target = $(this).attr('href');
94
+ $('.np-toggle-publish').removeClass('active');
95
+ $(this).addClass('active');
96
+ if ( target == '#published' ){
97
+ $('.nplist .page-row').hide();
98
+ $('.nplist .published').show();
99
+ } else {
100
+ $('.nplist .page-row').show();
101
+ }
102
+ });
103
+
104
+
105
+ /**
106
+ * Toggle Responsive Action Buttons (Quick edit, add child, etc)
107
+ */
108
+ $(document).on('click', '.np-toggle-edit', function(e){
109
+ e.preventDefault();
110
+ var buttons = $(this).siblings('.action-buttons');
111
+ if ( $(buttons).is(':visible') ){
112
+ $(this).removeClass('active');
113
+ $(buttons).hide();
114
+ } else {
115
+ $(this).addClass('active');
116
+ $(buttons).show();
117
+ }
118
+ });
119
+ /**
120
+ * Remove display block on action buttons when sizing up
121
+ */
122
+ var actiondelay = (function(){
123
+ var timer = 0;
124
+ return function(callback, ms){
125
+ clearTimeout (timer);
126
+ timer = setTimeout(callback, ms);
127
+ };
128
+ })();
129
+ $(window).resize(function() {
130
+ actiondelay(function(){
131
+ $('.action-buttons').removeAttr('style');
132
+ $('.np-toggle-edit').removeClass('active');
133
+ }, 500);
134
+ });
135
+
136
+ /**
137
+ * Make the Menu sortable
138
+ */
139
+ $(document).ready(function(){
140
+ $('.sortable').not('.no-sort').nestedSortable({
141
+ items : 'li',
142
+ toleranceElement: '> .row',
143
+ handle: '.handle',
144
+ placeholder: "ui-sortable-placeholder",
145
+ start: function(e, ui){
146
+ ui.placeholder.height(ui.item.height());
147
+ },
148
+ sort: function(e, ui){
149
+ update_placeholder_width(ui);
150
+ },
151
+ stop: function(e, ui){
152
+ setTimeout(
153
+ function(){
154
+ add_remove_submenu_toggles();
155
+ np_set_borders();
156
+ }, 100
157
+ );
158
+ submit_sortable_form();
159
+ },
160
+ update: function(e, ui){
161
+ }
162
+ });
163
+ });
164
+
165
+ /**
166
+ * Update the width of the placeholder
167
+ */
168
+ function update_placeholder_width(ui)
169
+ {
170
+ var parentCount = $(ui.placeholder).parents('ol').length;
171
+ var listWidth = $('.sortable').width();
172
+ var offset = ( parentCount * 40 ) - 40;
173
+ var newWidth = listWidth - offset;
174
+ $(ui.placeholder).width(newWidth).css('margin-left', offset + 'px');
175
+ update_list_visibility(ui);
176
+ }
177
+
178
+ /**
179
+ * Make new list items visible
180
+ */
181
+ function update_list_visibility(ui)
182
+ {
183
+ var parentList = $(ui.placeholder).parent('ol');
184
+ if ( !$(parentList).is(':visible') ){
185
+ $(parentList).show();
186
+ }
187
+ }
188
+
189
+
190
+ /**
191
+ * Add or Remove the submenu toggle after the list has changed
192
+ */
193
+ function add_remove_submenu_toggles()
194
+ {
195
+ $('.child-toggle').each(function(i, v){
196
+ var row = $(this).parent('.row').parent('li');
197
+
198
+ if ( $(row).children('ol').length > 0 ){
199
+ var icon = ( $(row).children('ol:visible').length > 0 ) ? 'np-icon-arrow-down' : 'np-icon-arrow-right';
200
+ $(this).html('<a href="#"><i class="' + icon + '"></i></a>');
201
+ } else {
202
+ $(this).empty();
203
+ }
204
+ });
205
+ }
206
+
207
+
208
+ /**
209
+ * Submit Sortable Form
210
+ * @todo add error div, pass message to it and show on error
211
+ */
212
+ function submit_sortable_form()
213
+ {
214
+ $('#np-error').hide();
215
+ $('#nested-loading').show();
216
+ var syncmenu = ( $('.np-sync-menu').is(':checked') ) ? 'sync' : 'nosync';
217
+
218
+ list = $('ol.sortable').nestedSortable('toHierarchy', {startDepthCount: 0});
219
+
220
+ $.ajax({
221
+ url: ajaxurl,
222
+ type: 'post',
223
+ datatype: 'json',
224
+ data: {
225
+ action : 'npsort',
226
+ nonce : nestedpages.np_nonce,
227
+ list : list,
228
+ syncmenu : syncmenu
229
+ },
230
+ success: function(data){
231
+ if (data.status === 'error'){
232
+ $('#np-error').text(data.message).show();
233
+ $('#nested-loading').hide();
234
+ } else {
235
+ $('#nested-loading').hide();
236
+ }
237
+ }
238
+ });
239
+ }
240
+
241
+
242
+
243
+
244
+
245
+ /**
246
+ * ------------------------------------------------------------------------
247
+ * Sync Menu Toggle
248
+ * ------------------------------------------------------------------------
249
+ **/
250
+ $('.np-sync-menu').on('change', function(){
251
+ var setting = ( $(this).is(':checked') ) ? 'sync' : 'nosync';
252
+ np_updated_sync_menu(setting);
253
+ });
254
+
255
+ function np_updated_sync_menu(setting)
256
+ {
257
+ $.ajax({
258
+ url: ajaxurl,
259
+ type: 'post',
260
+ datatype: 'json',
261
+ data: {
262
+ action : 'npsyncmenu',
263
+ nonce : nestedpages.np_nonce,
264
+ syncmenu : setting
265
+ },
266
+ success: function(data){
267
+ if (data.status === 'error'){
268
+ alert('There was an error saving the sync setting.')
269
+ }
270
+ }
271
+ });
272
+ }
273
+
274
+
275
+
276
+
277
+
278
+
279
+ /**
280
+ * ------------------------------------------------------------------------
281
+ * Quick Edit
282
+ * ------------------------------------------------------------------------
283
+ **/
284
+
285
+ // Show the form
286
+ $(document).on('click', '.np-quick-edit', function(e){
287
+ e.preventDefault();
288
+ revert_quick_edit();
289
+ set_quick_edit_data($(this));
290
+ });
291
+
292
+ // Cancel the form
293
+ $(document).on('click', '.np-cancel-quickedit', function(e){
294
+ var row = $(this).parents('.page-row');
295
+ revert_quick_edit(row);
296
+ e.preventDefault();
297
+ });
298
+
299
+ // Submit the form
300
+ $(document).on('click', '.np-save-quickedit', function(e){
301
+ e.preventDefault();
302
+ $('.row').removeClass('np-updated').removeClass('np-updated-show');
303
+ var form = $(this).parents('form');
304
+ $(this).attr('disabled', 'disabled');
305
+ $(form).find('.np-qe-loading').show();
306
+ submit_np_quickedit(form);
307
+ });
308
+
309
+ // Toggle the Taxonomies
310
+ $(document).on('click', '.np-toggle-taxonomies', function(e){
311
+ $(this).parents('form').find('.np-taxonomies').toggle();
312
+ });
313
+
314
+
315
+ /**
316
+ * Set Quick Edit data
317
+ */
318
+ function set_quick_edit_data(item)
319
+ {
320
+ var data = {
321
+ id : $(item).attr('data-id'),
322
+ title : $(item).attr('data-title'),
323
+ slug : $(item).attr('data-slug'),
324
+ author : $(item).attr('data-author'),
325
+ cs : $(item).attr('data-commentstatus'),
326
+ status : $(item).attr('data-status'),
327
+ template : $(item).attr('data-template'),
328
+ month : $(item).attr('data-month'),
329
+ day : $(item).attr('data-day'),
330
+ year : $(item).attr('data-year'),
331
+ hour : $(item).attr('data-hour'),
332
+ minute : $(item).attr('data-minute'),
333
+ navstatus : $(item).attr('data-navstatus'),
334
+ npstatus : $(item).attr('data-np-status'),
335
+ navtitle : $(item).attr('data-navtitle')
336
+ };
337
+ var parent_li = $(item).closest('.row').parent('li');
338
+
339
+ // Add Array of Taxonomies to the data object
340
+ data.taxonomies = [];
341
+ var classes = $(parent_li).attr('class').split(/\s+/);
342
+ for ( i = 0; i < classes.length; i++ ){
343
+ if ( classes[i].substring(0, 3) === 'in-'){
344
+ data.taxonomies.push(classes[i]);
345
+ }
346
+ }
347
+
348
+ // Append the form to the list item
349
+ if ( $(parent_li).children('ol').length > 0 ){
350
+ var child_ol = $(parent_li).children('ol');
351
+ var newform = $('.quick-edit-form').clone().insertBefore(child_ol);
352
+ } else {
353
+ var newform = $('.quick-edit-form').clone().appendTo(parent_li);
354
+ }
355
+
356
+ var row = $(newform).siblings('.row').hide();
357
+ populate_quick_edit(newform, data);
358
+ }
359
+
360
+
361
+ /**
362
+ * Populate the Quick Edit Form
363
+ */
364
+ function populate_quick_edit(form, data)
365
+ {
366
+ $(form).find('.np_id').val(data.id);
367
+ $(form).find('.np_title').val(data.title);
368
+ $(form).find('.np_slug').val(data.slug);
369
+ $(form).find('.np_author select').val(data.author);
370
+ $(form).find('.np_template').val(data.template);
371
+ $(form).find('.np_status').val(data.status);
372
+ $(form).find('.np_nav_title').val(data.navtitle);
373
+ if ( data.cs === 'open' ) $(form).find('.np_cs').prop('checked', 'checked');
374
+
375
+ if ( data.npstatus === 'hide' ){
376
+ $(form).find('.np_status').prop('checked', 'checked');
377
+ } else {
378
+ $(form).find('.np_status').removeAttr('checked');
379
+ }
380
+
381
+ if ( data.navstatus === 'hide' ) {
382
+ $(form).find('.np_nav_status').prop('checked', 'checked');
383
+ } else {
384
+ $(form).find('.np_nav_status').removeAttr('checked');
385
+ }
386
+
387
+ // Date Fields
388
+ $(form).find('select[name="mm"]').val(data.month);
389
+ $(form).find('input[name="jj"]').val(data.day);
390
+ $(form).find('input[name="aa"]').val(data.year);
391
+ $(form).find('input[name="hh"]').val(data.hour);
392
+ $(form).find('input[name="mn"]').val(data.minute);
393
+
394
+ // Populate Taxonomy Checkboxes
395
+ if ( data.hasOwnProperty('taxonomies') ){
396
+ var taxonomies = data.taxonomies;
397
+ for ( i = 0; i < taxonomies.length; i++ ){
398
+ var tax = '#' + taxonomies[i];
399
+ $(form).find(tax).prop('checked', 'checked');
400
+ }
401
+ }
402
+
403
+ $(form).show();
404
+ }
405
+
406
+
407
+ /**
408
+ * Remove the quick edit form and restore the row
409
+ */
410
+ function revert_quick_edit()
411
+ {
412
+ $('.np-quickedit-error').hide();
413
+ $('.sortable .quick-edit').remove();
414
+ $('.row').show();
415
+ }
416
+
417
+
418
+ /**
419
+ * Submit the Quick Edit Form
420
+ */
421
+ function submit_np_quickedit(form)
422
+ {
423
+ $('.np-quickedit-error').hide();
424
+ var syncmenu = ( $('.np-sync-menu').is(':checked') ) ? 'sync' : 'nosync';
425
+
426
+ $.ajax({
427
+ url: ajaxurl,
428
+ type: 'post',
429
+ datatype: 'json',
430
+ data: $(form).serialize() + '&action=npquickedit&nonce=' + nestedpages.np_nonce + '&syncmenu=' + syncmenu,
431
+ success: function(data){
432
+ if (data.status === 'error'){
433
+ np_remove_qe_loading(form);
434
+ $(form).find('.np-quickedit-error').text(data.message).show();
435
+ } else {
436
+ np_remove_qe_loading(form);
437
+ np_update_qe_data(form, data.post_data);
438
+ np_qe_update_animate(form);
439
+ }
440
+ }
441
+ });
442
+ }
443
+
444
+
445
+ /**
446
+ * Update Row Data after Quick Edit
447
+ */
448
+ function np_update_qe_data(form, data)
449
+ {
450
+ var row = $(form).parent('.quick-edit').siblings('.row');
451
+ $(row).find('.title').text(data.post_title);
452
+
453
+ var status = $(row).find('.status');
454
+ if ( (data._status !== 'publish') && (data._status !== 'future') ){
455
+ $(status).text('(' + data._status + ')');
456
+ } else {
457
+ $(status).text('');
458
+ }
459
+
460
+ // Hide / Show in Nav
461
+ var nav_status = $(row).find('.nav-status');
462
+ if ( (data.nav_status == 'hide') ){
463
+ $(nav_status).text('(Hidden)');
464
+ } else {
465
+ $(nav_status).text('');
466
+ }
467
+
468
+ // Hide / Show in Nested Pages
469
+ var li = $(row).parent('li');
470
+ if ( (data.np_status == 'hide') ){
471
+ $(li).addClass('np-hide');
472
+ $(row).find('.status').after('<i class="np-icon-eye-blocked"></i>');
473
+ } else {
474
+ $(li).removeClass('np-hide');
475
+ $(row).find('.np-icon-eye-blocked').remove();
476
+ }
477
+
478
+ var button = $(row).find('.np-quick-edit');
479
+
480
+ $(button).attr('data-id', data.post_id);
481
+ $(button).attr('data-template', data.page_template);
482
+ $(button).attr('data-title', data.post_title);
483
+ $(button).attr('data-slug', data.post_name);
484
+ $(button).attr('data-commentstatus', data.comment_status);
485
+ $(button).attr('data-status', data._status);
486
+ $(button).attr('data-author', data.post_author);
487
+ $(button).attr('data-navstatus', data.nav_status);
488
+ $(button).attr('data-np-status', data.np_status);
489
+ $(button).attr('data-navtitle', data.np_nav_title);
490
+
491
+ $(button).attr('data-month', data.mm);
492
+ $(button).attr('data-day', data.jj);
493
+ $(button).attr('data-year', data.aa);
494
+ $(button).attr('data-hour', data.hh);
495
+ $(button).attr('data-minute', data.mn);
496
+
497
+ np_remove_taxonomy_classes(li);
498
+ np_add_category_classes(li, data);
499
+ np_add_taxonomy_classes(li, data);
500
+
501
+ }
502
+
503
+
504
+ /**
505
+ * Remove taxonomy classes from the row
506
+ */
507
+ function np_remove_taxonomy_classes(row)
508
+ {
509
+ taxonomies = [];
510
+ var classes = $(row).attr('class').split(/\s+/);
511
+ for ( i = 0; i < classes.length; i++ ){
512
+ if ( classes[i].substring(0, 3) === 'in-'){
513
+ $(row).removeClass(classes[i]);
514
+ }
515
+ }
516
+ }
517
+
518
+
519
+ /**
520
+ * Add category classes to the row
521
+ */
522
+ function np_add_category_classes(row, data)
523
+ {
524
+ if ( data.hasOwnProperty('post_category') ){
525
+ var cats = data.post_category;
526
+ for ( i = 0; i < cats.length; i++ ){
527
+ var taxclass = 'in-category-' + cats[i];
528
+ $(row).addClass(taxclass);
529
+ }
530
+ }
531
+ }
532
+
533
+
534
+ /**
535
+ * Add Taxonomy Classes to the row
536
+ */
537
+ function np_add_taxonomy_classes(row, data)
538
+ {
539
+ if ( data.hasOwnProperty('tax_input') )
540
+ {
541
+ var taxonomies = data.tax_input;
542
+ $.each(taxonomies, function(tax, terms){
543
+ for (i = 0; i < terms.length; i++){
544
+ var taxclass = 'in-' + tax + '-' + terms[i];
545
+ $(row).addClass(taxclass);
546
+ }
547
+ });
548
+
549
+ }
550
+ }
551
+
552
+
553
+ /**
554
+ * Remove loading state from Quick Edit form
555
+ */
556
+ function np_remove_qe_loading(form)
557
+ {
558
+ $(form).find('.np-save-quickedit').removeAttr('disabled');
559
+ $(form).find('.np-qe-loading').hide();
560
+ }
561
+
562
+ /**
563
+ * Show quick edit update animation
564
+ */
565
+ function np_qe_update_animate(form)
566
+ {
567
+ var row = $(form).parent('.quick-edit').siblings('.row');
568
+ $(row).addClass('np-updated');
569
+ $(row).show();
570
+ $(form).parent('.quick-edit').remove();
571
+ np_set_borders();
572
+ setTimeout(function(){
573
+ $(row).addClass('np-updated-show');
574
+ }, 1500);
575
+ }
576
+
577
+
578
+ }); //$
assets/js/nestedpages.min.js ADDED
@@ -0,0 +1 @@
 
1
+ jQuery(function(t){function e(){var e=t(".nplist");t(".page-row").removeClass("no-border"),t.each(e,function(){t(this).find(".page-row:visible:first").addClass("no-border")})}function a(e){var a=t(e.placeholder).parents("ol").length,i=t(".sortable").width(),s=40*a-40,o=i-s;t(e.placeholder).width(o).css("margin-left",s+"px"),n(e)}function n(e){var a=t(e.placeholder).parent("ol");t(a).is(":visible")||t(a).show()}function s(){t(".child-toggle").each(function(){var e=t(this).parent(".row").parent("li");if(t(e).children("ol").length>0){var a=t(e).children("ol:visible").length>0?"np-icon-arrow-down":"np-icon-arrow-right";t(this).html('<a href="#"><i class="'+a+'"></i></a>')}else t(this).empty()})}function o(){t("#np-error").hide(),t("#nested-loading").show();var e=t(".np-sync-menu").is(":checked")?"sync":"nosync";list=t("ol.sortable").nestedSortable("toHierarchy",{startDepthCount:0}),t.ajax({url:ajaxurl,type:"post",datatype:"json",data:{action:"npsort",nonce:nestedpages.np_nonce,list:list,syncmenu:e},success:function(e){"error"===e.status?(t("#np-error").text(e.message).show(),t("#nested-loading").hide()):t("#nested-loading").hide()}})}function r(e){t.ajax({url:ajaxurl,type:"post",datatype:"json",data:{action:"npsyncmenu",nonce:nestedpages.np_nonce,syncmenu:e},success:function(t){"error"===t.status&&alert("There was an error saving the sync setting.")}})}function d(e){var a={id:t(e).attr("data-id"),title:t(e).attr("data-title"),slug:t(e).attr("data-slug"),author:t(e).attr("data-author"),cs:t(e).attr("data-commentstatus"),status:t(e).attr("data-status"),template:t(e).attr("data-template"),month:t(e).attr("data-month"),day:t(e).attr("data-day"),year:t(e).attr("data-year"),hour:t(e).attr("data-hour"),minute:t(e).attr("data-minute"),navstatus:t(e).attr("data-navstatus"),npstatus:t(e).attr("data-np-status"),navtitle:t(e).attr("data-navtitle")},n=t(e).closest(".row").parent("li");a.taxonomies=[];var s=t(n).attr("class").split(/\s+/);for(i=0;i<s.length;i++)"in-"===s[i].substring(0,3)&&a.taxonomies.push(s[i]);if(t(n).children("ol").length>0)var o=t(n).children("ol"),r=t(".quick-edit-form").clone().insertBefore(o);else var r=t(".quick-edit-form").clone().appendTo(n);t(r).siblings(".row").hide();l(r,a)}function l(e,a){if(t(e).find(".np_id").val(a.id),t(e).find(".np_title").val(a.title),t(e).find(".np_slug").val(a.slug),t(e).find(".np_author select").val(a.author),t(e).find(".np_template").val(a.template),t(e).find(".np_status").val(a.status),t(e).find(".np_nav_title").val(a.navtitle),"open"===a.cs&&t(e).find(".np_cs").prop("checked","checked"),"hide"===a.npstatus?t(e).find(".np_status").prop("checked","checked"):t(e).find(".np_status").removeAttr("checked"),"hide"===a.navstatus?t(e).find(".np_nav_status").prop("checked","checked"):t(e).find(".np_nav_status").removeAttr("checked"),t(e).find('select[name="mm"]').val(a.month),t(e).find('input[name="jj"]').val(a.day),t(e).find('input[name="aa"]').val(a.year),t(e).find('input[name="hh"]').val(a.hour),t(e).find('input[name="mn"]').val(a.minute),a.hasOwnProperty("taxonomies")){var n=a.taxonomies;for(i=0;i<n.length;i++){var s="#"+n[i];t(e).find(s).prop("checked","checked")}}t(e).show()}function c(){t(".np-quickedit-error").hide(),t(".sortable .quick-edit").remove(),t(".row").show()}function u(e){t(".np-quickedit-error").hide();var a=t(".np-sync-menu").is(":checked")?"sync":"nosync";t.ajax({url:ajaxurl,type:"post",datatype:"json",data:t(e).serialize()+"&action=npquickedit&nonce="+nestedpages.np_nonce+"&syncmenu="+a,success:function(a){"error"===a.status?(g(e),t(e).find(".np-quickedit-error").text(a.message).show()):(g(e),p(e,a.post_data),m(e))}})}function p(e,a){var n=t(e).parent(".quick-edit").siblings(".row");t(n).find(".title").text(a.post_title);var i=t(n).find(".status");t(i).text("publish"!==a._status&&"future"!==a._status?"("+a._status+")":"");var s=t(n).find(".nav-status");t(s).text("hide"==a.nav_status?"(Hidden)":"");var o=t(n).parent("li");"hide"==a.np_status?(t(o).addClass("np-hide"),t(n).find(".status").after('<i class="np-icon-eye-blocked"></i>')):(t(o).removeClass("np-hide"),t(n).find(".np-icon-eye-blocked").remove());var r=t(n).find(".np-quick-edit");t(r).attr("data-id",a.post_id),t(r).attr("data-template",a.page_template),t(r).attr("data-title",a.post_title),t(r).attr("data-slug",a.post_name),t(r).attr("data-commentstatus",a.comment_status),t(r).attr("data-status",a._status),t(r).attr("data-author",a.post_author),t(r).attr("data-navstatus",a.nav_status),t(r).attr("data-np-status",a.np_status),t(r).attr("data-navtitle",a.np_nav_title),t(r).attr("data-month",a.mm),t(r).attr("data-day",a.jj),t(r).attr("data-year",a.aa),t(r).attr("data-hour",a.hh),t(r).attr("data-minute",a.mn),h(o),f(o,a),v(o,a)}function h(e){taxonomies=[];var a=t(e).attr("class").split(/\s+/);for(i=0;i<a.length;i++)"in-"===a[i].substring(0,3)&&t(e).removeClass(a[i])}function f(e,a){if(a.hasOwnProperty("post_category")){var n=a.post_category;for(i=0;i<n.length;i++){var s="in-category-"+n[i];t(e).addClass(s)}}}function v(e,a){if(a.hasOwnProperty("tax_input")){var n=a.tax_input;t.each(n,function(a,n){for(i=0;i<n.length;i++){var s="in-"+a+"-"+n[i];t(e).addClass(s)}})}}function g(e){t(e).find(".np-save-quickedit").removeAttr("disabled"),t(e).find(".np-qe-loading").hide()}function m(a){var n=t(a).parent(".quick-edit").siblings(".row");t(n).addClass("np-updated"),t(n).show(),t(a).parent(".quick-edit").remove(),e(),setTimeout(function(){t(n).addClass("np-updated-show")},1500)}t(document).ready(function(){s(),e()}),t(document).on("click",".child-toggle a",function(a){a.preventDefault();var n=t(this).parent(".child-toggle").parent(".row").siblings("ol");t(this).find("i").toggleClass("np-icon-arrow-down").toggleClass("np-icon-arrow-right"),t(n).toggle(),e()}),t(document).on("click",".nestedpages-toggleall a",function(a){a.preventDefault(),"closed"==t(this).attr("data-toggle")?(t(".nestedpages ol li ol").show(),t(this).attr("data-toggle","opened"),t(this).text(nestedpages.collapse_text),t(".child-toggle i").removeClass("np-icon-arrow-right").addClass("np-icon-arrow-down"),c(),e()):(t(".nestedpages ol li ol").hide(),t(this).attr("data-toggle","closed"),t(this).text(nestedpages.expand_text),t(".child-toggle i").removeClass("np-icon-arrow-down").addClass("np-icon-arrow-right"),c(),e())}),t(document).on("click",".np-toggle-hidden",function(a){a.preventDefault();var n=t(this).attr("href");"show"===n?(t(this).attr("href","hide"),t(this).text("Show Hidden Pages"),t(".np-hide").removeClass("shown").hide(),e()):(t(this).attr("href","show"),t(this).text("Hide Hidden Pages"),t(".np-hide").addClass("shown").show(),e())}),t(document).on("click",".np-toggle-publish",function(e){e.preventDefault();var a=t(this).attr("href");t(".np-toggle-publish").removeClass("active"),t(this).addClass("active"),"#published"==a?(t(".nplist .page-row").hide(),t(".nplist .published").show()):t(".nplist .page-row").show()}),t(document).on("click",".np-toggle-edit",function(e){e.preventDefault();var a=t(this).siblings(".action-buttons");t(a).is(":visible")?(t(this).removeClass("active"),t(a).hide()):(t(this).addClass("active"),t(a).show())});var w=function(){var t=0;return function(e,a){clearTimeout(t),t=setTimeout(e,a)}}();t(window).resize(function(){w(function(){t(".action-buttons").removeAttr("style"),t(".np-toggle-edit").removeClass("active")},500)}),t(document).ready(function(){t(".sortable").not(".no-sort").nestedSortable({items:"li",toleranceElement:"> .row",handle:".handle",placeholder:"ui-sortable-placeholder",start:function(t,e){e.placeholder.height(e.item.height())},sort:function(t,e){a(e)},stop:function(){setTimeout(function(){s(),e()},100),o()},update:function(){}})}),t(".np-sync-menu").on("change",function(){var e=t(this).is(":checked")?"sync":"nosync";r(e)}),t(document).on("click",".np-quick-edit",function(e){e.preventDefault(),c(),d(t(this))}),t(document).on("click",".np-cancel-quickedit",function(e){var a=t(this).parents(".page-row");c(a),e.preventDefault()}),t(document).on("click",".np-save-quickedit",function(e){e.preventDefault(),t(".row").removeClass("np-updated").removeClass("np-updated-show");var a=t(this).parents("form");t(this).attr("disabled","disabled"),t(a).find(".np-qe-loading").show(),u(a)}),t(document).on("click",".np-toggle-taxonomies",function(){t(this).parents("form").find(".np-taxonomies").toggle()})});
assets/screenshot-1.png ADDED
Binary file
assets/screenshot-2.png ADDED
Binary file
assets/screenshot-3.gif ADDED
Binary file
assets/screenshot-4.gif ADDED
Binary file
assets/scss/_alerts.scss ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // Alerts
3
+ // --------------------------------------------------
4
+
5
+ // error in quick edit form
6
+ .np-quickedit-error {
7
+ border-left: 4px solid #dd3d36;
8
+ padding: 4px 0 4px 8px;
9
+ margin-bottom: 10px;
10
+ background-color: $gray-lighter;
11
+ }
assets/scss/_buttons.scss ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // Buttons
3
+ // --------------------------------------------------
4
+ .np-btn {
5
+ text-decoration: none;
6
+ color: #555;
7
+ display: inline-block;
8
+ background-color: #f7f7f7;
9
+ border: 1px solid $border;
10
+ padding: 3px 8px;
11
+ box-shadow: inset 0 1px 0 #fff, 0 1px 0 rgba(0,0,0,.08);
12
+ transition: all 200ms ease;
13
+ &:hover {
14
+ background-color: $blue;
15
+ color: $white;
16
+ transition: all 200ms ease;
17
+ box-shadow: 0 1px 0 rgba(0,0,0,.08);
18
+ }
19
+ }
20
+
21
+
22
+ .np-btn-trash {
23
+ background-color: $red;
24
+ border-color: $red;
25
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .3), 0 1px 0 rgba(0,0,0,.08);
26
+ color: $white;
27
+ &:hover {
28
+ background-color: darken($red, 15%);
29
+ border-color: darken($red, 15%);
30
+ }
31
+ }
32
+
33
+ // Toggle button for edit buttons (responsive)
34
+ .np-toggle-edit {
35
+ display: none;
36
+ float: right;
37
+ margin-right: 10px;
38
+ @extend .np-btn;
39
+ &.active {
40
+ background-color: $blue;
41
+ color: $white;
42
+ box-shadow: none;
43
+ border-color: $blue;
44
+ }
45
+ }
46
+ @media (max-width: 767px)
47
+ {
48
+ .np-toggle-edit {
49
+ display: inline-block;
50
+ }
51
+ }
assets/scss/_expand-handle.scss ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Expand/Contract Button
2
+ .wppages-handle-expand {
3
+ float: left;
4
+ background-color: darken($white, 5%);
5
+ font-size: 18px;
6
+ width: 46px;
7
+ height: 46px;
8
+ margin-right: 5px;
9
+ text-align: center;
10
+ border-right: 1px solid $border;
11
+ div {
12
+ background-color: $white;
13
+ border: 1px solid $border;
14
+ width: 24px;
15
+ height: 24px;
16
+ line-height: 24px;
17
+ border-radius: 15px;
18
+ margin-top: 9px;
19
+ cursor: pointer;
20
+ transition: all 200ms ease;
21
+ &:hover {
22
+ background-color: $blue;
23
+ border-color: $blue;
24
+ color: $white;
25
+ transition: all 200ms ease;
26
+ }
27
+ }
28
+ }
assets/scss/_icons.scss ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @font-face {
2
+ font-family: 'nestedpages';
3
+ src:url('fonts/nestedpages.eot?-cjbqo6');
4
+ src:url('fonts/nestedpages.eot?#iefix-cjbqo6') format('embedded-opentype'),
5
+ url('fonts/nestedpages.woff?-cjbqo6') format('woff'),
6
+ url('fonts/nestedpages.ttf?-cjbqo6') format('truetype'),
7
+ url('fonts/nestedpages.svg?-cjbqo6#nestedpages') format('svg');
8
+ font-weight: normal;
9
+ font-style: normal;
10
+ }
11
+
12
+ [class^="np-icon-"], [class*=" np-icon-"] {
13
+ font-family: 'nestedpages';
14
+ speak: none;
15
+ font-style: normal;
16
+ font-weight: normal;
17
+ font-variant: normal;
18
+ text-transform: none;
19
+ line-height: 1;
20
+
21
+ /* Better Font Rendering =========== */
22
+ -webkit-font-smoothing: antialiased;
23
+ -moz-osx-font-smoothing: grayscale;
24
+ }
25
+ .np-icon-no:before {
26
+ content: "\e601";
27
+ }
28
+ .np-icon-yes:before {
29
+ content: "\e602";
30
+ }
31
+ .np-icon-menu:before {
32
+ content: "\e603";
33
+ }
34
+ .np-icon-arrow-down:before {
35
+ content: "\e604";
36
+ }
37
+ .np-icon-arrow-right:before {
38
+ content: "\e605";
39
+ }
40
+ .np-icon-sub-menu:before {
41
+ content: "\e600";
42
+ }
43
+ .np-icon-pencil:before {
44
+ content: "\e608";
45
+ }
46
+ .np-icon-bubble:before {
47
+ content: "\e607";
48
+ }
49
+ .np-icon-lock:before {
50
+ content: "\e609";
51
+ }
52
+ .np-icon-remove:before {
53
+ content: "\e60a";
54
+ }
55
+ .np-icon-menu2:before {
56
+ content: "\e606";
57
+ }
58
+ .np-icon-eye:before {
59
+ content: "\e60b";
60
+ }
61
+ .np-icon-eye-blocked:before {
62
+ content: "\e60c";
63
+ }
assets/scss/_mixins.scss ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // Mixins
3
+ // --------------------------------------------------
4
+ @mixin clearfix {
5
+ zoom: 1;
6
+ &:before,
7
+ &:after {
8
+ content: " "; /* 1 */
9
+ display: table; /* 2 */
10
+ }
11
+ &:after {
12
+ clear: both;
13
+ }
14
+ }
15
+
16
+ @mixin unstyled {
17
+ list-style-type: none;
18
+ margin: 0;
19
+ padding: 0;
20
+ }
21
+
22
+ // WP Dashboard Styling
23
+ @mixin wptable {
24
+ box-shadow: 0 1px 1px rgba(0,0,0,.06);
25
+ border: 1px solid $border-light;
26
+ border-radius: 3px;
27
+ }
assets/scss/_page-listing.scss ADDED
@@ -0,0 +1,309 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // The Page Listing
3
+ // --------------------------------------------------
4
+
5
+ .nestedpages {
6
+ clear: both;
7
+ border-radius: 4px;
8
+
9
+ // Sortable Placeholder
10
+ .ui-sortable-placeholder {
11
+ display: block !important;
12
+ position: relative;
13
+ min-height: 46px;
14
+ border: 0;
15
+ border: 1px dashed $blue !important;
16
+ background-color: lighten($blue, 65%);
17
+ margin: 0;
18
+ }
19
+
20
+ // Sortable Helper
21
+ .ui-sortable-helper {
22
+ opacity: 0.8;
23
+ box-shadow: 2px 2px 3px 0px rgba(0,0,0,.5);
24
+ }
25
+
26
+
27
+ ol {
28
+ list-style-type: none;
29
+ clear: both;
30
+ margin: 0;
31
+ @include wptable;
32
+
33
+ a {
34
+ text-decoration: none;
35
+ }
36
+
37
+
38
+ .page-link {
39
+ line-height: 26px;
40
+ .edit-indicator {
41
+ margin-left: 10px;
42
+ display: none;
43
+ i {
44
+ font-size: 12px;
45
+ margin-right: 3px;
46
+ }
47
+ }
48
+ &:hover {
49
+ .edit-indicator {
50
+ display: inline-block;
51
+ }
52
+ }
53
+ }
54
+
55
+ // Indicates post is being edited
56
+ .locked {
57
+ color: $black;
58
+ margin-left: 20px;
59
+ em {
60
+ font-style: normal;
61
+ }
62
+ }
63
+
64
+ // Indicates status if not published
65
+ .status {
66
+ color: darken($white, 40%);
67
+ margin: 0px 10px;
68
+ }
69
+
70
+ // Indicates page is hidden from nested pages
71
+ .np-icon-eye-blocked {
72
+ color: darken($white, 40%);
73
+ }
74
+
75
+ // Indicates hidden from nav is selected
76
+ .nav-status {
77
+ color: darken($white, 30%);
78
+ }
79
+
80
+ // Hidden from Nested Pages
81
+ .np-hide {
82
+ display: none;
83
+ }
84
+
85
+ // Yoast SEO Indicator
86
+ // See Yoast's metabox-tabs.css
87
+ .np-seo-indicator {
88
+ display: block;
89
+ float: right;
90
+ width: 12px;
91
+ height: 12px;
92
+ border-radius: 8px;
93
+ background-color: darken($white, 40%);
94
+ margin: 6px 10px 0 0;
95
+ &.good {
96
+ background-color: #7ad03a;
97
+ }
98
+ &.ok {
99
+ background-color: #ffba00;
100
+ }
101
+ &.poor {
102
+ background-color: #ee7c1b;
103
+ }
104
+ &.bad {
105
+ background-color: #dd3d36;
106
+ }
107
+ &.warn {
108
+ background-color: maroon;
109
+ }
110
+ &.wrong {
111
+ background-color: red;
112
+ }
113
+ }
114
+
115
+ li {
116
+ margin: 0;
117
+ border-top: 1px solid $border;
118
+ background-color: $blue;
119
+ &.first {
120
+ border: 0;
121
+ }
122
+ &:first-child {
123
+ border: 0;
124
+ }
125
+ &.no-border {
126
+ border: 0;
127
+ }
128
+ } // li
129
+
130
+ ol {
131
+ display: none;
132
+ border-radius: 0;
133
+ list-style-type: none;
134
+ border: 0;
135
+ box-shadow: none;
136
+ border-top: 1px solid $border;
137
+ } // ol 2
138
+
139
+ } // ol 1
140
+
141
+ // Block that holds the toggle child arrow
142
+ .child-toggle {
143
+ float: left;
144
+ margin: -10px 10px 0 0;
145
+ width: 46px;
146
+ height: 46px;
147
+ background-color: darken($white, 6%);
148
+ text-align: center;
149
+ a { // Arrow Toggle
150
+ display: inline-block;
151
+ margin-top: 7px;
152
+ width: 28px;
153
+ height: 28px;
154
+ background-color: $white;
155
+ border: 1px solid $border;
156
+ border-radius: 20px;
157
+ font-size: 20px;
158
+ line-height: 30px;
159
+ color: $black;
160
+ transition: all 200ms ease;
161
+ i {
162
+ line-height: 26px;
163
+ }
164
+ &:hover {
165
+ background-color: $blue;
166
+ color: $white;
167
+ border-color: $blue;
168
+ }
169
+ }
170
+ } // .child-toggle
171
+
172
+
173
+ // Handle for sortable functionality
174
+ .handle {
175
+ display: inline-block;
176
+ cursor: move;
177
+ font-size: 20px;
178
+ color: darken($white, 30%);
179
+ transition: all 200ms ease;
180
+ position: relative;
181
+ top: 3px;
182
+ &:hover {
183
+ transition: all 200ms ease;
184
+ color: $blue;
185
+ }
186
+ } // .handle
187
+
188
+
189
+ // Submenu Indicator
190
+ .np-icon-sub-menu {
191
+ display: none;
192
+ color: darken($white, 40%);
193
+ position: relative;
194
+ left: 2px;
195
+ }
196
+
197
+
198
+ // Normalize the submenu and handle icons
199
+ .handle, .np-icon-sub-menu {
200
+ width: 30px;
201
+ height: 46px;
202
+ line-height: 36px;
203
+ margin-top: -10px;
204
+ }
205
+
206
+ // Hide/show the submenu indicator & handle on hover of the row
207
+ li ol .row {
208
+ .np-icon-sub-menu { display: inline-block; }
209
+ .handle { display: none; }
210
+ &:hover {
211
+ .np-icon-sub-menu { display: none; }
212
+ .handle { display: inline-block; }
213
+ }
214
+ }
215
+
216
+
217
+ // Main Row Element
218
+ .row {
219
+ background-color: $white;
220
+ display: block;
221
+ padding: 10px 0px 0px 0px;
222
+ height: 36px;
223
+ @include clearfix;
224
+ &:hover {
225
+ background-color: darken($white, 6%);
226
+ }
227
+ &.np-updated {
228
+ background-color: lighten(#7ad03a, 40%);
229
+ transition: background-color 400ms ease;
230
+ }
231
+ &.np-updated-show {
232
+ background-color: $white;
233
+ transition: background-color 400ms ease;
234
+ }
235
+ } // .row
236
+
237
+
238
+ // Inner row element gets padding to give visual indicator of nested depth
239
+ ol li ol {
240
+ .row-inner {
241
+ padding-left: 86px;
242
+ }
243
+ li ol {
244
+ .row-inner {
245
+ padding-left: 116px;
246
+ }
247
+ li ol {
248
+ .row-inner {
249
+ padding-left: 156px;
250
+ }
251
+ }
252
+ }
253
+ }
254
+
255
+ // Action Buttons
256
+ .action-buttons {
257
+ display: none;
258
+ float: right;
259
+ margin: 0 10px 0 0;
260
+ a {
261
+ margin-left: 5px;
262
+ }
263
+ }
264
+
265
+
266
+ } // .nestedpages
267
+
268
+ @media (min-width: 768px)
269
+ {
270
+ .nestedpages .row:hover .action-buttons {
271
+ display: block;
272
+ }
273
+ }
274
+
275
+
276
+ @media (max-width: 767px)
277
+ {
278
+ .nestedpages {
279
+ ol .page-link {
280
+ line-height: 24px;
281
+ &:hover span {
282
+ display: none;
283
+ }
284
+ }
285
+
286
+ ol .locked em {
287
+ display: none;
288
+ }
289
+
290
+ .child-toggle {
291
+ background: transparent;
292
+ }
293
+
294
+ .row {
295
+ height: auto;
296
+ }
297
+
298
+ .action-buttons {
299
+ display: none;
300
+ background-color: $blue;
301
+ float: none;
302
+ margin: 0;
303
+ padding: 8px;
304
+ a {
305
+ margin-left: 5px;
306
+ }
307
+ }
308
+ } // .nestedpages
309
+ } // media query
assets/scss/_quick-edit.scss ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // Quick Edit Form
3
+ // --------------------------------------------------
4
+ .nestedpages .quick-edit {
5
+ background-color: $white;
6
+ border-radius: 0;
7
+ .form-interior {
8
+ padding: 10px;
9
+ }
10
+ h3 {
11
+ margin: 0 0 8px 0;
12
+ font-size: 14px;
13
+ }
14
+ .fields {
15
+ margin-bottom: 10px;
16
+ background: url('../images/border.png') repeat-y;
17
+ background-position: center;
18
+ @include clearfix;
19
+ }
20
+ .left {
21
+ float: left;
22
+ width: 48%;
23
+ }
24
+ .right {
25
+ float: right;
26
+ width: 48%;
27
+ }
28
+ label {
29
+ font-style: oblique;
30
+ }
31
+ .buttons {
32
+ clear: both;
33
+ @include clearfix;
34
+ background-color: darken($white, 75%);
35
+ padding: 8px;
36
+ }
37
+ .form-control {
38
+ clear: both;
39
+ @include clearfix;
40
+ margin-bottom: 5px;
41
+ input[type='text'],
42
+ input[type='password'],
43
+ select {
44
+ float: right;
45
+ width: 75%;
46
+ }
47
+ label {
48
+ float: left;
49
+ width: 20%;
50
+ }
51
+ }
52
+ .comments {
53
+ float: right;
54
+ width: 75%;
55
+ margin-bottom: 10px;
56
+ @include clearfix;
57
+ }
58
+ .dates {
59
+ float: right;
60
+ width: 75%;
61
+ margin-bottom: 6px;
62
+ select {
63
+ width: 25%;
64
+ }
65
+ input {
66
+ width: 12%;
67
+ }
68
+ }
69
+ .np-qe-loading {
70
+ display: none;
71
+ float: right;
72
+ width: 25px;
73
+ height: 25px;
74
+ margin: 2px 10px 0 0;
75
+ background: url('../images/loading-white.gif') no-repeat;
76
+ }
77
+
78
+ // Taxonomies
79
+ .np-toggle-taxonomies {
80
+ clear: both;
81
+ float: right;
82
+ width: 71%;
83
+ text-align: center;
84
+ }
85
+ .np-taxonomies {
86
+ display: none;
87
+ clear: both;
88
+ background-color: $gray-lighter;
89
+ padding: 8px;
90
+ @include clearfix;
91
+ }
92
+ .np-taxonomy {
93
+ float: left;
94
+ width: 30%;
95
+ margin-right: 3.33%;
96
+ .title {
97
+ font-weight: bold;
98
+ margin-bottom: 4px;
99
+ display: block;
100
+ }
101
+ li {
102
+ background-color: $white;
103
+ border: 0;
104
+ }
105
+ } // .np-taxonomy
106
+ }
107
+
108
+ @media (max-width: 767px)
109
+ {
110
+ .nestedpages .quick-edit {
111
+ .fields {
112
+ background: transparent;
113
+ }
114
+ .left, .right {
115
+ float: none;
116
+ width: 100%;
117
+ }
118
+ .form-control {
119
+ margin-bottom: 10px;
120
+ input[type='text'],
121
+ input[type='password'],
122
+ select {
123
+ float: none;
124
+ width: 100%;
125
+ }
126
+ label {
127
+ display: block;
128
+ float: none;
129
+ width: 100%;
130
+ margin-bottom: 4px;
131
+ }
132
+ }
133
+ .comments {
134
+ float: none;
135
+ width: 100%;
136
+ }
137
+ .dates {
138
+ float: none;
139
+ width: 100%;
140
+ margin-bottom: 6px;
141
+ }
142
+ }
143
+ }
assets/scss/_toggle-all.scss ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // Toggle Visibility of pages
3
+ // --------------------------------------------------
4
+ .nestedpages-toggleall {
5
+ float: right;
6
+ margin-top: -30px;
7
+ }
8
+
9
+ // Publish Toggle
10
+ .np-toggle-publish {
11
+ color: darken($white, 40%);
12
+ &.active {
13
+ color: $black;
14
+ font-weight: bold;
15
+ }
16
+ }
17
+
18
+ // Sync Menu
19
+ .np-sync-menu-cont {
20
+ float: right;
21
+ margin: -27px 15px 0px 0px;
22
+ }
23
+
24
+ #nested-loading {
25
+ display: none;
26
+ float: right;
27
+ width: 30px;
28
+ margin: -31px 120px 0 0;
29
+ }
assets/scss/_top-tools.scss ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // Links/Tools Above the Page Listing
3
+ // --------------------------------------------------
4
+ .wppages-top-tools {
5
+ margin-bottom: 20px;
6
+ padding-top: 10px;
7
+ a {
8
+ text-decoration: none;
9
+ }
10
+ }
assets/scss/_variables.scss ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // Variables
3
+ // --------------------------------------------------
4
+ $black: #333;
5
+ $white: #ffffff;
6
+ $gray-lighter: #f9f9f9; // WP BG
7
+
8
+ $border: #e1e1e1;
9
+ $border-light: #e5e5e5;
10
+
11
+ $blue: #0074a2; // WP Blue
12
+ $red: #e14d43; // WP red
assets/scss/nestedpages.scss ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // WP Pages Styles
3
+ // --------------------------------------------------
4
+ @import "_variables.scss";
5
+ @import "_mixins.scss";
6
+
7
+ @import "_icons.scss";
8
+ @import "_buttons.scss";
9
+ @import "_alerts.scss";
10
+ @import "_toggle-all.scss";
11
+
12
+ @import "_top-tools.scss";
13
+ @import "_expand-handle.scss";
14
+ @import "_page-listing.scss";
15
+ @import "_quick-edit.scss";
includes/class-nestedpages.php ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // Activate and Check Versions
3
+ require_once('class-np-activate.php');
4
+
5
+ // Form Handlers
6
+ require_once('class-np-handler-sort.php');
7
+ require_once('class-np-handler-quickedit.php');
8
+ require_once('class-np-handler-syncmenu.php');
9
+
10
+ // Required Classes
11
+ require_once('class-np-dependencies.php');
12
+ require_once('class-np-pagelisting.php');
13
+ require_once('class-np-newpage.php');
14
+
15
+ /**
16
+ * Primary Plugin Class
17
+ */
18
+ class NestedPages {
19
+
20
+
21
+ public function __construct()
22
+ {
23
+ $this->init();
24
+ $this->formActions();
25
+ add_action('init', array($this, 'addLocalization') );
26
+ }
27
+
28
+
29
+ /**
30
+ * Initialize Plugin
31
+ */
32
+ public function init()
33
+ {
34
+ new NP_Activate;
35
+ new NP_Dependencies;
36
+ new NP_PageListing;
37
+ new NP_NewPage;
38
+ }
39
+
40
+
41
+ /**
42
+ * Set Form Actions & Handlers
43
+ */
44
+ public function formActions()
45
+ {
46
+ if ( is_admin() ) {
47
+ add_action( 'wp_ajax_npsort', 'nestedpages_sort_handler' );
48
+ add_action( 'wp_ajax_npquickedit', 'nestedpages_quickedit_handler' );
49
+ add_action( 'wp_ajax_npsyncmenu', 'nestedpages_syncmenu_handler' );
50
+ }
51
+ }
52
+
53
+
54
+ /**
55
+ * Localization Domain
56
+ */
57
+ public function addLocalization()
58
+ {
59
+ load_plugin_textdomain('nestedpages', false, dirname( dirname( plugin_basename( __FILE__ ) ) ) . '/languages' );
60
+ }
61
+
62
+
63
+ }
includes/class-np-activate.php ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Plugin Activation
4
+ */
5
+ require_once('class-np-navmenu.php');
6
+ class NP_Activate {
7
+
8
+ /**
9
+ * Plugin Version
10
+ */
11
+ private $version;
12
+
13
+
14
+ public function __construct()
15
+ {
16
+ register_activation_hook( dirname( dirname(__FILE__) ) . '/nestedpages.php', array($this, 'install') );
17
+ $this->version = 1.0;
18
+ $this->setVersion();
19
+ $this->addMenu();
20
+ }
21
+
22
+
23
+ /**
24
+ * Activation Hook
25
+ */
26
+ public function install()
27
+ {
28
+ $this->checkVersions();
29
+ $this->setOptions();
30
+ }
31
+
32
+
33
+ /**
34
+ * Check Wordpress and PHP versions
35
+ */
36
+ private function checkVersions( $wp = '3.9', $php = '5.3.0' ) {
37
+ global $wp_version;
38
+ if ( version_compare( PHP_VERSION, $php, '<' ) )
39
+ $flag = 'PHP';
40
+ elseif ( version_compare( $wp_version, $wp, '<' ) )
41
+ $flag = 'WordPress';
42
+ else
43
+ return;
44
+ $version = 'PHP' == $flag ? $php : $wp;
45
+ deactivate_plugins( basename( __FILE__ ) );
46
+
47
+ wp_die('<p><strong>Nested Pages</strong> plugin requires'.$flag.' version '.$version.' or greater.</p>','Plugin Activation Error', array( 'response'=>200, 'back_link'=>TRUE ) );
48
+ }
49
+
50
+
51
+ /**
52
+ * Set the Plugin Version
53
+ */
54
+ private function setVersion()
55
+ {
56
+ if ( !get_option('nestedpages_version') ){
57
+ update_option('nestedpages_version', $this->version);
58
+ }
59
+ elseif ( get_option('nestedpages_version') < $this->version ){
60
+ update_option('nestedpages_version', $this->version);
61
+ }
62
+ }
63
+
64
+
65
+ /**
66
+ * Add the nav menu
67
+ */
68
+ public function addMenu()
69
+ {
70
+ $menu_e = get_term_by('slug', 'nestedpages', 'nav_menu');
71
+ if ( !$menu_e ){
72
+ $menu = new NP_NavMenu;
73
+ $menu->addMenu();
74
+ }
75
+ }
76
+
77
+
78
+ /**
79
+ * Set Default Options
80
+ */
81
+ private function setOptions()
82
+ {
83
+ if ( !get_option('nestedpages_menusync') ){
84
+ update_option('nestedpages_menusync', 'sync');
85
+ }
86
+ }
87
+
88
+
89
+ }
includes/class-np-dependencies.php ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Plugin JS & CSS Dependencies
4
+ */
5
+ class NP_Dependencies {
6
+
7
+ /**
8
+ * Plugin Directory
9
+ */
10
+ private $plugin_dir;
11
+
12
+ public function __construct()
13
+ {
14
+ add_action( 'admin_enqueue_scripts', array($this, 'styles') );
15
+ add_action( 'admin_enqueue_scripts', array($this, 'scripts') );
16
+ $this->plugin_dir = plugins_url() . '/wp-nested-pages';
17
+ }
18
+
19
+
20
+ /**
21
+ * Admin Styles
22
+ */
23
+ public function styles()
24
+ {
25
+ wp_enqueue_style(
26
+ 'nestedpages',
27
+ $this->plugin_dir . '/assets/css/nestedpages.css',
28
+ array(),
29
+ '1.0'
30
+ );
31
+ }
32
+
33
+
34
+ /**
35
+ * Admin Scripts required by plugin
36
+ * Only Loads on the Nested Pages screen
37
+ */
38
+ public function scripts()
39
+ {
40
+ $screen = get_current_screen();
41
+ if ( strpos( $screen->id, 'nestedpages' ) ) :
42
+ wp_enqueue_script('jquery-ui-core');
43
+
44
+ wp_enqueue_script('jquery-ui-sortable');
45
+
46
+ wp_enqueue_script(
47
+ 'ui-touch-punch',
48
+ $this->plugin_dir . '/assets/js/lib/jquery.ui.touch-punch.min.js',
49
+ array('jquery', 'jquery-ui-sortable'),
50
+ '1.0'
51
+ );
52
+
53
+ wp_enqueue_script(
54
+ 'nested-sortable',
55
+ $this->plugin_dir . '/assets/js/lib/jquery.mjs.nestedSortable.js',
56
+ array('jquery', 'jquery-ui-sortable'),
57
+ '1.0'
58
+ );
59
+
60
+ wp_enqueue_script(
61
+ 'nestedpages',
62
+ $this->plugin_dir . '/assets/js/nestedpages.min.js',
63
+ array('jquery'),
64
+ '1.0'
65
+ );
66
+
67
+ wp_localize_script(
68
+ 'nestedpages',
69
+ 'nestedpages',
70
+ array(
71
+ 'np_nonce' => wp_create_nonce( 'nestedpages-nonce' ),
72
+ 'expand_text' => __('Expand Pages', 'nestedpages'),
73
+ 'collapse_text' => __('Collapse Pages', 'nestedpages')
74
+ )
75
+ );
76
+ endif;
77
+ }
78
+
79
+ }
includes/class-np-handler-base.php ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once('class-np-navmenu.php');
4
+ require_once('class-np-postrepository.php');
5
+
6
+ /**
7
+ * Base Form Handler Class
8
+ */
9
+ abstract class NP_BaseHandler {
10
+
11
+ /**
12
+ * Nonce
13
+ * @var string
14
+ */
15
+ protected $nonce;
16
+
17
+ /**
18
+ * Form Data
19
+ * @var array
20
+ */
21
+ protected $data;
22
+
23
+ /**
24
+ * Post Repo
25
+ * @var object
26
+ */
27
+ protected $post_repo;
28
+
29
+
30
+ /**
31
+ * Response
32
+ * @var array;
33
+ */
34
+ protected $response;
35
+
36
+ public function __construct()
37
+ {
38
+ $this->post_repo = new NP_PostRepository;
39
+ $this->setData();
40
+ $this->validateNonce();
41
+ }
42
+
43
+
44
+ /**
45
+ * Set the Form Data
46
+ */
47
+ protected function setData()
48
+ {
49
+ $this->nonce = sanitize_text_field($_POST['nonce']);
50
+ $data = array();
51
+ foreach( $_POST as $key => $value ){
52
+ $data[$key] = $value;
53
+ }
54
+ $this->data = $data;
55
+ }
56
+
57
+
58
+ /**
59
+ * Validate the Nonce
60
+ */
61
+ protected function validateNonce()
62
+ {
63
+ if ( ! wp_verify_nonce( $this->nonce, 'nestedpages-nonce' ) ){
64
+ $this->response = array( 'status' => 'error', 'message' => __('Incorrect Form Field') );
65
+ $this->sendResponse();
66
+ die();
67
+ }
68
+ }
69
+
70
+
71
+ /**
72
+ * Sync the Nav Menu
73
+ */
74
+ protected function syncMenu()
75
+ {
76
+ if ( $_POST['syncmenu'] == 'sync' ){
77
+ $menu = new NP_NavMenu;
78
+ $menu->clearMenu();
79
+ $menu->sync();
80
+ update_option('nestedpages_menusync', 'sync');
81
+ } else {
82
+ update_option('nestedpages_menusync', 'nosync');
83
+ }
84
+ }
85
+
86
+
87
+ /**
88
+ * Send a Generic Success Message
89
+ */
90
+ protected function sendErrorResponse()
91
+ {
92
+ $this->response = array(
93
+ 'status' => 'error',
94
+ 'message' => __('There was an error updating the page.')
95
+ );
96
+ $this->sendResponse();
97
+ }
98
+
99
+
100
+ /**
101
+ * Return Response
102
+ */
103
+ protected function sendResponse()
104
+ {
105
+ return wp_send_json($this->response);
106
+ }
107
+
108
+ }
includes/class-np-handler-quickedit.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ function nestedpages_quickedit_handler()
4
+ {
5
+ new NP_QuickEdit_Handler;
6
+ }
7
+
8
+ require_once('class-np-handler-base.php');
9
+
10
+ /**
11
+ * Handles processing the quick edit form
12
+ * @return json response
13
+ */
14
+ class NP_QuickEdit_Handler extends NP_BaseHandler {
15
+
16
+
17
+ public function __construct()
18
+ {
19
+ parent::__construct();
20
+ $this->updatePost();
21
+ $this->syncMenu();
22
+ $this->sendResponse();
23
+ }
24
+
25
+
26
+ /**
27
+ * Update the Post
28
+ * @todo update taxonomies
29
+ */
30
+ private function updatePost()
31
+ {
32
+ $updated = $this->post_repo->updatePost($this->data);
33
+ if ( !$updated ) $this->sendErrorResponse();
34
+ $this->addData();
35
+ $this->response = array(
36
+ 'status' => 'success',
37
+ 'message' => __('Post successfully updated'),
38
+ 'post_data' => $this->data
39
+ );
40
+ }
41
+
42
+
43
+ /**
44
+ * Add additional data to the response object
45
+ */
46
+ private function addData()
47
+ {
48
+ $this->data['nav_status'] = ( isset($this->data['nav_status']) ) ? 'hide' : 'show';
49
+ $this->data['np_status'] = ( isset($this->data['nested_pages_status']) ) ? 'hide' : 'show';
50
+ if ( !isset($_POST['comment_status']) ) $this->data['comment_status'] = 'closed';
51
+ }
52
+
53
+ }
includes/class-np-handler-sort.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ function nestedpages_sort_handler()
4
+ {
5
+ new NP_SortHandler;
6
+ }
7
+
8
+ /**
9
+ * Handles processing sortable pages
10
+ * updates menu order & page parents
11
+ * @return json response
12
+ */
13
+ require_once('class-np-handler-base.php');
14
+ require_once('class-np-navmenu.php');
15
+
16
+ class NP_SortHandler extends NP_BaseHandler {
17
+
18
+
19
+ public function __construct()
20
+ {
21
+ parent::__construct();
22
+ $this->updateOrder();
23
+ $this->syncMenu();
24
+ $this->sendResponse();
25
+ }
26
+
27
+
28
+ /**
29
+ * Update Post Order
30
+ */
31
+ private function updateOrder()
32
+ {
33
+ $posts = $this->data['list'];
34
+ $order = $this->post_repo->updateOrder($posts);
35
+ if ( $order ){
36
+ $this->response = array('status' => 'success', 'message' => __('Page order successfully updated.','nestedpages') );
37
+ } else {
38
+ $this->response = array('status'=>'error', 'message'=> __('There was an order updating the page order.','nestedpages') );
39
+ }
40
+ }
41
+
42
+
43
+ }
includes/class-np-handler-syncmenu.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ function nestedpages_syncmenu_handler()
4
+ {
5
+ new NP_SyncMenu_Handler;
6
+ }
7
+
8
+ require_once('class-np-handler-base.php');
9
+
10
+ /**
11
+ * Turn on/off menu sync
12
+ * @return json response
13
+ */
14
+ class NP_SyncMenu_Handler extends NP_BaseHandler {
15
+
16
+ public function __construct()
17
+ {
18
+ parent::__construct();
19
+ $this->updateSync();
20
+ $this->sendResponse();
21
+ }
22
+
23
+
24
+ /**
25
+ * Update the sync setting
26
+ */
27
+ private function updateSync()
28
+ {
29
+ if ( $this->data['syncmenu'] == 'sync' ){
30
+ update_option('nestedpages_menusync', 'sync');
31
+ $this->syncMenu();
32
+ $this->response = array('status'=>'success', 'message'=> __('Menu sync enabled.'));
33
+ } else {
34
+ update_option('nestedpages_menusync', 'nosync');
35
+ $this->response = array('status'=>'success', 'message'=> __('Menu sync disabled.'));
36
+ }
37
+ }
38
+
39
+ }
includes/class-np-navmenu.php ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The generated nav menu that matches the nested pages structure
4
+ */
5
+ class NP_NavMenu {
6
+
7
+ /**
8
+ * The Menu ID
9
+ */
10
+ public $id;
11
+
12
+ /**
13
+ * The Menu Items
14
+ */
15
+ public $items;
16
+
17
+
18
+ public function __construct()
19
+ {
20
+ $this->setID();
21
+ $this->setItems();
22
+ }
23
+
24
+
25
+ /**
26
+ * Add the Nav Menu
27
+ */
28
+ public function addMenu()
29
+ {
30
+ $menu = wp_create_nav_menu('nestedpages');
31
+ $this->id = $menu;
32
+ }
33
+
34
+
35
+ /**
36
+ * Set the Menu ID
37
+ */
38
+ public function setID()
39
+ {
40
+ $menu = get_term_by('slug', 'nestedpages', 'nav_menu');
41
+ if ( $menu ) $this->id = $menu->term_id;
42
+ }
43
+
44
+
45
+ /**
46
+ * Set the Menu Items
47
+ */
48
+ public function setItems()
49
+ {
50
+ $menu = get_term_by('slug', 'nestedpages', 'nav_menu');
51
+ if ( $menu ) $this->items = wp_get_nav_menu_items($this->id);
52
+ }
53
+
54
+
55
+ /**
56
+ * Create the menu with nested pages (Recursive function)
57
+ */
58
+ public function sync($parent = 0, $menu_parent = 0)
59
+ {
60
+ $page_q = new WP_Query(array(
61
+ 'post_type' => 'page',
62
+ 'posts_per_page' => -1,
63
+ 'post_status' => 'publish',
64
+ 'orderby' => 'menu_order',
65
+ 'order' => 'ASC',
66
+ 'post_parent' => $parent
67
+ ));
68
+ if ( $page_q->have_posts() ) : while ( $page_q->have_posts() ) : $page_q->the_post();
69
+
70
+ // Nav Status
71
+ $ns = get_post_meta( get_the_id(), 'np_nav_status', true);
72
+
73
+ // Nested Pages Visibility
74
+ $np_status = get_post_meta( get_the_id(), 'nested_pages_status', true );
75
+
76
+ // Nav Title
77
+ $nav_title = get_post_meta( get_the_id(), 'np_nav_title', true );
78
+ $nav_title = ( $nav_title !== "" ) ? $nav_title : get_the_title();
79
+
80
+ if ( ($ns == 'show') || ($ns == '') ) {
81
+ if ( $np_status !== 'hide' ){
82
+ $menu = wp_update_nav_menu_item($this->id, 0, array(
83
+ 'menu-item-title' => $nav_title,
84
+ 'menu-item-url' => get_the_permalink(),
85
+ 'menu-item-status' => 'publish',
86
+ 'menu-item-type' => 'post_type',
87
+ 'menu-item-object' => 'page',
88
+ 'menu-item-object-id' => get_the_id(),
89
+ 'menu-item-parent-id' => $menu_parent
90
+ ));
91
+ $this->sync( get_the_id(), $menu );
92
+ }
93
+ }
94
+
95
+ endwhile; endif; wp_reset_postdata();
96
+
97
+ }
98
+
99
+
100
+ /**
101
+ * Clear out the menu
102
+ */
103
+ public function clearMenu()
104
+ {
105
+ $menu_items = wp_get_nav_menu_items($this->id);
106
+ foreach ( $menu_items as $i ){
107
+ wp_delete_post($i->ID, true);
108
+ }
109
+ }
110
+
111
+
112
+ }
includes/class-np-newpage.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Performs Hooks to check for new page screen
4
+ * Select appropriate parent page if applicable & shows message
5
+ */
6
+ class NP_NewPage {
7
+
8
+ /**
9
+ * Parent Page
10
+ */
11
+ private $parent_page;
12
+
13
+
14
+ public function __construct()
15
+ {
16
+ add_action('admin_notices', array($this, 'showNotice'));
17
+ add_action('admin_head', array($this, 'selectParent'));
18
+ }
19
+
20
+
21
+ /**
22
+ * Check if this is a new child page
23
+ */
24
+ private function isChild()
25
+ {
26
+ $page = get_current_screen();
27
+ if ( ($page->id == 'page') && ($page->action == 'add') && (isset($_GET['npparent'])) ){
28
+ $this->parent_page = (int) sanitize_text_field($_GET['npparent']);
29
+ return true;
30
+ } else {
31
+ return false;
32
+ }
33
+ }
34
+
35
+
36
+ /**
37
+ * Show the admin notice
38
+ */
39
+ public function showNotice()
40
+ {
41
+ if ( $this->isChild() ) {
42
+ echo '<div id="message" class="updated"><p>' . __('Adding child page under:') . ' <strong>' . get_the_title($this->parent_page) . '</strong></p></div>';
43
+ }
44
+ }
45
+
46
+
47
+ /**
48
+ * Preselect the parent page
49
+ */
50
+ public function selectParent()
51
+ {
52
+ if ( $this->isChild() ) {
53
+ echo '<script>jQuery(document).ready(function(){ jQuery("#parent_id").val("' . $this->parent_page . '"); });</script>';
54
+ }
55
+ }
56
+
57
+ }
58
+ ?>
includes/class-np-pagelisting.php ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Primary Listing Class
5
+ * Initiates Page Listing screen (overwriting default), and displays primary plugin view.
6
+ */
7
+ class NP_PageListing {
8
+
9
+ /**
10
+ * Post Type
11
+ * @var object
12
+ */
13
+ private $post_type;
14
+
15
+
16
+ /**
17
+ * Hierarchical Taxonomies
18
+ * @var array
19
+ */
20
+ private $h_taxonomies;
21
+
22
+
23
+ /**
24
+ * Flat Taxonomies
25
+ * @var array
26
+ */
27
+ private $f_taxonomies;
28
+
29
+
30
+ public function __construct()
31
+ {
32
+ $this->post_type = get_post_type_object('page');
33
+ add_action( 'admin_menu', array($this, 'adminMenu') );
34
+ add_action( 'admin_menu', array($this, 'submenu') );
35
+ }
36
+
37
+
38
+ /**
39
+ * Add the admin menu item
40
+ */
41
+ public function adminMenu()
42
+ {
43
+ if ( current_user_can('edit_pages') ){
44
+ add_menu_page(
45
+ $this->post_type->labels->name,
46
+ $this->post_type->labels->name,
47
+ 'delete_pages',
48
+ 'nestedpages',
49
+ array( $this, 'pageListing' ),
50
+ 'dashicons-admin-page',
51
+ 20
52
+ );
53
+ }
54
+ }
55
+
56
+
57
+ /**
58
+ * Add Submenu
59
+ */
60
+ public function submenu()
61
+ {
62
+ global $submenu;
63
+ $submenu['nestedpages'][50] = array( __('All Pages','nestedpages'), 'publish_pages', esc_url(admin_url('admin.php?page=nestedpages')) );
64
+ $submenu['nestedpages'][60] = array( __('Add New','nestedpages'), 'publish_pages', $this->addNewPageLink() );
65
+ $submenu['nestedpages'][70] = array( __('Default Pages','nestedpages'), 'publish_pages', $this->defaultPagesLink() );
66
+ }
67
+
68
+
69
+ /**
70
+ * Add New Page Link
71
+ * @return string
72
+ */
73
+ private function addNewPageLink()
74
+ {
75
+ return esc_url( admin_url('post-new.php?post_type=page') );
76
+ }
77
+
78
+
79
+ /**
80
+ * Link to the default WP Pages listing
81
+ * @return string
82
+ */
83
+ private function defaultPagesLink()
84
+ {
85
+ $link = esc_url( admin_url('edit.php?post_type=page') );
86
+ return $link;
87
+ }
88
+
89
+
90
+ /**
91
+ * The Main View
92
+ * Replaces Default Pages Listing
93
+ */
94
+ public function pageListing()
95
+ {
96
+ include( dirname( dirname(__FILE__) ) . '/views/pages.php');
97
+ }
98
+
99
+
100
+ /**
101
+ * Set the Taxonomies for Pages
102
+ */
103
+ private function setTaxonomies()
104
+ {
105
+ $taxonomy_names = get_object_taxonomies( 'page' );
106
+ $hierarchical_taxonomies = array();
107
+ $flat_taxonomies = array();
108
+ foreach ( $taxonomy_names as $taxonomy_name ) {
109
+ $taxonomy = get_taxonomy( $taxonomy_name );
110
+ if ( !$taxonomy->show_ui )
111
+ continue;
112
+
113
+ if ( $taxonomy->hierarchical )
114
+ $hierarchical_taxonomies[] = $taxonomy;
115
+ else
116
+ $flat_taxonomies[] = $taxonomy;
117
+ }
118
+ $this->h_taxonomies = $hierarchical_taxonomies;
119
+ $this->f_taxonomies = $flat_taxonomies;
120
+ }
121
+
122
+
123
+ /**
124
+ * Get a Posts Taxonomies
125
+ */
126
+ private function hierarchicalTaxonomies($page_id)
127
+ {
128
+ $out = '';
129
+ if ( count($this->h_taxonomies) > 0 ) {
130
+ foreach ( $this->h_taxonomies as $taxonomy ){
131
+ $terms = wp_get_post_terms($page_id, $taxonomy->name);
132
+ foreach ( $terms as $term ){
133
+ $out .= 'in-' . $taxonomy->name . '-' . $term->term_id . ' ';
134
+ }
135
+ }
136
+ }
137
+ if ( $out !== '' ) $out .= ' has-tax ';
138
+ return $out;
139
+ }
140
+
141
+
142
+ /**
143
+ * Loop through all the pages and create the nested / sortable list
144
+ * Recursive Method, called in page.php view
145
+ */
146
+ private function loopPages($parent_id = 0, $count = 0)
147
+ {
148
+ $pages = new WP_Query(array(
149
+ 'post_type' => 'page',
150
+ 'posts_per_page' => -1,
151
+ 'orderby' => 'menu_order',
152
+ 'post_parent' => $parent_id,
153
+ 'order' => 'ASC'
154
+ ));
155
+ if ( $pages->have_posts() ) :
156
+ $count++;
157
+
158
+ if ( $count == 1 ) {
159
+
160
+ $this->setTaxonomies();
161
+
162
+ echo ( current_user_can('edit_theme_options') )
163
+ ? '<ol class="sortable nplist">'
164
+ : '<ol class="sortable no-sort nplist">';
165
+ } else {
166
+ echo '<ol class="nplist">';
167
+ }
168
+
169
+ while ( $pages->have_posts() ) : $pages->the_post();
170
+
171
+ global $post;
172
+
173
+ echo '<li id="menuItem_' . get_the_id() . '" class="page-row';
174
+
175
+ // Published?
176
+ if ( $post->post_status == 'publish' ) echo ' published';
177
+
178
+ // Hidden in Nested Pages?
179
+ $np_status = get_post_meta( get_the_id(), 'nested_pages_status', true );
180
+ $np_status = ( $np_status == 'hide' ) ? 'hide' : 'show';
181
+ if ( $np_status == 'hide' ) echo ' np-hide';
182
+
183
+ // Taxonomies
184
+ echo ' ' . $this->hierarchicalTaxonomies( get_the_id() );
185
+
186
+ echo '">';
187
+ $count++;
188
+
189
+ $template = get_post_meta(get_the_id(), '_wp_page_template', true);
190
+
191
+ // Show Hide in generated nav menu
192
+ $ns = get_post_meta( get_the_id(), 'np_nav_status', true);
193
+ $nav_status = ( $ns == 'hide' ) ? 'hide' : 'show';
194
+
195
+ // Menu Title
196
+ $nav_title = get_post_meta(get_the_id(), 'np_nav_title', true);
197
+
198
+ // Date Vars
199
+ $d = get_the_time('d');
200
+ $month = get_the_time('m');
201
+ $y = get_the_time('Y');
202
+ $h = get_the_time('H');
203
+ $m = get_the_time('i');
204
+
205
+ if ( function_exists('wpseo_translate_score') ) {
206
+ $yoast_score = get_post_meta(get_the_id(), '_yoast_wpseo_linkdex', true);
207
+ $score = wpseo_translate_score($yoast_score);
208
+ };
209
+
210
+ include( dirname( dirname(__FILE__) ) . '/views/row.php');
211
+ $this->loopPages(get_the_id(), $count);
212
+ echo '</li>';
213
+
214
+ endwhile; // Loop
215
+ echo '</ol>';
216
+ endif; wp_reset_postdata();
217
+ }
218
+
219
+
220
+ }
includes/class-np-pagemeta.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class NP_PageMeta {
4
+
5
+ function __construct()
6
+ {
7
+ add_action( 'add_meta_boxes', array( $this, 'metaBox' ));
8
+ add_action( 'save_post', array($this, 'saveMeta' ));
9
+ }
10
+
11
+
12
+ /**
13
+ * Register the Meta Box
14
+ */
15
+ public function metaBox()
16
+ {
17
+ add_meta_box(
18
+ 'nestedpages',
19
+ 'Nested Pages',
20
+ array($this, 'metaFields'),
21
+ 'page',
22
+ 'side',
23
+ 'low'
24
+ );
25
+ }
26
+
27
+
28
+ /**
29
+ * Meta Boxes for Output
30
+ */
31
+ public function metaFields($post)
32
+ {
33
+ wp_nonce_field( 'nestedpages_meta_box_nonce', 'np_meta_box_nonce' );
34
+ $np_nav_status = get_post_meta($post->ID, 'np_nav_status', true);
35
+ $np_nav_title = get_post_meta($post->ID, 'np_nav_title', true);
36
+ $nested_pages_status = get_post_meta($post->ID, 'nested_pages_status', true);
37
+ include( dirname( dirname(__FILE__) ) . '/views/page-meta.php');
38
+ }
39
+
40
+
41
+ /**
42
+ * Save the custom post meta
43
+ */
44
+ public function saveMeta( $post_id )
45
+ {
46
+ if( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
47
+
48
+ // Verify the nonce & permissions.
49
+ if( !isset( $_POST['np_meta_box_nonce'] ) || !wp_verify_nonce( $_POST['np_meta_box_nonce'], 'nestedpages_meta_box_nonce' ) ) return;
50
+ //if( !current_user_can( 'edit_post' ) ) return;
51
+
52
+ // Save the Nav Status
53
+ if( isset( $_POST['np_nav_status'] ) ) {
54
+ update_post_meta( $post_id, 'np_nav_status', 'hide' );
55
+ } else {
56
+ update_post_meta( $post_id, 'np_nav_status', 'show' );
57
+ }
58
+
59
+ // Save the Nav Title
60
+ if( isset( $_POST['np_nav_title'] ) )
61
+ update_post_meta( $post_id, 'np_nav_title', esc_attr( $_POST['np_nav_title'] ) );
62
+
63
+ // Save the NP Status
64
+ if ( isset( $_POST['nested_pages_status'] ) ){
65
+ update_post_meta( $post_id, 'nested_pages_status', 'hide' );
66
+ } else {
67
+ update_post_meta( $post_id, 'nested_pages_status', 'show' );
68
+ }
69
+
70
+ }
71
+
72
+ }
includes/class-np-postrepository.php ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once('class-np-validation.php');
4
+
5
+ class NP_PostRepository {
6
+
7
+ /**
8
+ * Validation Class
9
+ * @var NP_Validation instance
10
+ */
11
+ protected $validation;
12
+
13
+
14
+ public function __construct()
15
+ {
16
+ $this->validation = new NP_Validation;
17
+ }
18
+
19
+
20
+ /**
21
+ * Update Order
22
+ */
23
+ public function updateOrder($posts, $parent = 0)
24
+ {
25
+ $this->validation->validatePostIDs($posts);
26
+ foreach( $posts as $key => $post )
27
+ {
28
+ wp_update_post(array(
29
+ 'ID' => $post['id'],
30
+ 'menu_order' => $key,
31
+ 'post_parent' => $parent
32
+ ));
33
+
34
+ if ( isset($post['children']) ){
35
+ $this->updateOrder($post['children'], $post['id']);
36
+ }
37
+ }
38
+ return true;
39
+ }
40
+
41
+
42
+ /**
43
+ * Update Post
44
+ */
45
+ public function updatePost($data)
46
+ {
47
+ $date = $this->validation->validateDate($data);
48
+ if ( !isset($_POST['comment_status']) ) $data['comment_status'] = 'closed';
49
+
50
+ $updated_post = array(
51
+ 'ID' => sanitize_text_field($data['post_id']),
52
+ 'post_title' => sanitize_text_field($data['post_title']),
53
+ 'post_author' => sanitize_text_field($data['post_author']),
54
+ 'post_name' => sanitize_text_field($data['post_name']),
55
+ 'post_date' => $date,
56
+ 'comment_status' => sanitize_text_field($data['comment_status']),
57
+ 'post_status' => sanitize_text_field($data['_status'])
58
+ );
59
+ wp_update_post($updated_post);
60
+
61
+ $this->updateTemplate($data);
62
+ $this->updateNavStatus($data);
63
+ $this->updateNestedPagesStatus($data);
64
+ $this->updateNavTitle($data);
65
+ $this->updateCategories($data);
66
+ $this->updateHierarchicalTaxonomies($data);
67
+
68
+ return true;
69
+ }
70
+
71
+
72
+ /**
73
+ * Update Page Template
74
+ */
75
+ private function updateTemplate($data)
76
+ {
77
+ $template = sanitize_text_field($data['page_template']);
78
+ update_post_meta(
79
+ $data['post_id'],
80
+ '_wp_page_template',
81
+ $template
82
+ );
83
+ }
84
+
85
+
86
+ /**
87
+ * Update Nav Status (show/hide in nav menu)
88
+ */
89
+ private function updateNavStatus($data)
90
+ {
91
+ $status = ( isset($data['nav_status']) ) ? 'hide' : 'show';
92
+ update_post_meta(
93
+ $data['post_id'],
94
+ 'np_nav_status',
95
+ $status
96
+ );
97
+ }
98
+
99
+
100
+ /**
101
+ * Update Nested Pages Visibility (how/hide in Nested Pages interface)
102
+ */
103
+ private function updateNestedPagesStatus($data)
104
+ {
105
+ $status = ( isset($data['nested_pages_status']) ) ? 'hide' : 'show';
106
+ update_post_meta(
107
+ $data['post_id'],
108
+ 'nested_pages_status',
109
+ $status
110
+ );
111
+ }
112
+
113
+
114
+ /**
115
+ * Update Nested Pages Menu Title
116
+ */
117
+ private function updateNavTitle($data)
118
+ {
119
+ if ( isset($data['np_nav_title']) ){
120
+ $title = sanitize_text_field($data['np_nav_title']);
121
+ update_post_meta(
122
+ $data['post_id'],
123
+ 'np_nav_title',
124
+ $title
125
+ );
126
+ }
127
+ }
128
+
129
+
130
+ /**
131
+ * Update Categories
132
+ */
133
+ private function updateCategories($data)
134
+ {
135
+ if ( isset($data['post_category']) )
136
+ {
137
+ $this->validation->validateIntegerArray($data['post_category']);
138
+ $cats = array();
139
+ foreach($data['post_category'] as $cat) {
140
+ if ( $cat !== 0 ) $cats[] = (int) $cat;
141
+ }
142
+ wp_set_post_terms($data['post_id'], $cats, 'category');
143
+ }
144
+ }
145
+
146
+
147
+ /**
148
+ * Update Hierarchical Taxonomy Terms
149
+ */
150
+ private function updateHierarchicalTaxonomies($data)
151
+ {
152
+ if ( isset($data['tax_input']) ) {
153
+ foreach ( $data['tax_input'] as $taxonomy => $term_ids ){
154
+ $this->validation->validateIntegerArray($term_ids);
155
+ $terms = array();
156
+ foreach ( $term_ids as $term ){
157
+ if ( $term !== 0 ) $terms[] = (int) $term;
158
+ }
159
+ wp_set_post_terms($data['post_id'], $terms, $taxonomy);
160
+ }
161
+ }
162
+ }
163
+
164
+ }
includes/class-np-validation.php ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Nested Pages Form Validation
5
+ */
6
+ class NP_Validation {
7
+
8
+
9
+ /**
10
+ * Validate Post IDs in an array of posts
11
+ */
12
+ public function validatePostIDs($posts)
13
+ {
14
+ foreach ($posts as $post)
15
+ {
16
+ if ( !is_numeric($post['id']) ){
17
+ return wp_send_json(array('status'=>'error', 'message'=>'Incorrect Form Field'));
18
+ }
19
+ }
20
+ }
21
+
22
+ /**
23
+ * Validate IDs in an array (tax ids)
24
+ */
25
+ public function validateIntegerArray($items)
26
+ {
27
+ foreach ( $items as $item )
28
+ {
29
+ if ( !is_numeric($item) ){
30
+ return wp_send_json(array('status'=>'error', 'message'=>'Incorrect Form Field'));
31
+ }
32
+ }
33
+ }
34
+
35
+
36
+ /**
37
+ * Validate Date Input
38
+ */
39
+ public function validateDate($data)
40
+ {
41
+ // First validate that it is an actual date
42
+ if ( !wp_checkdate(
43
+ intval($data['mm']),
44
+ intval($data['jj']),
45
+ intval($data['aa']),
46
+ $data['aa'] . '-' . $data['mm'] . '-' . $data['jj']
47
+ )
48
+ ){
49
+ return wp_send_json(array('status' => 'error', 'message' => __('Please provide a valid date.', 'nestedpages') ));
50
+ die();
51
+ }
52
+
53
+ // Validate all the fields are there
54
+ if ( ($data['aa'] !== "")
55
+ && ( $data['mm'] !== "" )
56
+ && ( $data['jj'] !== "" )
57
+ && ( $data['hh'] !== "" )
58
+ && ( $data['mm'] !== "" )
59
+ && ( $data['ss'] !== "" ) )
60
+ {
61
+ $date = strtotime($data['aa'] . '-' . $data['mm'] . '-' . $data['jj'] . ' ' . $data['hh'] . ':' . $data['mm'] . ':' . $data['ss']);
62
+ return date('Y-m-d H:i:s', $date);
63
+ } else {
64
+ return wp_send_json(array('status' => 'error', 'message' => __('Please provide a valid date.', 'nestedpages') ));
65
+ die();
66
+ }
67
+ }
68
+
69
+
70
+ }
languages/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ //Nothing to see here
languages/nestedpages.mo ADDED
Binary file
languages/nestedpages.pot ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: Nested Pages\n"
4
+ "POT-Creation-Date: 2014-10-19 22:04-0500\n"
5
+ "PO-Revision-Date: 2014-10-19 22:05-0500\n"
6
+ "Last-Translator: \n"
7
+ "Language-Team: \n"
8
+ "Language: es\n"
9
+ "MIME-Version: 1.0\n"
10
+ "Content-Type: text/plain; charset=UTF-8\n"
11
+ "Content-Transfer-Encoding: 8bit\n"
12
+ "X-Generator: Poedit 1.6.4\n"
13
+ "X-Poedit-Basepath: ..\n"
14
+ "X-Poedit-SourceCharset: UTF-8\n"
15
+ "X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;"
16
+ "esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;"
17
+ "_nx_noop:3c,1,2;__ngettext_noop:1,2\n"
18
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
19
+ "X-Poedit-SearchPath-0: .\n"
20
+
21
+ #: includes/class-np-dependencies.php:72 views/pages.php:9
22
+ msgid "Expand Pages"
23
+ msgstr ""
24
+
25
+ #: includes/class-np-dependencies.php:73
26
+ msgid "Collapse Pages"
27
+ msgstr ""
28
+
29
+ #: includes/class-np-handler-base.php:57
30
+ msgid "Incorrect Form Field"
31
+ msgstr ""
32
+
33
+ #: includes/class-np-handler-quickedit.php:46
34
+ msgid "Post successfully updated"
35
+ msgstr ""
36
+
37
+ #: includes/class-np-handler-quickedit.php:52
38
+ msgid "There was an error updating the page."
39
+ msgstr ""
40
+
41
+ #: includes/class-np-handler-sort.php:39
42
+ msgid "Page order successfully updated."
43
+ msgstr ""
44
+
45
+ #: includes/class-np-handler-sort.php:41
46
+ msgid "There was an order updating the page order."
47
+ msgstr ""
48
+
49
+ #: includes/class-np-handler-syncmenu.php:33
50
+ msgid "Menu sync enabled."
51
+ msgstr ""
52
+
53
+ #: includes/class-np-handler-syncmenu.php:36
54
+ msgid "Menu sync disabled."
55
+ msgstr ""
56
+
57
+ #: includes/class-np-newpage.php:42
58
+ msgid "Adding child page under:"
59
+ msgstr ""
60
+
61
+ #: includes/class-np-pagelisting.php:49
62
+ msgid "All Pages"
63
+ msgstr ""
64
+
65
+ #: includes/class-np-pagelisting.php:50
66
+ msgid "Add New"
67
+ msgstr ""
68
+
69
+ #: includes/class-np-pagelisting.php:51
70
+ msgid "Default Pages"
71
+ msgstr ""
72
+
73
+ #: includes/class-np-validation.php:36 includes/class-np-validation.php:51
74
+ msgid "Please provide a valid date."
75
+ msgstr ""
76
+
77
+ #: views/pages.php:15
78
+ msgid "Sync Menu"
79
+ msgstr ""
80
+
81
+ #: views/pages.php:23
82
+ msgid "All"
83
+ msgstr ""
84
+
85
+ #: views/pages.php:24 views/quickedit.php:78
86
+ msgid "Published"
87
+ msgstr ""
88
+
89
+ #: views/pages.php:25
90
+ msgid "Show Hidden Pages"
91
+ msgstr ""
92
+
93
+ #: views/pages.php:26
94
+ msgid "Default"
95
+ msgstr ""
96
+
97
+ #: views/quickedit.php:31 views/row.php:81
98
+ msgid "Quick Edit"
99
+ msgstr ""
100
+
101
+ #: views/quickedit.php:40
102
+ msgid "Title"
103
+ msgstr ""
104
+
105
+ #: views/quickedit.php:44
106
+ msgid "Slug"
107
+ msgstr ""
108
+
109
+ #: views/quickedit.php:48
110
+ msgid "Date"
111
+ msgstr ""
112
+
113
+ #: views/quickedit.php:66
114
+ msgid "Author"
115
+ msgstr ""
116
+
117
+ #: views/quickedit.php:75
118
+ msgid "Status"
119
+ msgstr ""
120
+
121
+ #: views/quickedit.php:79
122
+ msgid "Scheduled"
123
+ msgstr ""
124
+
125
+ #: views/quickedit.php:81
126
+ msgid "Pending Review"
127
+ msgstr ""
128
+
129
+ #: views/quickedit.php:82
130
+ msgid "Draft"
131
+ msgstr ""
132
+
133
+ #: views/quickedit.php:90
134
+ msgid "Template"
135
+ msgstr ""
136
+
137
+ #: views/quickedit.php:92
138
+ msgid "Default Template"
139
+ msgstr ""
140
+
141
+ #: views/quickedit.php:99
142
+ msgid "Allow Comments"
143
+ msgstr ""
144
+
145
+ #: views/quickedit.php:104
146
+ msgid "Menu Title"
147
+ msgstr ""
148
+
149
+ #: views/quickedit.php:110
150
+ msgid "Hide in Nav Menu"
151
+ msgstr ""
152
+
153
+ #: views/quickedit.php:116
154
+ msgid "Hide in Nested Pages"
155
+ msgstr ""
156
+
157
+ #: views/quickedit.php:141
158
+ msgid "Cancel"
159
+ msgstr ""
160
+
161
+ #: views/quickedit.php:144
162
+ msgid "Update"
163
+ msgstr ""
164
+
165
+ #: views/row.php:42
166
+ msgid "currently editing"
167
+ msgstr ""
168
+
169
+ #: views/row.php:44
170
+ msgid "Edit"
171
+ msgstr ""
172
+
173
+ #: views/row.php:61
174
+ msgid "Add Child"
175
+ msgstr ""
176
+
177
+ #: views/row.php:85
178
+ msgid "View"
179
+ msgstr ""
nestedpages.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: Nested Pages
4
+ Plugin URI: http://nestedpages.com
5
+ Description: Provides an intuitive drag and drop interface for managing pages in the Wordpress admin, while maintaining quick edit functionality.
6
+ Version: 1.0
7
+ Author: Kyle Phillips
8
+ Author URI: https://github.com/kylephillips
9
+ License: GPLv2 or later.
10
+ Copyright: Kyle Phillips
11
+ */
12
+
13
+ /* Copyright 2014 Kyle Phillips (email : support@nestedpages.com)
14
+
15
+ This program is free software; you can redistribute it and/or modify
16
+ it under the terms of the GNU General Public License, version 2, as
17
+ published by the Free Software Foundation.
18
+
19
+ This program is distributed in the hope that it will be useful,
20
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
21
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
+ GNU General Public License for more details.
23
+
24
+ You should have received a copy of the GNU General Public License
25
+ along with this program; if not, write to the Free Software
26
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27
+ */
28
+
29
+ if( !class_exists('NestedPages') ) :
30
+ require_once('includes/class-nestedpages.php');
31
+ $nested_pages = new NestedPages;
32
+ endif;
readme.txt ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Nested Pages ===
2
+ Contributors: kylephillips
3
+ Donate link: http://nestedpages.com/
4
+ Tags: pages, admin, nested, tree view, page tree, sort, quick edit
5
+ Requires at least: 3.8
6
+ Tested up to: 4.0
7
+ Stable tag: trunk
8
+ License: GPLv2 or later
9
+ License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
+
11
+ Nested Pages provides an intuitive drag and drop interface for managing pages in the Wordpress admin, while maintaining quick edit functionality.
12
+
13
+ == Description ==
14
+
15
+ **Nested Pages offers**
16
+
17
+ * A drag and drop interface for managing your pages - simple and intuitive
18
+ * Quick edit functionality
19
+ * An expandable, sortable tree view of your site's page structure
20
+ * A native Wordpress menu, automatically generated to match your Nested Pages screen
21
+ * A touch-friendly interface
22
+
23
+ For more information visit [nestedpages.com](http://nestedpages.com).
24
+
25
+ **Nested Pages requires Wordpress version 3.8 or higher, and PHP version 5.4 or higher.**
26
+
27
+ == Installation ==
28
+
29
+ 1. Upload wp-nested-pages to the wp-content/plugins/ directory
30
+ 2. Activate the plugin through the Plugins menu in WordPress
31
+ 3. Click on the Pages Menu item to begin ordering pages. Nested Pages replaces the default Page management screen.
32
+ 4. To access the default the pages screen, select Default Pages located in the Pages submenu, or on the Nested Pages screen
33
+
34
+ == Frequently Asked Questions ==
35
+
36
+ = Can I use Nested Pages with other post types? =
37
+ Nested Pages is currently limited to the WordPress “Page” post type.
38
+
39
+ = How do I access the WordPress “Pages” screen? =
40
+ Click the “Default Pages” link in the page subnav, or on the Nested Pages screen.
41
+
42
+ = How do I save the order I create? =
43
+ Page sorting and nesting is saved in the background after changes are made to the structure.
44
+
45
+ = How do I edit in bulk? =
46
+ Bulk quick edits are not currently supported by Nested Pages. To edit in bulk, click on “Default Pages” to use the native interface.
47
+
48
+ = What about custom columns? =
49
+ Custom columns are not currently supported by Nested Pages. To view custom columns, click on “Default Pages” to view the native interface. If you are using WordPress SEO by Yoast, a page analysis indicator is shown.
50
+
51
+ = What are those dots in my page rows? =
52
+ If you have Wordpress SEO by Yoast installed, your page score indicators are shown along with the pages.
53
+
54
+ = Does quick edit support taxonomies? =
55
+ Hierarchical taxonomies are currently supported
56
+
57
+ == Screenshots ==
58
+
59
+ 1. Expandable tree view of your page structure
60
+
61
+ 2. Retains most quick edit functionality
62
+
63
+ 3. Sortable page nesting updates in real time
64
+
65
+ 4. Toggle nested child pages for a clutter-free tree
66
+
67
+ == Changelog ==
68
+
69
+ = 1.0 =
70
+ * Nested Pages
71
+
72
+ == More Information ==
73
+
74
+ = Generated Menu =
75
+ The generated menu is available for use with the name "nestedpages".
76
+
77
+
78
+ = Toggling the Page Tree =
79
+
80
+ To toggle the child pages in and out of view, click the arrow to the left of a parent page. To quickly expand and collapse all pages, click the button in the upper right corner of the Nested Pages Screen.
81
+
82
+
83
+ = Theme Use =
84
+
85
+ To order by nested pages ordering in your theme, use the `menu_order` order option in your queries.
86
+
87
+ Additionally, the generated menu is available for use, with the name `nestedpages`.
88
+
89
+
90
+ = Hiding Pages from the Tree View =
91
+
92
+ To hide a page from the tree view, open the quick edit form, select the option to “Hide in Nested Pages” and click Update to save the change.
93
+
94
+ To toggle the page back into view, click the “Show Hidden Pages” link at the top of the screen. The hidden pages are now visible, and can be re-edited to be shown.
95
+
96
+
97
+ = Sorting Pages =
98
+
99
+ To sort pages, hover over the page row. A menu icon (three lines) will appear. Click (or tap) this icon and drag to reorder within the menu. To drag a page underneath another, drag the page to the right and underneath the target parent. Visual indication is provided with an indentation. The drag and drop functionality works similarly to WordPress menus.
100
+
101
+ = Menu Sync =
102
+
103
+ After installing Nested Pages, a new menu will be available with the name `nestedpages`. By default, menu syncing is enabled. To disable the sync, uncheck “Sync Menu” at the top of the Nested Pages screen. Recheck the box to enable it again and to run the sync.
104
+
105
+ **Saving Performance:** If your site has a very large number of pages, disabling page sync may help speed up the save time when using Nested Pages.
106
+
107
+ **Editing the generated menu:** Any manual changes made to the menu outside of the Nested Pages interface will be overwritten after the synchronization runs.
108
+
109
+ **Hiding Pages in the Menu:** To hide a page from the nestedpages menu, click “Quick Edit” on it’s row, select “Hide in Nav Menu”, and click “update”. If menu sync is disabled, enable it now to sync the setting. Hidden pages are marked “(Hidden)”. If a page with child pages is hidden from the menu, all of it’s child pages will also be hidden.
views/pages.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="wrap">
2
+
3
+ <h2>
4
+ <?php echo $this->post_type->labels->name; ?>
5
+ <a href="<?php echo $this->addNewPageLink(); ?>" class="add-new-h2"><?php echo $this->post_type->labels->add_new; ?></a>
6
+ </h2>
7
+
8
+ <ul class="nestedpages-toggleall">
9
+ <li><a href="#" class="np-btn" data-toggle="closed"><?php _e('Expand Pages'); ?></a></li>
10
+ </ul>
11
+
12
+ <?php if ( current_user_can('edit_theme_options') ) : ?>
13
+ <div class="np-sync-menu-cont">
14
+ <label>
15
+ <input type="checkbox" name="np_sync_menu" class="np-sync-menu" value="sync" <?php if ( get_option('nestedpages_menusync') == 'sync' ) echo 'checked'; ?>/> <?php _e('Sync Menu'); ?>
16
+ </label>
17
+ </div>
18
+ <?php endif; ?>
19
+
20
+ <img src="<?php echo plugins_url(); ?>/wp-nested-pages/assets/images/loading.gif" alt="loading" id="nested-loading" />
21
+
22
+ <ul class="subsubsub">
23
+ <li><a href="#all" class="np-toggle-publish active"><?php _e('All'); ?></a> | </li>
24
+ <li><a href="#published" class="np-toggle-publish"><?php _e('Published'); ?></a> | </li>
25
+ <li><a href="#show" class="np-toggle-hidden"><?php _e('Show Hidden Pages'); ?></a> | </li>
26
+ <li><a href="<?php echo $this->defaultPagesLink(); ?>"><?php _e('Default'); ?> <?php echo $this->post_type->labels->name; ?></a></li>
27
+ </ul>
28
+
29
+ <div id="np-error" class="updated error" style="clear:both;display:none;"></div>
30
+
31
+ <div class="nestedpages">
32
+ <?php $this->loopPages(); ?>
33
+
34
+ <div class="quick-edit quick-edit-form" style="display:none;">
35
+ <?php include('quickedit.php'); ?>
36
+ </div>
37
+ </div>
38
+
39
+ </div><!-- .wrap -->
views/quickedit.php ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * See public inline_edit method of WP_Posts_List_Table class
4
+ */
5
+ $post_type_object = get_post_type_object( 'page' );
6
+ $can_publish = current_user_can( $post_type_object->cap->publish_posts );
7
+ ?>
8
+
9
+ <form method="get" action="">
10
+ <div class="form-interior">
11
+ <h3><?php _e('Quick Edit', 'nestedpages'); ?></h3>
12
+
13
+ <div class="np-quickedit-error" style="clear:both;display:none;"></div>
14
+
15
+ <div class="fields">
16
+
17
+ <div class="left">
18
+
19
+ <div class="form-control">
20
+ <label><?php _e( 'Title' ); ?></label>
21
+ <input type="text" name="post_title" class="np_title" value="" />
22
+ </div>
23
+ <div class="form-control">
24
+ <label><?php _e( 'Slug' ); ?></label>
25
+ <input type="text" name="post_name" class="np_slug" value="" />
26
+ </div>
27
+ <div>
28
+ <label><?php _e( 'Date' ); ?></label>
29
+ <div class="dates"><?php touch_time( 1, 1, 0, 1 ); ?></div>
30
+ </div>
31
+
32
+ <?php
33
+ $authors_dropdown = '';
34
+ if ( is_super_admin() || current_user_can( $post_type_object->cap->edit_others_posts ) ) :
35
+ $users_opt = array(
36
+ 'hide_if_only_one_author' => false,
37
+ 'who' => 'authors',
38
+ 'name' => 'post_author',
39
+ 'id' => 'post_author',
40
+ 'class'=> 'authors',
41
+ 'multi' => 1,
42
+ 'echo' => 0
43
+ );
44
+
45
+ if ( $authors = wp_dropdown_users( $users_opt ) ) :
46
+ $authors_dropdown = '<div class="form-control np_author"><label>' . __( 'Author' ) . '</label>';
47
+ $authors_dropdown .= $authors;
48
+ $authors_dropdown .= '</div>';
49
+ endif;
50
+ echo $authors_dropdown;
51
+ endif;
52
+ ?>
53
+
54
+ <div class="form-control">
55
+ <label><?php _e( 'Status' ); ?></label>
56
+ <select name="_status" class="np_status">
57
+ <?php if ( $can_publish ) : ?>
58
+ <option value="publish"><?php _e( 'Published' ); ?></option>
59
+ <option value="future"><?php _e( 'Scheduled' ); ?></option>
60
+ <?php endif; ?>
61
+ <option value="pending"><?php _e( 'Pending Review' ); ?></option>
62
+ <option value="draft"><?php _e( 'Draft' ); ?></option>
63
+ </select>
64
+ </div>
65
+
66
+ </div><!-- .left -->
67
+
68
+ <div class="right">
69
+ <div class="form-control">
70
+ <label><?php _e( 'Template' ); ?></label>
71
+ <select name="page_template" class="np_template">
72
+ <option value="default"><?php _e( 'Default Template' ); ?></option>
73
+ <?php page_template_dropdown() ?>
74
+ </select>
75
+ </div>
76
+ <div class="comments">
77
+ <label>
78
+ <input type="checkbox" name="comment_status" class="np_cs" value="open" />
79
+ <span class="checkbox-title"><?php _e( 'Allow Comments' ); ?></span>
80
+ </label>
81
+ </div>
82
+ <?php if ( current_user_can('edit_theme_options') ) : ?>
83
+ <div class="form-control">
84
+ <label><?php _e( 'Menu Title' ); ?></label>
85
+ <input type="text" name="np_nav_title" class="np_nav_title" value="" />
86
+ </div>
87
+ <div class="comments">
88
+ <label>
89
+ <input type="checkbox" name="nav_status" class="np_nav_status" value="hide" />
90
+ <span class="checkbox-title"><?php _e( 'Hide in Nav Menu' ); ?></span>
91
+ </label>
92
+ </div>
93
+ <div class="comments">
94
+ <label>
95
+ <input type="checkbox" name="nested_pages_status" class="np_status" value="hide" />
96
+ <span class="checkbox-title"><?php _e( 'Hide in Nested Pages' ); ?></span>
97
+ </label>
98
+ </div>
99
+ <?php endif; // Edit theme options?>
100
+
101
+ <?php if ( !empty($this->h_taxonomies) ) : ?>
102
+ <div class="form-control">
103
+ <a href="#" class="np-btn np-toggle-taxonomies"><?php _e('Edit Taxonomies'); ?></a>
104
+ </div>
105
+ <?php endif; ?>
106
+
107
+ </div><!-- .right -->
108
+
109
+ <?php if ( !empty($this->h_taxonomies) ) : ?>
110
+ <div class="np-taxonomies">
111
+ <?php foreach ( $this->h_taxonomies as $taxonomy ) : ?>
112
+ <div class="np-taxonomy">
113
+ <span class="title"><?php echo esc_html( $taxonomy->labels->name ) ?></span>
114
+ <input type="hidden" name="<?php echo ( $taxonomy->name == 'category' ) ? 'post_category[]' : 'tax_input[' . esc_attr( $taxonomy->name ) . '][]'; ?>" value="0" />
115
+ <ul class="cat-checklist <?php echo esc_attr( $taxonomy->name )?>-checklist">
116
+ <?php wp_terms_checklist( null, array( 'taxonomy' => $taxonomy->name ) ) ?>
117
+ </ul>
118
+ </div><!-- .np-taxonomy -->
119
+ <?php endforeach; ?>
120
+ </div><!-- .taxonomies -->
121
+ <?php endif; // if taxonomies ?>
122
+
123
+ </div><!-- .fields -->
124
+
125
+ </div><!-- .form-interior -->
126
+
127
+ <div class="buttons">
128
+ <input type="hidden" name="post_id" class="np_id" value="<?php echo get_the_id(); ?>">
129
+ <a accesskey="c" href="#inline-edit" class="button-secondary alignleft np-cancel-quickedit">
130
+ <?php _e( 'Cancel' ); ?>
131
+ </a>
132
+ <a accesskey="s" href="#inline-edit" class="button-primary np-save-quickedit alignright">
133
+ <?php _e( 'Update' ); ?>
134
+ </a>
135
+ <span class="np-qe-loading"></span>
136
+ </div>
137
+ </form>
views/row.php ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Row represents a single page
4
+ */
5
+ ?>
6
+ <div class="row">
7
+ <div class="child-toggle"></div>
8
+ <div class="row-inner">
9
+ <i class="np-icon-sub-menu"></i>
10
+ <?php if ( current_user_can('edit_theme_options') ) : ?>
11
+ <i class="handle np-icon-menu"></i>
12
+ <?php endif; ?>
13
+ <a href="<?php echo get_edit_post_link(); ?>" class="page-link page-title">
14
+ <span class="title"><?php the_title(); ?></span>
15
+ <?php
16
+
17
+ if ( function_exists('wpseo_translate_score') ){
18
+ echo '<span class="np-seo-indicator ' . $score . '"></span>';
19
+ }
20
+
21
+ // Post Status
22
+ if ( $post->post_status !== 'publish' ){
23
+ echo '<span class="status">(' . $post->post_status . ')</span>';
24
+ } else {
25
+ echo '<span class="status"></span>';
26
+ }
27
+
28
+ // Nested Pages Status
29
+ if ( $np_status == 'hide' )
30
+ echo '<i class="np-icon-eye-blocked"></i>';
31
+
32
+ // Nav Status
33
+ if ( $nav_status == 'hide' ){
34
+ echo '<span class="nav-status">(Hidden)</span>';
35
+ } else {
36
+ echo '<span class="nav-status"></span>';
37
+ }
38
+
39
+ // Post Lock
40
+ if ( $user = wp_check_post_lock(get_the_id()) ){
41
+ $u = get_userdata($user);
42
+ echo '<span class="locked"><i class="np-icon-lock"></i><em> ' . $u->display_name . ' ' . __('currently editing', 'nestedpages') . '</em></span>';
43
+ } else {
44
+ echo '<span class="edit-indicator"><i class="np-icon-pencil"></i>' . __('Edit', 'nestedpages') . '</span>';
45
+ }
46
+ ?>
47
+ </a>
48
+
49
+ <a href="#" class="np-toggle-edit"><i class="np-icon-pencil"></i></a>
50
+
51
+ <div class="action-buttons">
52
+
53
+ <?php if ( $post->comment_status == 'open' ) : $comments = wp_count_comments(get_the_id()); $cs = 'open' ?>
54
+
55
+ <a href="<?php echo admin_url( 'edit-comments.php?p=' . get_the_id() ); ?>" class="np-btn">
56
+ <i class="np-icon-bubble"></i> <?php echo $comments->total_comments; ?>
57
+ </a>
58
+
59
+ <?php else : $cs = 'closed'; endif; ?>
60
+
61
+ <a href="<?php echo $this->addNewPageLink(); ?>&npparent=<?php echo get_the_id(); ?>" class="np-btn"><?php _e('Add Child', 'nestedpages'); ?></a>
62
+
63
+ <?php if ( !$user = wp_check_post_lock(get_the_id()) ) : ?>
64
+ <a href="#"
65
+ class="np-btn np-quick-edit"
66
+ data-id="<?php echo get_the_id(); ?>"
67
+ data-template="<?php echo $template; ?>"
68
+ data-title="<?php the_title(); ?>"
69
+ data-slug="<?php echo $post->post_name; ?>"
70
+ data-commentstatus="<?php echo $cs; ?>"
71
+ data-status="<?php echo get_post_status(); ?>"
72
+ data-np-status="<?php echo $np_status; ?>"
73
+ data-navstatus="<?php echo $nav_status; ?>"
74
+ data-navtitle="<?php echo $nav_title; ?>"
75
+ data-author="<?php echo $post->post_author; ?>"
76
+ data-month="<?php echo $month; ?>"
77
+ data-day="<?php echo $d; ?>"
78
+ data-year="<?php echo $y; ?>"
79
+ data-hour="<?php echo $h; ?>"
80
+ data-minute="<?php echo $m; ?>">
81
+ <?php _e('Quick Edit', 'nestedpages'); ?>
82
+ </a>
83
+ <?php endif; ?>
84
+
85
+ <a href="<?php echo get_the_permalink(); ?>" class="np-btn"><?php _e('View', 'nestedpages'); ?></a>
86
+ <!--
87
+ <a href="#" class="np-btn np-btn-trash">
88
+ <i class="np-icon-remove"></i>
89
+ </a> -->
90
+ </div><!-- .action-buttons -->
91
+ </div><!-- .row-inner -->
92
+ </div><!-- .row -->