Merge branch 'master' of github.com:torkelo/grafana-private into pro

This commit is contained in:
Torkel Ödegaard 2014-11-20 09:16:49 +01:00
commit 4b5eadf7b5
26 changed files with 207 additions and 80 deletions

View File

@ -1,5 +1,12 @@
# 1.9.0 (unreleased) # 1.9.0 (unreleased)
**Fixes**
- [Issue #1087](https://github.com/grafana/grafana/issues/1087). Panel: Fixed IE9 crash due to angular drag drop
- [Issue #1093](https://github.com/grafana/grafana/issues/1093). SingleStatPanel: Fixed position for drilldown link tooltip when dashboard requires scrolling
- [Issue #1095](https://github.com/grafana/grafana/issues/1095). DrilldownLink: template variables in params property was not interpolated
# 1.9.0-rc1 (2014-11-17)
**UI Improvements* **UI Improvements*
- [Issue #770](https://github.com/grafana/grafana/issues/770). UI: Panel dropdown menu replaced with a new panel menu - [Issue #770](https://github.com/grafana/grafana/issues/770). UI: Panel dropdown menu replaced with a new panel menu
@ -14,6 +21,7 @@
- [Issue #951](https://github.com/grafana/grafana/issues/951). SingleStat: New singlestat panel - [Issue #951](https://github.com/grafana/grafana/issues/951). SingleStat: New singlestat panel
**Misc** **Misc**
- [Issue #864](https://github.com/grafana/grafana/issues/846). Panel: Share panel feature, get a link to panel with the current time range
- [Issue #938](https://github.com/grafana/grafana/issues/938). Panel: Plugin panels now reside outside of app/panels directory - [Issue #938](https://github.com/grafana/grafana/issues/938). Panel: Plugin panels now reside outside of app/panels directory
- [Issue #952](https://github.com/grafana/grafana/issues/952). Help: Shortcut "?" to open help modal with list of all shortcuts - [Issue #952](https://github.com/grafana/grafana/issues/952). Help: Shortcut "?" to open help modal with list of all shortcuts
- [Issue #991](https://github.com/grafana/grafana/issues/991). ScriptedDashboard: datasource services are now available in scripted dashboards, you can query datasource for metric keys, generate dashboards, and even save them in a scripted dashboard (see scripted_gen_and_save.js for example) - [Issue #991](https://github.com/grafana/grafana/issues/991). ScriptedDashboard: datasource services are now available in scripted dashboards, you can query datasource for metric keys, generate dashboards, and even save them in a scripted dashboard (see scripted_gen_and_save.js for example)

View File

@ -1,4 +1,4 @@
{ {
"version": "1.8.1", "version": "1.9.0-rc1",
"url": "http://grafanarel.s3.amazonaws.com/grafana-1.8.1.tar.gz" "url": "http://grafanarel.s3.amazonaws.com/grafana-1.9.0-rc1.tar.gz"
} }

View File

@ -4,7 +4,7 @@
"company": "Coding Instinct AB" "company": "Coding Instinct AB"
}, },
"name": "grafana", "name": "grafana",
"version": "1.9.0", "version": "1.9.0-rc1",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "http://github.com/torkelo/grafana.git" "url": "http://github.com/torkelo/grafana.git"

View File

@ -61,7 +61,7 @@ function (angular, $, _, appLevelRequire, config) {
var apps_deps = [ var apps_deps = [
'ngRoute', 'ngRoute',
'$strap.directives', '$strap.directives',
'ngDragDrop', 'ang-drag-drop',
'grafana', 'grafana',
'pasvaz.bindonce' 'pasvaz.bindonce'
]; ];

View File

@ -12,12 +12,12 @@ function () {
this.extendedMenu = []; this.extendedMenu = [];
if (options.fullscreen) { if (options.fullscreen) {
this.addMenuItem('view', 'icon-eye-open', 'toggleFullscreen(false)'); this.addMenuItem('view', 'icon-eye-open', 'toggleFullscreen(false); dismiss();');
} }
this.addMenuItem('edit', 'icon-cog', 'editPanel()'); this.addMenuItem('edit', 'icon-cog', 'editPanel(); dismiss();');
this.addMenuItem('duplicate', 'icon-copy', 'duplicatePanel()'); this.addMenuItem('duplicate', 'icon-copy', 'duplicatePanel()');
this.addMenuItem('share', 'icon-share', 'sharePanel()'); this.addMenuItem('share', 'icon-share', 'sharePanel(); dismiss();');
this.addEditorTab('General', 'app/partials/panelgeneral.html'); this.addEditorTab('General', 'app/partials/panelgeneral.html');
@ -25,7 +25,7 @@ function () {
this.addEditorTab('Metrics', 'app/partials/metrics.html'); this.addEditorTab('Metrics', 'app/partials/metrics.html');
} }
this.addExtendedMenuItem('Panel JSON', '', 'editPanelJson()'); this.addExtendedMenuItem('Panel JSON', '', 'editPanelJson(); dismiss();');
} }
PanelMeta.prototype.addMenuItem = function(text, icon, click) { PanelMeta.prototype.addMenuItem = function(text, icon, click) {

View File

@ -107,7 +107,7 @@ function (angular, app, _) {
var _as = 12 - $scope.dashboard.rowSpan($scope.row); var _as = 12 - $scope.dashboard.rowSpan($scope.row);
$scope.panel = { $scope.panel = {
title: 'no title [click here]', title: 'no title (click here)',
error : false, error : false,
span : _as < defaultSpan && _as > 0 ? _as : defaultSpan, span : _as < defaultSpan && _as > 0 ? _as : defaultSpan,
editable: true, editable: true,

View File

@ -22,9 +22,6 @@ var dashboard, timspan;
// All url parameters are available via the ARGS object // All url parameters are available via the ARGS object
var ARGS; var ARGS;
// Set a default timespan if one isn't specified
timspan = '1d';
// Intialize a skeleton with nothing but a rows array and service object // Intialize a skeleton with nothing but a rows array and service object
dashboard = { dashboard = {
rows : [], rows : [],
@ -32,8 +29,12 @@ dashboard = {
// Set a title // Set a title
dashboard.title = 'Scripted dash'; dashboard.title = 'Scripted dash';
// set default time
// time can be overriden in the url using from/to parameteres, but this is
// handled automatically in grafana core during dashboard initialization
dashboard.time = { dashboard.time = {
from: "now-" + (ARGS.from || timspan), from: 'now-6h',
to: "now" to: "now"
}; };

View File

@ -25,7 +25,7 @@ return function(callback) {
var dashboard, timspan; var dashboard, timspan;
// Set a default timespan if one isn't specified // Set a default timespan if one isn't specified
timspan = '1d'; timspan = ARGS.from || 'now-1d';
// Intialize a skeleton with nothing but a rows array and service object // Intialize a skeleton with nothing but a rows array and service object
dashboard = { dashboard = {
@ -36,7 +36,7 @@ return function(callback) {
// Set a title // Set a title
dashboard.title = 'Scripted dash'; dashboard.title = 'Scripted dash';
dashboard.time = { dashboard.time = {
from: "now-" + (ARGS.from || timspan), from: timspan,
to: "now" to: "now"
}; };

View File

@ -23,7 +23,7 @@ var dashboard, timspan;
var ARGS; var ARGS;
// Set a default timespan if one isn't specified // Set a default timespan if one isn't specified
timspan = '1d'; timspan = ARGS.from || 'now-1d';
// Intialize a skeleton with nothing but a rows array and service object // Intialize a skeleton with nothing but a rows array and service object
dashboard = { dashboard = {
@ -33,7 +33,7 @@ dashboard = {
// Set a title // Set a title
dashboard.title = 'Scripted dash'; dashboard.title = 'Scripted dash';
dashboard.time = { dashboard.time = {
from: "now-" + (ARGS.from || timspan), from: timspan,
to: "now" to: "now"
}; };
dashboard.templating = { dashboard.templating = {

View File

@ -206,6 +206,7 @@ function (angular, _, $) {
if ($target.hasClass('icon-arrow-left')) { if ($target.hasClass('icon-arrow-left')) {
$scope.$apply(function() { $scope.$apply(function() {
_.move($scope.functions, $scope.$index, $scope.$index - 1); _.move($scope.functions, $scope.$index, $scope.$index - 1);
$scope.targetChanged();
}); });
return; return;
} }
@ -213,6 +214,7 @@ function (angular, _, $) {
if ($target.hasClass('icon-arrow-right')) { if ($target.hasClass('icon-arrow-right')) {
$scope.$apply(function() { $scope.$apply(function() {
_.move($scope.functions, $scope.$index, $scope.$index + 1); _.move($scope.functions, $scope.$index, $scope.$index + 1);
$scope.targetChanged();
}); });
return; return;
} }

View File

@ -72,7 +72,7 @@ function (angular, $, _) {
$link.toggleClass('has-panel-links', showIcon); $link.toggleClass('has-panel-links', showIcon);
}); });
function dismiss(time) { function dismiss(time, force) {
clearTimeout(timeout); clearTimeout(timeout);
timeout = null; timeout = null;
@ -82,9 +82,11 @@ function (angular, $, _) {
} }
// if hovering or draging pospone close // if hovering or draging pospone close
if ($menu.is(':hover') || $scope.dashboard.$$panelDragging) { if (force !== true) {
dismiss(2500); if ($menu.is(':hover') || $scope.dashboard.$$panelDragging) {
return; dismiss(2200);
return;
}
} }
if (menuScope) { if (menuScope) {
@ -97,7 +99,12 @@ function (angular, $, _) {
} }
} }
var showMenu = function() { var showMenu = function(e) {
// if menu item is clicked and menu was just removed from dom ignore this event
if (!$.contains(document, e.target)) {
return;
}
if ($menu) { if ($menu) {
dismiss(); dismiss();
return; return;
@ -124,6 +131,9 @@ function (angular, $, _) {
menuScope = $scope.$new(); menuScope = $scope.$new();
menuScope.extendedMenu = getExtendedMenu($scope); menuScope.extendedMenu = getExtendedMenu($scope);
menuScope.dismiss = function() {
dismiss(null, true);
};
$('.panel-menu').remove(); $('.panel-menu').remove();
elem.append($menu); elem.append($menu);
@ -134,7 +144,7 @@ function (angular, $, _) {
$(".panel-container").removeClass('panel-highlight'); $(".panel-container").removeClass('panel-highlight');
$panelContainer.toggleClass('panel-highlight'); $panelContainer.toggleClass('panel-highlight');
dismiss(2500); dismiss(2200);
}; };
if ($scope.panelMeta.titlePos && $scope.panel.title) { if ($scope.panelMeta.titlePos && $scope.panel.title) {

View File

@ -29,7 +29,7 @@ function (angular, kbn) {
info.href += '&to=' + range.to; info.href += '&to=' + range.to;
if (link.params) { if (link.params) {
info.href += "&" + link.params; info.href += "&" + templateSrv.replace(link.params);
} }
return info; return info;

View File

@ -72,10 +72,11 @@ function (angular, $, kbn, moment, _, GraphTooltip) {
height = parseInt(height.replace('px', ''), 10); height = parseInt(height.replace('px', ''), 10);
} }
height -= 5; // padding
height -= scope.panel.title ? 24 : 9; // subtract panel title bar height -= scope.panel.title ? 24 : 9; // subtract panel title bar
if (scope.panel.legend.show && !scope.panel.legend.rightSide) { if (scope.panel.legend.show && !scope.panel.legend.rightSide) {
height = height - 21; // subtract one line legend height = height - 26; // subtract one line legend
} }
elem.css('height', height + 'px'); elem.css('height', height + 'px');
@ -114,7 +115,12 @@ function (angular, $, kbn, moment, _, GraphTooltip) {
var series = data[i]; var series = data[i];
var axis = yaxis[series.yaxis - 1]; var axis = yaxis[series.yaxis - 1];
var formater = kbn.valueFormats[scope.panel.y_formats[series.yaxis - 1]]; var formater = kbn.valueFormats[scope.panel.y_formats[series.yaxis - 1]];
series.updateLegendValues(formater, axis.tickDecimals, axis.scaledDecimals + 2);
// legend and tooltip gets one more decimal precision
// than graph legend ticks
var tickDecimals = (axis.tickDecimals || -1) + 1;
series.updateLegendValues(formater, tickDecimals, axis.scaledDecimals + 2);
if(!scope.$$phase) { scope.$digest(); } if(!scope.$$phase) { scope.$digest(); }
} }
} }

View File

@ -38,18 +38,26 @@ function ($) {
}; };
this.getMultiSeriesPlotHoverInfo = function(seriesList, pos) { this.getMultiSeriesPlotHoverInfo = function(seriesList, pos) {
var value, i, series, hoverIndex; var value, i, series, hoverIndex, seriesTmp;
var results = []; var results = [];
var pointCount = seriesList[0].data.length; var pointCount;
for (i = 1; i < seriesList.length; i++) { for (i = 0; i < seriesList.length; i++) {
if (seriesList[i].data.length !== pointCount) { seriesTmp = seriesList[i];
if (!seriesTmp.data.length) { continue; }
if (!pointCount) {
series = seriesTmp;
pointCount = series.data.length;
continue;
}
if (seriesTmp.data.length !== pointCount) {
results.pointCountMismatch = true; results.pointCountMismatch = true;
return results; return results;
} }
} }
series = seriesList[0];
hoverIndex = this.findHoverIndexFromData(pos.x, series); hoverIndex = this.findHoverIndexFromData(pos.x, series);
var lasthoverIndex = 0; var lasthoverIndex = 0;
if(!scope.panel.steppedLine) { if(!scope.panel.steppedLine) {
@ -62,6 +70,7 @@ function ($) {
for (i = 0; i < seriesList.length; i++) { for (i = 0; i < seriesList.length; i++) {
series = seriesList[i]; series = seriesList[i];
if (!series.data.length) { continue; }
if (scope.panel.stack) { if (scope.panel.stack) {
if (scope.panel.tooltip.value_type === 'individual') { if (scope.panel.tooltip.value_type === 'individual') {

View File

@ -4,7 +4,9 @@
<div class="graph-canvas-wrapper"> <div class="graph-canvas-wrapper">
<div ng-if="datapointsWarning" class="datapoints-warning"> <div ng-if="datapointsWarning" class="datapoints-warning">
<span class="small" ng-show="!datapointsCount">No datapoints <tip>Can be caused by timezone mismatch between browser and graphite server</tip></span> <span class="small" ng-show="!datapointsCount">
No datapoints <tip>No datapoints returned from metric query</tip>
</span>
<span class="small" ng-show="datapointsOutside">Datapoints outside time range <tip>Can be caused by timezone mismatch between browser and graphite server</tip></span> <span class="small" ng-show="datapointsOutside">Datapoints outside time range <tip>Can be caused by timezone mismatch between browser and graphite server</tip></span>
</div> </div>

View File

@ -42,12 +42,12 @@
<h5>Coloring</h5> <h5>Coloring</h5>
<editor-opt-bool text="Background" model="panel.colorBackground" change="setColoring({background: true})"></editor-opt-bool> <editor-opt-bool text="Background" model="panel.colorBackground" change="setColoring({background: true})"></editor-opt-bool>
<editor-opt-bool text="Value" model="panel.colorValue" change="setColoring({value: true})"></editor-opt-bool> <editor-opt-bool text="Value" model="panel.colorValue" change="setColoring({value: true})"></editor-opt-bool>
<div class="editor-option"> <div class="editor-option" ng-show="panel.colorBackground || panel.colorValue">
<label class="small">Thresholds<tip>Comma seperated values</tip></label> <label class="small">Thresholds<tip>Comma seperated values</tip></label>
<input type="text" class="input-large" ng-model="panel.thresholds" ng-blur="render()" placeholder="0,50,80"></input> <input type="text" class="input-large" ng-model="panel.thresholds" ng-blur="render()" placeholder="0,50,80"></input>
</div> </div>
<div class="editor-option"> <div class="editor-option" ng-show="panel.colorBackground || panel.colorValue">
<label class="small">Color</label> <label class="small">Colors</label>
<spectrum-picker ng-model="panel.colors[0]" ng-change="render()" ></spectrum-picker> <spectrum-picker ng-model="panel.colors[0]" ng-change="render()" ></spectrum-picker>
<spectrum-picker ng-model="panel.colors[1]" ng-change="render()" ></spectrum-picker> <spectrum-picker ng-model="panel.colors[1]" ng-change="render()" ></spectrum-picker>
<spectrum-picker ng-model="panel.colors[2]" ng-change="render()" ></spectrum-picker> <spectrum-picker ng-model="panel.colors[2]" ng-change="render()" ></spectrum-picker>

View File

@ -125,7 +125,7 @@ function (angular, app, _, TimeSeries, kbn, PanelMeta) {
$scope.getDecimalsForValue = function(value) { $scope.getDecimalsForValue = function(value) {
var opts = {}; var opts = {};
if (value === 0) { if (value === 0 || value === 1) {
return { decimals: 0, scaledDecimals: 0 }; return { decimals: 0, scaledDecimals: 0 };
} }

View File

@ -29,6 +29,7 @@ function (angular, app, _, $) {
height = parseInt(height.replace('px', ''), 10); height = parseInt(height.replace('px', ''), 10);
} }
height -= 5; // padding
height -= panel.title ? 24 : 9; // subtract panel title bar height -= panel.title ? 24 : 9; // subtract panel title bar
elem.css('height', height + 'px'); elem.css('height', height + 'px');
@ -195,7 +196,7 @@ function (angular, app, _, $) {
drilldownTooltip.text('click to go to: ' + panel.links[0].title); drilldownTooltip.text('click to go to: ' + panel.links[0].title);
drilldownTooltip.place_tt(e.clientX+20, e.clientY-15); drilldownTooltip.place_tt(e.pageX+20, e.pageY-15);
}); });
} }
}; };

View File

@ -88,7 +88,7 @@ function (_) {
_.each(series.points, function (point) { _.each(series.points, function (point) {
var data = { var data = {
annotation: self.annotation, annotation: self.annotation,
time: point[timeCol] * 1000, time: point[timeCol],
title: point[titleCol], title: point[titleCol],
tags: point[tagsCol], tags: point[tagsCol],
text: point[textCol] text: point[textCol]

View File

@ -575,3 +575,12 @@ a:hover {
// MEDIA QUERIES // MEDIA QUERIES
// ----------------------------------------------------- // -----------------------------------------------------
.caret {
color: @textColor
}
.dropdown-submenu > a:after {
border-left-color: @textColor;
}

View File

@ -111,28 +111,6 @@
font-size: 12px; font-size: 12px;
} }
.panel-fullscreen {
z-index: 100;
display: block;
position: fixed;
left: 0px;
right: 0px;
top: 51px;
height: 100%;
padding: 0 10px;
background: @grafanaPanelBackground;
overflow-y: scroll;
height: 100%;
.panel-content {
padding-bottom: 130px;
}
.dropdown-menu {
margin-bottom: 70px;
}
}
.dashboard-fullscreen { .dashboard-fullscreen {
.main-view-container { .main-view-container {
overflow: hidden; overflow: hidden;
@ -462,8 +440,6 @@ select.grafana-target-segment-input {
line-height: 14px; line-height: 14px;
} }
.grafana-tooltip hr { .grafana-tooltip hr {
padding: 2px; padding: 2px;
color: #c8c8c8; color: #c8c8c8;

View File

@ -10,6 +10,11 @@
background: @grafanaPanelBackground; background: @grafanaPanelBackground;
margin: 5px; margin: 5px;
position: relative; position: relative;
&:hover {
.panel-actions {
display: block;
}
}
} }
.panel-content { .panel-content {
@ -27,6 +32,8 @@
font-weight: bold; font-weight: bold;
position: relative; position: relative;
cursor: context-menu; cursor: context-menu;
width: 100%;
display: block;
&.has-panel-links { &.has-panel-links {
.panel-title-text:after { .panel-title-text:after {
@ -72,6 +79,32 @@
bottom: 0; bottom: 0;
} }
.panel-fullscreen {
z-index: 100;
display: block;
position: fixed;
left: 0px;
right: 0px;
top: 51px;
height: 100%;
padding: 0 10px;
background: @grafanaPanelBackground;
overflow-y: scroll;
height: 100%;
.panel-content {
padding-bottom: 130px;
}
.dropdown-menu {
margin-bottom: 70px;
}
.panel-menu {
top: 0px;
}
}
.panel-menu { .panel-menu {
z-index: 1000; z-index: 1000;
position: absolute; position: absolute;
@ -124,3 +157,5 @@
border: 1px solid @grayDark; border: 1px solid @grayDark;
} }
} }

View File

@ -277,7 +277,7 @@
// Tooltips and popovers // Tooltips and popovers
// ------------------------- // -------------------------
@tooltipColor: #fff; @tooltipColor: #fff;
@tooltipBackground: @heroUnitBackground; @tooltipBackground: rgb(58, 57, 57);
@tooltipArrowWidth: 5px; @tooltipArrowWidth: 5px;
@tooltipArrowColor: @tooltipBackground; @tooltipArrowColor: @tooltipBackground;

View File

@ -59,6 +59,34 @@ define([
}); });
}); });
describeSharedTooltip("point count missmatch", function(ctx) {
ctx.setup(function() {
ctx.data = [
{ data: [[10, 15], [12, 20]], },
{ data: [[10, 2]] }
];
ctx.pos = { x: 11 };
});
it('should set pointCountMismatch to true', function() {
expect(ctx.results.pointCountMismatch).to.be(true);
});
});
describeSharedTooltip("one series is hidden", function(ctx) {
ctx.setup(function() {
ctx.data = [
{ data: [[10, 15], [12, 20]], },
{ data: [] }
];
ctx.pos = { x: 11 };
});
it('should set pointCountMismatch to false', function() {
expect(ctx.results.pointCountMismatch).to.be(undefined);
});
});
describeSharedTooltip("steppedLine false, stack true, individual false", function(ctx) { describeSharedTooltip("steppedLine false, stack true, individual false", function(ctx) {
ctx.setup(function() { ctx.setup(function() {
ctx.data = [ ctx.data = [

View File

@ -146,7 +146,7 @@ define([
{ {
columns: ['time', 'text', 'sequence_number', 'title', 'tags'], columns: ['time', 'text', 'sequence_number', 'title', 'tags'],
name: 'events1', name: 'events1',
points: [[1402596000, 'some text', 1, 'Hello', 'B'], [1402596001, 'asd', 2, 'Hello2', 'B']] points: [[1402596000000, 'some text', 1, 'Hello', 'B'], [1402596001000, 'asd', 2, 'Hello2', 'B']]
} }
], ],
annotation: { annotation: {
@ -176,7 +176,7 @@ define([
{ {
columns: ['time', 'text', 'sequence_number'], columns: ['time', 'text', 'sequence_number'],
name: 'events1', name: 'events1',
points: [[1402596000, 'some text', 1]] points: [[1402596000000, 'some text', 1]]
} }
], ],
annotation: { query: 'select' } annotation: { query: 'select' }

View File

@ -6,13 +6,14 @@
* To change this template use File | Settings | File Templates. * To change this template use File | Settings | File Templates.
*/ */
(function(){ (function(angular){
function isDnDsSupported(){ function isDnDsSupported(){
return 'draggable' in document.createElement("span"); return 'ondrag' in document.createElement("a");
} }
if(!isDnDsSupported()){ if(!isDnDsSupported()){
angular.module("ang-drag-drop", []);
return; return;
} }
@ -22,7 +23,7 @@ if (window.jQuery && (-1 == window.jQuery.event.props.indexOf("dataTransfer")))
var currentData; var currentData;
angular.module("ngDragDrop",[]) angular.module("ang-drag-drop",[])
.directive("uiDraggable", [ .directive("uiDraggable", [
'$parse', '$parse',
'$rootScope', '$rootScope',
@ -71,13 +72,13 @@ angular.module("ngDragDrop",[])
if (e.dataTransfer && e.dataTransfer.dropEffect !== "none") { if (e.dataTransfer && e.dataTransfer.dropEffect !== "none") {
if (attrs.onDropSuccess) { if (attrs.onDropSuccess) {
var fn = $parse(attrs.onDropSuccess); var fn = $parse(attrs.onDropSuccess);
scope.$apply(function () { scope.$evalAsync(function () {
fn(scope, {$event: e}); fn(scope, {$event: e});
}); });
} else { } else {
if (attrs.onDropFailure) { if (attrs.onDropFailure) {
var fn = $parse(attrs.onDropFailure); var fn = $parse(attrs.onDropFailure);
scope.$apply(function () { scope.$evalAsync(function () {
fn(scope, {$event: e}); fn(scope, {$event: e});
}); });
} }
@ -101,7 +102,7 @@ angular.module("ngDragDrop",[])
if (dragImage) { if (dragImage) {
var dragImageFn = $parse(attrs.dragImage); var dragImageFn = $parse(attrs.dragImage);
scope.$apply(function() { scope.$evalAsync(function() {
var dragImageParameters = dragImageFn(scope, {$event: e}); var dragImageParameters = dragImageFn(scope, {$event: e});
if (dragImageParameters) { if (dragImageParameters) {
if (angular.isString(dragImageParameters)) { if (angular.isString(dragImageParameters)) {
@ -116,10 +117,10 @@ angular.module("ngDragDrop",[])
}); });
} }
e.dataTransfer.setData("Text", sendData); e.dataTransfer.setData("dataToSend", sendData);
currentData = angular.fromJson(sendData); currentData = angular.fromJson(sendData);
e.dataTransfer.effectAllowed = "copyMove"; e.dataTransfer.effectAllowed = "copyMove";
$rootScope.$broadcast("ANGULAR_DRAG_START", sendChannel); $rootScope.$broadcast("ANGULAR_DRAG_START", sendChannel, currentData.data);
} }
else { else {
e.preventDefault(); e.preventDefault();
@ -138,6 +139,8 @@ angular.module("ngDragDrop",[])
var dragChannel = ""; var dragChannel = "";
var dragEnterClass = attr.dragEnterClass || "on-drag-enter"; var dragEnterClass = attr.dragEnterClass || "on-drag-enter";
var dragHoverClass = attr.dragHoverClass || "on-drag-hover"; var dragHoverClass = attr.dragHoverClass || "on-drag-hover";
var customDragEnterEvent = $parse(attr.onDragEnter);
var customDragLeaveEvent = $parse(attr.onDragLeave);
function onDragOver(e) { function onDragOver(e) {
if (e.preventDefault) { if (e.preventDefault) {
@ -148,20 +151,57 @@ angular.module("ngDragDrop",[])
e.stopPropagation(); e.stopPropagation();
} }
var fn = $parse(attr.uiOnDragOver);
scope.$evalAsync(function () {
fn(scope, {$event: e, $channel: dropChannel});
});
e.dataTransfer.dropEffect = e.shiftKey ? 'copy' : 'move'; e.dataTransfer.dropEffect = e.shiftKey ? 'copy' : 'move';
return false; return false;
} }
function onDragLeave(e) { function onDragLeave(e) {
dragging--; if (e.preventDefault) {
if (dragging == 0) { e.preventDefault();
element.removeClass(dragHoverClass); }
}
if (e.stopPropagation) {
e.stopPropagation();
}
dragging--;
if (dragging == 0) {
scope.$evalAsync(function () {
customDragEnterEvent(scope, {$event: e});
});
element.removeClass(dragHoverClass);
}
var fn = $parse(attr.uiOnDragLeave);
scope.$evalAsync(function () {
fn(scope, {$event: e, $channel: dropChannel});
});
} }
function onDragEnter(e) { function onDragEnter(e) {
if (e.preventDefault) {
e.preventDefault();
}
if (e.stopPropagation) {
e.stopPropagation();
}
dragging++; dragging++;
var fn = $parse(attr.uiOnDragEnter);
scope.$evalAsync(function () {
fn(scope, {$event: e, $channel: dropChannel});
});
$rootScope.$broadcast("ANGULAR_HOVER", dragChannel); $rootScope.$broadcast("ANGULAR_HOVER", dragChannel);
scope.$evalAsync(function () {
customDragLeaveEvent(scope, {$event: e});
});
element.addClass(dragHoverClass); element.addClass(dragHoverClass);
} }
@ -173,11 +213,11 @@ angular.module("ngDragDrop",[])
e.stopPropagation(); // Necessary. Allows us to drop. e.stopPropagation(); // Necessary. Allows us to drop.
} }
var sendData = e.dataTransfer.getData("Text"); var sendData = e.dataTransfer.getData("dataToSend");
sendData = angular.fromJson(sendData); sendData = angular.fromJson(sendData);
var fn = $parse(attr.uiOnDrop); var fn = $parse(attr.uiOnDrop);
scope.$apply(function () { scope.$evalAsync(function () {
fn(scope, {$data: sendData.data, $event: e, $channel: sendData.channel}); fn(scope, {$data: sendData.data, $event: e, $channel: sendData.channel});
}); });
element.removeClass(dragEnterClass); element.removeClass(dragEnterClass);
@ -338,4 +378,4 @@ angular.module("ngDragDrop",[])
} }
]); ]);
}()); }(angular));