mirror of
https://github.com/phpbb/phpbb.git
synced 2025-06-08 04:18:52 +00:00
Merge pull request #5979 from gijsmartens/ticket/15769
[ticket/15769] Crop avatar on upload
This commit is contained in:
commit
8faabb559d
23 changed files with 4647 additions and 21 deletions
|
@ -14,13 +14,18 @@
|
|||
"phpBB/adm/style/permissions.js",
|
||||
"phpBB/adm/style/tooltip.js",
|
||||
"phpBB/assets/javascript/core.js",
|
||||
"phpBB/assets/javascript/cropper.js",
|
||||
"phpBB/assets/javascript/editor.js",
|
||||
"phpBB/assets/javascript/hermite.js",
|
||||
"phpBB/assets/javascript/installer.js",
|
||||
"phpBB/assets/javascript/jquery-cropper.js",
|
||||
"phpBB/assets/javascript/plupload.js",
|
||||
"phpBB/ext/**/*.js",
|
||||
"phpBB/styles/prosilver/template/ajax.js",
|
||||
"phpBB/styles/prosilver/template/forum_fn.js",
|
||||
"phpBB/**/*.min.js",
|
||||
"phpBB/vendor/**/*.js",
|
||||
"phpBB/vendor-ext/**/*.js",
|
||||
"phpBB/phpbb/**/*.js",
|
||||
"phpBB/tests/**/*.js"
|
||||
],
|
||||
|
@ -40,6 +45,10 @@
|
|||
],
|
||||
"multiline-comment-style": "off",
|
||||
"computed-property-spacing": "off",
|
||||
"space-before-function-paren": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"space-in-parens": "off",
|
||||
"capitalized-comments": "off",
|
||||
"object-curly-spacing": [
|
||||
|
|
|
@ -2,3 +2,68 @@
|
|||
<dt><label for="avatar_upload_file">{L_UPLOAD_AVATAR_FILE}{L_COLON}</label></dt>
|
||||
<dd><input type="hidden" name="MAX_FILE_SIZE" value="{AVATAR_UPLOAD_SIZE}" /><input type="file" name="avatar_upload_file" id="avatar_upload_file" class="inputbox autowidth" accept="{{ AVATAR_ALLOWED_EXTENSIONS }}" /></dd>
|
||||
</dl>
|
||||
|
||||
{% INCLUDECSS T_ASSETS_PATH ~ '/css/cropper.min.css' %}
|
||||
{% INCLUDEJS T_ASSETS_PATH ~ '/javascript/cropper.min.js' %}
|
||||
{% INCLUDEJS T_ASSETS_PATH ~ '/javascript/jquery-cropper.js' %}
|
||||
{% INCLUDEJS T_ASSETS_PATH ~ '/javascript/phpbb-avatars.js' %}
|
||||
|
||||
<input type="hidden" id="avatar-cropper-data" name="avatar_cropper_data" value=""
|
||||
data-min-width="{{ AVATAR_MIN_WIDTH }}" data-max-width="{{ AVATAR_MAX_WIDTH }}"
|
||||
data-min-height="{{ AVATAR_MIN_HEIGHT }}" data-max-height="{{ AVATAR_MAX_HEIGHT }}"
|
||||
/>
|
||||
|
||||
{% apply spaceless %}
|
||||
<div class="avatar-cropper-buttons" id="avatar-cropper-buttons">
|
||||
<div class="button-group">
|
||||
<button class="button" type="button" title="{{ lang('ZOOM_IN') }}" data-cropper-action="zoom,0.1">
|
||||
<i class="icon fa-search-plus fa-fw"></i>
|
||||
</button>
|
||||
<button class="button" type="button" title="{{ lang('ZOOM_OUT') }}" data-cropper-action="zoom,-0.1">
|
||||
<i class="icon fa-search-minus fa-fw"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="button-group">
|
||||
<button class="button" type="button" title="{{ lang('MOVE_LEFT') }}" data-cropper-action="move,-10,0">
|
||||
<i class="icon fa-arrow-left fa-fw"></i>
|
||||
</button>
|
||||
<button class="button" type="button" title="{{ lang('MOVE_RIGHT') }}" data-cropper-action="move,10,0">
|
||||
<i class="icon fa-arrow-right fa-fw"></i>
|
||||
</button>
|
||||
<button class="button" type="button" title="{{ lang('MOVE_UP') }}" data-cropper-action="move,0,-10">
|
||||
<i class="icon fa-arrow-up fa-fw"></i>
|
||||
</button>
|
||||
<button class="button" type="button" title="{{ lang('MOVE_DOWN') }}" data-cropper-action="move,0,10">
|
||||
<i class="icon fa-arrow-down fa-fw"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="button-group">
|
||||
<button class="button" type="button" title="{{ lang('ROTATE_LEFT') }}" data-cropper-action="rotate,-90">
|
||||
<i class="icon fa-rotate-left fa-fw"></i>
|
||||
</button>
|
||||
<button class="button" type="button" title="{{ lang('ROTATE_RIGHT') }}" data-cropper-action="rotate,90">
|
||||
<i class="icon fa-rotate-right fa-fw"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="button-group">
|
||||
<button class="button" type="button" title="{{ lang('FLIP_HORIZONTALLY') }}" data-cropper-action="scaleX">
|
||||
<i class="icon fa-arrows-h fa-fw"></i>
|
||||
</button>
|
||||
<button class="button" type="button" title="{{ lang('FLIP_VERTICALLY') }}" data-cropper-action="scaleY">
|
||||
<i class="icon fa-arrows-v fa-fw"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="button-group">
|
||||
<button class="button" type="button" title="{{ lang('RESET') }}" data-cropper-action="reset">
|
||||
<i class="icon fa-refresh fa-fw"></i>
|
||||
</button>
|
||||
<button class="button" type="button" title="{{ lang('CLEAR') }}" data-cropper-action="clear">
|
||||
<i class="icon fa-times fa-fw"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endapply %}
|
||||
|
|
|
@ -113,7 +113,7 @@
|
|||
<legend>{L_GROUP_AVATAR}</legend>
|
||||
<dl>
|
||||
<dt><label>{L_CURRENT_IMAGE}{L_COLON}</label><br /><span>{L_AVATAR_EXPLAIN}</span></dt>
|
||||
<dd>{% if AVATAR_HTML %}{{ AVATAR_HTML }}{% else %}<img src="{{ ADMIN_ROOT_PATH ~ 'images/no_avatar.gif' }}" alt="">{% endif %}</dd>
|
||||
<dd class="c-avatar-box">{% if AVATAR_HTML %}{{ AVATAR_HTML }}{% else %}<img src="{{ ADMIN_ROOT_PATH ~ 'images/no_avatar.gif' }}" alt="">{% endif %}</dd>
|
||||
<dd><label for="avatar_delete"><input type="checkbox" name="avatar_delete" id="avatar_delete" /> {L_DELETE_AVATAR}</label></dd>
|
||||
</dl>
|
||||
<dl>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<!-- IF ERROR --><p class="error">{ERROR}</p><!-- ENDIF -->
|
||||
<dl>
|
||||
<dt><label>{L_CURRENT_IMAGE}{L_COLON}</label><br /><span>{L_AVATAR_EXPLAIN}</span></dt>
|
||||
<dd>{% if AVATAR_HTML %}{{ AVATAR_HTML }}{% else %}<img src="{{ ADMIN_ROOT_PATH ~ 'images/no_avatar.gif' }}" alt="">{% endif %}</dd>
|
||||
<dd class="c-avatar-box">{% if AVATAR_HTML %}{{ AVATAR_HTML }}{% else %}<img src="{{ ADMIN_ROOT_PATH ~ 'images/no_avatar.gif' }}" alt="">{% endif %}</dd>
|
||||
<dd><label for="avatar_delete"><input type="checkbox" name="avatar_delete" id="avatar_delete" /> {L_DELETE_AVATAR}</label></dd>
|
||||
</dl>
|
||||
</fieldset>
|
||||
|
|
|
@ -1708,6 +1708,7 @@ input.autowidth {
|
|||
|
||||
/* Form button styles
|
||||
---------------------------------------- */
|
||||
.button,
|
||||
a.button1,
|
||||
input.button1,
|
||||
a.button2,
|
||||
|
@ -1721,6 +1722,7 @@ input.button2 {
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.button,
|
||||
a.button1,
|
||||
input.button1 {
|
||||
font-weight: bold;
|
||||
|
@ -1734,6 +1736,10 @@ input.button2 {
|
|||
}
|
||||
|
||||
/* <a> button in the style of the form buttons */
|
||||
.button,
|
||||
.button:link,
|
||||
.button:visited,
|
||||
.button:active,
|
||||
a.button1,
|
||||
a.button1:link,
|
||||
a.button1:visited,
|
||||
|
@ -1748,6 +1754,7 @@ a.button2:active {
|
|||
}
|
||||
|
||||
/* Hover states */
|
||||
.button:hover,
|
||||
a.button1:hover,
|
||||
input.button1:hover,
|
||||
a.button2:hover,
|
||||
|
@ -1768,6 +1775,37 @@ input.button2:focus {
|
|||
outline-style: none;
|
||||
}
|
||||
|
||||
/* Avatar cropper */
|
||||
.avatar-cropper-buttons {
|
||||
text-align: center;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/** Button groups */
|
||||
.button-group {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.button-group + .button-group {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.button-group > .button:first-child {
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
.button-group > .button:last-child {
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
|
||||
.button-group > .button:not(:first-child):not(:last-child) {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.avatar-cropper-buttons > .button-group {
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
/* jQuery popups
|
||||
---------------------------------------- */
|
||||
.phpbb_alert {
|
||||
|
|
304
phpBB/assets/css/cropper.css
Normal file
304
phpBB/assets/css/cropper.css
Normal file
|
@ -0,0 +1,304 @@
|
|||
/*!
|
||||
* Cropper.js v1.5.11
|
||||
* https://fengyuanchen.github.io/cropperjs
|
||||
*
|
||||
* Copyright 2015-present Chen Fengyuan
|
||||
* Released under the MIT license
|
||||
*
|
||||
* Date: 2021-02-17T11:53:21.992Z
|
||||
*/
|
||||
|
||||
.cropper-container {
|
||||
direction: ltr;
|
||||
font-size: 0;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.cropper-container img {
|
||||
display: block;
|
||||
height: 100%;
|
||||
image-orientation: 0deg;
|
||||
max-height: none !important;
|
||||
max-width: none !important;
|
||||
min-height: 0 !important;
|
||||
min-width: 0 !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cropper-wrap-box,
|
||||
.cropper-canvas,
|
||||
.cropper-drag-box,
|
||||
.cropper-crop-box,
|
||||
.cropper-modal {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.cropper-wrap-box,
|
||||
.cropper-canvas {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.cropper-drag-box {
|
||||
background-color: #fff;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.cropper-modal {
|
||||
background-color: #000;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.cropper-view-box {
|
||||
display: block;
|
||||
height: 100%;
|
||||
outline: 1px solid #39f;
|
||||
outline-color: rgba(51, 153, 255, 0.75);
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cropper-dashed {
|
||||
border: 0 dashed #eee;
|
||||
display: block;
|
||||
opacity: 0.5;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.cropper-dashed.dashed-h {
|
||||
border-bottom-width: 1px;
|
||||
border-top-width: 1px;
|
||||
height: calc(100% / 3);
|
||||
left: 0;
|
||||
top: calc(100% / 3);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cropper-dashed.dashed-v {
|
||||
border-left-width: 1px;
|
||||
border-right-width: 1px;
|
||||
height: 100%;
|
||||
left: calc(100% / 3);
|
||||
top: 0;
|
||||
width: calc(100% / 3);
|
||||
}
|
||||
|
||||
.cropper-center {
|
||||
display: block;
|
||||
height: 0;
|
||||
left: 50%;
|
||||
opacity: 0.75;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.cropper-center::before,
|
||||
.cropper-center::after {
|
||||
background-color: #eee;
|
||||
content: ' ';
|
||||
display: block;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.cropper-center::before {
|
||||
height: 1px;
|
||||
left: -3px;
|
||||
top: 0;
|
||||
width: 7px;
|
||||
}
|
||||
|
||||
.cropper-center::after {
|
||||
height: 7px;
|
||||
left: 0;
|
||||
top: -3px;
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
.cropper-face,
|
||||
.cropper-line,
|
||||
.cropper-point {
|
||||
display: block;
|
||||
height: 100%;
|
||||
opacity: 0.1;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cropper-face {
|
||||
background-color: #fff;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.cropper-line {
|
||||
background-color: #39f;
|
||||
}
|
||||
|
||||
.cropper-line.line-e {
|
||||
cursor: ew-resize;
|
||||
right: -3px;
|
||||
top: 0;
|
||||
width: 5px;
|
||||
}
|
||||
|
||||
.cropper-line.line-n {
|
||||
cursor: ns-resize;
|
||||
height: 5px;
|
||||
left: 0;
|
||||
top: -3px;
|
||||
}
|
||||
|
||||
.cropper-line.line-w {
|
||||
cursor: ew-resize;
|
||||
left: -3px;
|
||||
top: 0;
|
||||
width: 5px;
|
||||
}
|
||||
|
||||
.cropper-line.line-s {
|
||||
bottom: -3px;
|
||||
cursor: ns-resize;
|
||||
height: 5px;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.cropper-point {
|
||||
background-color: #39f;
|
||||
height: 5px;
|
||||
opacity: 0.75;
|
||||
width: 5px;
|
||||
}
|
||||
|
||||
.cropper-point.point-e {
|
||||
cursor: ew-resize;
|
||||
margin-top: -3px;
|
||||
right: -3px;
|
||||
top: 50%;
|
||||
}
|
||||
|
||||
.cropper-point.point-n {
|
||||
cursor: ns-resize;
|
||||
left: 50%;
|
||||
margin-left: -3px;
|
||||
top: -3px;
|
||||
}
|
||||
|
||||
.cropper-point.point-w {
|
||||
cursor: ew-resize;
|
||||
left: -3px;
|
||||
margin-top: -3px;
|
||||
top: 50%;
|
||||
}
|
||||
|
||||
.cropper-point.point-s {
|
||||
bottom: -3px;
|
||||
cursor: s-resize;
|
||||
left: 50%;
|
||||
margin-left: -3px;
|
||||
}
|
||||
|
||||
.cropper-point.point-ne {
|
||||
cursor: nesw-resize;
|
||||
right: -3px;
|
||||
top: -3px;
|
||||
}
|
||||
|
||||
.cropper-point.point-nw {
|
||||
cursor: nwse-resize;
|
||||
left: -3px;
|
||||
top: -3px;
|
||||
}
|
||||
|
||||
.cropper-point.point-sw {
|
||||
bottom: -3px;
|
||||
cursor: nesw-resize;
|
||||
left: -3px;
|
||||
}
|
||||
|
||||
.cropper-point.point-se {
|
||||
bottom: -3px;
|
||||
cursor: nwse-resize;
|
||||
height: 20px;
|
||||
opacity: 1;
|
||||
right: -3px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.cropper-point.point-se {
|
||||
height: 15px;
|
||||
width: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.cropper-point.point-se {
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.cropper-point.point-se {
|
||||
height: 5px;
|
||||
opacity: 0.75;
|
||||
width: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.cropper-point.point-se::before {
|
||||
background-color: #39f;
|
||||
bottom: -50%;
|
||||
content: ' ';
|
||||
display: block;
|
||||
height: 200%;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
right: -50%;
|
||||
width: 200%;
|
||||
}
|
||||
|
||||
.cropper-invisible {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.cropper-bg {
|
||||
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC');
|
||||
}
|
||||
|
||||
.cropper-hide {
|
||||
display: block;
|
||||
height: 0;
|
||||
position: absolute;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.cropper-hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.cropper-move {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.cropper-crop {
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.cropper-disabled .cropper-drag-box,
|
||||
.cropper-disabled .cropper-face,
|
||||
.cropper-disabled .cropper-line,
|
||||
.cropper-disabled .cropper-point {
|
||||
cursor: not-allowed;
|
||||
}
|
9
phpBB/assets/css/cropper.min.css
vendored
Normal file
9
phpBB/assets/css/cropper.min.css
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
/*!
|
||||
* Cropper.js v1.5.11
|
||||
* https://fengyuanchen.github.io/cropperjs
|
||||
*
|
||||
* Copyright 2015-present Chen Fengyuan
|
||||
* Released under the MIT license
|
||||
*
|
||||
* Date: 2021-02-17T11:53:21.992Z
|
||||
*/.cropper-container{direction:ltr;font-size:0;line-height:0;position:relative;-ms-touch-action:none;touch-action:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.cropper-container img{display:block;height:100%;image-orientation:0deg;max-height:none!important;max-width:none!important;min-height:0!important;min-width:0!important;width:100%}.cropper-canvas,.cropper-crop-box,.cropper-drag-box,.cropper-modal,.cropper-wrap-box{bottom:0;left:0;position:absolute;right:0;top:0}.cropper-canvas,.cropper-wrap-box{overflow:hidden}.cropper-drag-box{background-color:#fff;opacity:0}.cropper-modal{background-color:#000;opacity:.5}.cropper-view-box{display:block;height:100%;outline:1px solid #39f;outline-color:rgba(51,153,255,.75);overflow:hidden;width:100%}.cropper-dashed{border:0 dashed #eee;display:block;opacity:.5;position:absolute}.cropper-dashed.dashed-h{border-bottom-width:1px;border-top-width:1px;height:33.33333%;left:0;top:33.33333%;width:100%}.cropper-dashed.dashed-v{border-left-width:1px;border-right-width:1px;height:100%;left:33.33333%;top:0;width:33.33333%}.cropper-center{display:block;height:0;left:50%;opacity:.75;position:absolute;top:50%;width:0}.cropper-center:after,.cropper-center:before{background-color:#eee;content:" ";display:block;position:absolute}.cropper-center:before{height:1px;left:-3px;top:0;width:7px}.cropper-center:after{height:7px;left:0;top:-3px;width:1px}.cropper-face,.cropper-line,.cropper-point{display:block;height:100%;opacity:.1;position:absolute;width:100%}.cropper-face{background-color:#fff;left:0;top:0}.cropper-line{background-color:#39f}.cropper-line.line-e{cursor:ew-resize;right:-3px;top:0;width:5px}.cropper-line.line-n{cursor:ns-resize;height:5px;left:0;top:-3px}.cropper-line.line-w{cursor:ew-resize;left:-3px;top:0;width:5px}.cropper-line.line-s{bottom:-3px;cursor:ns-resize;height:5px;left:0}.cropper-point{background-color:#39f;height:5px;opacity:.75;width:5px}.cropper-point.point-e{cursor:ew-resize;margin-top:-3px;right:-3px;top:50%}.cropper-point.point-n{cursor:ns-resize;left:50%;margin-left:-3px;top:-3px}.cropper-point.point-w{cursor:ew-resize;left:-3px;margin-top:-3px;top:50%}.cropper-point.point-s{bottom:-3px;cursor:s-resize;left:50%;margin-left:-3px}.cropper-point.point-ne{cursor:nesw-resize;right:-3px;top:-3px}.cropper-point.point-nw{cursor:nwse-resize;left:-3px;top:-3px}.cropper-point.point-sw{bottom:-3px;cursor:nesw-resize;left:-3px}.cropper-point.point-se{bottom:-3px;cursor:nwse-resize;height:20px;opacity:1;right:-3px;width:20px}@media (min-width:768px){.cropper-point.point-se{height:15px;width:15px}}@media (min-width:992px){.cropper-point.point-se{height:10px;width:10px}}@media (min-width:1200px){.cropper-point.point-se{height:5px;opacity:.75;width:5px}}.cropper-point.point-se:before{background-color:#39f;bottom:-50%;content:" ";display:block;height:200%;opacity:0;position:absolute;right:-50%;width:200%}.cropper-invisible{opacity:0}.cropper-bg{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC")}.cropper-hide{display:block;height:0;position:absolute;width:0}.cropper-hidden{display:none!important}.cropper-move{cursor:move}.cropper-crop{cursor:crosshair}.cropper-disabled .cropper-drag-box,.cropper-disabled .cropper-face,.cropper-disabled .cropper-line,.cropper-disabled .cropper-point{cursor:not-allowed}
|
3625
phpBB/assets/javascript/cropper.js
Normal file
3625
phpBB/assets/javascript/cropper.js
Normal file
File diff suppressed because it is too large
Load diff
10
phpBB/assets/javascript/cropper.min.js
vendored
Normal file
10
phpBB/assets/javascript/cropper.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7
phpBB/assets/javascript/hermite.js
Normal file
7
phpBB/assets/javascript/hermite.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
/**
|
||||
* hermite-resize - Canvas image resize/resample using Hermite filter with JavaScript.
|
||||
* @version v2.2.10
|
||||
* @link https://github.com/viliusle/miniPaint
|
||||
* @license MIT
|
||||
*/
|
||||
function Hermite_class(){var w,p,_=[];this.init=void(w=navigator.hardwareConcurrency||4),this.getCores=function(){return w},this.resample_auto=function(t,a,e,r,h){var i=this.getCores();window.Worker&&1<i?this.resample(t,a,e,r,h):(this.resample_single(t,a,e,!0),null!=h&&h())},this.resize_image=function(t,a,e,r,h){var i=document.getElementById(t),n=document.createElement("canvas");if(n.width=i.width,n.height=i.height,n.getContext("2d").drawImage(i,0,0),null==a&&null==e&&null!=r&&(a=i.width/100*r,e=i.height/100*r),null==e){var o=i.width/a;e=i.height/o}a=Math.round(a),e=Math.round(e);function l(){var t=n.toDataURL();i.width=a,i.height=e,i.src=t,n=t=null}null==h||1==h?this.resample(n,a,e,!0,l):(this.resample_single(n,a,e,!0),l())},this.resample=function(t,r,a,e,h){var i=t.width,n=t.height;r=Math.round(r);var o=n/(a=Math.round(a));if(0<_.length)for(var l=0;l<w;l++)null!=_[l]&&(_[l].terminate(),delete _[l]);_=new Array(w);var s=t.getContext("2d"),c=[],g=2*Math.ceil(n/w/2),d=-1;for(l=0;l<w;l++){var u=d+1;if(!(n<=u)){d=u+g-1,d=Math.min(d,n-1);var f;f=Math.min(g,n-u),c[l]={},c[l].source=s.getImageData(0,u,i,g),c[l].target=!0,c[l].start_y=Math.ceil(u/o),c[l].height=f}}!0===e?(t.width=r,t.height=a):s.clearRect(0,0,i,n);var M=0;for(l=0;l<w;l++)if(null!=c[l]){M++;var v=new Worker(p);(_[l]=v).onmessage=function(t){M--;var a=t.data.core;_[a].terminate(),delete _[a];var e=Math.ceil(c[a].height/o);c[a].target=s.createImageData(r,e),c[a].target.data.set(t.data.target),s.putImageData(c[a].target,0,c[a].start_y),M<=0&&null!=h&&h()};var m={width_source:i,height_source:c[l].height,width:r,height:Math.ceil(c[l].height/o),core:l,source:c[l].source.data.buffer};v.postMessage(m,[m.source])}},p=window.URL.createObjectURL(new Blob(["(",function(){onmessage=function(t){for(var a=t.data.core,e=t.data.width_source,r=t.data.height_source,h=t.data.width,i=t.data.height,n=e/h,o=r/i,l=Math.ceil(n/2),s=Math.ceil(o/2),c=new Uint8ClampedArray(t.data.source),g=(c.length,h*i*4),d=new ArrayBuffer(g),u=new Uint8ClampedArray(d,0,g),f=0;f<i;f++)for(var M=0;M<h;M++){var v=4*(M+f*h),m=0,w=0,p=0,_=0,y=0,b=0,C=0,I=f*o,D=Math.floor(M*n),R=Math.ceil((M+1)*n),U=Math.floor(f*o),A=Math.ceil((f+1)*o);R=Math.min(R,e),A=Math.min(A,r);for(var x=U;x<A;x++)for(var B=Math.abs(I-x)/s,L=M*n,j=B*B,k=D;k<R;k++){var q=Math.abs(L-k)/l,E=Math.sqrt(j+q*q);if(!(1<=E)){var W=4*(k+x*e);C+=(m=2*E*E*E-3*E*E+1)*c[3+W],p+=m,c[3+W]<255&&(m=m*c[3+W]/250),_+=m*c[W],y+=m*c[1+W],b+=m*c[2+W],w+=m}}u[v]=_/w,u[1+v]=y/w,u[2+v]=b/w,u[3+v]=C/p}postMessage({core:a,target:u},[u.buffer])}}.toString(),")()"],{type:"application/javascript"})),this.resample_single=function(t,a,e,r){for(var h=t.width,i=t.height,n=h/(a=Math.round(a)),o=i/(e=Math.round(e)),l=Math.ceil(n/2),s=Math.ceil(o/2),c=t.getContext("2d"),g=c.getImageData(0,0,h,i),d=c.createImageData(a,e),u=g.data,f=d.data,M=0;M<e;M++)for(var v=0;v<a;v++){var m=4*(v+M*a),w=0,p=0,_=0,y=0,b=0,C=0,I=0,D=M*o,R=Math.floor(v*n),U=Math.ceil((v+1)*n),A=Math.floor(M*o),x=Math.ceil((M+1)*o);U=Math.min(U,h),x=Math.min(x,i);for(var B=A;B<x;B++)for(var L=Math.abs(D-B)/s,j=v*n,k=L*L,q=R;q<U;q++){var E=Math.abs(j-q)/l,W=Math.sqrt(k+E*E);if(!(1<=W)){var z=4*(q+B*h);I+=(w=2*W*W*W-3*W*W+1)*u[3+z],_+=w,u[3+z]<255&&(w=w*u[3+z]/250),y+=w*u[z],b+=w*u[1+z],C+=w*u[2+z],p+=w}}f[m]=y/p,f[1+m]=b/p,f[2+m]=C/p,f[3+m]=I/_}!0===r?(t.width=a,t.height=e):c.clearRect(0,0,h,i),c.putImageData(d,0,0)}}
|
73
phpBB/assets/javascript/jquery-cropper.js
vendored
Normal file
73
phpBB/assets/javascript/jquery-cropper.js
vendored
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*!
|
||||
* jQuery Cropper v1.0.1
|
||||
* https://fengyuanchen.github.io/jquery-cropper
|
||||
*
|
||||
* Copyright 2018-present Chen Fengyuan
|
||||
* Released under the MIT license
|
||||
*
|
||||
* Date: 2019-10-19T08:48:33.062Z
|
||||
*/
|
||||
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('jquery'), require('cropperjs')) :
|
||||
typeof define === 'function' && define.amd ? define(['jquery', 'cropperjs'], factory) :
|
||||
(global = global || self, factory(global.jQuery, global.Cropper));
|
||||
}(this, function ($, Cropper) { 'use strict';
|
||||
|
||||
$ = $ && $.hasOwnProperty('default') ? $['default'] : $;
|
||||
Cropper = Cropper && Cropper.hasOwnProperty('default') ? Cropper['default'] : Cropper;
|
||||
|
||||
if ($ && $.fn && Cropper) {
|
||||
var AnotherCropper = $.fn.cropper;
|
||||
var NAMESPACE = 'cropper';
|
||||
|
||||
$.fn.cropper = function jQueryCropper(option) {
|
||||
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
||||
args[_key - 1] = arguments[_key];
|
||||
}
|
||||
|
||||
var result;
|
||||
this.each(function (i, element) {
|
||||
var $element = $(element);
|
||||
var isDestroy = option === 'destroy';
|
||||
var cropper = $element.data(NAMESPACE);
|
||||
|
||||
if (!cropper) {
|
||||
if (isDestroy) {
|
||||
return;
|
||||
}
|
||||
|
||||
var options = $.extend({}, $element.data(), $.isPlainObject(option) && option);
|
||||
cropper = new Cropper(element, options);
|
||||
$element.data(NAMESPACE, cropper);
|
||||
}
|
||||
|
||||
if (typeof option === 'string') {
|
||||
var fn = cropper[option];
|
||||
|
||||
if ($.isFunction(fn)) {
|
||||
result = fn.apply(cropper, args);
|
||||
|
||||
if (result === cropper) {
|
||||
result = undefined;
|
||||
}
|
||||
|
||||
if (isDestroy) {
|
||||
$element.removeData(NAMESPACE);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return result !== undefined ? result : this;
|
||||
};
|
||||
|
||||
$.fn.cropper.Constructor = Cropper;
|
||||
$.fn.cropper.setDefaults = Cropper.setDefaults;
|
||||
|
||||
$.fn.cropper.noConflict = function noConflict() {
|
||||
$.fn.cropper = AnotherCropper;
|
||||
return this;
|
||||
};
|
||||
}
|
||||
|
||||
}));
|
10
phpBB/assets/javascript/jquery-cropper.min.js
vendored
Normal file
10
phpBB/assets/javascript/jquery-cropper.min.js
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
/*!
|
||||
* jQuery Cropper v1.0.1
|
||||
* https://fengyuanchen.github.io/jquery-cropper
|
||||
*
|
||||
* Copyright 2018-present Chen Fengyuan
|
||||
* Released under the MIT license
|
||||
*
|
||||
* Date: 2019-10-19T08:48:33.062Z
|
||||
*/
|
||||
!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?r(require("jquery"),require("cropperjs")):"function"==typeof define&&define.amd?define(["jquery","cropperjs"],r):r((e=e||self).jQuery,e.Cropper)}(this,function(c,s){"use strict";if(c=c&&c.hasOwnProperty("default")?c.default:c,s=s&&s.hasOwnProperty("default")?s.default:s,c&&c.fn&&s){var e=c.fn.cropper,d="cropper";c.fn.cropper=function(p){for(var e=arguments.length,a=new Array(1<e?e-1:0),r=1;r<e;r++)a[r-1]=arguments[r];var u;return this.each(function(e,r){var t=c(r),n="destroy"===p,o=t.data(d);if(!o){if(n)return;var f=c.extend({},t.data(),c.isPlainObject(p)&&p);o=new s(r,f),t.data(d,o)}if("string"==typeof p){var i=o[p];c.isFunction(i)&&((u=i.apply(o,a))===o&&(u=void 0),n&&t.removeData(d))}}),void 0!==u?u:this},c.fn.cropper.Constructor=s,c.fn.cropper.setDefaults=s.setDefaults,c.fn.cropper.noConflict=function(){return c.fn.cropper=e,this}}});
|
281
phpBB/assets/javascript/phpbb-avatars.js
Normal file
281
phpBB/assets/javascript/phpbb-avatars.js
Normal file
|
@ -0,0 +1,281 @@
|
|||
/* global phpbb */
|
||||
(function($) { // Avoid conflicts with other libraries
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* phpBB Avatars namespace.
|
||||
*
|
||||
* Handles cropping for local file uploads.
|
||||
*/
|
||||
phpbb.avatars = {
|
||||
cropper: null,
|
||||
image: null,
|
||||
|
||||
/** @type {jQuery} */
|
||||
$form: null,
|
||||
|
||||
/** @type {jQuery} */
|
||||
$buttons: $('#avatar-cropper-buttons'),
|
||||
|
||||
/** @type {jQuery} */
|
||||
$box: $('.c-avatar-box'),
|
||||
|
||||
/** @type {jQuery} */
|
||||
$data: $('#avatar-cropper-data'),
|
||||
|
||||
/** @type {jQuery} */
|
||||
$input: $('#avatar_upload_file'),
|
||||
|
||||
/** @type {jQuery} */
|
||||
$driver: $('#avatar_driver'),
|
||||
|
||||
/** @type {string} */
|
||||
driverUpload: 'avatar_driver_upload',
|
||||
|
||||
/**
|
||||
* Initialise avatar cropping.
|
||||
*/
|
||||
init() {
|
||||
// If the cropper library is not available
|
||||
if (!$.isFunction($.fn.cropper)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Correctly position the cropper buttons
|
||||
this.$buttons.appendTo(this.$box);
|
||||
|
||||
// Ensure we have an img for the cropping
|
||||
if (this.$box.children('img').length === 0) {
|
||||
const $avatarImg = $('<img src="" alt="">');
|
||||
$avatarImg.setAttribute('width', phpbb.avatars.$data.data().maxWidth);
|
||||
$avatarImg.setAttribute('height', phpbb.avatars.$data.data().maxHeight);
|
||||
$avatarImg.addClass('avatar');
|
||||
this.image = $avatarImg;
|
||||
this.$box.prepend($avatarImg);
|
||||
} else {
|
||||
this.image = this.$box.children('img');
|
||||
}
|
||||
|
||||
this.bindInput();
|
||||
this.bindSelect();
|
||||
this.bindSubmit();
|
||||
},
|
||||
|
||||
/**
|
||||
* Destroy (undo) any initialisation.
|
||||
*/
|
||||
destroy() {
|
||||
this.$buttons.find('[data-cropper-action]').off('click.phpbb.avatars');
|
||||
this.image.off('crop.phpbb.avatars');
|
||||
this.$form.off('submit');
|
||||
|
||||
this.$data.val('');
|
||||
this.$buttons.hide();
|
||||
this.$box.removeClass('c-cropper-avatar-box');
|
||||
|
||||
if (this.cropper !== null) {
|
||||
this.cropper.destroy();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind a function to the avatar driver <select> element.
|
||||
*
|
||||
* If a different driver than the "upload" driver is selected, the cropper is destroyed.
|
||||
* Otherwise if the "upload" driver is (re-)selected, and it has a value, initialise it.
|
||||
*/
|
||||
bindSelect() {
|
||||
this.$driver.on('change', function() {
|
||||
if ($(this).val() === phpbb.avatars.driverUpload) {
|
||||
if (phpbb.avatars.$input.val() !== '') {
|
||||
phpbb.avatars.$input.trigger('change');
|
||||
}
|
||||
} else {
|
||||
phpbb.avatars.destroy();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind a function to the avatar file upload <input> element.
|
||||
*
|
||||
* If a file was chosen and it is a valid image file, the cropper is initialised.
|
||||
* Otherwise the cropper is destroyed.
|
||||
*/
|
||||
bindInput() {
|
||||
this.$input.on('change', function() {
|
||||
const fileReader = new FileReader();
|
||||
|
||||
if (this.files[0].type.match('image.*')) {
|
||||
fileReader.readAsDataURL(this.files[0]);
|
||||
|
||||
fileReader.addEventListener('load', function() {
|
||||
phpbb.avatars.image.cropper('destroy').attr('src', this.result).addClass('avatar');
|
||||
phpbb.avatars.$box.addClass('c-cropper-avatar-box');
|
||||
phpbb.avatars.initCropper();
|
||||
phpbb.avatars.initButtons();
|
||||
});
|
||||
} else {
|
||||
phpbb.avatars.destroy();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind submit button to be handled by ajax submit
|
||||
*/
|
||||
bindSubmit() {
|
||||
const $this = this;
|
||||
$this.$form = this.$input.closest('form');
|
||||
$this.$form.on('submit', () => {
|
||||
const data = phpbb.avatars.$data.data();
|
||||
|
||||
const avatarCanvas = phpbb.avatars.cropper.getCroppedCanvas({
|
||||
maxWidth: 4096, // High values for max quality cropping
|
||||
maxHeight: 4096, // High values for max quality cropping
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
const hermiteResize = new Hermite_class();
|
||||
hermiteResize.resample_single(avatarCanvas, data.maxWidth, data.maxHeight, true);
|
||||
|
||||
avatarCanvas.toBlob(blob => {
|
||||
const formData = new FormData($this.$form[0]);
|
||||
formData.set('avatar_upload_file', blob, $this.getUploadFileName());
|
||||
formData.set('submit', '1');
|
||||
|
||||
const canvasDataUrl = avatarCanvas.toDataURL('image/png');
|
||||
|
||||
$.ajax({
|
||||
url: $this.$form.attr('action'),
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success(response) {
|
||||
$this.uploadDone(response, canvasDataUrl);
|
||||
},
|
||||
error() {
|
||||
console.log('Upload error');
|
||||
},
|
||||
});
|
||||
}, 'image/png');
|
||||
|
||||
return false;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Get upload filename for the blob data
|
||||
*
|
||||
* As the blob data is always in png format, we'll replace the file
|
||||
* extension in the upload name with one that ends with .png
|
||||
*
|
||||
* @return {string} Upload file name
|
||||
*/
|
||||
getUploadFileName() {
|
||||
const originalName = this.$input[0].files[0].name;
|
||||
|
||||
return originalName.replace(/\.[^/\\.]+$/, '.png');
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle response from avatar submission
|
||||
* @param {Object} response AJAX response object
|
||||
* @param {string} canvasDataUrl Uploaded canvas element as data URL
|
||||
*/
|
||||
uploadDone(response, canvasDataUrl) {
|
||||
if (typeof response !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle errors while deleting file
|
||||
if (typeof response.error === 'undefined') {
|
||||
const alert = phpbb.alert(response.MESSAGE_TITLE, response.MESSAGE_TEXT);
|
||||
|
||||
setTimeout(() => {
|
||||
window.location = response.REFRESH_DATA.url.replace('&', '&');
|
||||
alert.hide();
|
||||
}, response.REFRESH_DATA.time * 1000);
|
||||
|
||||
phpbb.avatars.image.attr('src', canvasDataUrl);
|
||||
phpbb.avatars.destroy();
|
||||
} else {
|
||||
phpbb.alert(response.error.title, response.error.messages.join('<br>'));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind a function to all the cropper <button> elements.
|
||||
*
|
||||
* Only buttons with a data-cropper-action attribute are recognized.
|
||||
* The value for this data attribute should be a function available in the cropper.
|
||||
* It also takes two optional parameters, imploded by a comma.
|
||||
* For example: data-cropper-action="move,0,10" which results in $().cropper('move', 0, 10)
|
||||
*/
|
||||
initButtons() {
|
||||
this.$buttons.show().find('[data-cropper-action]').off('click.phpbb.avatars').on('click.phpbb.avatars', function() {
|
||||
const option = $(this).data('cropper-action').split(',');
|
||||
const action = option[0];
|
||||
|
||||
if (typeof phpbb.avatars.cropper[action] === 'function') {
|
||||
// Special case: flip, set it to the opposite value (-1 and 1).
|
||||
if (action === 'scaleX' || action === 'scaleY') {
|
||||
phpbb.avatars.image.cropper(action, -phpbb.avatars.cropper.getData(true)[action]);
|
||||
} else {
|
||||
phpbb.avatars.image.cropper(action, option[1], option[2]);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialise the cropper (CropperJS).
|
||||
*
|
||||
* @see https://github.com/fengyuanchen/cropperjs
|
||||
*
|
||||
* This creates a cropper instance with a 1 to 1 (square) aspect ratio,
|
||||
* automatically creates the maximum available and allowed cropping area,
|
||||
* and registers a callback function for the 'crop' event.
|
||||
*/
|
||||
initCropper() {
|
||||
this.cropper = this.image.cropper({
|
||||
aspectRatio: 1,
|
||||
autoCropArea: 1,
|
||||
}).data('cropper');
|
||||
|
||||
this.image.off('crop.phpbb.avatars').on('crop.phpbb.avatars', phpbb.avatars.onCrop);
|
||||
},
|
||||
|
||||
/**
|
||||
* The callback function for the 'crop' event.
|
||||
*
|
||||
* This function ensures that the crop area is within the configured dimensions.
|
||||
* Meaning the width and height can not exceed the limits set by an Administrator.
|
||||
*
|
||||
* It also JSON encodes the data array and places it into an <input> element,
|
||||
* which will be requested server side, and crop the image accordingly.
|
||||
* Image cropping is done server side, to ensure the best image quality
|
||||
* and image blobs (from .toBlob()) can only be send through AJAX requests.
|
||||
*
|
||||
* @param {object} event
|
||||
*/
|
||||
onCrop(event) {
|
||||
const data = phpbb.avatars.$data.data();
|
||||
let { width, height } = event.detail;
|
||||
|
||||
if (width < data.minWidth || height < data.minHeight) {
|
||||
width = Math.max(data.minWidth, Math.min(data.maxWidth, width));
|
||||
height = Math.max(data.minHeight, Math.min(data.maxHeight, height));
|
||||
phpbb.avatars.cropper.setData({
|
||||
width,
|
||||
height,
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
$(() => {
|
||||
phpbb.avatars.init();
|
||||
});
|
||||
})(jQuery); // Avoid conflicts with other libraries
|
|
@ -32,7 +32,7 @@ class ucp_profile
|
|||
function main($id, $mode)
|
||||
{
|
||||
global $config, $db, $user, $auth, $template, $phpbb_root_path, $phpEx;
|
||||
global $request, $phpbb_container, $phpbb_log, $phpbb_dispatcher;
|
||||
global $request, $phpbb_container, $phpbb_log, $phpbb_dispatcher, $language;
|
||||
|
||||
$user->add_lang('posting');
|
||||
|
||||
|
@ -669,7 +669,7 @@ class ucp_profile
|
|||
);
|
||||
|
||||
/**
|
||||
* Trigger events on successfull avatar change
|
||||
* Trigger events on successful avatar change
|
||||
*
|
||||
* @event core.ucp_profile_avatar_sql
|
||||
* @var array result Array with data to be stored in DB
|
||||
|
@ -683,9 +683,46 @@ class ucp_profile
|
|||
WHERE user_id = ' . (int) $user->data['user_id'];
|
||||
$db->sql_query($sql);
|
||||
|
||||
meta_refresh(3, $this->u_action);
|
||||
$message = $user->lang['PROFILE_UPDATED'] . '<br /><br />' . sprintf($user->lang['RETURN_UCP'], '<a href="' . $this->u_action . '">', '</a>');
|
||||
trigger_error($message);
|
||||
if ($request->is_ajax())
|
||||
{
|
||||
/** @var \phpbb\avatar\helper $avatar_helper */
|
||||
$avatar_helper = $phpbb_container->get('avatar.helper');
|
||||
|
||||
$avatar = $avatar_helper->get_user_avatar($user->data, 'USER_AVATAR', true);
|
||||
|
||||
$json_response = new \phpbb\json_response;
|
||||
$json_response->send(array(
|
||||
'success' => true,
|
||||
|
||||
'MESSAGE_TITLE' => $language->lang('INFORMATION'),
|
||||
'MESSAGE_TEXT' => $language->lang('PROFILE_UPDATED'),
|
||||
'AVATAR' => $avatar_helper->get_template_vars($avatar),
|
||||
'REFRESH_DATA' => [
|
||||
'time' => 3,
|
||||
'url' => $this->u_action,
|
||||
'text' => $language->lang('RETURN_TO_UCP'),
|
||||
]
|
||||
));
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_refresh(3, $this->u_action);
|
||||
$message = $language->lang('PROFILE_UPDATED') . '<br><br>' . $language->lang('RETURN_UCP', '<a href="' . $this->u_action . '">', '</a>');
|
||||
trigger_error($message);
|
||||
}
|
||||
}
|
||||
else if ($request->is_ajax())
|
||||
{
|
||||
$error = $phpbb_avatar_manager->localize_errors($user, $error);
|
||||
|
||||
$json_response = new \phpbb\json_response;
|
||||
$json_response->send([
|
||||
'success' => false,
|
||||
'error' => [
|
||||
'title' => $language->lang('INFORMATION'),
|
||||
'messages' => $error,
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,12 +46,12 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('auth_bbcode_pm', '
|
|||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('auth_img_pm', '1');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('auth_method', 'db');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('auth_smilies_pm', '1');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('avatar_filesize', '6144');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('avatar_filesize', '262144');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('avatar_gallery_path', 'images/avatars/gallery');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('avatar_max_height', '90');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('avatar_max_width', '90');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('avatar_min_height', '20');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('avatar_min_width', '20');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('avatar_max_height', '120');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('avatar_max_width', '120');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('avatar_min_height', '40');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('avatar_min_width', '40');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('avatar_salt', 'phpbb_avatar');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('board_contact', 'contact@yourdomain.tld');
|
||||
INSERT INTO phpbb_config (config_name, config_value) VALUES ('board_contact_name', '');
|
||||
|
|
|
@ -130,6 +130,7 @@ $lang = array_merge($lang, array(
|
|||
'CANNOT_REMOVE_FOLDER' => 'This folder cannot be removed.',
|
||||
'CHANGE_DEFAULT_GROUP' => 'Change default group',
|
||||
'CHANGE_PASSWORD' => 'Change password',
|
||||
'CLEAR' => 'Clear',
|
||||
'CLICK_GOTO_FOLDER' => '%1$sGo to your “%3$s” folder%2$s',
|
||||
'CLICK_RETURN_FOLDER' => '%1$sReturn to your “%3$s” folder%2$s',
|
||||
'CONFIRMATION' => 'Confirmation of registration',
|
||||
|
@ -222,6 +223,8 @@ $lang = array_merge($lang, array(
|
|||
'FIELD_INVALID_URL' => 'The field “%s” has an invalid url.',
|
||||
'FIELD_INVALID_VALUE' => 'The field “%s” has an invalid value.',
|
||||
|
||||
'FLIP_HORIZONTALLY' => 'Flip horizontally',
|
||||
'FLIP_VERTICALLY' => 'Flip vertically',
|
||||
'FOE_MESSAGE' => 'Message from foe',
|
||||
'FOES_EXPLAIN' => 'Foes are users which will be ignored by default. Posts by these users will not be fully visible. Private messages from foes are still permitted. Please note that you cannot ignore moderators or administrators.',
|
||||
'FOES_UPDATED' => 'Your foes list has been updated successfully.',
|
||||
|
@ -304,11 +307,13 @@ $lang = array_merge($lang, array(
|
|||
'MESSAGES_DELETED' => 'Messages successfully deleted',
|
||||
'MOVE_DELETED_MESSAGES_TO' => 'Move messages from removed folder to',
|
||||
'MOVE_DOWN' => 'Move down',
|
||||
'MOVE_LEFT' => 'Move left',
|
||||
'MOVE_MARKED_TO_FOLDER' => 'Move marked to %s',
|
||||
'MOVE_PM_ERROR' => array(
|
||||
1 => 'An error occurred while moving the messages to the new folder, only %2$d out of %1$s was moved.',
|
||||
2 => 'An error occurred while moving the messages to the new folder, only %2$d out of %1$s were moved.',
|
||||
),
|
||||
'MOVE_RIGHT' => 'Move right',
|
||||
'MOVE_TO_FOLDER' => 'Move to folder',
|
||||
'MOVE_UP' => 'Move up',
|
||||
|
||||
|
@ -468,6 +473,9 @@ $lang = array_merge($lang, array(
|
|||
'RESIGN_SELECTED' => 'Resign selected',
|
||||
'RETURN_FOLDER' => '%1$sReturn to previous folder%2$s',
|
||||
'RETURN_UCP' => '%sReturn to the User Control Panel%s',
|
||||
'RETURN_TO_UCP' => 'Return to the User Control Panel',
|
||||
'ROTATE_LEFT' => 'Rotate left',
|
||||
'ROTATE_RIGHT' => 'Rotate right',
|
||||
'RULE_ADDED' => 'Rule successfully added.',
|
||||
'RULE_ALREADY_DEFINED' => 'This rule was defined previously.',
|
||||
'RULE_DELETED' => 'Rule successfully removed.',
|
||||
|
@ -649,6 +657,9 @@ $lang = array_merge($lang, array(
|
|||
'TO_ME' => 'to me',
|
||||
),
|
||||
|
||||
'ZOOM_IN' => 'Zoom in',
|
||||
'ZOOM_OUT' => 'Zoom out',
|
||||
|
||||
'GROUPS_EXPLAIN' => 'Usergroups enable board admins to better administer users. By default you will be placed in a specific group, this is your default group. This group defines how you may appear to other users, for example your username colouration, avatar, rank, etc. Depending on whether the administrator allows it you may be allowed to change your default group. You may also be placed in or allowed to join other groups. Some groups may give you additional permissions to view content or increase your capabilities in other areas.',
|
||||
'GROUP_LEADER' => 'Leaderships',
|
||||
'GROUP_MEMBER' => 'Memberships',
|
||||
|
|
|
@ -23,7 +23,7 @@ use phpbb\storage\exception\exception as storage_exception;
|
|||
use phpbb\storage\storage;
|
||||
|
||||
/**
|
||||
* Handles avatars uploaded to the board
|
||||
* Handles avatars uploaded to the board.
|
||||
*/
|
||||
class upload extends \phpbb\avatar\driver\driver
|
||||
{
|
||||
|
@ -100,10 +100,14 @@ class upload extends \phpbb\avatar\driver\driver
|
|||
return false;
|
||||
}
|
||||
|
||||
$template->assign_vars(array(
|
||||
'AVATAR_UPLOAD_SIZE' => $this->config['avatar_filesize'],
|
||||
$use_board = defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH;
|
||||
$web_path = $use_board ? generate_board_url() . '/' : $this->path_helper->get_web_root_path();
|
||||
|
||||
$template->assign_vars([
|
||||
'AVATAR_ALLOWED_EXTENSIONS' => implode(',', preg_replace('/^/', '.', $this->allowed_extensions)),
|
||||
));
|
||||
'AVATAR_UPLOAD_SIZE' => $this->config['avatar_filesize'],
|
||||
'T_ASSETS_PATH' => $web_path . '/assets',
|
||||
]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -137,6 +141,7 @@ class upload extends \phpbb\avatar\driver\driver
|
|||
return false;
|
||||
}
|
||||
|
||||
/** @var \phpbb\files\filespec_storage $file */
|
||||
$file = $upload->handle_upload('files.types.form_storage', 'avatar_upload_file');
|
||||
|
||||
$prefix = $this->config['avatar_salt'] . '_';
|
||||
|
@ -226,7 +231,6 @@ class upload extends \phpbb\avatar\driver\driver
|
|||
*/
|
||||
public function delete($row)
|
||||
{
|
||||
|
||||
$error = array();
|
||||
$prefix = $this->config['avatar_salt'] . '_';
|
||||
$ext = substr(strrchr($row['avatar'], '.'), 1);
|
||||
|
|
40
phpBB/phpbb/db/migration/data/v400/increase_avatar_size.php
Normal file
40
phpBB/phpbb/db/migration/data/v400/increase_avatar_size.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\db\migration\data\v400;
|
||||
|
||||
use phpbb\db\migration\container_aware_migration;
|
||||
|
||||
class increase_avatar_size extends container_aware_migration
|
||||
{
|
||||
public static function depends_on()
|
||||
{
|
||||
return ['\phpbb\db\migration\data\v400\dev'];
|
||||
}
|
||||
|
||||
public function update_data()
|
||||
{
|
||||
return [
|
||||
['custom', [[$this, 'increase_size']]],
|
||||
];
|
||||
}
|
||||
|
||||
public function increase_size(): void
|
||||
{
|
||||
$this->config->set('avatar_filesize', max(262144, $this->config['avatar_filesize'])); // Increase to 256 KiB
|
||||
$this->config->set('avatar_max_height', max('120', $this->config['avatar_max_height'])); // Increase to max 120px height
|
||||
$this->config->set('avatar_max_width', max('120', $this->config['avatar_max_width'])); // Increase to max 120px width
|
||||
$this->config->set('avatar_min_height', max('40', $this->config['avatar_min_height'])); // Increase to min 40px height
|
||||
$this->config->set('avatar_min_width', max('40', $this->config['avatar_min_width'])); // Increase to max 40px width
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@
|
|||
<!-- IF ERROR --><p class="error">{ERROR}</p><!-- ENDIF -->
|
||||
<dl>
|
||||
<dt><label>{L_CURRENT_IMAGE}{L_COLON}</label><br /><span>{L_AVATAR_EXPLAIN}</span></dt>
|
||||
<dd><!-- IF AVATAR -->{AVATAR_HTML}<!-- ELSE --><img src="{{ NO_AVATAR_SOURCE }}" alt="" /><!-- ENDIF --></dd>
|
||||
<dd class="c-avatar-box"><!-- IF AVATAR -->{AVATAR_HTML}<!-- ELSE --><img src="{{ NO_AVATAR_SOURCE }}" alt="" /><!-- ENDIF --></dd>
|
||||
<dd><label for="avatar_delete"><input type="checkbox" name="avatar_delete" id="avatar_delete" /> {L_DELETE_AVATAR}</label></dd>
|
||||
</dl>
|
||||
</fieldset>
|
||||
|
|
|
@ -2,3 +2,68 @@
|
|||
<dt><label for="avatar_upload_file">{L_UPLOAD_AVATAR_FILE}{L_COLON}</label></dt>
|
||||
<dd><input type="hidden" name="MAX_FILE_SIZE" value="{AVATAR_UPLOAD_SIZE}" /><input type="file" name="avatar_upload_file" id="avatar_upload_file" class="inputbox autowidth" accept="{{ AVATAR_ALLOWED_EXTENSIONS }}" /></dd>
|
||||
</dl>
|
||||
|
||||
{% INCLUDECSS T_ASSETS_PATH ~ '/css/cropper.min.css' %}
|
||||
{% INCLUDEJS T_ASSETS_PATH ~ '/javascript/cropper.min.js' %}
|
||||
{% INCLUDEJS T_ASSETS_PATH ~ '/javascript/jquery-cropper.js' %}
|
||||
{% INCLUDEJS T_ASSETS_PATH ~ '/javascript/hermite.js' %}
|
||||
{% INCLUDEJS T_ASSETS_PATH ~ '/javascript/phpbb-avatars.js' %}
|
||||
|
||||
<input type="hidden" id="avatar-cropper-data" name="avatar_cropper_data" value=""
|
||||
data-min-width="{{ AVATAR_MIN_WIDTH }}" data-max-width="{{ AVATAR_MAX_WIDTH }}"
|
||||
data-min-height="{{ AVATAR_MIN_HEIGHT }}" data-max-height="{{ AVATAR_MAX_HEIGHT }}" />
|
||||
|
||||
{% apply spaceless %}
|
||||
<div class="avatar-cropper-buttons" id="avatar-cropper-buttons">
|
||||
<div class="button-group">
|
||||
<button class="button" type="button" title="{{ lang('ZOOM_IN') }}" data-cropper-action="zoom,0.1">
|
||||
{{ Icon('iconify', 'fa:search-plus', '', true) }}
|
||||
</button>
|
||||
<button class="button" type="button" title="{{ lang('ZOOM_OUT') }}" data-cropper-action="zoom,-0.1">
|
||||
{{ Icon('iconify', 'fa:search-minus', '', true) }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="button-group">
|
||||
<button class="button" type="button" title="{{ lang('MOVE_LEFT') }}" data-cropper-action="move,-10,0">
|
||||
{{ Icon('iconify', 'fa:arrow-left', '', true) }}
|
||||
</button>
|
||||
<button class="button" type="button" title="{{ lang('MOVE_RIGHT') }}" data-cropper-action="move,10,0">
|
||||
{{ Icon('iconify', 'fa:arrow-right', '', true) }}
|
||||
</button>
|
||||
<button class="button" type="button" title="{{ lang('MOVE_UP') }}" data-cropper-action="move,0,-10">
|
||||
{{ Icon('iconify', 'fa:arrow-up', '', true) }}
|
||||
</button>
|
||||
<button class="button" type="button" title="{{ lang('MOVE_DOWN') }}" data-cropper-action="move,0,10">
|
||||
{{ Icon('iconify', 'fa:arrow-down', '', true) }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="button-group">
|
||||
<button class="button" type="button" title="{{ lang('ROTATE_LEFT') }}" data-cropper-action="rotate,-90">
|
||||
{{ Icon('iconify', 'fa:rotate-left', '', true) }}
|
||||
</button>
|
||||
<button class="button" type="button" title="{{ lang('ROTATE_RIGHT') }}" data-cropper-action="rotate,90">
|
||||
{{ Icon('iconify', 'fa:rotate-right', '', true) }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="button-group">
|
||||
<button class="button" type="button" title="{{ lang('FLIP_HORIZONTALLY') }}" data-cropper-action="scaleX">
|
||||
{{ Icon('iconify', 'fa:arrows-h', '', true) }}
|
||||
</button>
|
||||
<button class="button" type="button" title="{{ lang('FLIP_VERTICALLY') }}" data-cropper-action="scaleY">
|
||||
{{ Icon('iconify', 'fa:arrows-v', '', true) }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="button-group">
|
||||
<button class="button" type="button" title="{{ lang('RESET') }}" data-cropper-action="reset">
|
||||
{{ Icon('iconify', 'fa:refresh', '', true) }}
|
||||
</button>
|
||||
<button class="button" type="button" title="{{ lang('CLEAR') }}" data-cropper-action="clear">
|
||||
{{ Icon('iconify', 'fa:times', '', true) }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endapply %}
|
||||
|
|
|
@ -42,6 +42,29 @@
|
|||
vertical-align: top;
|
||||
}
|
||||
|
||||
/** Button groups */
|
||||
.button-group {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.button-group + .button-group {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.button-group > .button:first-child {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.button-group > .button:last-child {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
.button-group > .button:not(:first-child):not(:last-child) {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* Posting page styles
|
||||
---------------------------------------- */
|
||||
.button-form,
|
||||
|
@ -173,3 +196,13 @@ button::-moz-focus-inner {
|
|||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* UCP: Avatar cropper */
|
||||
.avatar-cropper-buttons {
|
||||
text-align: center;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.avatar-cropper-buttons > .button-group {
|
||||
margin: 4px;
|
||||
}
|
||||
|
|
|
@ -357,6 +357,11 @@ ol.def-rules li {
|
|||
padding: 5px;
|
||||
}
|
||||
|
||||
.c-cropper-avatar-box {
|
||||
min-height: 240px;
|
||||
max-height: 400px;
|
||||
}
|
||||
|
||||
p.notification-title,
|
||||
p.notification-forum,
|
||||
p.notification-reason,
|
||||
|
|
|
@ -38,12 +38,12 @@ class phpbb_functional_avatar_acp_groups_test extends phpbb_functional_common_av
|
|||
),
|
||||
// Gravatar with incorrect size
|
||||
array(
|
||||
'The submitted avatar is 120 wide and 120 high. Avatars must be at least 20 wide and 20 high, but no larger than 90 wide and 90 high.',
|
||||
'The submitted avatar is 140 wide and 140 high. Avatars must be at least 40 wide and 40 high, but no larger than 120 wide and 120 high.',
|
||||
'avatar_driver_gravatar',
|
||||
array(
|
||||
'avatar_gravatar_email' => 'test@example.com',
|
||||
'avatar_gravatar_width' => 120,
|
||||
'avatar_gravatar_height' => 120,
|
||||
'avatar_gravatar_width' => 140,
|
||||
'avatar_gravatar_height' => 140,
|
||||
),
|
||||
),
|
||||
// Delete avatar image to reset group settings
|
||||
|
|
Loading…
Add table
Reference in a new issue