mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Added sticky positioning to layout editor toolbox.
This commit is contained in:
@@ -113,7 +113,6 @@
|
||||
<Content Include="Scripts\LayoutEditor\Services\ScopeConfigurator.js" />
|
||||
<Content Include="Scripts\Lib.js" />
|
||||
<Content Include="Scripts\Lib.min.js" />
|
||||
<Content Include="Scripts\Lib\affix.js" />
|
||||
<Content Include="Scripts\Lib\angular-resource.js" />
|
||||
<Content Include="Scripts\Lib\angular-sanitize.js" />
|
||||
<Content Include="Scripts\Lib\angular.js" />
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -166,7 +166,29 @@
|
||||
}
|
||||
],
|
||||
templateUrl: environment.templateUrl("Toolbox"),
|
||||
replace: true
|
||||
replace: true,
|
||||
link: function (scope, element) {
|
||||
var toolbox = element.find(".layout-toolbox");
|
||||
$(window).on("resize scroll", function (e) {
|
||||
var canvas = element.parent().find(".layout-canvas");
|
||||
// If the canvas is taller than the toolbox, make the toolbox sticky-positioned within the editor
|
||||
// to help the user avoid excessive vertical scrolling.
|
||||
var canvasIsTaller = !!canvas && canvas.height() > toolbox.height();
|
||||
var windowPos = $(window).scrollTop();
|
||||
if (canvasIsTaller && windowPos > element.offset().top + element.height() - toolbox.height()) {
|
||||
toolbox.addClass("sticky-bottom");
|
||||
toolbox.removeClass("sticky-top");
|
||||
}
|
||||
else if (canvasIsTaller && windowPos > element.offset().top) {
|
||||
toolbox.addClass("sticky-top");
|
||||
toolbox.removeClass("sticky-bottom");
|
||||
}
|
||||
else {
|
||||
toolbox.removeClass("sticky-top");
|
||||
toolbox.removeClass("sticky-bottom");
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
]);
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,162 +0,0 @@
|
||||
/* ========================================================================
|
||||
* Bootstrap: affix.js v3.3.1
|
||||
* http://getbootstrap.com/javascript/#affix
|
||||
* ========================================================================
|
||||
* Copyright 2011-2014 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* ======================================================================== */
|
||||
|
||||
|
||||
+function ($) {
|
||||
'use strict';
|
||||
|
||||
// AFFIX CLASS DEFINITION
|
||||
// ======================
|
||||
|
||||
var Affix = function (element, options) {
|
||||
this.options = $.extend({}, Affix.DEFAULTS, options)
|
||||
|
||||
this.$target = $(this.options.target)
|
||||
.on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
|
||||
.on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this))
|
||||
|
||||
this.$element = $(element)
|
||||
this.affixed =
|
||||
this.unpin =
|
||||
this.pinnedOffset = null
|
||||
|
||||
this.checkPosition()
|
||||
}
|
||||
|
||||
Affix.VERSION = '3.3.1'
|
||||
|
||||
Affix.RESET = 'affix affix-top affix-bottom'
|
||||
|
||||
Affix.DEFAULTS = {
|
||||
offset: 0,
|
||||
target: window
|
||||
}
|
||||
|
||||
Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
|
||||
var scrollTop = this.$target.scrollTop()
|
||||
var position = this.$element.offset()
|
||||
var targetHeight = this.$target.height()
|
||||
|
||||
if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false
|
||||
|
||||
if (this.affixed == 'bottom') {
|
||||
if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
|
||||
return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
|
||||
}
|
||||
|
||||
var initializing = this.affixed == null
|
||||
var colliderTop = initializing ? scrollTop : position.top
|
||||
var colliderHeight = initializing ? targetHeight : height
|
||||
|
||||
if (offsetTop != null && colliderTop <= offsetTop) return 'top'
|
||||
if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
Affix.prototype.getPinnedOffset = function () {
|
||||
if (this.pinnedOffset) return this.pinnedOffset
|
||||
this.$element.removeClass(Affix.RESET).addClass('affix')
|
||||
var scrollTop = this.$target.scrollTop()
|
||||
var position = this.$element.offset()
|
||||
return (this.pinnedOffset = position.top - scrollTop)
|
||||
}
|
||||
|
||||
Affix.prototype.checkPositionWithEventLoop = function () {
|
||||
setTimeout($.proxy(this.checkPosition, this), 1)
|
||||
}
|
||||
|
||||
Affix.prototype.checkPosition = function () {
|
||||
if (!this.$element.is(':visible')) return
|
||||
|
||||
var height = this.$element.height()
|
||||
var offset = this.options.offset
|
||||
var offsetTop = offset.top
|
||||
var offsetBottom = offset.bottom
|
||||
var scrollHeight = $('body').height()
|
||||
|
||||
if (typeof offset != 'object') offsetBottom = offsetTop = offset
|
||||
if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element)
|
||||
if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
|
||||
|
||||
var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)
|
||||
|
||||
if (this.affixed != affix) {
|
||||
if (this.unpin != null) this.$element.css('top', '')
|
||||
|
||||
var affixType = 'affix' + (affix ? '-' + affix : '')
|
||||
var e = $.Event(affixType + '.bs.affix')
|
||||
|
||||
this.$element.trigger(e)
|
||||
|
||||
if (e.isDefaultPrevented()) return
|
||||
|
||||
this.affixed = affix
|
||||
this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
|
||||
|
||||
this.$element
|
||||
.removeClass(Affix.RESET)
|
||||
.addClass(affixType)
|
||||
.trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
|
||||
}
|
||||
|
||||
if (affix == 'bottom') {
|
||||
this.$element.offset({
|
||||
top: scrollHeight - height - offsetBottom
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// AFFIX PLUGIN DEFINITION
|
||||
// =======================
|
||||
|
||||
function Plugin(option) {
|
||||
return this.each(function () {
|
||||
var $this = $(this)
|
||||
var data = $this.data('bs.affix')
|
||||
var options = typeof option == 'object' && option
|
||||
|
||||
if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
|
||||
if (typeof option == 'string') data[option]()
|
||||
})
|
||||
}
|
||||
|
||||
var old = $.fn.affix
|
||||
|
||||
$.fn.affix = Plugin
|
||||
$.fn.affix.Constructor = Affix
|
||||
|
||||
|
||||
// AFFIX NO CONFLICT
|
||||
// =================
|
||||
|
||||
$.fn.affix.noConflict = function () {
|
||||
$.fn.affix = old
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
// AFFIX DATA-API
|
||||
// ==============
|
||||
|
||||
$(window).on('load', function () {
|
||||
$('[data-spy="affix"]').each(function () {
|
||||
var $spy = $(this)
|
||||
var data = $spy.data()
|
||||
|
||||
data.offset = data.offset || {}
|
||||
|
||||
if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
|
||||
if (data.offsetTop != null) data.offset.top = data.offsetTop
|
||||
|
||||
Plugin.call($spy, data)
|
||||
})
|
||||
})
|
||||
|
||||
}(jQuery);
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -4,7 +4,7 @@
|
||||
display: flex;
|
||||
margin-top: 1em;
|
||||
font-size: @font-size;
|
||||
align-items: flex-start;
|
||||
align-items: stretch;
|
||||
|
||||
> .layout-canvas-wrapper {
|
||||
flex-grow: 1;
|
||||
|
@@ -1,66 +1,81 @@
|
||||
@import "Variables.less";
|
||||
|
||||
.layout-editor {
|
||||
> .layout-toolbox {
|
||||
> .layout-toolbox-wrapper {
|
||||
position: relative;
|
||||
margin-left: @container-padding;
|
||||
border: 1px solid @gray-border;
|
||||
width: 220px;
|
||||
flex-shrink: 0;
|
||||
min-height: 400px;
|
||||
padding: @container-padding / 2;
|
||||
background-color: @gray-bg;
|
||||
|
||||
.layout-toolbox-group {
|
||||
margin-top: @container-padding;
|
||||
> .layout-toolbox {
|
||||
border: 1px solid @gray-border;
|
||||
width: 220px;
|
||||
min-height: 400px;
|
||||
padding: @container-padding / 2;
|
||||
background-color: @gray-bg;
|
||||
|
||||
.layout-toolbox-group-heading {
|
||||
display: block;
|
||||
margin-bottom: @container-padding / 3;
|
||||
text-decoration: none;
|
||||
&.sticky-top {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
&.sticky-bottom {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.layout-toolbox-group {
|
||||
margin-top: @container-padding;
|
||||
|
||||
.layout-toolbox-group-heading {
|
||||
display: block;
|
||||
margin-bottom: @container-padding / 3;
|
||||
text-decoration: none;
|
||||
|
||||
&:before {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
margin-right: @container-padding / 3;
|
||||
font: normal normal normal 14px/1 FontAwesome;
|
||||
text-align: center;
|
||||
content: "\f0d7";
|
||||
&:before {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
margin-right: @container-padding / 3;
|
||||
font: normal normal normal 14px/1 FontAwesome;
|
||||
text-align: center;
|
||||
content: "\f0d7";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.collapsed {
|
||||
.layout-toolbox-group-heading:before {
|
||||
content: "\f0da";
|
||||
&.collapsed {
|
||||
.layout-toolbox-group-heading:before {
|
||||
content: "\f0da";
|
||||
}
|
||||
|
||||
.layout-toolbox-items {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.layout-toolbox-items {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.layout-toolbox-section + .layout-toolbox-section {
|
||||
margin-top: @container-padding / 3;
|
||||
}
|
||||
|
||||
.layout-toolbox-item {
|
||||
border: 1px solid @gray-border;
|
||||
background-color: #fff;
|
||||
padding: (@container-padding - 3) @container-padding;
|
||||
cursor: default;
|
||||
|
||||
i {
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
font: normal normal normal 14px/1 FontAwesome;
|
||||
}
|
||||
|
||||
+ .layout-toolbox-item {
|
||||
.layout-toolbox-section + .layout-toolbox-section {
|
||||
margin-top: @container-padding / 3;
|
||||
}
|
||||
}
|
||||
|
||||
+ .layout-toolbox-group {
|
||||
margin-top: @container-padding / 2;
|
||||
.layout-toolbox-item {
|
||||
border: 1px solid @gray-border;
|
||||
background-color: #fff;
|
||||
padding: (@container-padding - 3) @container-padding;
|
||||
cursor: default;
|
||||
|
||||
i {
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
font: normal normal normal 14px/1 FontAwesome;
|
||||
}
|
||||
|
||||
+ .layout-toolbox-item {
|
||||
margin-top: @container-padding / 3;
|
||||
}
|
||||
}
|
||||
|
||||
+ .layout-toolbox-group {
|
||||
margin-top: @container-padding / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,23 +1,25 @@
|
||||
<div class="layout-toolbox">
|
||||
<label>
|
||||
<input type="checkbox" ng-checked="element.inlineEditingIsActive" ng-click="toggleInlineEditing()" />
|
||||
@T("Edit HTML content inline")
|
||||
</label>
|
||||
<ul class="layout-toolbox-groups" ng-hide="element.inlineEditingIsActive">
|
||||
<li class="layout-toolbox-group" ng-class="{collapsed: layoutIsCollapsed}">
|
||||
<a href="#" class="layout-toolbox-group-heading" ng-click="toggleLayoutIsCollapsed($event)">@T("Layout")</a>
|
||||
<ul class="layout-toolbox-items">
|
||||
<section class="layout-toolbox-section layout-toolbox-section-grid" ng-model="gridElements" ui-sortable="getSortableOptions('Grid')">
|
||||
<li class="layout-toolbox-item layout-toolbox-item-grid" title="{{item.toolboxDescription}}" ng-repeat="item in gridElements"><i>{{item.toolboxIcon}}</i> {{item.toolboxLabel}}</li>
|
||||
</section>
|
||||
<section class="layout-toolbox-section layout-toolbox-section-row" ng-model="rowElements" ui-sortable="getSortableOptions('Row')">
|
||||
<li class="layout-toolbox-item layout-toolbox-item-row" title="{{item.toolboxDescription}}" ng-repeat="item in rowElements"><i>{{item.toolboxIcon}}</i> {{item.toolboxLabel}}</li>
|
||||
</section>
|
||||
<section class="layout-toolbox-section layout-toolbox-section-column" ng-model="columnElements" ui-sortable="getSortableOptions('Column')">
|
||||
<li class="layout-toolbox-item layout-toolbox-item-column" title="{{item.toolboxDescription}}" ng-repeat="item in columnElements"><i>{{item.toolboxIcon}}</i> {{item.toolboxLabel}}</li>
|
||||
</section>
|
||||
</ul>
|
||||
</li>
|
||||
<orc-layout-toolbox-group category="category" ng-repeat="category in contentElementCategories" />
|
||||
</ul>
|
||||
<div class="layout-toolbox-wrapper">
|
||||
<div class="layout-toolbox">
|
||||
<label>
|
||||
<input type="checkbox" ng-checked="element.inlineEditingIsActive" ng-click="toggleInlineEditing()" />
|
||||
@T("Edit HTML content inline")
|
||||
</label>
|
||||
<ul class="layout-toolbox-groups" ng-hide="element.inlineEditingIsActive">
|
||||
<li class="layout-toolbox-group" ng-class="{collapsed: layoutIsCollapsed}">
|
||||
<a href="#" class="layout-toolbox-group-heading" ng-click="toggleLayoutIsCollapsed($event)">@T("Layout")</a>
|
||||
<ul class="layout-toolbox-items">
|
||||
<section class="layout-toolbox-section layout-toolbox-section-grid" ng-model="gridElements" ui-sortable="getSortableOptions('Grid')">
|
||||
<li class="layout-toolbox-item layout-toolbox-item-grid" title="{{item.toolboxDescription}}" ng-repeat="item in gridElements"><i>{{item.toolboxIcon}}</i> {{item.toolboxLabel}}</li>
|
||||
</section>
|
||||
<section class="layout-toolbox-section layout-toolbox-section-row" ng-model="rowElements" ui-sortable="getSortableOptions('Row')">
|
||||
<li class="layout-toolbox-item layout-toolbox-item-row" title="{{item.toolboxDescription}}" ng-repeat="item in rowElements"><i>{{item.toolboxIcon}}</i> {{item.toolboxLabel}}</li>
|
||||
</section>
|
||||
<section class="layout-toolbox-section layout-toolbox-section-column" ng-model="columnElements" ui-sortable="getSortableOptions('Column')">
|
||||
<li class="layout-toolbox-item layout-toolbox-item-column" title="{{item.toolboxDescription}}" ng-repeat="item in columnElements"><i>{{item.toolboxIcon}}</i> {{item.toolboxLabel}}</li>
|
||||
</section>
|
||||
</ul>
|
||||
</li>
|
||||
<orc-layout-toolbox-group category="category" ng-repeat="category in contentElementCategories" />
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
@@ -96,8 +96,7 @@ var srcJsLib = [
|
||||
"Scripts/Lib/angular.js",
|
||||
"Scripts/Lib/angular-sanitize.js",
|
||||
"Scripts/Lib/angular-resource.js",
|
||||
"Scripts/Lib/sortable.js",
|
||||
"Scripts/Lib/affix.js"
|
||||
"Scripts/Lib/sortable.js"
|
||||
];
|
||||
|
||||
var srcJsLayoutEditor = [
|
||||
|
Reference in New Issue
Block a user