Implemented (draft) support for touch devices. Minor fixes. Reworked the proxy implementation in the base class. The Media Manager JS class now uses the base class.

This commit is contained in:
alekseybobkov 2015-03-24 20:47:49 -07:00
parent 1e5c34b702
commit ed2ca5308b
9 changed files with 252 additions and 185 deletions

View File

@ -69,7 +69,24 @@ if($.oc===undefined)
$.oc={}
$.oc.escapeHtmlString=function(string){var htmlEscapes={'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#x27;','/':'&#x2F;'},htmlEscaper=/[&<>"'\/]/g
return(''+string).replace(htmlEscaper,function(match){return htmlEscapes[match];})}
+function($){"use strict";var TriggerOn=function(element,options){var $el=this.$el=$(element);this.options=options||{};if(this.options.triggerType!==false&&this.options.triggerAction===false)this.options.triggerAction=this.options.triggerType
+function($){"use strict";if($.oc===undefined)
$.oc={}
if($.oc.foundation===undefined)
$.oc.foundation={}
var Base=function(){this.proxiedMethods=[]
this.proxyCounter=0}
Base.prototype.dispose=function()
{for(var index in this.proxiedMethods)
this.proxiedMethods[index]=null
this.proxiedMethods=null}
Base.prototype.proxy=function(method){if(method.ocProxyId!==undefined){if(this.proxiedMethods[method.ocProxyId]===undefined)
throw new Error('Proxied method is not found in the proxy method scope.')
return this.proxiedMethods[method.ocProxyId]}
this.proxyCounter++
method.ocProxyId=this.proxyCounter
this.proxiedMethods[method.ocProxyId]=method.bind(this)
return this.proxiedMethods[method.ocProxyId]}
$.oc.foundation.base=Base;}(window.jQuery);+function($){"use strict";var TriggerOn=function(element,options){var $el=this.$el=$(element);this.options=options||{};if(this.options.triggerType!==false&&this.options.triggerAction===false)this.options.triggerAction=this.options.triggerType
if(this.options.triggerCondition===false)
throw new Error('Trigger condition is not specified.')
if(this.options.trigger===false)

View File

@ -2,17 +2,11 @@
* Base class for OctoberCMS back-end classes.
*
* The class defines base functionality for dealing with memory management
* and cleaning up bound (proxied) methods, references to the DOM elements
* and timers.
* and cleaning up bound (proxied) methods.
*
* The class should be used as a parent class for JavaScript classes that
* handle DOM events and require binding and unbinding methods to the events.
* That is especially important for classes that should free the memory during
* a single page execution.
*
* The base class defines the dispose method that cleans up references to the DOM
* elements and proxied methods. If child classes implement their own dispose()
* method, they should call the base class dispose method (see the example below).
* The base class defines the dispose method that cleans up proxied methods.
* If child classes implement their own dispose() method, they should call
* the base class dispose method (see the example below).
*
* Use the simple parasitic combination inheritance pattern to create child classes:
*
@ -21,7 +15,7 @@
*
* var SubClass = function(params) {
* // Call the parent constructor
* Base.call()
* Base.call(this)
* }
*
* SubClass.prototype = Object.create(BaseProto)
@ -51,45 +45,34 @@
var Base = function() {
this.proxiedMethods = []
this.domReferences = []
this.timers = []
this.proxyCounter = 0
}
Base.prototype.dispose = function()
{
for (var proxyName in this.proxiedMethods)
this.proxiedMethods[proxyName] = null
for (var index in this.proxiedMethods)
this.proxiedMethods[index] = null
for (var domReference in this.domReferences)
this.domReferences[domReference] = null
for (var timer in this.timers) {
clearTimeout(this.timers[timer])
this.timers[timer] = null
}
this.proxiedMethods = null
}
/*
* Creates a proxied method reference or returns an existing proxied method.
*/
Base.prototype.proxyMethod = function(method, proxyName) {
if (this.proxiedMethods[proxyName] === undefined)
return this.proxiedMethods[proxyName] = method.bind(this)
Base.prototype.proxy = function(method) {
if (method.ocProxyId !== undefined) {
if (this.proxiedMethods[method.ocProxyId] === undefined)
throw new Error('Proxied method is not found in the proxy method scope.')
return this.proxiedMethods[proxyName]
}
Base.prototype.setTimeout = function(timerName, method, delay) {
this.clearTimeout(timerName)
this.timers[timerName] = setTimeout(method, delay)
}
Base.prototype.clearTimeout = function(timerName) {
if (this.timers[timerName] !== undefined) {
clearTimeout(this.timers[timerName])
this.timers[timerName] = null
return this.proxiedMethods[method.ocProxyId]
}
this.proxyCounter++
method.ocProxyId = this.proxyCounter
this.proxiedMethods[method.ocProxyId] = method.bind(this)
return this.proxiedMethods[method.ocProxyId]
}
$.oc.foundation.base = Base;

View File

@ -9,6 +9,7 @@
=require october.controls.js
=require october.utils.js
=require october.foundation.baseclass.js
=require october.triggerapi.js
=require october.dragscroll.js
=require october.dragvalue.js
@ -45,5 +46,4 @@
=require october.autocomplete.js
=require october.callout.js
=require october.sidenav-tree.js
*/

View File

@ -1,7 +1,7 @@
<?= Block::put('head') ?><?= Block::endPut() ?>
<?= Block::put('body') ?>
<?= Form::open(['class'=>'layout']) ?>
<?= Form::open(['class'=>'layout', 'onsubmit'=>'return false']) ?>
<?= $this->widget->manager->render() ?>
<?= Form::close() ?>
<?= Block::endPut() ?>

View File

@ -26,7 +26,8 @@ div[data-control="media-manager"] p.thumbnail-error-message {
color: #bdc3c7;
}
div[data-control="media-manager"] .media-list {
padding: 0 0 20px 20px;
padding: 0 0 0 20px;
margin: 0;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
@ -311,6 +312,7 @@ div[data-control="media-manager"] [data-control="item-list"] {
}
div[data-control="media-manager"] table.table {
table-layout: fixed;
margin-bottom: 0;
white-space: nowrap;
}
div[data-control="media-manager"] table.table div.no-wrap-text {
@ -340,7 +342,7 @@ div[data-control="media-manager"] table.table tr[data-item-type=folder] i.icon-f
}
div[data-control="media-manager"] div[data-control="selection-marker"] {
position: absolute;
z-index: 50;
z-index: 250;
border: 1px dashed #95a5a6;
}
div[data-control="media-manager"] .upload-progress {
@ -400,17 +402,17 @@ body:not(.no-select) div[data-control="media-manager"] .media-list.tiles li:hove
body:not(.no-select) div[data-control="media-manager"] .media-list.tiles li:hover h4 {
color: #2581b8;
}
body:not(.no-select) div[data-control="media-manager"] .media-list .list li:hover {
body:not(.no-select) div[data-control="media-manager"] .media-list .list li:hover:not(:active) {
background: #4da7e8 !important;
}
body:not(.no-select) div[data-control="media-manager"] .media-list .list li:hover i,
body:not(.no-select) div[data-control="media-manager"] .media-list .list li:hover p.size {
body:not(.no-select) div[data-control="media-manager"] .media-list .list li:hover:not(:active) i,
body:not(.no-select) div[data-control="media-manager"] .media-list .list li:hover:not(:active) p.size {
color: #ecf0f1;
}
body:not(.no-select) div[data-control="media-manager"] .media-list .list li:hover h4 {
body:not(.no-select) div[data-control="media-manager"] .media-list .list li:hover:not(:active) h4 {
color: white;
}
body:not(.no-select) div[data-control="media-manager"] .media-list .list li:hover .icon-container {
body:not(.no-select) div[data-control="media-manager"] .media-list .list li:hover:not(:active) .icon-container {
border-right-color: #4da7e8 !important;
}
@media (max-width: 1280px) {
@ -418,3 +420,32 @@ body:not(.no-select) div[data-control="media-manager"] .media-list .list li:hove
width: 230px;
}
}
@media (max-width: 1024px) {
div[data-control="media-manager"] .media-list.list li {
display: block;
width: auto;
}
}
@media (max-width: 768px) {
div[data-control="media-manager"] [data-control="preview-sidebar"],
div[data-control="media-manager"] [data-command="toggle-sidebar"] {
display: none!important;
}
div[data-control="media-manager"] .media-list.list {
padding: 0;
}
div[data-control="media-manager"] .media-list.list li {
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
margin: 0;
border-right: none;
border-left: none;
border-bottom: none;
}
}
@media (max-width: 480px) {
div[data-control="media-manager"] [data-control="left-sidebar"] {
display: none!important;
}
}

View File

@ -6,6 +6,9 @@
*/
+function ($) { "use strict";
var Base = $.oc.foundation.base,
BaseProto = Base.prototype
// MEDIA MANAGER CLASS DEFINITION
// ============================
@ -15,40 +18,7 @@
this.options = options
// Event handlers
this.navigateHandler = this.onNavigate.bind(this)
this.commandClickHandler = this.onCommandClick.bind(this)
this.itemClickHandler = this.onItemClick.bind(this)
this.listMouseDownHandler = this.onListMouseDown.bind(this)
this.listMouseUpHandler = this.onListMouseUp.bind(this)
this.listMouseMoveHandler = this.onListMouseMove.bind(this)
this.sortingChangedHandler = this.onSortingChanged.bind(this)
this.searchChangedHandler = this.onSearchChanged.bind(this)
this.folderPopupShownHandler = this.onFolderPopupShown.bind(this)
this.newFolderSubmitHandler = this.onNewFolderSubmit.bind(this)
this.folderPopupHiddenHandler = this.onFolderPopupHidden.bind(this)
this.movePopupShownHandler = this.onMovePopupShown.bind(this)
this.moveItemsSubmitHandler = this.onMoveItemsSubmit.bind(this)
this.movePopupHiddenHandler = this.onMovePopupHidden.bind(this)
// Instance-bound methods
this.updateSidebarPreviewBound = this.updateSidebarPreview.bind(this)
this.replacePlaceholderBound = this.replacePlaceholder.bind(this)
this.placeholdersUpdatedBound = this.placeholdersUpdated.bind(this)
this.afterNavigateBound = this.afterNavigate.bind(this)
this.releaseSidebarThumbnailAjaxBound = this.releaseSidebarThumbnailAjax.bind(this)
this.replaceSidebarPlaceholderBound = this.replaceSidebarPlaceholder.bind(this)
this.uploadFileAddedBound = this.uploadFileAdded.bind(this)
this.uploadUpdateTotalProgressBound = this.uploadUpdateTotalProgress.bind(this)
this.uploadQueueCompleteBound = this.uploadQueueComplete.bind(this)
this.uploadSendingBound = this.uploadSending.bind(this)
this.uploadErrorBound = this.uploadError.bind(this)
this.updateSearchResultsBound = this.updateSearchResults.bind(this)
this.releaseNavigationAjaxBound = this.releaseNavigationAjax.bind(this)
this.deleteConfirmationBound = this.deleteConfirmation.bind(this)
this.refreshBound = this.refresh.bind(this)
this.folderCreatedBound = this.folderCreated.bind(this)
this.itemsMovedBound = this.itemsMoved.bind(this)
Base.call(this)
// State properties
this.selectTimer = null
@ -61,6 +31,8 @@
this.dropzone = null
this.searchTrackInputTimer = null
this.navigationAjax = null
this.dblTouchTimer = null
this.dblTouchFlag = null
//
// Initialization
@ -69,32 +41,19 @@
this.init()
}
MediaManager.prototype = Object.create(BaseProto)
MediaManager.prototype.constructor = MediaManager
MediaManager.prototype.dispose = function() {
this.unregisterHandlers()
this.clearSelectTimer()
this.disableUploader()
this.clearSearchTrackInputTimer()
this.releaseNavigationAjax()
this.clearDblTouchTimer()
this.$el = null
this.$form = null
this.updateSidebarPreviewBound = null
this.replacePlaceholderBound = null
this.placeholdersUpdatedBound = null
this.afterNavigateBound = null
this.replaceSidebarPlaceholderBound = null
this.uploadFileAddedBound = null
this.releaseSidebarThumbnailAjaxBound = null
this.uploadUpdateTotalProgressBound = null
this.uploadQueueCompleteBound = null
this.uploadSendingBound = null
this.uploadErrorBound = null
this.updateSearchResultsBound = null
this.releaseNavigationAjaxBound = null
this.deleteConfirmationBound = null
this.refreshBound = null
this.folderCreatedBound = null
this.itemsMovedBound = null
this.sidebarPreviewElement = null
this.itemListElement = null
@ -102,6 +61,8 @@
this.selectionMarker = null
this.thumbnailQueue = []
this.navigationAjax = null
BaseProto.dispose.call(this)
}
// MEDIA MANAGER INTERNAL METHODS
@ -117,54 +78,54 @@
}
MediaManager.prototype.registerHandlers = function() {
this.$el.on('dblclick', this.navigateHandler)
this.$el.on('click.tree-path', 'ul.tree-path, [data-control="sidebar-labels"]', this.navigateHandler)
this.$el.on('click.command', '[data-command]', this.commandClickHandler)
this.$el.on('click.item', '[data-type="media-item"]', this.itemClickHandler)
this.$el.on('change', '[data-control="sorting"]', this.sortingChangedHandler)
this.$el.on('keyup', '[data-control="search"]', this.searchChangedHandler)
this.$el.on('mediarefresh', this.refreshBound)
this.$el.on('shown.oc.popup', '[data-command="create-folder"]', this.folderPopupShownHandler)
this.$el.on('hidden.oc.popup', '[data-command="create-folder"]', this.folderPopupHiddenHandler)
this.$el.on('shown.oc.popup', '[data-command="move"]', this.movePopupShownHandler)
this.$el.on('hidden.oc.popup', '[data-command="move"]', this.movePopupHiddenHandler)
this.$el.on('dblclick', this.proxy(this.onNavigate))
this.$el.on('click.tree-path', 'ul.tree-path, [data-control="sidebar-labels"]', this.proxy(this.onNavigate))
this.$el.on('click.command', '[data-command]', this.proxy(this.onCommandClick))
// Touch devices use double-tap for the navigation and single tap for selecting.
// Another option is checkboxes visible only on touch devices, but this approach
// will require more significant changes in the code for the touch device support.
if (!Modernizr.touch)
this.$el.on('click.item', '[data-type="media-item"]', this.proxy(this.onItemClick))
else
this.$el.on('touchend', '[data-type="media-item"]', this.proxy(this.onItemTouch))
this.$el.on('change', '[data-control="sorting"]', this.proxy(this.onSortingChanged))
this.$el.on('keyup', '[data-control="search"]', this.proxy(this.onSearchChanged))
this.$el.on('mediarefresh', this.proxy(this.refresh))
this.$el.on('shown.oc.popup', '[data-command="create-folder"]', this.proxy(this.onFolderPopupShown))
this.$el.on('hidden.oc.popup', '[data-command="create-folder"]', this.proxy(this.onFolderPopupHidden))
this.$el.on('shown.oc.popup', '[data-command="move"]', this.proxy(this.onMovePopupShown))
this.$el.on('hidden.oc.popup', '[data-command="move"]', this.proxy(this.onMovePopupHidden))
if (this.itemListElement)
this.itemListElement.addEventListener('mousedown', this.listMouseDownHandler)
this.itemListElement.addEventListener('mousedown', this.proxy(this.onListMouseDown))
}
MediaManager.prototype.unregisterHandlers = function() {
this.$el.off('dblclick', this.navigateHandler)
this.$el.off('click.tree-path', this.navigateHandler)
this.$el.off('click.command', this.commandClickHandler)
this.$el.off('click.item', this.itemClickHandler)
this.$el.off('change', '[data-control="sorting"]', this.sortingChangedHandler)
this.$el.off('keyup', '[data-control="search"]', this.searchChangedHandler)
this.$el.off('shown.oc.popup', '[data-command="create-folder"]', this.folderPopupShownHandler)
this.$el.off('hidden.oc.popup', '[data-command="create-folder"]', this.folderPopupHiddenHandler)
this.$el.off('shown.oc.popup', '[data-command="move"]', this.movePopupShownHandler)
this.$el.off('hidden.oc.popup', '[data-command="move"]', this.movePopupHiddenHandler)
this.$el.off('dblclick', this.proxy(this.onNavigate))
this.$el.off('click.tree-path', this.proxy(this.onNavigate))
this.$el.off('click.command', this.proxy(this.onCommandClick))
if (!Modernizr.touch)
this.$el.off('click.item', this.proxy(this.onItemClick))
else
this.$el.off('touchend', '[data-type="media-item"]', this.proxy(this.onItemTouch))
this.$el.off('change', '[data-control="sorting"]', this.proxy(this.onSortingChanged))
this.$el.off('keyup', '[data-control="search"]', this.proxy(this.onSearchChanged))
this.$el.off('shown.oc.popup', '[data-command="create-folder"]', this.proxy(this.onFolderPopupShown))
this.$el.off('hidden.oc.popup', '[data-command="create-folder"]', this.proxy(this.onFolderPopupHidden))
this.$el.off('shown.oc.popup', '[data-command="move"]', this.proxy(this.onMovePopupShown))
this.$el.off('hidden.oc.popup', '[data-command="move"]', this.proxy(this.onMovePopupHidden))
if (this.itemListElement) {
this.itemListElement.removeEventListener('mousedown', this.listMouseDownHandler)
this.itemListElement.removeEventListener('mousemove', this.listMouseMoveHandler)
this.itemListElement.removeEventListener('mousedown', this.proxy(this.onListMouseDown))
this.itemListElement.removeEventListener('mousemove', this.proxy(this.onListMouseMove))
}
document.removeEventListener('mouseup', this.listMouseUpHandler)
this.navigateHandler = null
this.commandClickHandler = null
this.itemClickHandler = null
this.listMouseDownHandler = null
this.listMouseUpHandler = null
this.listMouseMoveHandler = null
this.sortingChangedHandler = null
this.searchChangedHandler = null
this.folderPopupShownHandler = null
this.folderPopupHiddenHandler = null
this.newFolderSubmitHandler = null
this.movePopupShownHandler = null
this.moveItemsSubmitHandler = null
this.movePopupHiddenHandler = null
document.removeEventListener('mouseup', this.proxy(this.onListMouseUp))
}
MediaManager.prototype.changeView = function(view) {
@ -224,10 +185,22 @@
if (this.isPreviewSidebarVisible()) {
// Use the timeout to prevent too many AJAX requests
// when the selection changes too quickly (with the keyboard arrows)
this.selectTimer = setTimeout(this.updateSidebarPreviewBound, 100)
this.selectTimer = setTimeout(this.proxy(this.updateSidebarPreview), 100)
}
}
MediaManager.prototype.clearDblTouchTimer = function() {
if (this.dblTouchTimer === null)
return
clearTimeout(this.dblTouchTimer)
this.dblTouchTimer = null
}
MediaManager.prototype.clearDblTouchFlag = function() {
this.dblTouchFlag = false
}
//
// Navigation
//
@ -274,8 +247,8 @@
}).always(function() {
$.oc.stripeLoadIndicator.hide()
})
.done(this.afterNavigateBound)
.always(this.releaseNavigationAjaxBound)
.done(this.proxy(this.afterNavigate))
.always(this.proxy(this.releaseNavigationAjax))
}
MediaManager.prototype.releaseNavigationAjax = function() {
@ -419,8 +392,8 @@
this.sidebarThumbnailAjax = this.$form.request(this.options.alias+'::onGetSidebarThumbnail', {
data: data
})
.done(this.replaceSidebarPlaceholderBound)
.always(this.releaseSidebarThumbnailAjaxBound)
.done(this.proxy(this.replaceSidebarPlaceholder))
.always(this.proxy(this.releaseSidebarThumbnailAjax))
}
MediaManager.prototype.replaceSidebarPlaceholder = function(response) {
@ -474,7 +447,7 @@
this.activeThumbnailQueueLength++
this.handleThumbnailBatch(batch).always(this.placeholdersUpdatedBound)
this.handleThumbnailBatch(batch).always(this.proxy(this.placeholdersUpdated))
}
}
@ -493,7 +466,7 @@
data: data
})
promise.done(this.replacePlaceholderBound)
promise.done(this.proxy(this.replacePlaceholder))
return promise
}
@ -615,11 +588,11 @@
}
this.dropzone = new Dropzone(this.$el.get(0), uploaderOptions)
this.dropzone.on('addedfile', this.uploadFileAddedBound)
this.dropzone.on('totaluploadprogress', this.uploadUpdateTotalProgressBound)
this.dropzone.on('queuecomplete', this.uploadQueueCompleteBound)
this.dropzone.on('sending', this.uploadSendingBound)
this.dropzone.on('error', this.uploadErrorBound)
this.dropzone.on('addedfile', this.proxy(this.uploadFileAdded))
this.dropzone.on('totaluploadprogress', this.proxy(this.uploadUpdateTotalProgress))
this.dropzone.on('queuecomplete', this.proxy(this.uploadQueueComplete))
this.dropzone.on('sending', this.proxy(this.uploadSending))
this.dropzone.on('error', this.proxy(this.uploadError))
}
MediaManager.prototype.disableUploader = function() {
@ -737,7 +710,7 @@
this.clearSearchTrackInputTimer()
this.searchTrackInputTimer = window.setTimeout(this.updateSearchResultsBound, 300)
this.searchTrackInputTimer = window.setTimeout(this.proxy(this.updateSearchResults), 300)
}
//
@ -760,7 +733,7 @@
title: this.options.deleteConfirm,
confirmButtonClass: 'btn-default',
showCancelButton: true
}, this.deleteConfirmationBound)
}, this.proxy(this.deleteConfirmation))
}
MediaManager.prototype.deleteConfirmation = function(confirmed) {
@ -786,7 +759,7 @@
data: data
}).always(function() {
$.oc.stripeLoadIndicator.hide()
}).done(this.afterNavigateBound)
}).done(this.proxy(this.afterNavigate))
}
MediaManager.prototype.createFolder = function(ev) {
@ -797,7 +770,7 @@
MediaManager.prototype.onFolderPopupShown = function(ev, button, popup) {
$(popup).find('input[name=name]').focus()
$(popup).on('submit.media', 'form', this.newFolderSubmitHandler)
$(popup).on('submit.media', 'form', this.proxy(this.onNewFolderSubmit))
}
MediaManager.prototype.onFolderPopupHidden = function(ev, button, popup) {
@ -815,7 +788,7 @@
data: data
}).always(function() {
$.oc.stripeLoadIndicator.hide()
}).done(this.folderCreatedBound)
}).done(this.proxy(this.folderCreated))
ev.preventDefault()
return false
@ -824,7 +797,7 @@
MediaManager.prototype.folderCreated = function() {
this.$el.find('button[data-command="create-folder"]').popup('hide')
this.afterNavigateBound
this.afterNavigate()
}
MediaManager.prototype.moveItems = function(ev) {
@ -859,7 +832,7 @@
}
MediaManager.prototype.onMovePopupShown = function(ev, button, popup) {
$(popup).on('submit.media', 'form', this.moveItemsSubmitHandler)
$(popup).on('submit.media', 'form', this.proxy(this.onMoveItemsSubmit))
}
MediaManager.prototype.onMoveItemsSubmit = function(ev) {
@ -886,7 +859,7 @@
data: data
}).always(function() {
$.oc.stripeLoadIndicator.hide()
}).done(this.itemsMovedBound)
}).done(this.proxy(this.itemsMoved))
ev.preventDefault()
return false
@ -899,7 +872,7 @@
MediaManager.prototype.itemsMoved = function() {
this.$el.find('button[data-command="move"]').popup('hide')
this.afterNavigateBound
this.afterNavigate()
}
// EVENT HANDLERS
@ -967,9 +940,24 @@
this.selectItem(ev.currentTarget, ev.shiftKey)
}
MediaManager.prototype.onItemTouch = function(ev) {
this.onItemClick(ev)
if (this.dblTouchFlag) {
this.onNavigate(ev)
this.dblTouchFlag = null
}
else
this.dblTouchFlag = true
this.clearDblTouchTimer()
this.dblTouchTimer = setTimeout(this.proxy(this.clearDblTouchFlag), 300)
}
MediaManager.prototype.onListMouseDown = function(ev) {
this.itemListElement.addEventListener('mousemove', this.listMouseMoveHandler)
document.addEventListener('mouseup', this.listMouseUpHandler)
this.itemListElement.addEventListener('mousemove', this.proxy(this.onListMouseMove))
document.addEventListener('mouseup', this.proxy(this.onListMouseUp))
var pagePosition = this.getEventPagePosition(ev),
relativePosition = this.getRelativePosition(this.itemListElement, pagePosition.x, pagePosition.y)
@ -979,8 +967,8 @@
}
MediaManager.prototype.onListMouseUp = function(ev) {
this.itemListElement.removeEventListener('mousemove', this.listMouseMoveHandler)
document.removeEventListener('mouseup', this.listMouseUpHandler)
this.itemListElement.removeEventListener('mousemove', this.proxy(this.onListMouseMove))
document.removeEventListener('mouseup', this.proxy(this.onListMouseUp))
$(document.body).removeClass('no-select')
if (this.selectionStarted) {

View File

@ -85,7 +85,8 @@ div[data-control="media-manager"] {
}
.media-list {
padding: 0 0 20px 20px;
padding: 0 0 0 20px;
margin: 0;
.user-select(none);
li {
@ -366,6 +367,7 @@ div[data-control="media-manager"] {
table.table {
table-layout: fixed;
margin-bottom: 0;
white-space: nowrap;
div.no-wrap-text {
@ -401,7 +403,7 @@ div[data-control="media-manager"] {
div[data-control="selection-marker"] {
position: absolute;
z-index: 50;
z-index: 250;
border: 1px dashed #95a5a6;
}
@ -470,7 +472,7 @@ body:not(.no-select) {
}
.list {
li:hover {
li:hover:not(:active) {
.media-selected-list();
}
}
@ -487,4 +489,48 @@ body:not(.no-select) {
}
}
}
}
@media (max-width: 1024px) {
div[data-control="media-manager"] {
.media-list {
&.list {
li {
display: block;
width: auto;
}
}
}
}
}
@media (max-width: @screen-sm) {
div[data-control="media-manager"] {
[data-control="preview-sidebar"],
[data-command="toggle-sidebar"] {
display: none!important;
}
.media-list {
&.list {
padding: 0;
li {
.border-radius(0);
margin: 0;
border-right: none;
border-left: none;
border-bottom: none;
}
}
}
}
}
@media (max-width: 480px) {
div[data-control="media-manager"] {
[data-control="left-sidebar"] {
display: none!important;
}
}
}

View File

@ -13,7 +13,7 @@
<div class="layout-row whiteboard">
<div class="layout">
<div class="layout-row">
<div class="layout-cell width-200 panel border-right">
<div class="layout-cell width-200 panel border-right" data-control="left-sidebar">
<?= $this->makePartial('left-sidebar') ?>
</div>
<div class="layout-cell">

View File

@ -1,29 +1,31 @@
<div class="layout-row min-size">
<div class="layout control-toolbar standalone-paddings">
<div class="layout-cell">
<div class="btn-group offset-right">
<button type="button" class="btn btn-primary oc-icon-upload" data-control="upload"
><?= e(trans('cms::lang.media.upload')) ?></button>
<button type="button" class="btn btn-primary oc-icon-folder" data-command="create-folder"><?= e(trans('cms::lang.media.add_folder')) ?></button>
</div>
<div class="layout-cell toolbar-item">
<div data-control="toolbar">
<div class="btn-group offset-right">
<button type="button" class="btn btn-primary oc-icon-upload" data-control="upload"
><?= e(trans('cms::lang.media.upload')) ?></button>
<button type="button" class="btn btn-primary oc-icon-folder" data-command="create-folder"><?= e(trans('cms::lang.media.add_folder')) ?></button>
</div>
<button type="button" class="btn btn-default oc-icon-refresh empty offset-right" data-command="refresh"></button>
<button type="button" class="btn btn-default oc-icon-refresh empty offset-right" data-command="refresh"></button>
<div class="btn-group offset-right">
<button type="button" class="btn btn-default oc-icon-reply-all" data-command="move"
><?= e(trans('cms::lang.media.move')) ?></button>
<button type="button" class="btn btn-default oc-icon-trash" data-command="delete"
><?= e(trans('cms::lang.media.delete')) ?></button>
</div>
<div class="btn-group offset-right">
<button type="button" class="btn btn-default oc-icon-reply-all" data-command="move"
><?= e(trans('cms::lang.media.move')) ?></button>
<button type="button" class="btn btn-default oc-icon-trash" data-command="delete"
><?= e(trans('cms::lang.media.delete')) ?></button>
</div>
<div class="btn-group offset-right" id="<?= $this->getId('view-mode-buttons') ?>">
<?= $this->makePartial('view-mode-buttons') ?>
<div class="btn-group offset-right" id="<?= $this->getId('view-mode-buttons') ?>">
<?= $this->makePartial('view-mode-buttons') ?>
</div>
</div>
</div>
<div class="layout-cell width-fix">
<div class="relative toolbar-item loading-indicator-container size-input-text last">
<div class="layout-cell toolbar-item width-fix">
<div class="relative loading-indicator-container size-input-text">
<input placeholder="<?= e(trans('cms::lang.media.search')) ?>" type="text" name="search" value="<?= e($searchTerm) ?>"
class="form-control icon search"
class="form-control icon search growable"
data-control="search"
autocomplete="off"
data-load-indicator