From e7767176cedb6ec45e945a4cd941dc3eb7d8bf86 Mon Sep 17 00:00:00 2001 From: alekseybobkov Date: Fri, 22 Aug 2014 18:45:05 +1100 Subject: [PATCH] Updated the treeview control, updated Redactor scripts, the CMS Content is now a compound object --- modules/backend/assets/css/october.css | 468 +++++++++++++----- .../backend/assets/images/treeview-icons.png | Bin 0 -> 2491 bytes .../backend/assets/images/treeview-icons.svg | 57 --- .../backend/assets/js/october.sidepaneltab.js | 5 +- modules/backend/assets/js/october.sortable.js | 19 +- modules/backend/assets/js/october.treelist.js | 9 +- modules/backend/assets/js/october.treeview.js | 270 +++++----- .../assets/less/controls/fancylayout.less | 22 + .../assets/less/controls/treeview.less | 306 +++++++++--- .../backend/assets/less/core/variables.less | 3 +- .../richeditor/assets/css/iframe.css | 5 + .../richeditor/assets/css/richeditor.css | 30 +- .../richeditor/assets/js/richeditor.js | 12 +- .../richeditor/assets/less/richeditor.less | 36 +- .../richeditor/partials/_richeditor.htm | 2 +- modules/cms/classes/CmsCompoundObject.php | 25 + modules/cms/classes/Content.php | 2 +- modules/system/traits/PropertyContainer.php | 2 +- 18 files changed, 901 insertions(+), 372 deletions(-) create mode 100644 modules/backend/assets/images/treeview-icons.png delete mode 100644 modules/backend/assets/images/treeview-icons.svg diff --git a/modules/backend/assets/css/october.css b/modules/backend/assets/css/october.css index 036561942..b361ea112 100644 --- a/modules/backend/assets/css/october.css +++ b/modules/backend/assets/css/october.css @@ -13008,6 +13008,22 @@ div.popover-overlay { -moz-border-radius: 0; border-radius: 0; } +.fancy-layout .field-richeditor { + border: none; + border-left: 1px solid #e0e0e0; +} +.fancy-layout .field-richeditor, +.fancy-layout .field-richeditor .redactor_box, +.fancy-layout .field-richeditor .redactor_toolbar { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + border-top-right-radius: 0; + border-top-left-radius: 0; +} +body.side-panel-not-fixed .fancy-layout .field-richeditor { + border-left: none; +} html.cssanimations .fancy-layout .form-tabless-fields .loading-indicator-container .loading-indicator > span { -webkit-animation: spin 1s linear infinite; animation: spin 1s linear infinite; @@ -13455,35 +13471,35 @@ div[data-control="balloon-selector"]:not(.control-disabled) ul li:hover { margin: 0; padding: 0; list-style: none; + background: #ffffff; } .control-treeview ol > li { - position: relative; -} -.control-treeview ol > li span.expand { - display: none; + -webkit-transition: width 1s; + transition: width 1s; } .control-treeview ol > li > div { - font-size: 14px; + font-size: 13px; font-weight: 600; color: #2b3e50; background: #ffffff; - margin-bottom: 1px; - padding: 16px 16px 15px 51px; + border-bottom: 1px solid #ecf0f1; + padding: 16px 16px 15px 61px; position: relative; + cursor: pointer; } .control-treeview ol > li > div:before { content: ' '; - background-image: url(../images/treeview-icons.svg); - background-position: 0px top; + background-image: url(../images/treeview-icons.png); + background-position: 0px -28px; background-repeat: no-repeat; - background-size: 25px auto; + background-size: 42px auto; position: absolute; width: 21px; - height: 26px; - left: 18px; + height: 22px; + left: 28px; top: 20px; } -.control-treeview ol > li > div > span { +.control-treeview ol > li > div span.comment { display: block; font-weight: 400; color: #95a5a6; @@ -13492,113 +13508,25 @@ div[data-control="balloon-selector"]:not(.control-disabled) ul li:hover { overflow: hidden; text-overflow: ellipsis; } -.control-treeview ol > li > div:hover { - background-color: #58b6f7; - color: #ffffff; -} -.control-treeview ol > li > div:hover:before { - background-position: 0px -65px; -} -.control-treeview ol > li > div:hover > span { - color: #ffffff; -} -.control-treeview ol > li[data-status=collapsed] > ol { - display: none; -} -.control-treeview ol > li.has-subitems > div:before { - background-position: 0 -29px; - width: 23px; - height: 29px; - left: 16px; -} -.control-treeview ol > li.has-subitems > div:hover:before { - background-position: 0px -95px; -} -.control-treeview ol > li > ol > li > div { - padding-left: 71px; -} -.control-treeview ol > li > ol > li > div:before { - margin-left: 20px; -} -.control-treeview ol > li > ol > li > ol > li > div { - padding-left: 91px; -} -.control-treeview ol > li > ol > li > ol > li > div:before { - margin-left: 40px; -} -.control-treeview ol > li > ol > li > ol > li > ol > li > div { - padding-left: 111px; -} -.control-treeview ol > li > ol > li > ol > li > ol > li > div:before { - margin-left: 60px; -} -.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > div { - padding-left: 131px; -} -.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > div:before { - margin-left: 80px; -} -.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div { - padding-left: 151px; -} -.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div:before { - margin-left: 100px; -} -.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div { - padding-left: 171px; -} -.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div:before { - margin-left: 120px; -} -.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div { - padding-left: 191px; -} -.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div:before { - margin-left: 140px; -} -.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div { - padding-left: 211px; -} -.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div:before { - margin-left: 160px; -} -.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div { - padding-left: 231px; -} -.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div:before { - margin-left: 180px; -} -.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div { - padding-left: 251px; -} -.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div:before { - margin-left: 200px; -} -.oc-treeview-expand-control { +.control-treeview ol > li > div > span.expand { font: 0/0 a; color: transparent; text-shadow: none; background-color: transparent; border: 0; - position: absolute; - width: 23px; - height: 23px; - border-radius: 20px; - background: #ffffff; - display: block; - z-index: 100; - cursor: pointer; - -webkit-transition: opacity 0.2s; - transition: opacity 0.2s; -} -.oc-treeview-expand-control.expand-hidden { display: none; + position: absolute; + left: 0; + width: 20px; + height: 20px; + top: 24px; + left: 2px; + cursor: pointer; + color: #bdc3c7; + -webkit-transition: transform 0.1s ease; + transition: transform 0.1s ease; } -.oc-treeview-expand-control.expand-drag-hidden { - opacity: 0; - filter: alpha(opacity=0); -} -.oc-treeview-expand-control:before { +.control-treeview ol > li > div > span.expand:before { font-family: FontAwesome; font-weight: normal; font-style: normal; @@ -13606,25 +13534,321 @@ div[data-control="balloon-selector"]:not(.control-disabled) ul li:hover { -webkit-font-smoothing: antialiased; *margin-right: .3em; content: "\f0da"; + line-height: 100%; font-size: 15px; + position: relative; + left: 8px; + top: 2px; +} +.control-treeview ol > li > div > span.drag-handle { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; + -webkit-transition: opacity 0.4s; + transition: opacity 0.4s; position: absolute; - left: 7px; - top: 12px; - color: #33495f; - -webkit-transition: all 0.1s ease; - transition: all 0.1s ease; + right: 10px; + bottom: 5px; + width: 14px; + height: 14px; + cursor: move; + color: #bdc3c7; + opacity: 0; + filter: alpha(opacity=0); } -.oc-treeview-expand-control.hover { - background-color: #58b6f7; +.control-treeview ol > li > div > span.drag-handle:before { + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + text-decoration: inherit; + -webkit-font-smoothing: antialiased; + *margin-right: .3em; + content: "\f0c9"; + font-size: 14px; } -.oc-treeview-expand-control.hover:before { +.control-treeview ol > li > div span.borders { + font-size: 0; +} +.control-treeview ol > li.dragged div, +.control-treeview ol > li > div:hover { + background-color: #58b6f7 !important; + color: #ffffff !important; +} +.control-treeview ol > li.dragged div:before, +.control-treeview ol > li > div:hover:before { + background-position: 0px -80px; +} +.control-treeview ol > li.dragged div:after, +.control-treeview ol > li > div:hover:after { + top: 0!important; + bottom: 0!important; +} +.control-treeview ol > li.dragged div span, +.control-treeview ol > li > div:hover span { + color: #ffffff !important; +} +.control-treeview ol > li.dragged div span.drag-handle, +.control-treeview ol > li > div:hover span.drag-handle { + cursor: move; + opacity: 1; + filter: alpha(opacity=100); +} +.control-treeview ol > li.dragged div span.borders, +.control-treeview ol > li > div:hover span.borders { + display: none; +} +.control-treeview ol > li.dragged li.has-subitems > div:before, +.control-treeview ol > li.dragged.has-subitems > div:before { + background-position: 0px -52px; +} +.control-treeview ol > li > ol { + padding-left: 20px; +} +.control-treeview ol > li[data-status=collapsed] > ol { + display: none; +} +.control-treeview ol > li.has-subitems > div:before { + background-position: 0 0; + width: 23px; + height: 26px; + left: 26px; +} +.control-treeview ol > li.has-subitems > div:hover:before { + background-position: 0px -52px; +} +.control-treeview ol > li.has-subitems > div span.expand { + display: block; +} +.control-treeview ol > li.placeholder { + height: 0; + position: relative; + border-bottom: 1px dotted #c03f31; +} +.control-treeview ol > li.placeholder:before { + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + text-decoration: inherit; + -webkit-font-smoothing: antialiased; + *margin-right: .3em; + content: "\f0da"; + font-size: 23px; + color: white; + position: absolute; + left: -11px; + top: -17px; + z-index: 1900; +} +.control-treeview ol > li.placeholder:after { + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + text-decoration: inherit; + -webkit-font-smoothing: antialiased; + *margin-right: .3em; + content: "\f0da"; + font-size: 21px; + color: #c03f31; + position: absolute; + left: -10px; + top: -14px; + z-index: 1901; +} +.control-treeview ol > li.dragged { + position: absolute; + z-index: 2000; + opacity: 0.5; + filter: alpha(opacity=50); +} +.control-treeview ol > li.dragged > div { + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.control-treeview ol > li.drop-target > div { + background-color: #2581b8!important; color: #ffffff; } -.oc-treeview-expand-control[data-status=expanded]:before { +.control-treeview ol > li.drop-target > div:before { + background-position: 0px -80px; +} +.control-treeview ol > li.drop-target > div > span.comment { + color: #ffffff; +} +.control-treeview ol > li.drop-target.has-subitems > div:before { + background-position: 0px -52px; +} +.control-treeview ol > li[data-status=expanded] > div > span.expand { -webkit-transform: rotate(90deg) translate(0, 0); -ms-transform: rotate(90deg) translate(0, 0); transform: rotate(90deg) translate(0, 0); } +.control-treeview ol > li.drag-ghost { + background-color: transparent; + box-sizing: content-box; +} +.control-treeview ol > li.active > div { + background: #dddddd; +} +.control-treeview ol > li.active > div:after { + position: absolute; + width: 4px; + left: 0; + top: -1px; + bottom: -1px; + background: #e67e22; + display: block; + content: ' '; +} +.control-treeview ol > li.active > div > span.comment, +.control-treeview ol > li.active > div > span.expand { + color: #8f8f8f; +} +.control-treeview ol > li.active > div > span.borders:before, +.control-treeview ol > li.active > div > span.borders:after { + content: ' '; + position: absolute; + width: 100%; + height: 1px; + display: block; + left: 0; + background-color: #dddddd; +} +.control-treeview ol > li.active > div > span.borders:before { + top: -1px; +} +.control-treeview ol > li.active > div > span.borders:after { + bottom: -1px; +} +.control-treeview ol > li > ol > li > div { + margin-left: -20px; + padding-left: 71px; +} +.control-treeview ol > li > ol > li > div:before { + margin-left: 10px; +} +.control-treeview ol > li > ol > li > div > span.expand { + left: 12px; +} +.control-treeview ol > li > ol > li > ol > li > div { + margin-left: -40px; + padding-left: 81px; +} +.control-treeview ol > li > ol > li > ol > li > div:before { + margin-left: 20px; +} +.control-treeview ol > li > ol > li > ol > li > div > span.expand { + left: 22px; +} +.control-treeview ol > li > ol > li > ol > li > ol > li > div { + margin-left: -60px; + padding-left: 91px; +} +.control-treeview ol > li > ol > li > ol > li > ol > li > div:before { + margin-left: 30px; +} +.control-treeview ol > li > ol > li > ol > li > ol > li > div > span.expand { + left: 32px; +} +.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > div { + margin-left: -80px; + padding-left: 101px; +} +.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > div:before { + margin-left: 40px; +} +.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > div > span.expand { + left: 42px; +} +.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div { + margin-left: -100px; + padding-left: 111px; +} +.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div:before { + margin-left: 50px; +} +.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div > span.expand { + left: 52px; +} +.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div { + margin-left: -120px; + padding-left: 121px; +} +.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div:before { + margin-left: 60px; +} +.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div > span.expand { + left: 62px; +} +.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div { + margin-left: -140px; + padding-left: 131px; +} +.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div:before { + margin-left: 70px; +} +.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div > span.expand { + left: 72px; +} +.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div { + margin-left: -160px; + padding-left: 141px; +} +.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div:before { + margin-left: 80px; +} +.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div > span.expand { + left: 82px; +} +.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div { + margin-left: -180px; + padding-left: 151px; +} +.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div:before { + margin-left: 90px; +} +.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div > span.expand { + left: 92px; +} +.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div { + margin-left: -200px; + padding-left: 161px; +} +.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div:before { + margin-left: 100px; +} +.control-treeview ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > ol > li > div > span.expand { + left: 102px; +} +@media only screen and (-moz-min-device-pixel-ratio: 1.5), only screen and (-o-min-device-pixel-ratio: 3/2), only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-devicepixel-ratio: 1.5), only screen and (min-resolution: 1.5dppx) { + .control-treeview ol > li > div:before { + background-position: 0px -79px; + background-size: 21px auto; + } + .control-treeview ol > li.has-subitems > div:before { + background-position: 0px -52px; + } + .control-treeview ol > li.has-subitems > div:hover:before { + background-position: 0px -102px; + } + .control-treeview ol > li.dragged > div:before, + .control-treeview ol > li.dragged li > div:before, + .control-treeview ol > li > div:hover:before { + background-position: 0px -129px; + } + .control-treeview ol > li.dragged li.has-subitems > div:before, + .control-treeview ol > li.dragged.has-subitems > div:before { + background-position: 0px -102px; + } + .control-treeview ol > li.drop-target > div:before { + background-position: 0px -129px; + } + .control-treeview ol > li.drop-target.has-subitems > div:before { + background-position: 0px -102px; + } +} .callout { font-size: 14px; margin-bottom: 20px; diff --git a/modules/backend/assets/images/treeview-icons.png b/modules/backend/assets/images/treeview-icons.png new file mode 100644 index 0000000000000000000000000000000000000000..ecf99f366c2d1e34a4ece28d80ae21067dbf5633 GIT binary patch literal 2491 zcmbVOcTiL577tOnprRtC5lfj7w;u0U5=V3xtqjav{hnqJpzDWfc)o zsp6x!1h4@LF4!9amMA{t;esM{K@r9FZUo$YZ=C((-I+UIJHK;&-|w6=^QHLvdYc$o z86gk|6ZRTrAUrxD5IR@`J$UwRdE$F`u!LB_&^lQ-q~a++gojYZ2T^PZF9Hk%dBSa5 zZ-T23h*?TeP%sqC@c{%f36`g|!Ny7CFdBha;Sw4p64KFJ z3J1@TGr&mEns^1cF5Wjt5HA+cglM_7rSJXD+{TB-!%=;*J00eG(6#-UMP zO&~EHJw+;*GYxnnow1zMnz)vB9lfsK;$^gm_W`I1^h0$DYR0{uT=`6d(_hDS~9O=$R_;kCZ_& zWu#1wVlYsS9G*ZV)vi})b2N2jCa4g_fJiGXn>Qv^aHNx&1jxT2@=!v9x1983zQt(3o1&de5Ej@s$BK7beBIti4*?W2JE zMBII_41v&n#%6j1#dQoGuahqHn721#OR@yH53!4c%xg|tgRc_$auV@}Gi`;+JxK<& z!aMU(^A597SKWV`FBo0Q)U&a1N7^P?ly6mAQ0b&jQYZcFg`Mn@YSqhk=O!yFf6X{( zm(s3~PWCSW$i@8k9za5@f^Tnxx=mJ7Ow>aT4c^P5Wd^P9UKC&daq~M@w=bG21A6*` zPTipiwr}QU^e0Yz*Lm>pp@z)WH$dRnfr;85v#np7IQ0t;1TJ};W)@qQ)cN~@GavFAsM_LpSuqUY~!7@Bn^;B9kkG1|CXW+E5)$cn8_1QeZ}Tk>UD7bW)} z&Sv=;Wwx^m5W0@;IvutJ8AWXGUn1?7H#q~`(LC9n;4FLVqnJv+o-1}<)(?Zp-Ou_% z9lk?h7C5O~0(8)?5s#lEe3|(AWU&%d-ap-xkVqfo{jXAKq@nmb& zx!b*IV{snMsf`mhnhndYXnM+j8XFdu2fhhm3?de%J$f#760{YXZMc?eI7KEkhW==r zrx}lMaPap&+;aZ_^C30mh;!yXQRPHYwbe)dlTv2RHJx_-m_>ATOyjjXlABI@-+XZB z?Ygv`yXPVxLY6lVj~eC%%{Gq*bT2%mMjk2BG$l;vbd&}*Fe+cKv_EO*`#I)BHNUKO z_o3hOtUYy%{1cH23+T0#>KePUt3}S5_w{VUG`7KZzdz_D{f?6Xnu2~6s|Kz(6`)O~E z$Y(A0o%hp4OA0Sz+D%OJKWwfPhSf)ppSNasjV1W8RrRwsjg*nOnX3!U#4(=ML$=2$ zyD-t?QT4N4UIzsQ zT-sXk;&I`G1XJ(zc}MU@7mRUxjhgnbZJ@oTe7`%nY6$Re^K0>r&+j`H@mOs2_>fub zQKSCi{4(mk>lls&*3l^!&dnzn00y;r+tUj#i+LqtF zGV^8NuaA8CPnpCloJ#eS?%EQ(fOrsZ9+msLEyzdpxxT#54gc?tk;r(*jnHw;^5;+V zjR*Sbo0>v^J1-tQ3H1Bt2ket&7G0DMs3T|TtxU}Zb@iOdHgsA|I_6brLKe$SguGRh zPcAF2`*cD^xNGn2A@H0N3?fc9=I{t4hK)#;!aM6+)8h@>AWU+n`N2I0PaX~xfaQn zMW^m%G;t{ZuNSN3R@T~#E@zb6r&b?L%A`#iI-qT#tc zFA_@^Jm|0M^Jcs${<*!(DAm#WXhKb&-A81_+}4Yoy){n58ik=#Y95@G6xJ`Z(4M9S z)ZH)}_u!sHx$e{VG!)wMPk}v54MO1`KElXf6%cg(mxpW9aLrs;#U-h2!(+>I^bn`b V%StkeQnb%A1e@i{tn}Qn`#&U^` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/modules/backend/assets/js/october.sidepaneltab.js b/modules/backend/assets/js/october.sidepaneltab.js index 989956cb0..f172e15f7 100644 --- a/modules/backend/assets/js/october.sidepaneltab.js +++ b/modules/backend/assets/js/october.sidepaneltab.js @@ -115,7 +115,10 @@ } SidePanelTab.prototype.updatePanelPosition = function() { - this.$el.height($(document).height() - this.mainNavHeight) + if (!this.panelFixed()) + this.$el.height($(document).height() - this.mainNavHeight) + else + this.$el.css('height', '') if (this.panelVisible && $(window).width() > this.options.breakpoint && this.panelFixed()) this.hideSidePanel() diff --git a/modules/backend/assets/js/october.sortable.js b/modules/backend/assets/js/october.sortable.js index 36bee454e..881e7556d 100644 --- a/modules/backend/assets/js/october.sortable.js +++ b/modules/backend/assets/js/october.sortable.js @@ -55,6 +55,8 @@ handle: "", // The exact css path between the item and its subcontainers itemPath: "", + // Use animation when an item is removed or inserted into the tree + useAnimation : false, // The css selector of the items itemSelector: "li", // Check if the dragged item may be inside the container. @@ -67,6 +69,10 @@ // This happens if pullPlaceholder is set to false and the drop occurs outside a container. onCancel: function ($item, container, _super, event) { }, + + tweakCursorAdjustment: function(adjustment) { + return adjustment + }, // Called after the drag has been started, // that is the mouse button is beeing held down and // the mouse is moving. @@ -87,10 +93,16 @@ cursorAdjustment = null } + cursorAdjustment = this.tweakCursorAdjustment(cursorAdjustment) + $item.css({ height: $item.height(), width: $item.width() }) + + if (this.useAnimation) + $item.data('oc.animated', true) + $item.addClass("dragged") $("body").addClass("dragging") }, @@ -109,10 +121,15 @@ $item.css(position) } }, - // Called when the mouse button is beeing released + // Called when the mouse button is being released onDrop: function ($item, container, _super, event) { $item.removeClass("dragged").removeAttr("style") $("body").removeClass("dragging") + + if ($item.data('oc.animated')) { + $item.hide() + $item.slideDown(200) + } }, // Called on mousedown. If falsy value is returned, the dragging will not start. onMousedown: function ($item, _super, event) { diff --git a/modules/backend/assets/js/october.treelist.js b/modules/backend/assets/js/october.treelist.js index 903ce2ec8..0c6e1907d 100644 --- a/modules/backend/assets/js/october.treelist.js +++ b/modules/backend/assets/js/october.treelist.js @@ -19,15 +19,18 @@ this.options = options || {}; - $el.find('> ol').sortable({ + var sortableOptions = { handle: options.handle, onDrop: function($item, container, _super) { self.$el.trigger('move.oc.treelist', { item: $item, container: container }) _super($item, container) + }, + afterMove: function($placeholder, container, $closestEl) { + self.$el.trigger('aftermove.oc.treelist', { placeholder: $placeholder, container: container, closestEl: $closestEl }) } + } - }) - + $el.find('> ol').sortable($.extend(sortableOptions, options)) } TreeListWidget.DEFAULTS = { diff --git a/modules/backend/assets/js/october.treeview.js b/modules/backend/assets/js/october.treeview.js index ad166c666..a85421a9c 100644 --- a/modules/backend/assets/js/october.treeview.js +++ b/modules/backend/assets/js/october.treeview.js @@ -1,159 +1,137 @@ /* * TreeView Widget. Represents a sortable and draggable tree view. This widget was first used in the Pages plugin, for the sidebar page tree. * - * Supported options: + * Data attributes: + * - data-group-status-handler - AJAX handler to execute when an item is collapsed or expanded by a user + * - data-reorder-handler - AJAX handler to execute when items are reordered * - * Events: + * Events + * - open.oc.treeview - this event is triggered on the list element when an item is clicked. * * Dependences: + * - Tree list (october.treelist.js) * */ +function ($) { "use strict"; var TreeView = function (element, options) { this.$el = $(element) this.options = options - this.expandControls = [] this.init() } TreeView.prototype.init = function () { - this.$expandControlContainer = this.options.expandControlContainer !== null ? - this.$el.closest(this.options.expandControlContainer) : - $(document.body) - - /* - * Delete existing expand/collapse icons - */ - - $.each(this.expandControls, function(){ - $(this).remove() - }) - - /* - * Create new expand/collapse icons - */ + this.$allItems = $('li', this.$el) + this.$scrollbar = this.$el.closest('[data-control=scrollbar]') var self = this - $('li', this.$el).each(function() { - var $el = $(this), - $expand = $('> span.expand', $el), - $info = $('> div', $el) - - $expand - .data('oc.treeview-parent', $el) - .addClass('oc-treeview-expand-control') - .addClass('hidden') - - self.$expandControlContainer.append($expand) - - self.expandControls.push($expand) - - $expand.click(function(){ - self.toggleGroup($expand) - }) - - $info.mouseenter(function() { - $expand.addClass('hover') - }) - - $info.mouseleave(function() { - $expand.removeClass('hover') - }) - }) - - this.realignExpandControls() - - /* - * Bind to a scrollbar events, if the treeview is hosted inside a scrollbar - */ - - var $scrollbar = this.$el.closest('[data-control=scrollbar]') - - if ($scrollbar.length > 0) { - $scrollbar.on('oc.scrollStart', $.proxy(this.hideExpandControls, this)) - $scrollbar.on('oc.scrollEnd', $.proxy(this.showExpandControls, this)) - } - - /* - * Ralign expand controls after window resize - */ - - $(window).on('resize, oc.updateUi', $.proxy(this.realignExpandControls, this)) - /* * Init the sortable */ - this.$el.treeListWidget() + this.$el.treeListWidget({ + tweakCursorAdjustment: function(adjustment) { + if (!adjustment) + return adjustment + + if (self.$scrollbar.length > 0) { + adjustment.top -= self.$scrollbar.scrollTop() + } + + return adjustment; + }, + isValidTarget: function($item, container) { + return $(container.el).closest('li').attr('data-status') != 'collapsed' + }, + useAnimation: true, + handle: 'span.drag-handle' + }) + + this.$el.on('move.oc.treelist', function(){ + setTimeout(function(){ + self.$allItems.removeClass('drop-target') + self.fixSubItems() + self.sendReorderRequest() + }, 50) + }) + + this.$el.on('aftermove.oc.treelist', function(event, data) { + self.$allItems.removeClass('drop-target') + data.container.el.closest('li').addClass('drop-target') + }) + + /* + * Create expand/collapse icons and drag handles + */ + + this.createItemControls() + + /* + * Bind the click events + */ + + this.$el.on('click', 'li > div', function(event) { + var e = $.Event('open.oc.treeview', {relatedTarget: $(this).parent().get(0), clickEvent: event}) + self.$el.trigger(e, this) + + return false + }) + + /* + * Listen for the AJAX updates and update the widget + */ + this.$el.on('ajaxUpdate', $.proxy(this.update, this)) } - TreeView.prototype.alignExpandControls = function() { - var expandControlOffset = this.$expandControlContainer.offset(), - expandControlHeight = this.$expandControlContainer.height() + TreeView.prototype.createItemControls = function() { + var self = this - $.each(this.expandControls, function(){ - var $expand = $(this), - $li = $expand.data('oc.treeview-parent'), - offset = $li.offset(), - top = offset.top+14-expandControlOffset.top, - outside = top < 0 || (top+20) > expandControlHeight + $('li', this.$el).each(function() { + var $container = $('> div', this), + $expand = $('> span.expand', $container), + group = this - $expand.css({ - left: offset.left-7-expandControlOffset.left, - top: top + if ($expand.length > 0) + return + + $expand = $('Expand').click(function(){ + self.toggleGroup($(group)) + + return false }) - $expand.toggleClass('expand-hidden', !$li.hasClass('has-subitems') || outside) + $container.prepend($expand) + + $container.append($('Drag')) + $container.append($('')) }) } - TreeView.prototype.hideExpandControls = function() { - $.each(this.expandControls, function(){ - $(this).addClass('expand-drag-hidden') - }) - } - - TreeView.prototype.showExpandControls = function() { - $.each(this.expandControls, function(){ - $(this).removeClass('expand-drag-hidden') - }) - - this.realignExpandControls() - } - - TreeView.prototype.realignExpandControls = function() { - this.alignExpandControls() - - $.each(this.expandControls, function(){ - $(this).removeClass('hidden') - }) - } - - TreeView.prototype.collapseGroup = function($expandControl, $list) { + TreeView.prototype.collapseGroup = function($group) { var self = this, - $subitems = $('> ol', $list) + $subitems = $('> ol', $group) - $subitems.css('overflow', 'hidden') - $expandControl.attr('data-status', 'collapsed') + $subitems.css({ + 'overflow': 'hidden' + }) $subitems.animate({'height': 0}, { duration: 100, queue: false, complete: function() { $subitems.css({ 'overflow': 'visible', - 'display': 'none' + 'display': 'none', + 'height' : 'auto' }) - $list.attr('data-status', 'collapsed') - self.alignExpandControls() + $group.attr('data-status', 'collapsed') $(window).trigger('resize') } }) - // this.sendGroupStatusRequest(group, 0); + this.sendGroupStatusRequest($group, 0) } - TreeView.prototype.expandGroup = function($expandControl, $list) { + TreeView.prototype.expandGroup = function($group) { var self = this, - $subitems = $('> ol', $list) + $subitems = $('> ol', $group) $subitems.css({ 'overflow': 'hidden', @@ -161,31 +139,77 @@ 'height': 0 }) - $list.attr('data-status', 'expanded') + $group.attr('data-status', 'expanded') $subitems.animate({'height': $subitems[0].scrollHeight}, { duration: 100, queue: false, complete: function() { $subitems.css({ 'overflow': 'visible', 'height': 'auto' }) - $expandControl.attr('data-status', 'expanded') - self.alignExpandControls() $(window).trigger('resize') } }) -// this.sendGroupStatusRequest(group, 1); + this.sendGroupStatusRequest($group, 1); + } + + TreeView.prototype.fixSubItems = function() { + $('li', this.$el).each(function(){ + var $li = $(this), + $subitems = $('> ol > li', $li) + $li.toggleClass('has-subitems', $subitems.length > 0) + }) } TreeView.prototype.toggleGroup = function(group) { var $group = $(group); $group.attr('data-status') == 'expanded' ? - this.collapseGroup($group, $group.data('oc.treeview-parent')) : - this.expandGroup($group, $group.data('oc.treeview-parent')) + this.collapseGroup($group) : + this.expandGroup($group) + } + + TreeView.prototype.sendGroupStatusRequest = function($group, status) { + if (this.options.groupStatusHandler !== undefined) { + var groupId = $group.data('group-id') + + $group.request(this.options.groupStatusHandler, {data: {group: groupId, status: status}}) + } + } + + TreeView.prototype.sendReorderRequest = function() { + var groups = {} + + function iterator($container, node) { + $('> li', $container).each(function(){ + var subnodes = {} + iterator($('> ol', this), subnodes) + + node[$(this).data('groupId')] = subnodes + }) + } + + iterator($('> ol', this.$el), groups) + + this.$el.request(this.options.reorderHandler, {data: {structure: JSON.stringify(groups)}}) + } + + TreeView.prototype.markActive = function(dataId) { + $('li', this.$el).removeClass('active') + + if (dataId) + $('li[data-id="'+dataId+'"]', this.$el).addClass('active') + + this.dataId = dataId + } + + TreeView.prototype.update = function() { + this.createItemControls() + + if (this.dataId !== undefined) + this.markActive(this.dataId) } TreeView.DEFAULTS = { - sortableHandle: null, - expandControlContainer: null + } // TREEVIEW PLUGIN DEFINITION @@ -194,11 +218,21 @@ var old = $.fn.treeView $.fn.treeView = function (option) { + var args = arguments + return this.each(function () { var $this = $(this) var data = $this.data('oc.treeView') var options = $.extend({}, TreeView.DEFAULTS, $this.data(), typeof option == 'object' && option) if (!data) $this.data('oc.treeView', (data = new TreeView(this, options))) + + if (typeof option == 'string') { + var methodArgs = []; + for (var i=1; i li { - position: relative; - - span.expand { - display: none; - } + .transition(width 1s); > div { - font-size: 14px; + font-size: 13px; font-weight: 600; color: @color-treeview-item-title; background: @color-treeview-item-bg; - margin-bottom: 1px; - padding: 16px 16px 15px 51px; + border-bottom: 1px solid @color-panel-light; + padding: 16px 16px 15px 61px; position: relative; + cursor: pointer; &:before { content: ' '; - background-image: url(../images/treeview-icons.svg); - background-position: 0px top; + background-image: url(../images/treeview-icons.png); + background-position: 0px -28px; background-repeat: no-repeat; - background-size: 25px auto; + background-size: 42px auto; position: absolute; width: 21px; - height: 26px; - left: 18px; + height: 22px; + left: 28px; top: 20px; } - > span { + span.comment { display: block; font-weight: 400; color: @color-treeview-item-comment; @@ -44,18 +42,91 @@ text-overflow: ellipsis; } - &:hover { - background-color: @color-treeview-hover-bg; - color: @color-treeview-hover-text; + > span.expand { + .hide-text(); + display: none; + position: absolute; + left: 0; + width: 20px; + height: 20px; + top: 24px; + left: 2px; + cursor: pointer; + color: @color-treeview-control; + .transition(transform 0.1s ease); &:before { - background-position: 0px -65px; - } + .icon(@caret-right); + line-height: 100%; + font-size: 15px; - > span { - color: @color-treeview-hover-text; + position: relative; + left: 8px; + top: 2px; } } + + > span.drag-handle { + .hide-text(); + .transition(opacity 0.4s); + + position: absolute; + right: 10px; + bottom: 5px; + width: 14px; + height: 14px; + cursor: move; + color: @color-treeview-control; + .opacity(0); + + &:before { + .icon(@bars); + font-size: 14px; + } + } + + span.borders { + font-size: 0; + } + } + + &.dragged div, > div:hover { + background-color: @color-treeview-hover-bg!important; + color: @color-treeview-hover-text!important; + + &:before { + background-position: 0px -80px; + } + + &:after { + top: 0!important; + bottom: 0!important; + } + + span { + color: @color-treeview-hover-text!important; + + &.drag-handle { + cursor: move; + .opacity(1); + } + + &.borders { + display: none; + } + } + } + + &.dragged { + li.has-subitems, &.has-subitems { + > div:before { + background-position: 0px -52px; + } + } + } + + > ol { + padding-left: 20px; } &[data-status=collapsed] > ol { @@ -65,14 +136,120 @@ &.has-subitems { >div { &:before { - background-position: 0 -29px; + background-position: 0 0; width: 23px; - height: 29px; - left: 16px; + height: 26px; + left: 26px; } &:hover:before { - background-position: 0px -95px; + background-position: 0px -52px; + } + + span.expand { + display: block; + } + } + } + + &.placeholder { + height: 0; + position: relative; + border-bottom: 1px dotted #c03f31; + + &:before { + .icon(@caret-right); + font-size: 23px; + color: white; + position: absolute; + left: -11px; + top: -17px; + z-index: 1900; + } + + &:after { + .icon(@caret-right); + font-size: 21px; + color: #c03f31; + position: absolute; + left: -10px; + top: -14px; + z-index: 1901; + } + } + + &.dragged { + position: absolute; + z-index: 2000; + // width: auto!important; + // height: auto!important; + .opacity(0.5); + + > div { + .border-radius(3px); + } + } + + &.drop-target { + > div { + background-color: #2581b8!important; + color: @color-treeview-hover-text; + + &:before { + background-position: 0px -80px; + } + + > span.comment { + color: @color-treeview-hover-text; + } + } + + &.has-subitems > div:before { + background-position: 0px -52px; + } + } + + &[data-status=expanded] > div > span.expand { + .transform( ~'rotate(90deg) translate(0, 0)' ); + } + + &.drag-ghost { + background-color: transparent; + box-sizing: content-box; + } + + &.active { + > div { + background: @color-list-active; + + &:after { + position: absolute; + width: 4px; + left: 0; + top: -1px; + bottom: -1px; + background: @color-list-active-border; + display: block; + content: ' '; + } + + > span.comment, > span.expand { + color: @color-treeview-item-active-comment; + } + + > span.borders { + &:before, &:after { + content: ' '; + position: absolute; + width: 100%; + height: 1px; + display: block; + left: 0; + background-color: @color-list-active; + } + + &:before {top: -1px;} + &:after {bottom: -1px;} } } } @@ -84,10 +261,15 @@ > li { > ol { > li > div { - padding-left: 71 + (@max-level - @level)*20px; + margin-left: -20-(@max-level - @level)*20px; + padding-left: 61+(@max-level - @level + 1)*10px; &:before { - margin-left: 20 + (@max-level - @level)*20px; + margin-left: (@max-level - @level + 1)*10px; + } + + > span.expand { + left: 2+(@max-level - @level + 1)*10px; } } @@ -100,47 +282,45 @@ } } -.oc-treeview-expand-control { - .hide-text(); - position: absolute; - width: 23px; - height: 23px; - border-radius: 20px; - background: @color-treeview-item-bg; - display: block; - z-index: 100; - cursor: pointer; - .transition(opacity 0.2s); +// Retina +@media only screen and (-moz-min-device-pixel-ratio: 1.5), only screen and (-o-min-device-pixel-ratio: 3/2), only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-devicepixel-ratio: 1.5), only screen and (min-resolution: 1.5dppx) { + .control-treeview { + ol { + > li { + > div{ + &:before { + background-position: 0px -79px; + background-size: 21px auto; + } + } - &.expand-hidden { - display: none; - } + &.has-subitems > div { + &:before {background-position: 0px -52px;} + &:hover:before {background-position: 0px -102px;} + } - &.expand-drag-hidden { - .opacity(0); - } + &.dragged > div, &.dragged li > div, > div:hover { + &:before {background-position: 0px -129px;} + } - &:before { - .icon(@caret-right); - font-size: 15px; - position: absolute; - left: 7px; - top: 12px; - color: @color-treeview-expand-icon; - .transition(all 0.1s ease); - } + &.dragged { + li.has-subitems, &.has-subitems { + > div:before { + background-position: 0px -102px; + } + } + } - &.hover { - background-color: @color-treeview-hover-bg; + &.drop-target { + > div:before { + background-position: 0px -129px; + } - &:before { - color: @color-treeview-hover-text; - } - } - - &[data-status=expanded] { - &:before { - .transform( ~'rotate(90deg) translate(0, 0)' ); + &.has-subitems > div:before { + background-position: 0px -102px; + } + } + } } } } \ No newline at end of file diff --git a/modules/backend/assets/less/core/variables.less b/modules/backend/assets/less/core/variables.less index 81eabb46c..9162120a0 100644 --- a/modules/backend/assets/less/core/variables.less +++ b/modules/backend/assets/less/core/variables.less @@ -266,9 +266,10 @@ @color-treeview-item-bg: #ffffff; @color-treeview-item-title: #2b3e50; @color-treeview-item-comment: #95a5a6; -@color-treeview-expand-icon: #33495f; +@color-treeview-control: #bdc3c7; @color-treeview-hover-bg: #58b6f7; @color-treeview-hover-text: #ffffff; +@color-treeview-item-active-comment: #8f8f8f; // // Sizes diff --git a/modules/backend/formwidgets/richeditor/assets/css/iframe.css b/modules/backend/formwidgets/richeditor/assets/css/iframe.css index 5d1bac335..9a6c3408d 100644 --- a/modules/backend/formwidgets/richeditor/assets/css/iframe.css +++ b/modules/backend/formwidgets/richeditor/assets/css/iframe.css @@ -21,6 +21,8 @@ ol, table, dl, blockquote, +td, +th, pre { font-size: 14px; line-height: 1.5rem; @@ -158,6 +160,9 @@ h5 { margin-bottom: 10px; font-size: 1em; } +table { + width: 100%; +} body.redactor_editor_wym { background: #f4f4f4; diff --git a/modules/backend/formwidgets/richeditor/assets/css/richeditor.css b/modules/backend/formwidgets/richeditor/assets/css/richeditor.css index f95f7b789..47ecf62be 100644 --- a/modules/backend/formwidgets/richeditor/assets/css/richeditor.css +++ b/modules/backend/formwidgets/richeditor/assets/css/richeditor.css @@ -9,7 +9,7 @@ border-radius: 5px; } .field-richeditor.editor-focus { - border: 1px solid #808c8d; + border-color: #808c8d; } .field-richeditor.size-tiny textarea { height: 20px; @@ -42,3 +42,31 @@ .field-richeditor .redactor_box iframe { border: none; } +.field-richeditor.stretch .redactor_box { + display: block; + position: relative; + height: 100%; + width: 100%; + overflow: hidden; +} +.field-richeditor.stretch .redactor_box .redactor_toolbar { + display: block; + border-bottom: none; + position: absolute; + top: 0; + width: 100%; +} +.field-richeditor.stretch .redactor_box .redactor_toolbar > li:first-child:after { + position: absolute; + content: ' '; + width: 100%; + height: 1px; + left: 0; + top: 32px; + background-color: #e0e0e0; +} +.field-richeditor.stretch .redactor_box iframe { + display: block; + position: absolute; + height: 100%!important; +} diff --git a/modules/backend/formwidgets/richeditor/assets/js/richeditor.js b/modules/backend/formwidgets/richeditor/assets/js/richeditor.js index 6339118fc..f3294cd91 100644 --- a/modules/backend/formwidgets/richeditor/assets/js/richeditor.js +++ b/modules/backend/formwidgets/richeditor/assets/js/richeditor.js @@ -44,7 +44,8 @@ */ var redactorOptions = { focusCallback: function() { self.$el.addClass('editor-focus') }, - blurCallback: function() { self.$el.removeClass('editor-focus') } + blurCallback: function() { self.$el.removeClass('editor-focus') }, + initCallback: function() { self.build() } } if (this.options.stylesheet) { @@ -59,6 +60,15 @@ this.$textarea.redactor(redactorOptions) } + RichEditor.prototype.build = function() { + if (this.$el.hasClass('stretch')) { + var $iframe = $('iframe', this.$el), + $toolbar = $('.redactor_toolbar', this.$el) + + $iframe.css('padding-top', $toolbar.height()) + } + } + // RICHEDITOR PLUGIN DEFINITION // ============================ diff --git a/modules/backend/formwidgets/richeditor/assets/less/richeditor.less b/modules/backend/formwidgets/richeditor/assets/less/richeditor.less index dea458577..54dc81578 100644 --- a/modules/backend/formwidgets/richeditor/assets/less/richeditor.less +++ b/modules/backend/formwidgets/richeditor/assets/less/richeditor.less @@ -9,7 +9,7 @@ } &.editor-focus { - border: 1px solid @color-form-field-border-focus; + border-color: @color-form-field-border-focus; } &.size-tiny textarea { height: (@size-tiny - @richeditor-toolbar-size); } @@ -31,4 +31,38 @@ border: none; } } + + &.stretch { + .redactor_box { + display: block; + position: relative; + height: 100%; + width: 100%; + overflow: hidden; + + .redactor_toolbar { + display: block; + border-bottom: none; + position: absolute; + top: 0; + width: 100%; + + > li:first-child:after { + position: absolute; + content: ' '; + width: 100%; + height: 1px; + left: 0; + top: 32px; + background-color: @color-form-field-border; + } + } + + iframe { + display: block; + position: absolute; + height: 100%!important; + } + } + } } \ No newline at end of file diff --git a/modules/backend/formwidgets/richeditor/partials/_richeditor.htm b/modules/backend/formwidgets/richeditor/partials/_richeditor.htm index 302b2378a..20d04c351 100644 --- a/modules/backend/formwidgets/richeditor/partials/_richeditor.htm +++ b/modules/backend/formwidgets/richeditor/partials/_richeditor.htm @@ -3,7 +3,7 @@
data-fullpage="true" data-control="richeditor"> diff --git a/modules/cms/classes/CmsCompoundObject.php b/modules/cms/classes/CmsCompoundObject.php index c37c46d7f..980040c44 100644 --- a/modules/cms/classes/CmsCompoundObject.php +++ b/modules/cms/classes/CmsCompoundObject.php @@ -47,6 +47,8 @@ class CmsCompoundObject extends CmsObject protected $settingsValidationMessages = []; + protected $viewBagCache = false; + /** * Loads the object from a file. * @param \Cms\Classes\Theme $theme Specifies the theme the object belongs to. @@ -202,6 +204,29 @@ class CmsCompoundObject extends CmsObject parent::save(); } + /** + * Returns the configured view bag component. + * This method is used only in the back-end and for internal system needs when + * the standard way to access components is not an option. + * @return \Cms\Classes\ViewBag Returns the view bag component instance. + */ + public function getViewBag() + { + if ($this->viewBagCache !== false) + return $this->viewBagCache; + + $componentName = 'viewBag'; + + if (!isset($this->settings['components'][$componentName])) + return $this->viewBagCache = null; + + return $this->viewBagCache = ComponentManager::instance()->makeComponent( + $componentName, + null, + $this->settings['components'][$componentName]); + } + + /** * Parses the settings array. * Child classes can override this method in order to update diff --git a/modules/cms/classes/Content.php b/modules/cms/classes/Content.php index 24fb369e6..e9f3d4e22 100644 --- a/modules/cms/classes/Content.php +++ b/modules/cms/classes/Content.php @@ -6,7 +6,7 @@ * @package october\cms * @author Alexey Bobkov, Samuel Georges */ -class Content extends CmsObject +class Content extends CmsCompoundObject { protected static $allowedExtensions = ['htm', 'txt', 'md']; diff --git a/modules/system/traits/PropertyContainer.php b/modules/system/traits/PropertyContainer.php index 5e9af376f..6bc0a6fe4 100644 --- a/modules/system/traits/PropertyContainer.php +++ b/modules/system/traits/PropertyContainer.php @@ -82,7 +82,7 @@ trait PropertyContainer */ public function property($name, $default = null) { - return isset($this->properties[$name]) + return array_key_exists($name, $this->properties) ? $this->properties[$name] : $default; }