From e68a54005c36b6a2282e4446fb04fda6cd9b953e Mon Sep 17 00:00:00 2001 From: zuber Date: Wed, 23 Sep 2009 16:09:53 +0200 Subject: [PATCH 1/1] =?utf8?q?Dzia=C5=82aj=C4=85cy=20widok=20SplitView.?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- project/static/css/master.css | 18 +- project/static/js/app.js | 70 ++++++ project/static/js/editor.ui.js | 374 +++++++++++++++---------------- project/static/js/views/split.js | 109 ++++----- 4 files changed, 329 insertions(+), 242 deletions(-) create mode 100644 project/static/js/app.js diff --git a/project/static/css/master.css b/project/static/css/master.css index de799891..256c09b3 100644 --- a/project/static/css/master.css +++ b/project/static/css/master.css @@ -35,7 +35,6 @@ body { top: 2.4em; left: 0px; right: 0px; bottom: 0px; overflow: auto; background-color: white; - padding: 0.2em 1em; } ul { @@ -107,8 +106,8 @@ label { /* ========== */ #panels { - position: absolute; - bottom: 0px; left: 0px; right: 0px; top: 0px; + height: 100%; + width: 100%; } .panel-wrap { @@ -341,4 +340,15 @@ text#commit-dialog-message { #split-dialog .container-box fieldset { margin: 0.5em; -} \ No newline at end of file +} + +/* ======= */ +/* = New = */ +/* ======= */ +.splitview-splitbar { + width: 5px; + border-left: 1px solid #999; + border-right: 1px solid #999; + height: 100%; + background-color: #CCC; +} diff --git a/project/static/js/app.js b/project/static/js/app.js new file mode 100644 index 00000000..702fb0cb --- /dev/null +++ b/project/static/js/app.js @@ -0,0 +1,70 @@ +/*global Class*/ +var editor; +var panel_hooks; + + +(function(){ + var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; + this.Class = function(){}; + Class.extend = function(prop) { + var _super = this.prototype; + initializing = true; + var prototype = new this(); + initializing = false; + for (var name in prop) { + prototype[name] = typeof prop[name] == "function" && + typeof _super[name] == "function" && fnTest.test(prop[name]) ? + (function(name, fn){ + return function() { + var tmp = this._super; + this._super = _super[name]; + var ret = fn.apply(this, arguments); + this._super = tmp; + return ret; + }; + })(name, prop[name]) : + prop[name]; + } + function Class() { + if ( !initializing && this.init ) + this.init.apply(this, arguments); + } + Class.prototype = prototype; + Class.constructor = Class; + Class.extend = arguments.callee; + return Class; + }; +})(); + +(function() { + var slice = Array.prototype.slice; + + function update(array, args) { + var arrayLength = array.length, length = args.length; + while (length--) array[arrayLength + length] = args[length]; + return array; + }; + + function merge(array, args) { + array = slice.call(array, 0); + return update(array, args); + }; + + Function.prototype.bind = function(context) { + if (arguments.length < 2 && typeof arguments[0] === 'undefined') { + return this; + } + var __method = this; + var args = slice.call(arguments, 1); + return function() { + var a = merge(args, arguments); + return __method.apply(context, a); + } + } + +})(); + + +$(function() { + var splitView = new SplitView('#panels'); +}); diff --git a/project/static/js/editor.ui.js b/project/static/js/editor.ui.js index 8932b4e6..de2d0bf8 100755 --- a/project/static/js/editor.ui.js +++ b/project/static/js/editor.ui.js @@ -2,193 +2,193 @@ * UI related Editor methods */ Editor.prototype.setupUI = function() { - // set up the UI visually and attach callbacks - var self = this; - - var resize_start = function(event, mydata) { - $(document).bind('mousemove', mydata, resize_changed). - bind('mouseup', mydata, resize_stop); - - $('.panel-overlay', mydata.root).css('display', 'block'); - return false; - } - var resize_changed = function(event) { - var old_width = parseInt(event.data.overlay.css('width')); - var delta = event.pageX + event.data.hotspot_x - old_width; - - if(old_width + delta < 12) delta = 12 - old_width; - if(old_width + delta > $(window).width()) - delta = $(window).width() - old_width; - - event.data.overlay.css({ - 'width': old_width + delta - }); - - if(event.data.overlay.next) { - var left = parseInt(event.data.overlay.next.css('left')); - event.data.overlay.next.css('left', left+delta); - } - - return false; - }; - - var resize_stop = function(event) { - $(document).unbind('mousemove', resize_changed).unbind('mouseup', resize_stop); - // $('.panel-content', event.data.root).css('display', 'block'); - var overlays = $('.panel-content-overlay', event.data.root); - $('.panel-content-overlay', event.data.root).each(function(i) { - if( $(this).data('panel').hasClass('last-panel') ) - $(this).data('panel').css({ - 'left': $(this).css('left'), - 'right': $(this).css('right') - }); - else - $(this).data('panel').css({ - 'left': $(this).css('left'), - 'width': $(this).css('width') - }); - }); - $('.panel-overlay', event.data.root).css('display', 'none'); - $(event.data.root).trigger('stopResize'); - }; - - /* - * Prepare panels (overlays & stuff) - */ - /* create an overlay */ - var panel_root = self.rootDiv; - var overlay_root = $("
"); - panel_root.append(overlay_root); - - var prev = null; - - $('*.panel-wrap', panel_root).each( function() - { - var panel = $(this); - var handle = $('.panel-slider', panel); - var overlay = $("
 
"); - overlay_root.append(overlay); - overlay.data('panel', panel); - overlay.data('next', null); - - if (prev) prev.next = overlay; - - if( panel.hasClass('last-panel') ) - { - overlay.css({ - 'left': panel.css('left'), - 'right': panel.css('right') - }); - } - else { - overlay.css({ - 'left': panel.css('left'), - 'width': panel.css('width') - }); - // $.log('Has handle: ' + panel.attr('id')); - overlay.append(handle.clone()); - /* attach the trigger */ - handle.mousedown(function(event) { - var touch_data = { - root: panel_root, - overlay: overlay, - hotspot_x: event.pageX - handle.position().left - }; - - $(this).trigger('hpanel:panel-resize-start', touch_data); - return false; - }); - $('.panel-content', panel).css('right', - (handle.outerWidth() || 10) + 'px'); - $('.panel-content-overlay', panel).css('right', - (handle.outerWidth() || 10) + 'px'); - }; - - prev = overlay; - }); - - panel_root.bind('hpanel:panel-resize-start', resize_start); - self.rootDiv.bind('stopResize', function() { - self.savePanelOptions(); - }); - - /* - * Connect panel actions - */ - $('#panels > *.panel-wrap').each(function() { - var panelWrap = $(this); - // $.log('wrap: ', panelWrap); - var panel = new Panel(panelWrap); - panelWrap.data('ctrl', panel); // attach controllers to wraps - panel.load($('.panel-toolbar select', panelWrap).val()); - - $('.panel-toolbar select', panelWrap).change(function() { - var url = $(this).val(); - panelWrap.data('ctrl').load(url); - self.savePanelOptions(); - }); - - $('.panel-toolbar button.refresh-button', panelWrap).click( - function() { - panel.refresh(); - } ); - - self.rootDiv.bind('stopResize', function() { - panel.callHook('toolbarResized'); - }); - }); - - $(document).bind('panel:contentChanged', function() { - self.onContentChanged.apply(self, arguments) - }); - - /* - * Connect various buttons - */ - - $('#toolbar-button-quick-save').click( function (event, data) { - self.saveToBranch(); - } ); - - $('#toolbar-button-save').click( function (event, data) { - $('#commit-dialog').jqmShow( {callback: $.fbind(self, self.saveToBranch)} ); - } ); - - $('#toolbar-button-update').click( function (event, data) { - if (self.updateUserBranch()) { - // commit/update can be called only after proper, save - // this means all panels are clean, and will get refreshed - // do this only, when there are any changes to local branch - self.refreshPanels(); - } - } ); - - /* COMMIT DIALOG */ - $('#commit-dialog'). - jqm({ - modal: true, - onShow: $.fbind(self, self.loadRelatedIssues) - }); - - $('#toolbar-button-commit').click( function (event, data) { - $('#commit-dialog').jqmShow( {callback: $.fbind(self, self.sendMergeRequest)} ); - } ); - - /* STATIC BINDS */ - $('#commit-dialog-cancel-button').click(function() { - $('#commit-dialog-error-empty-message').hide(); - $('#commit-dialog').jqmHide(); - }); - - - /* SPLIT DIALOG */ - $('#split-dialog').jqm({ - modal: true, - onShow: $.fbind(self, self.loadSplitDialog) - }). - jqmAddClose('button.dialog-close-button'); - -// $('#split-dialog'). +// // set up the UI visually and attach callbacks +// var self = this; +// +// var resize_start = function(event, mydata) { +// $(document).bind('mousemove', mydata, resize_changed). +// bind('mouseup', mydata, resize_stop); +// +// $('.panel-overlay', mydata.root).css('display', 'block'); +// return false; +// } +// var resize_changed = function(event) { +// var old_width = parseInt(event.data.overlay.css('width')); +// var delta = event.pageX + event.data.hotspot_x - old_width; +// +// if(old_width + delta < 12) delta = 12 - old_width; +// if(old_width + delta > $(window).width()) +// delta = $(window).width() - old_width; +// +// event.data.overlay.css({ +// 'width': old_width + delta +// }); +// +// if(event.data.overlay.next) { +// var left = parseInt(event.data.overlay.next.css('left')); +// event.data.overlay.next.css('left', left+delta); +// } +// +// return false; +// }; +// +// var resize_stop = function(event) { +// $(document).unbind('mousemove', resize_changed).unbind('mouseup', resize_stop); +// // $('.panel-content', event.data.root).css('display', 'block'); +// var overlays = $('.panel-content-overlay', event.data.root); +// $('.panel-content-overlay', event.data.root).each(function(i) { +// if( $(this).data('panel').hasClass('last-panel') ) +// $(this).data('panel').css({ +// 'left': $(this).css('left'), +// 'right': $(this).css('right') +// }); +// else +// $(this).data('panel').css({ +// 'left': $(this).css('left'), +// 'width': $(this).css('width') +// }); +// }); +// $('.panel-overlay', event.data.root).css('display', 'none'); +// $(event.data.root).trigger('stopResize'); +// }; +// +// /* +// * Prepare panels (overlays & stuff) +// */ +// /* create an overlay */ +// var panel_root = self.rootDiv; +// var overlay_root = $("
"); +// panel_root.append(overlay_root); +// +// var prev = null; +// +// $('*.panel-wrap', panel_root).each( function() +// { +// var panel = $(this); +// var handle = $('.panel-slider', panel); +// var overlay = $("
 
"); +// overlay_root.append(overlay); +// overlay.data('panel', panel); +// overlay.data('next', null); +// +// if (prev) prev.next = overlay; +// +// if( panel.hasClass('last-panel') ) +// { +// overlay.css({ +// 'left': panel.css('left'), +// 'right': panel.css('right') +// }); +// } +// else { +// overlay.css({ +// 'left': panel.css('left'), +// 'width': panel.css('width') +// }); +// // $.log('Has handle: ' + panel.attr('id')); +// overlay.append(handle.clone()); +// /* attach the trigger */ +// handle.mousedown(function(event) { +// var touch_data = { +// root: panel_root, +// overlay: overlay, +// hotspot_x: event.pageX - handle.position().left +// }; +// +// $(this).trigger('hpanel:panel-resize-start', touch_data); +// return false; +// }); +// $('.panel-content', panel).css('right', +// (handle.outerWidth() || 10) + 'px'); +// $('.panel-content-overlay', panel).css('right', +// (handle.outerWidth() || 10) + 'px'); +// }; +// +// prev = overlay; +// }); +// +// panel_root.bind('hpanel:panel-resize-start', resize_start); +// self.rootDiv.bind('stopResize', function() { +// self.savePanelOptions(); +// }); +// +// /* +// * Connect panel actions +// */ +// $('#panels > *.panel-wrap').each(function() { +// var panelWrap = $(this); +// // $.log('wrap: ', panelWrap); +// var panel = new Panel(panelWrap); +// panelWrap.data('ctrl', panel); // attach controllers to wraps +// panel.load($('.panel-toolbar select', panelWrap).val()); +// +// $('.panel-toolbar select', panelWrap).change(function() { +// var url = $(this).val(); +// panelWrap.data('ctrl').load(url); +// self.savePanelOptions(); +// }); +// +// $('.panel-toolbar button.refresh-button', panelWrap).click( +// function() { +// panel.refresh(); +// } ); +// +// self.rootDiv.bind('stopResize', function() { +// panel.callHook('toolbarResized'); +// }); +// }); +// +// $(document).bind('panel:contentChanged', function() { +// self.onContentChanged.apply(self, arguments) +// }); +// +// /* +// * Connect various buttons +// */ +// +// $('#toolbar-button-quick-save').click( function (event, data) { +// self.saveToBranch(); +// } ); +// +// $('#toolbar-button-save').click( function (event, data) { +// $('#commit-dialog').jqmShow( {callback: $.fbind(self, self.saveToBranch)} ); +// } ); +// +// $('#toolbar-button-update').click( function (event, data) { +// if (self.updateUserBranch()) { +// // commit/update can be called only after proper, save +// // this means all panels are clean, and will get refreshed +// // do this only, when there are any changes to local branch +// self.refreshPanels(); +// } +// } ); +// +// /* COMMIT DIALOG */ +// $('#commit-dialog'). +// jqm({ +// modal: true, +// onShow: $.fbind(self, self.loadRelatedIssues) +// }); +// +// $('#toolbar-button-commit').click( function (event, data) { +// $('#commit-dialog').jqmShow( {callback: $.fbind(self, self.sendMergeRequest)} ); +// } ); +// +// /* STATIC BINDS */ +// $('#commit-dialog-cancel-button').click(function() { +// $('#commit-dialog-error-empty-message').hide(); +// $('#commit-dialog').jqmHide(); +// }); +// +// +// /* SPLIT DIALOG */ +// $('#split-dialog').jqm({ +// modal: true, +// onShow: $.fbind(self, self.loadSplitDialog) +// }). +// jqmAddClose('button.dialog-close-button'); +// +// // $('#split-dialog'). } Editor.prototype.loadRelatedIssues = function(hash) diff --git a/project/static/js/views/split.js b/project/static/js/views/split.js index 84f48ead..d8c5e6bb 100644 --- a/project/static/js/views/split.js +++ b/project/static/js/views/split.js @@ -1,82 +1,89 @@ /*globals Class*/ +// Split view inspired by jQuery Splitter Plugin http://methvin.com/splitter/ var SplitView = Class.extend({ - leftPanelClass: 'splitview-left-panel', - rightPanelClass: 'splitview-right-panel', - splitterClass: 'splitview-splitter', - overlayClass: 'splitview-overlay', + splitbarClass: 'splitview-splitbar', + activeClass: 'splitview-active', element: null, + zombie: null, + leftViewOffset: 0, + + // Cache + _splitbarWidth: 0, init: function(element) { - this.element = $(element); - this.leftPanel = $(this.leftPanelClass, element); - this.rightPanel = $(this.rightPanelClass, element); - this.splitter = $(this.splitterClass, element); - this.overlay = this._createOverlay(this.overlayClass); + this.element = $(element).css('position', 'relative'); + this.views = $(">*", this.element[0]).css({ + position: 'absolute', // positioned inside splitter container + 'z-index': 1, // splitbar is positioned above + '-moz-outline-style': 'none', // don't show dotted outline + overflow: 'auto' + }); - this.splitter.bind('mousedown.splitview', this.beginResize.bind(this)); - }, - - _createOverlay: function(cssClass) { - var pos = this.root.position(); - return $('
') - .addClass(cssClass) + this.leftView = $(this.views[0]); + this.rightView = $(this.views[1]); + this.splitbar = $(this.views[2] || '
') + .insertAfter(this.leftView) .css({ position: 'absolute', - left: pos.left, - top: pos.top, - width: this.root.width(), - height: this.root.height() + 'user-select': 'none', + '-webkit-user-select': 'none', + '-khtml-user-select': 'none', + '-moz-user-select': 'none', + 'z-index': 100 }) - .hide() - .appendTo(this.element); + .attr('unselectable', 'on') + .addClass(this.splitbarClass) + .bind('mousedown.splitview', this.beginResize.bind(this)); + + this._splitbarWidth = this.splitbar.outerWidth(); + + // Solomon's algorithm ;-) + this.resplit(this.element.width() / 2); }, - + beginResize: function(event) { - this.hotspotX = event.pageX - this.splitter.position().left; + this.zombie = this.zombie || this.splitbar.clone(false).insertAfter(this.leftView); + this.views.css("-webkit-user-select", "none"); // Safari selects A/B text on a move + this.splitbar.addClass(this.activeClass); + this.leftViewOffset = this.leftView[0].offsetWidth - event.pageX; $(document) .bind('mousemove.splitview', this.resizeChanged.bind(this)) .bind('mouseup.splitview', this.endResize.bind(this)); - - this.overlay.show(); - return false; }, resizeChanged: function(event) { - var old_width = this.overlay.width(); - var delta = event.pageX + this.hotspotX - old_width; - - if(old_width + delta < 12) delta = 12 - old_width; - if(old_width + delta > $(window).width()) { - delta = $(window).width() - old_width; - } - - this.overlay.css({'width': old_width + delta}); - - if(this.overlay.next) { - var left = parseInt(this.overlay.next.css('left'), 10); - this.overlay.next.css('left', left+delta); - } - return false; + var newPosition = event.pageX + this.leftViewOffset; + newPosition = Math.max(0, Math.min(newPosition, this.element.width() - this._splitbarWidth)); + this.splitbar.css('left', newPosition); }, endResize: function(event) { + var newPosition = event.pageX + this.leftViewOffset; + this.zombie.remove(); + this.zombie = null; + this.resplit(newPosition); + $(document) .unbind('mousemove.splitview') .unbind('mouseup.splitview'); - - this.leftPanel.css({ + }, + + resplit: function(newPosition) { + newPosition = Math.max(0, Math.min(newPosition, this.element.width() - this._splitbarWidth)); + this.splitbar.css('left', newPosition); + this.leftView.css({ left: 0, - right: this.hotspotX + width: newPosition }); - - this.rightPanel.css({ - left: this.hotspotX, - right: 0 + this.rightView.css({ + left: newPosition + this._splitbarWidth, + width: this.element.width() - newPosition - this._splitbarWidth }); - - this.overlay.hide(); + if (!$.browser.msie) { + this.views.trigger("resize"); + } }, dispose: function() { -- 2.20.1