tech: remove bower and moved remaining bower dependencies to npm

pull/9339/head
Torkel Ödegaard 8 years ago
parent 6aad2a5b2d
commit c0c86c1138
  1. 3
      .bowerrc
  2. 20
      bower.json
  3. 3
      package.json
  4. 2
      public/app/core/directives/misc.js
  5. 7
      public/app/system.conf.js
  6. 5
      public/test/test-main.js
  7. 36
      public/vendor/angular-bindonce/.bower.json
  8. 43
      public/vendor/angular-bindonce/CHANGELOG.md
  9. 154
      public/vendor/angular-bindonce/README.md
  10. 325
      public/vendor/angular-bindonce/bindonce.js
  11. 1
      public/vendor/angular-bindonce/bindonce.min.js
  12. 28
      public/vendor/angular-bindonce/bower.json
  13. 28
      public/vendor/angular-bindonce/package.json
  14. 36
      public/vendor/angular-native-dragdrop/.bower.json
  15. 25
      public/vendor/angular-native-dragdrop/Gulpfile.js
  16. 10
      public/vendor/angular-native-dragdrop/LICENSE
  17. 36
      public/vendor/angular-native-dragdrop/README.md
  18. 27
      public/vendor/angular-native-dragdrop/bower.json
  19. 29
      public/vendor/angular-native-dragdrop/demo/css/styles.css
  20. 178
      public/vendor/angular-native-dragdrop/demo/index.html
  21. 54
      public/vendor/angular-native-dragdrop/demo/js/app.js
  22. 8
      public/vendor/angular-native-dragdrop/docs/examples.md
  23. 26
      public/vendor/angular-native-dragdrop/docs/getting-started.md
  24. 120
      public/vendor/angular-native-dragdrop/docs/index.md
  25. 459
      public/vendor/angular-native-dragdrop/draganddrop.js
  26. 1
      public/vendor/angular-native-dragdrop/draganddrop.min.js
  27. 2
      public/vendor/angular-native-dragdrop/index.js
  28. 14
      public/vendor/angular-native-dragdrop/mkdocs.yml
  29. 26
      public/vendor/angular-native-dragdrop/package.json
  30. 33
      public/vendor/clipboard/.bower.json
  31. 22
      public/vendor/clipboard/bower.json
  32. 28
      public/vendor/clipboard/contributing.md
  33. 755
      public/vendor/clipboard/dist/clipboard.js
  34. 7
      public/vendor/clipboard/dist/clipboard.min.js
  35. 12
      public/vendor/clipboard/package.js
  36. 48
      public/vendor/clipboard/package.json
  37. 173
      public/vendor/clipboard/readme.md
  38. 3
      tasks/options/copy.js
  39. 34
      yarn.lock

@ -1,3 +0,0 @@
{
"directory": "public/vendor/"
}

@ -1,20 +0,0 @@
{
"name": "grafana",
"version": "2.0.2",
"homepage": "https://github.com/grafana/grafana",
"authors": [],
"license": "Apache 2.0",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"public/vendor/",
"test",
"tests"
],
"dependencies": {
"angular-native-dragdrop": "1.2.2",
"angular-bindonce": "0.3.3",
"clipboard": "^1.5.16"
}
}

@ -65,9 +65,12 @@
"@types/enzyme": "^2.8.8",
"ace-builds": "^1.2.8",
"angular": "^1.6.6",
"angular-bindonce": "^0.3.1",
"angular-mocks": "^1.6.6",
"angular-native-dragdrop": "^1.2.2",
"angular-route": "^1.6.6",
"angular-sanitize": "^1.6.6",
"clipboard": "^1.7.1",
"eventemitter3": "^2.0.2",
"gaze": "^1.1.2",
"grunt-jscs": "3.0.1",

@ -25,7 +25,7 @@ function (angular, require, coreModule, kbn) {
getText: '&clipboardButton'
},
link: function(scope, elem) {
require(['vendor/clipboard/dist/clipboard'], function(Clipboard) {
require(['clipboard'], function(Clipboard) {
scope.clipboard = new Clipboard(elem[0], {
text: function() {
return scope.getText();

@ -20,8 +20,8 @@ System.config({
'angular-sanitize': 'vendor/npm/angular-sanitize/angular-sanitize.js',
"angular-ui": "vendor/angular-ui/ui-bootstrap-tpls.js",
"angular-strap": "vendor/angular-other/angular-strap.js",
"angular-dragdrop": "vendor/angular-native-dragdrop/draganddrop.js",
"angular-bindonce": "vendor/angular-bindonce/bindonce.js",
"angular-dragdrop": "vendor/npm/angular-native-dragdrop/draganddrop.js",
"angular-bindonce": "vendor/npm/angular-bindonce/bindonce.js",
"spectrum": "vendor/spectrum.js",
"bootstrap-tagsinput": "vendor/tagsinput/bootstrap-tagsinput.js",
"jquery.flot": "vendor/flot/jquery.flot",
@ -35,7 +35,8 @@ System.config({
"jquery.flot.gauge": "vendor/flot/jquery.flot.gauge",
"d3": "vendor/d3/d3.js",
"jquery.flot.dashes": "vendor/flot/jquery.flot.dashes",
"ace": "vendor/npm/ace-builds/src-noconflict/ace"
"ace": "vendor/npm/ace-builds/src-noconflict/ace",
"clipboard": "vendor/npm/clipboard/dist/clipboard.js"
},
packages: {

@ -29,8 +29,8 @@
'angular-sanitize': 'vendor/npm/angular-sanitize/angular-sanitize.js',
"angular-ui": "vendor/angular-ui/ui-bootstrap-tpls.js",
"angular-strap": "vendor/angular-other/angular-strap.js",
"angular-dragdrop": "vendor/angular-native-dragdrop/draganddrop.js",
"angular-bindonce": "vendor/angular-bindonce/bindonce.js",
"angular-dragdrop": "vendor/npm/angular-native-dragdrop/draganddrop.js",
"angular-bindonce": "vendor/npm/angular-bindonce/bindonce.js",
"spectrum": "vendor/spectrum.js",
"bootstrap-tagsinput": "vendor/tagsinput/bootstrap-tagsinput.js",
"jquery.flot": "vendor/flot/jquery.flot",
@ -45,6 +45,7 @@
"d3": "vendor/d3/d3.js",
"jquery.flot.dashes": "vendor/flot/jquery.flot.dashes",
"ace": "vendor/npm/ace-builds/src-noconflict/ace",
"clipboard": "vendor/npm/clipboard/dist/clipboard.js"
},
packages: {

@ -1,36 +0,0 @@
{
"name": "angular-bindonce",
"version": "0.3.3",
"main": "bindonce.js",
"description": "Zero watchers binding directives for AngularJS",
"homepage": "https://github.com/Pasvaz/bindonce",
"author": "Pasquale Vazzana <pasqualevazzana@gmail.com>",
"repository": {
"type": "git",
"url": "https://github.com/Pasvaz/bindonce.git"
},
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"components"
],
"dependencies": {},
"keywords": [
"angularjs",
"angular",
"directive",
"binding",
"watcher",
"bindonce"
],
"_release": "0.3.3",
"_resolution": {
"type": "version",
"tag": "0.3.3",
"commit": "0fcf71e6effc88179893c9c06baf6c6bf9037632"
},
"_source": "https://github.com/Pasvaz/bindonce.git",
"_target": "0.3.3",
"_originalSource": "angular-bindonce"
}

@ -1,43 +0,0 @@
# 0.3.3 (2014-02-12)
### Features
- **bo-disabled:**
- Add support for ng-disabled/bo-disabled #110
<hr />
# 0.3.2 (2014-11-23)
### Bug Fixes
- **Angular 1.3 compatibility**
<hr />
# 0.3.1 (2014-02-12)
### Features
- **bo-bind:**
- alias for bo-text
### Bug Fixes
- **Angular Promises**
- Ensures that promises are resolved before to run binders ([b3ef1b4](https://github.com/Pasvaz/bindonce/commit/b3ef1b46edfe83f10ed455d5520027f731563f32))
### Minor improvements
- Updated Readme
<hr />
# 0.3.0 (2014-01-21)
### Features
- **bo-switch:**
- Create new directive: bo-switch ([652d0db](https://github.com/Pasvaz/bindonce/commit/652d0db04325166a180377c738a376543b5f2357))
<hr />
# 0.2.3 (2014-01-20)
### Bug Fixes
- **bo-if:**
- Ensures that we both process newly added binders from bo-if, and that
we only process each binder once ([d11f863](https://github.com/Pasvaz/bindonce/commit/e091c273bbd17603d410fecc363874f0d1e6f38e))
### Features
- **Minification:**
- add min file ([47277ee](https://github.com/Pasvaz/bindonce/commit/47277eedd092b3210de362c725a7dadcddac8e87))
- **Changelog:**
- Created a changelog file

@ -1,154 +0,0 @@
Bindonce
========
High performance binding for AngularJs
## Usage
* download, clone or fork it or install it using [bower](http://twitter.github.com/bower/) `bower install angular-bindonce`
* Include the `bindonce.js` script provided by this component into your app.
* Add `'pasvaz.bindonce'` as a module dependency to your app: `angular.module('app', ['pasvaz.bindonce'])`
## Demo
Here is an example of how AngularJs can [freeze your UI](http://plnkr.co/edit/jwrHVb?p=preview), try to press and hold a key inside the input field, when the table is filled with only 1 person everything is ok, you can see how the DOM is updated by the input in real time, however if you try to load 1000 person *(or even 500 if the testing device is not powerfull)* and repeat the experiment you can see how the UI is frozen. In [this other demo](http://plnkr.co/edit/0DGOrk?p=preview) BindOnce will take care of your watchers and the UI will be reactive as it should be. The code is the same for both demos, the only difference is that I replaced any `ng-*` tag inside the table with the equivalent `bo-*` tag.
* [AngularJs regular Demo](http://plnkr.co/edit/jwrHVb?p=preview)
* [Demo with Bindonce](http://plnkr.co/edit/0DGOrk?p=preview)
## Overview
AngularJs provides a great data binding system but if you abuse of it the page can run into some performance issues, it's known that more of 2000 watchers can lag the UI and that amount can be reached easily if you don't pay attention to the data-binding. Sometime you really need to bind your data using watchers, especially for SPA because the data are updated in real time, but often you can avoid it with some efforts, most of the data presented in your page, once rendered, are immutable so you shouldn't keep watching them for changes.
For instance, take a look to this snippet:
```html
<ul>
<li ng-repeat="person in Persons">
<a ng-href="#/people/{{person.id}}"><img ng-src="{{person.imageUrl}}"></a>
<a ng-href="#/people/{{person.id}}"><span ng-bind="person.name"></span></a>
<p ng-class="{'cycled':person.generated}" ng-bind-html-unsafe="person.description"></p>
</li>
</ul>
```
Angular internally creates a `$watch` for each `ng-*` directive in order to keep the data up to date, so in this example just for displaying few info it creates 6 + 1 *(ngRepeatWatch)* watchers per `person`, even if the `person` is supposed to remain the same once shown. Iterate this amount for each person and you can have an idea about how easy is to reach 2000 watchers. Now if you need it because those data could change while you show the page or are bound to some models, it's ok. But most of the time they are static data that don't change once rendered. This is where **bindonce** can really help you.
The above example done with **bindonce**:
```html
<ul>
<li bindonce ng-repeat="person in Persons">
<a bo-href="'#/people/' + person.id"><img bo-src="person.imageUrl"></a>
<a bo-href="'#/people/' + person.id" bo-text="person.name"></a>
<p bo-class="{'cycled':person.generated}" bo-html="person.description"></p>
</li>
</ul>
```
Now this example uses **0 watches** per `person` and renders exactly the same result as the above that uses ng-*. *(Angular still uses 1 watcher for ngRepeatWatch)*
### The smart approach
OK until here nothing completely new, with a bit of efforts you could create your own directive and render the `person` inside the `link` function, or you could use [watch fighters](https://github.com/abourget/abourget-angular) that has a similar approach, but there is still one problem that you have to face and **bindonce** already handles it: *the existence of the data when the directive renders the content*. Usually the directives, unless you use watchers or bind their attributes to the scope (still a watcher), render the content when they are loaded into the markup, but if at that given time your data is not available, the directive can't render it. Bindonce can wait until the data is ready before to rendering the content.
Let's take a look at the follow snippet to better understand the concept:
```html
<span my-custom-set-text="Person.firstname"></span>
<span my-custom-set-text="Person.lastname"></span>
...
<script>
angular.module('testApp', [])
.directive('myCustomSetText', function () {
return {
link:function (scope, elem, attr, ctrl) {
elem.text(scope.$eval(attr.myCustomSetText));
}
}
});
</script>
```
This basic directive works as expected, it renders the `Person` data without using any watchers. However, if `Person` is not yet available inside the $scope when the page is loaded (say we get `Person` via $http or via $resource), the directive is useless, `scope.$eval(attr.myCustomSetText)` simply renders nothing and exits.
Here is how we can solve this issue with **bindonce**:
```html
<div bindonce="Person" bo-title="Person.title">
<span bo-text="Person.firstname"></span>
<span bo-text="Person.lastname"></span>
<img bo-src="Person.picture" bo-alt="Person.title">
<p bo-class="{'fancy':Person.isNice}" bo-html="Person.story"></p>
</div>
```
`bindonce="Person"` does the trick, any `bo-*` attribute belonging to `bindonce` waits until the parent `bindonce="{somedata}"` is validated and then renders its content. Once the scope contains the value `Person` then each bo-* child gets filled with the proper values. In order to accomplish this task, **bindonce** uses just **one** temporary watcher, no matters how many children need to be rendered. As soon as it gets `Person` the watcher is promptly removed. If the $scope already contains the data `bindonce` is looking for, then it doesn't create the temporary watcher and simply starts rendering its children.
You may have noticed that the first example didn't assign any value to the `bindonce` attribute:
```html
<ul>
<li bindonce ng-repeat="person in Persons">
...
```
when used with `ng-repeat` `bindonce` doesn't need to check if `person` is defined because `ng-repeat` creates the directives only when `person` exists. You could be more explicit: `<li bindonce="person" ng-repeat="person in Persons">`, however assigning a value to `bindonce` in an `ng-repeat` won't make any difference.
### Interpolation
Some directives (ng-href, ng-src) use interpolation, ie: `ng-href="/profile/{{User.profileId}}"`.
Both `ng-href` and `ng-src` have the bo-* equivalent directives: `bo-href-i` and `bo-src-i` (pay attention to the **-i**, it stands for **interpolate**). As expected they don't use watchers however Angular creates one watcher per interpolation, for instance `bo-href-i="/profile/{{User.profileId}}"` sets the element's href **once**, as expected, but Angular keeps a watcher active on `{{User.profileId}}` even if `bo-href-i` doesn't use it.
That's why by default the `bo-href` doesn't use interpolation or watchers. The above equivalent with 0 watchers would be `bo-href="'/profile/' + User.profileId"`. Nevertheless, `bo-href-i` and `bo-src-i` are still maintained for compatibility reasons.
### Filters
Almost every `bo-*` directive replace the equivalent `ng-*` and works in the same ways, except it is evaluated once.
Consequentially you can use any valid angular expression, including filters. This is an example how to use a filter:
```html
<div bindonce="Person">
<span bo-bind="Person.bill | currency:'USD$'"></span>
</div>
```
## Attribute Usage
| Directive | Description | Example |
|------------|----------------|-----|
| `bindonce="{somedata}"`| **bindonce** is the main directive. `{somedata}` is optional, and if present, forces bindonce to wait until `somedata` is defined before rendering its children | `<div bindonce="Person">...<div>` |
| `bo-if = "condition"` | equivalent to `ng-if` but doesn't use watchers |`<ANY bo-if="Person.isPublic"></ANY>`|
| `bo-switch = "expression"` | equivalent to `ng-switch` but doesn't use watchers |`<div bo-switch="Person.isPublic">` `<span bo-switch-when="'yes">public</span>` `<span bo-switch-default>private</span>` `</div>`|
| `bo-show = "condition"` | equivalent to `ng-show` but doesn't use watchers |`<ANY bo-show="Person.isPublic"></ANY>`|
| `bo-hide = "condition"` | equivalent to `ng-hide` but doesn't use watchers |`<ANY bo-hide="Person.isPrivate"></ANY>`|
| `bo-disabled = "condition"` | equivalent to `ng-disabled` but doesn't use watchers |`<ANY bo-disabled="Person.isUnavailable"></ANY>`|
| `bo-text = "text"` | evaluates "text" and print it as text inside the element | `<span bo-text="Person.name"></span>` |
| `bo-bind = "text"` | alias for `bo-text`, equivalent to `ng-bind` but doesn't use watchers | `<span bo-bind="Person.name"></span>` |
| `bo-html = "markup"` | evaluates "markup" and render it as html inside the element |`bo-html="Person.description"`|
| `bo-href-i = "url"`<br>*use `bo-href` instead* | **equivalent** to `ng-href`.<br>**Heads up!** Using interpolation `{{}}` it creates one watcher: <br>`bo-href-i="/p/{{Person.id}}"`. <br>Use `bo-href` to avoid the watcher:<br> `bo-href="'/p/' + Person.id"` |`<a bo-href-i="/profile{{Person.id}}"></a>`|
| `bo-href = "url"` | **similar** to `ng-href` but doesn't allow interpolation using `{{}}` like `ng-href`. <br>**Heads up!** You can't use interpolation `{{}}` inside the url, use bo-href-i for that purpose |`<a bo-href="'/profile' + Person.id"></a>` <br />or<br /> `<a bo-href="link" bo-text="Link"></a>`|
| `bo-src-i = "url"`<br>*use `bo-src` instead* | **equivalent** to `ng-src`. <br>**Heads up!** It creates one watcher |`<img bo-src-i="{{picture}}" bo-alt="title">`|
| `bo-src = "url"` | **similar** to `ng-src` but doesn't allow interpolation using `{{}}` like `ng-src`. <br>**Heads up!** You can't use interpolation `{{}}`, use bo-src-i for that purpose |`<img bo-src="picture" bo-alt="title">`|
| `bo-class = "object/string"` | equivalent to `ng-class` but doesn't use watchers |`<span bo-class="{'fancy':Person.condition}">`|
| `bo-alt = "text"` | evaluates "text" and render it as `alt` for the element |`<ANY bo-alt="title">`|
| `bo-title = "text"` | evaluates "text" and render it as `title` for the element |`<ANY bo-title="title">`|
| `bo-id = "#id"` | evaluates "#id" and render it as `id` for the element |`<ANY bo-id="id">`|
| `bo-style = "object"` | equivalent to `ng-style` but doesn't use watchers |`<ANY bo-style="{'color':Person.color}">`|
| `bo-value = "expression"` | evaluates "expression" and render it as `value` for the element |`<input type="radio" bo-value="value">`|
| `bo-attr bo-attr-foo = "text"` | evaluates "text" and render it as a custom attribute for the element |`<div bo-attr bo-attr-foo="bar"></div>`|
## Build
```
$ npm install uglify-js -g
$ uglifyjs bindonce.js -c -m -o bindonce.min.js
```
## Todo
Tests
## Copyright
BindOnce was written by **Pasquale Vazzana**, you can follow him on [google+](https://plus.google.com/101872882413388363602) or on [@twitter](https://twitter.com/PasqualeVazzana)
Thanks to all the [contributors](https://github.com/Pasvaz/bindonce/graphs/contributors)
## LICENSE - "MIT License"
Copyright (c) 2013-2014 Pasquale Vazzana
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

@ -1,325 +0,0 @@
(function () {
"use strict";
/**
* Bindonce - Zero watches binding for AngularJs
* @version v0.3.3
* @link https://github.com/Pasvaz/bindonce
* @author Pasquale Vazzana <pasqualevazzana@gmail.com>
* @license MIT License, http://www.opensource.org/licenses/MIT
*/
var bindonceModule = angular.module('pasvaz.bindonce', []);
bindonceModule.directive('bindonce', function ()
{
var toBoolean = function (value)
{
if (value && value.length !== 0)
{
var v = angular.lowercase("" + value);
value = !(v === 'f' || v === '0' || v === 'false' || v === 'no' || v === 'n' || v === '[]');
}
else
{
value = false;
}
return value;
};
var msie = parseInt((/msie (\d+)/.exec(angular.lowercase(navigator.userAgent)) || [])[1], 10);
if (isNaN(msie))
{
msie = parseInt((/trident\/.*; rv:(\d+)/.exec(angular.lowercase(navigator.userAgent)) || [])[1], 10);
}
var bindonceDirective =
{
restrict: "AM",
controller: ['$scope', '$element', '$attrs', '$interpolate', function ($scope, $element, $attrs, $interpolate)
{
var showHideBinder = function (elm, attr, value)
{
var show = (attr === 'show') ? '' : 'none';
var hide = (attr === 'hide') ? '' : 'none';
elm.css('display', toBoolean(value) ? show : hide);
};
var classBinder = function (elm, value)
{
if (angular.isObject(value) && !angular.isArray(value))
{
var results = [];
angular.forEach(value, function (value, index)
{
if (value) results.push(index);
});
value = results;
}
if (value)
{
elm.addClass(angular.isArray(value) ? value.join(' ') : value);
}
};
var transclude = function (transcluder, scope)
{
transcluder.transclude(scope, function (clone)
{
var parent = transcluder.element.parent();
var afterNode = transcluder.element && transcluder.element[transcluder.element.length - 1];
var parentNode = parent && parent[0] || afterNode && afterNode.parentNode;
var afterNextSibling = (afterNode && afterNode.nextSibling) || null;
angular.forEach(clone, function (node)
{
parentNode.insertBefore(node, afterNextSibling);
});
});
};
var ctrl =
{
watcherRemover: undefined,
binders: [],
group: $attrs.boName,
element: $element,
ran: false,
addBinder: function (binder)
{
this.binders.push(binder);
// In case of late binding (when using the directive bo-name/bo-parent)
// it happens only when you use nested bindonce, if the bo-children
// are not dom children the linking can follow another order
if (this.ran)
{
this.runBinders();
}
},
setupWatcher: function (bindonceValue)
{
var that = this;
this.watcherRemover = $scope.$watch(bindonceValue, function (newValue)
{
if (newValue === undefined) return;
that.removeWatcher();
that.checkBindonce(newValue);
}, true);
},
checkBindonce: function (value)
{
var that = this, promise = (value.$promise) ? value.$promise.then : value.then;
// since Angular 1.2 promises are no longer
// undefined until they don't get resolved
if (typeof promise === 'function')
{
promise(function ()
{
that.runBinders();
});
}
else
{
that.runBinders();
}
},
removeWatcher: function ()
{
if (this.watcherRemover !== undefined)
{
this.watcherRemover();
this.watcherRemover = undefined;
}
},
runBinders: function ()
{
while (this.binders.length > 0)
{
var binder = this.binders.shift();
if (this.group && this.group != binder.group) continue;
var value = binder.scope.$eval((binder.interpolate) ? $interpolate(binder.value) : binder.value);
switch (binder.attr)
{
case 'boIf':
if (toBoolean(value))
{
transclude(binder, binder.scope.$new());
}
break;
case 'boSwitch':
var selectedTranscludes, switchCtrl = binder.controller[0];
if ((selectedTranscludes = switchCtrl.cases['!' + value] || switchCtrl.cases['?']))
{
binder.scope.$eval(binder.attrs.change);
angular.forEach(selectedTranscludes, function (selectedTransclude)
{
transclude(selectedTransclude, binder.scope.$new());
});
}
break;
case 'boSwitchWhen':
var ctrl = binder.controller[0];
ctrl.cases['!' + binder.attrs.boSwitchWhen] = (ctrl.cases['!' + binder.attrs.boSwitchWhen] || []);
ctrl.cases['!' + binder.attrs.boSwitchWhen].push({ transclude: binder.transclude, element: binder.element });
break;
case 'boSwitchDefault':
var ctrl = binder.controller[0];
ctrl.cases['?'] = (ctrl.cases['?'] || []);
ctrl.cases['?'].push({ transclude: binder.transclude, element: binder.element });
break;
case 'hide':
case 'show':
showHideBinder(binder.element, binder.attr, value);
break;
case 'class':
classBinder(binder.element, value);
break;
case 'text':
binder.element.text(value);
break;
case 'html':
binder.element.html(value);
break;
case 'style':
binder.element.css(value);
break;
case 'disabled':
binder.element.prop('disabled', value);
break;
case 'src':
binder.element.attr(binder.attr, value);
if (msie) binder.element.prop('src', value);
break;
case 'attr':
angular.forEach(binder.attrs, function (attrValue, attrKey)
{
var newAttr, newValue;
if (attrKey.match(/^boAttr./) && binder.attrs[attrKey])
{
newAttr = attrKey.replace(/^boAttr/, '').replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
newValue = binder.scope.$eval(binder.attrs[attrKey]);
binder.element.attr(newAttr, newValue);
}
});
break;
case 'href':
case 'alt':
case 'title':
case 'id':
case 'value':
binder.element.attr(binder.attr, value);
break;
}
}
this.ran = true;
}
};
angular.extend(this, ctrl);
}],
link: function (scope, elm, attrs, bindonceController)
{
var value = attrs.bindonce && scope.$eval(attrs.bindonce);
if (value !== undefined)
{
bindonceController.checkBindonce(value);
}
else
{
bindonceController.setupWatcher(attrs.bindonce);
elm.bind("$destroy", bindonceController.removeWatcher);
}
}
};
return bindonceDirective;
});
angular.forEach(
[
{ directiveName: 'boShow', attribute: 'show' },
{ directiveName: 'boHide', attribute: 'hide' },
{ directiveName: 'boClass', attribute: 'class' },
{ directiveName: 'boText', attribute: 'text' },
{ directiveName: 'boBind', attribute: 'text' },
{ directiveName: 'boHtml', attribute: 'html' },
{ directiveName: 'boSrcI', attribute: 'src', interpolate: true },
{ directiveName: 'boSrc', attribute: 'src' },
{ directiveName: 'boHrefI', attribute: 'href', interpolate: true },
{ directiveName: 'boHref', attribute: 'href' },
{ directiveName: 'boAlt', attribute: 'alt' },
{ directiveName: 'boTitle', attribute: 'title' },
{ directiveName: 'boId', attribute: 'id' },
{ directiveName: 'boStyle', attribute: 'style' },
{ directiveName: 'boDisabled', attribute: 'disabled' },
{ directiveName: 'boValue', attribute: 'value' },
{ directiveName: 'boAttr', attribute: 'attr' },
{ directiveName: 'boIf', transclude: 'element', terminal: true, priority: 1000 },
{ directiveName: 'boSwitch', require: 'boSwitch', controller: function () { this.cases = {}; } },
{ directiveName: 'boSwitchWhen', transclude: 'element', priority: 800, require: '^boSwitch' },
{ directiveName: 'boSwitchDefault', transclude: 'element', priority: 800, require: '^boSwitch' }
],
function (boDirective)
{
var childPriority = 200;
return bindonceModule.directive(boDirective.directiveName, function ()
{
var bindonceDirective =
{
priority: boDirective.priority || childPriority,
transclude: boDirective.transclude || false,
terminal: boDirective.terminal || false,
require: ['^bindonce'].concat(boDirective.require || []),
controller: boDirective.controller,
compile: function (tElement, tAttrs, transclude)
{
return function (scope, elm, attrs, controllers)
{
var bindonceController = controllers[0];
var name = attrs.boParent;
if (name && bindonceController.group !== name)
{
var element = bindonceController.element.parent();
bindonceController = undefined;
var parentValue;
while (element[0].nodeType !== 9 && element.length)
{
if ((parentValue = element.data('$bindonceController'))
&& parentValue.group === name)
{
bindonceController = parentValue;
break;
}
element = element.parent();
}
if (!bindonceController)
{
throw new Error("No bindonce controller: " + name);
}
}
bindonceController.addBinder(
{
element: elm,
attr: boDirective.attribute || boDirective.directiveName,
attrs: attrs,
value: attrs[boDirective.directiveName],
interpolate: boDirective.interpolate,
group: name,
transclude: transclude,
controller: controllers.slice(1),
scope: scope
});
};
}
};
return bindonceDirective;
});
})
})();

@ -1 +0,0 @@
!function(){"use strict";var e=angular.module("pasvaz.bindonce",[]);e.directive("bindonce",function(){var e=function(e){if(e&&0!==e.length){var t=angular.lowercase(""+e);e=!("f"===t||"0"===t||"false"===t||"no"===t||"n"===t||"[]"===t)}else e=!1;return e},t=parseInt((/msie (\d+)/.exec(angular.lowercase(navigator.userAgent))||[])[1],10);isNaN(t)&&(t=parseInt((/trident\/.*; rv:(\d+)/.exec(angular.lowercase(navigator.userAgent))||[])[1],10));var r={restrict:"AM",controller:["$scope","$element","$attrs","$interpolate",function(r,a,i,n){var c=function(t,r,a){var i="show"===r?"":"none",n="hide"===r?"":"none";t.css("display",e(a)?i:n)},o=function(e,t){if(angular.isObject(t)&&!angular.isArray(t)){var r=[];angular.forEach(t,function(e,t){e&&r.push(t)}),t=r}t&&e.addClass(angular.isArray(t)?t.join(" "):t)},s=function(e,t){e.transclude(t,function(t){var r=e.element.parent(),a=e.element&&e.element[e.element.length-1],i=r&&r[0]||a&&a.parentNode,n=a&&a.nextSibling||null;angular.forEach(t,function(e){i.insertBefore(e,n)})})},l={watcherRemover:void 0,binders:[],group:i.boName,element:a,ran:!1,addBinder:function(e){this.binders.push(e),this.ran&&this.runBinders()},setupWatcher:function(e){var t=this;this.watcherRemover=r.$watch(e,function(e){void 0!==e&&(t.removeWatcher(),t.checkBindonce(e))},!0)},checkBindonce:function(e){var t=this,r=e.$promise?e.$promise.then:e.then;"function"==typeof r?r(function(){t.runBinders()}):t.runBinders()},removeWatcher:function(){void 0!==this.watcherRemover&&(this.watcherRemover(),this.watcherRemover=void 0)},runBinders:function(){for(;this.binders.length>0;){var r=this.binders.shift();if(!this.group||this.group==r.group){var a=r.scope.$eval(r.interpolate?n(r.value):r.value);switch(r.attr){case"boIf":e(a)&&s(r,r.scope.$new());break;case"boSwitch":var i,l=r.controller[0];(i=l.cases["!"+a]||l.cases["?"])&&(r.scope.$eval(r.attrs.change),angular.forEach(i,function(e){s(e,r.scope.$new())}));break;case"boSwitchWhen":var u=r.controller[0];u.cases["!"+r.attrs.boSwitchWhen]=u.cases["!"+r.attrs.boSwitchWhen]||[],u.cases["!"+r.attrs.boSwitchWhen].push({transclude:r.transclude,element:r.element});break;case"boSwitchDefault":var u=r.controller[0];u.cases["?"]=u.cases["?"]||[],u.cases["?"].push({transclude:r.transclude,element:r.element});break;case"hide":case"show":c(r.element,r.attr,a);break;case"class":o(r.element,a);break;case"text":r.element.text(a);break;case"html":r.element.html(a);break;case"style":r.element.css(a);break;case"disabled":r.element.prop("disabled",a);break;case"src":r.element.attr(r.attr,a),t&&r.element.prop("src",a);break;case"attr":angular.forEach(r.attrs,function(e,t){var a,i;t.match(/^boAttr./)&&r.attrs[t]&&(a=t.replace(/^boAttr/,"").replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase(),i=r.scope.$eval(r.attrs[t]),r.element.attr(a,i))});break;case"href":case"alt":case"title":case"id":case"value":r.element.attr(r.attr,a)}}}this.ran=!0}};angular.extend(this,l)}],link:function(e,t,r,a){var i=r.bindonce&&e.$eval(r.bindonce);void 0!==i?a.checkBindonce(i):(a.setupWatcher(r.bindonce),t.bind("$destroy",a.removeWatcher))}};return r}),angular.forEach([{directiveName:"boShow",attribute:"show"},{directiveName:"boHide",attribute:"hide"},{directiveName:"boClass",attribute:"class"},{directiveName:"boText",attribute:"text"},{directiveName:"boBind",attribute:"text"},{directiveName:"boHtml",attribute:"html"},{directiveName:"boSrcI",attribute:"src",interpolate:!0},{directiveName:"boSrc",attribute:"src"},{directiveName:"boHrefI",attribute:"href",interpolate:!0},{directiveName:"boHref",attribute:"href"},{directiveName:"boAlt",attribute:"alt"},{directiveName:"boTitle",attribute:"title"},{directiveName:"boId",attribute:"id"},{directiveName:"boStyle",attribute:"style"},{directiveName:"boDisabled",attribute:"disabled"},{directiveName:"boValue",attribute:"value"},{directiveName:"boAttr",attribute:"attr"},{directiveName:"boIf",transclude:"element",terminal:!0,priority:1e3},{directiveName:"boSwitch",require:"boSwitch",controller:function(){this.cases={}}},{directiveName:"boSwitchWhen",transclude:"element",priority:800,require:"^boSwitch"},{directiveName:"boSwitchDefault",transclude:"element",priority:800,require:"^boSwitch"}],function(t){var r=200;return e.directive(t.directiveName,function(){var e={priority:t.priority||r,transclude:t.transclude||!1,terminal:t.terminal||!1,require:["^bindonce"].concat(t.require||[]),controller:t.controller,compile:function(e,r,a){return function(e,r,i,n){var c=n[0],o=i.boParent;if(o&&c.group!==o){var s=c.element.parent();c=void 0;for(var l;9!==s[0].nodeType&&s.length;){if((l=s.data("$bindonceController"))&&l.group===o){c=l;break}s=s.parent()}if(!c)throw new Error("No bindonce controller: "+o)}c.addBinder({element:r,attr:t.attribute||t.directiveName,attrs:i,value:i[t.directiveName],interpolate:t.interpolate,group:o,transclude:a,controller:n.slice(1),scope:e})}}};return e})})}();

@ -1,28 +0,0 @@
{
"name": "angular-bindonce",
"version": "0.3.3",
"main": "bindonce.js",
"description": "Zero watchers binding directives for AngularJS",
"homepage": "https://github.com/Pasvaz/bindonce",
"author": "Pasquale Vazzana <pasqualevazzana@gmail.com>",
"repository": {
"type": "git",
"url": "https://github.com/Pasvaz/bindonce.git"
},
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"components"
],
"dependencies": {
},
"keywords": [
"angularjs",
"angular",
"directive",
"binding",
"watcher",
"bindonce"
]
}

@ -1,28 +0,0 @@
{
"name": "angular-bindonce",
"version": "0.3.3",
"main": "bindonce.js",
"description": "Zero watchers binding directives for AngularJS",
"homepage": "https://github.com/Pasvaz/bindonce",
"author": "Pasquale Vazzana <pasqualevazzana@gmail.com>",
"repository": {
"type": "git",
"url": "https://github.com/Pasvaz/bindonce.git"
},
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"components"
],
"dependencies": {
},
"keywords": [
"angularjs",
"angular",
"directive",
"binding",
"watcher",
"bindonce"
]
}

@ -1,36 +0,0 @@
{
"name": "angular-native-dragdrop",
"version": "1.2.2",
"homepage": "http://angular-dragdrop.github.io/angular-dragdrop",
"authors": [
"ganarajpr"
],
"description": "Angular HTML5 Drag and Drop directive written in pure with no dependency on JQuery.",
"main": "draganddrop.js",
"keywords": [
"angular",
"drag",
"drop",
"html5"
],
"dependencies": {
"angular": "^1.3"
},
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"_release": "1.2.2",
"_resolution": {
"type": "version",
"tag": "1.2.2",
"commit": "e630636fdc39fef815c1c534340aa16caf76a04c"
},
"_source": "https://github.com/angular-dragdrop/angular-dragdrop.git",
"_target": "1.2.2",
"_originalSource": "angular-native-dragdrop"
}

@ -1,25 +0,0 @@
/* jshint -W097 */
'use strict';
/* global require */
var jshint = require('gulp-jshint');
var stylish = require('jshint-stylish');
var uglify = require('gulp-uglify');
var rename = require('gulp-rename');
var gulp = require('gulp');
gulp.task('lint', function() {
return gulp.src('./draganddrop.js')
.pipe(jshint())
.pipe(jshint.reporter(stylish));
});
gulp.task('compress', function() {
return gulp.src('./draganddrop.js')
.pipe(uglify())
.pipe(rename({
extname: '.min.js'
}))
.pipe(gulp.dest('./'));
});
gulp.task('default', ['lint', 'compress']);

@ -1,10 +0,0 @@
The MIT License
Copyright (c) 2015 Ganaraj P R, [Nebithi](http://www.nebithi.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

@ -1,36 +0,0 @@
#Angular-DragDrop
[![npm version](http://img.shields.io/npm/v/angular-native-dragdrop.svg?style=flat)](https://npmjs.org/package/angular-native-dragdrop)
[![Build status](http://img.shields.io/travis/angular-dragdrop/angular-dragdrop.svg?style=flat)](https://travis-ci.org/angular-dragdrop/angular-dragdrop)
[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/ganarajpr/angular-dragdrop?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
Angular-DragDrop is a angular HTML5 Drag and Drop directive written in pure with no dependency on JQuery.
This is based on the work done by Jason Turim. While this [blog post](http://jasonturim.wordpress.com/2013/09/01/angularjs-drag-and-drop/) was the inspiration for creating a native Drag and Drop solution, the intention was to create something that was more generic.
This implementation is mainly different from the one posted in the blog in the following areas :
1. Angular-DragDrop does not create an isolate scope. This has huge benefits when it comes to working with other directives. **NOTE :** It also does not pollute the scope with any variables or functions.
2. It does not depend on any kind of an ID attribute ( being either present or generated on the fly ).
3. It allows one to create channels on which different drag and drop directive combinations can work on in the same page ( more on this later ) .
Pull requests are welcome.
[Documentation](http://angular-dragdrop.github.io/angular-dragdrop/)
#Looking for Active Contributors.
This repo needs active contributers and maintainers. If you are interested in being one of the people who would like to actively maintain this repo, please let me know.
The MIT License
Copyright (c) 2014 Ganaraj P R, [Nebithi](http://www.nebithi.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

@ -1,27 +0,0 @@
{
"name": "angular-native-dragdrop",
"version": "1.2.1",
"homepage": "http://angular-dragdrop.github.io/angular-dragdrop",
"authors": [
"ganarajpr"
],
"description": "Angular HTML5 Drag and Drop directive written in pure with no dependency on JQuery.",
"main": "draganddrop.js",
"keywords": [
"angular",
"drag",
"drop",
"html5"
],
"dependencies": {
"angular": "^1.3"
},
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
]
}

@ -1,29 +0,0 @@
body {
background-color: #f8f7f8;
}
.heading {
border-bottom: 1px solid #b7b7b7;
padding-bottom: 10px;
margin-bottom: 10px;
}
.topRow {
margin-bottom: 30px;
}
.on-drag-enter {
background-color : #677ba6;
}
.on-drag-enter-custom {
background-color : #d78cc7;
}
.on-drag-hover {
background-color : #3eb352;
}
.on-drag-hover-custom {
background-color : #d7a931;
}

@ -1,178 +0,0 @@
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<title>Angular DragDrop (Demo)</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="css/styles.css" />
<script data-require="angular.js@1.4.x" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.js" data-semver="1.4.3"></script>
<script src="http://pc035860.github.io/angular-highlightjs/angular-highlightjs.min.js"></script>
<script src="js/app.js"></script>
<script src="../draganddrop.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
</head>
<body >
<div class="container">
<div class="row topRow">
<h4 class="heading">
Drag and drop between the two lists.
</h4>
</div>
<h3>Beasts</h3>
<p>Left column of beasts is not draggable and accepts both beasts and priests</p>
<hr>
<div class="row" ng-controller="MainCtrl">
<div class="col-xs-6">
<ul ui-on-drop="onDrop($event,$data,men)" drag-enter-class="on-drag-enter-custom"
drop-channel="beasts,priests"
drop-validate="dropValidateHandler($drop, $event, $data)">
<li ui-draggable="false" drag="man" drag-channel="beasts"
on-drop-success="dropSuccessHandler($event,$index,men)"
ng-repeat="man in men track by $index">
{{man}}
</li>
</ul>
</div>
<div class="col-xs-6">
<ul ui-on-drop="onDrop($event,$data,women)"
drop-channel="beasts"
drop-validate="dropValidateHandler($drop, $event, $data)">
<li ui-draggable="true" drag="woman" drag-channel="beasts"
on-drop-success="dropSuccessHandler($event,$index,women)"
on-drop-failure="dropFailureHandler($event,$index,women)"
ng-repeat="woman in women track by $index">
{{woman}}
</li>
</ul>
</div>
</div>
<hr>
<h3>Priests</h3>
<hr>
<div class="row" ng-controller="MainCtrl">
<div class="col-xs-6">
<ul ui-on-drop="onDrop($event,$data,men)"
drop-channel="priests"
drop-validate="dropValidateHandler($drop, $event, $data)">
<li ui-draggable="true" drag="man"
drag-channel="priests"
on-drop-success="dropSuccessHandler($event,$index,men)"
ng-repeat="man in men track by $index">
{{man}}
</li>
</ul>
</div>
<div class="col-xs-6">
<ul ui-on-drop="onDrop($event,$data,women)"
drop-channel="priests"
drop-validate="dropValidateHandler($drop, $event, $data)">
<li ui-draggable="true" drag="woman"
drag-channel="priests"
on-drop-success="dropSuccessHandler($event,$index,women)"
ng-repeat="woman in women track by $index">
{{woman}}
</li>
</ul>
</div>
</div>
<hr>
<h3>Terrorists</h3>
<p>Each terrorist list item accepts a new terrorist. Shows inserting into a particular
position in an array.</p>
<hr>
<div class="row" ng-controller="MainCtrl">
<div class="col-xs-6">
<ul>
<li ui-draggable="true" drag="man"
drag-channel="terrorists2"
drop-validate="dropValidateHandler($drop, $event, $data)"
drag-hover-class="on-drag-hover-custom"
on-drop-success="dropSuccessHandler($event,$index,men)"
ui-on-drop="onDrop($event,$data,men,$index)" drop-channel="terrorists1"
ng-repeat="man in men track by $index">
{{man}}
</li>
</ul>
</div>
<div class="col-xs-6">
<ul>
<li ui-draggable="true" drag="woman"
drag-channel="terrorists1"
drop-validate="dropValidateHandler($drop, $event, $data)"
drag-hover-class="on-drag-hover-custom"
ui-on-drop="onDrop($event,$data,women,$index)" drop-channel="terrorists2"
on-drop-success="dropSuccessHandler($event,$index,women)"
ng-repeat="woman in women track by $index">
{{woman}}
</li>
</ul>
</div>
</div>
<hr>
<h3>Custom Drag Image</h3>
<p>You may specify a drag-image-element-id to use as the drag image. You can use the
<a href="http://www.kryogenix.org/code/browser/custom-drag-image.html" target="_blank">ghost image</a>
technique for the custom drag image.</p>
<hr>
<div class="row" ng-controller="MainCtrl">
<div class="col-xs-6">
<ul>
<li ui-draggable="true" drag="man"
drag-channel="customImage2"
drop-validate="dropValidateHandler($drop, $event, $data)"
drag-hover-class="on-drag-hover-custom"
drag-image-element-id="getCustomDragElementId($index)"
on-drop-success="dropSuccessHandler($event,$index,men)"
ui-on-drop="onDrop($event,$data,men,$index)"
drop-channel="customImage1"
ng-repeat="man in men track by $index">
{{man}}
</li>
</ul>
</div>
<div class="col-xs-6">
<ul>
<li ui-draggable="true" drag="woman"
drag-channel="customImage1"
drop-validate="dropValidateHandler($drop, $event, $data)"
drag-hover-class="on-drag-hover-custom"
drag-image-element-id="getCustomDragElementId($index)"
ui-on-drop="onDrop($event,$data,women,$index)"
drop-channel="customImage2"
on-drop-success="dropSuccessHandler($event,$index,women)"
ng-repeat="woman in women track by $index">
{{woman}}
</li>
</ul>
</div>
</div>
<div id="customDrag0" class="alert alert-info" style="max-width: 200px">Custom drag image #1</div>
<div id="customDrag1" class="alert alert-danger" style="position: absolute; top: 0; right: 0; z-index: -2; max-width: 200px">Custom drag image #2</div>
<div id="coverUp" style="position: absolute; top: 0; right: 0; z-index: -1; background-color: white; width: 200px; height: 60px"></div>
</div>
</body>
</html>

@ -1,54 +0,0 @@
angular.module('app', [
'hljs',
'ang-drag-drop'
]).controller('MainCtrl', function($scope) {
$scope.men = [
'John',
'Jack',
'Mark',
'Ernie',
'Mike (Locked)'
];
$scope.women = [
'Jane',
'Jill',
'Betty',
'Mary'
];
$scope.addText = '';
$scope.dropValidateHandler = function($drop, $event, $data) {
if ($data === 'Mike (Locked)') {
return false;
}
if ($drop.element[0] === $event.srcElement.parentNode) {
// Don't allow moving to same container
return false;
}
return true;
};
$scope.dropSuccessHandler = function($event, index, array) {
array.splice(index, 1);
};
$scope.dropFailureHandler = function($event, index, array) {
alert(array[index] + ' could be dropped into left list!')
};
$scope.onDrop = function($event, $data, array, index) {
if (index !== undefined) {
array.splice(index, 0, $data);
} else {
array.push($data);
}
};
$scope.getCustomDragElementId = function (index) {
return 'customDrag' + (index % 2);
}
});

@ -1,8 +0,0 @@
#Examples
##Simple Usage
<iframe style="width: 100%; height: 500px" src="http://embed.plnkr.co/5RLvCpDPoRcEk6u77dBM" frameborder="0" allowfullscreen="allowfullscreen"></iframe>
##With drop validation
<iframe style="width: 100%; height: 500px" src="http://embed.plnkr.co/xRmz4TlCvlJKxybGrhQH" frameborder="0" allowfullscreen="allowfullscreen"></iframe>

@ -1,26 +0,0 @@
#Installation
##Download
Download the file [**draganddrop.min.js**](https://raw.githubusercontent.com/angular-dragdrop/angular-dragdrop/master/draganddrop.min.js) or [**draganddrop.js**](https://raw.githubusercontent.com/angular-dragdrop/angular-dragdrop/master/draganddrop.js).
##Bower
You can also install via Bower using
`bower install angular-native-dragdrop --save`
---
#Usage
##Step - 1 **Add script**
```
<script src="path/to/draganddrop.min.js"></script>
```
##Step - 2 **Include in app**
```
myApp = angular.module('myApp','ang-drag-drop');
```
##Step - 3 ***Profit!!***

@ -1,120 +0,0 @@
# Angular Drag and Drop
**A Native ( without jquery ) Drag and Drop directive for AngularJS using HTML5 Drag and Drop**
---
##ui-draggable(expression)
Directive in module ang-drag-drop (since 1.0.5 - old module name ngDragDrop)
The ui-draggable attribute tells Angular that the element is draggable. ui-draggable takes an expression as the attribute value. The expression should evaluate to either true or false. You can toggle the draggability of an element using this expression.
###Additional Attributes
####_**drag**_(variable)
The class used to mark child elements of draggable object to be used as drag handle. Default class name is `drag-handle`
**NOTE**: If attribute is not present drag handle feature is not active.
####_**drag-handle-class**_(string)
The `drag` property is used to assign the data that needs to be passed along with the dragging element.
####_**on-drop-success**_(function)
The `on-drop-success` attribute takes a function. We can consider this to be an on-drop-success handler function. This can be useful if you need to do some post processing after the dragged element is dropped successfully on the drop site.
**NOTE**: This callback function is only called when the drop succeeds.
You can request the `drag-end` event ( very similiar to requesting the click event in `ng-click` ) by passing `$event` in the event handler.
####_**on-drop-failure**_(function)
The `on-drop-failure` attribute takes a function. We can consider this to be an on-drop-failure handler function. This can be useful if you need to do some post processing after the dragged element is dropped unsuccessfully on any drop site.
**NOTE**: This callback function is only called when the drop fails.
You can request the `drag-end` event ( very similiar to requesting the click event in `ng-click` ) by passing `$event` in the event handler.
####_**drag-channel**_(string)
The `on-drop-failure` attribute takes a function. We can consider this to be an on-drop-failure handler function. This can be useful if you need to do some post processing after the dragged element is dropped unsuccessfully on any drop site.
**NOTE**: This callback function is only called when the drop fails.
You can request the `drag-end` event ( very similiar to requesting the click event in `ng-click` ) by passing `$event` in the event handler.
###Usage
###Events
On start of dragging an Angular Event `ANGULAR_DRAG_START` is dispatched from the `$rootScope`. The event also carries carries the information about the channel in which the dragging has started.
On end of dragging an Angular Event `ANGULAR_DRAG_END` is dispatched from the `$rootScope`. The event also carries carries the information about the channel in which the dragging has started.
When hovering a draggable element on top of a drop area an Angular Event `ANGULAR_HOVER` is dispatched from the `$rootScope`. The event also carries the information about the channel in which the dragging has started.
---
##ui-on-drop(expression)
Directive in module ang-drag-drop (since 1.0.5 - old module name ngDragDrop)
The `ui-on-drop` attribute tells Angular that the element is a drop site. `ui-on-drop` takes a function as the attribute value. The function will be called when a valid dragged element is dropped in that location. A valid dragged element is one which has the same channel as the drop location.
**NOTE** : This callback function is only called when the drop succeeds.
The `ui-on-drop` callback can request additional parameters. The data that is dragged is available to the callback as $data and its channel as `$channel`. Apart from this the drop event is exposed as `$event`.
###Additional Attributes
####_**drop-channel**_(variable)
The channel that the drop site accepts. The dragged element should have the same channel as this drop site for it to be droppable at this location. It is possible to provide comma separated list of channels.
**NOTE**: Also special value of `drag-channel` attribute is available to accept dragged element with any channel value — *
####_**drop-validate**_(function)
Extra validation that makes sure that the drop site accepts the dragged element beyond having the same channel. If not defined, no extra validation is made.
**NOTE**: This callback function is called only if the channel condition is met, when the element starts being dragged
####_**drag-enter-class**_(string)
The class that will be added to the the droppable element when a dragged element ( which is droppable ) enters the drop location. The default value for this is `on-drag-enter`
####_**drag-hover-class**_(string)
The class that will be added to the drop area element when hovering with an element. The default value for this is `on-drag-hover`
###Usage
###Events
On start of dragging an Angular Event `ANGULAR_DRAG_START` is dispatched from the `$rootScope`. The event also carries carries the information about the channel in which the dragging has started.
On end of dragging an Angular Event `ANGULAR_DRAG_END` is dispatched from the `$rootScope`. The event also carries carries the information about the channel in which the dragging has started.
When hovering a draggable element on top of a drop area an Angular Event `ANGULAR_HOVER` is dispatched from the `$rootScope`. The event also carries the information about the channel in which the dragging has started.

@ -1,459 +0,0 @@
(function(angular) {
'use strict';
function isDnDsSupported() {
return 'ondrag' in document.createElement('a');
}
function determineEffectAllowed(e) {
if(e.originalEvent) {
e.dataTransfer = e.originalEvent.dataTransfer;
}
// Chrome doesn't set dropEffect, so we have to work it out ourselves
if (typeof e.dataTransfer !== 'undefined' && e.dataTransfer.dropEffect === 'none') {
if (e.dataTransfer.effectAllowed === 'copy' ||
e.dataTransfer.effectAllowed === 'move') {
e.dataTransfer.dropEffect = e.dataTransfer.effectAllowed;
} else if (e.dataTransfer.effectAllowed === 'copyMove' || e.dataTransfer.effectAllowed === 'copymove') {
e.dataTransfer.dropEffect = e.ctrlKey ? 'copy' : 'move';
}
}
}
if (!isDnDsSupported()) {
angular.module('ang-drag-drop', []);
return;
}
var module = angular.module('ang-drag-drop', []);
module.directive('uiDraggable', ['$parse', '$rootScope', '$dragImage', function($parse, $rootScope, $dragImage) {
return function(scope, element, attrs) {
var isDragHandleUsed = false,
dragHandleClass,
draggingClass = attrs.draggingClass || 'on-dragging',
dragTarget;
element.attr('draggable', false);
scope.$watch(attrs.uiDraggable, function(newValue) {
if (newValue) {
element.attr('draggable', newValue);
element.bind('dragend', dragendHandler);
element.bind('dragstart', dragstartHandler);
}
else {
element.removeAttr('draggable');
element.unbind('dragend', dragendHandler);
element.unbind('dragstart', dragstartHandler);
}
});
if (angular.isString(attrs.dragHandleClass)) {
isDragHandleUsed = true;
dragHandleClass = attrs.dragHandleClass.trim() || 'drag-handle';
element.bind('mousedown', function(e) {
dragTarget = e.target;
});
}
function dragendHandler(e) {
if(e.originalEvent) {
e.dataTransfer = e.originalEvent.dataTransfer;
}
setTimeout(function() {
element.unbind('$destroy', dragendHandler);
}, 0);
var sendChannel = attrs.dragChannel || 'defaultchannel';
$rootScope.$broadcast('ANGULAR_DRAG_END', e, sendChannel);
determineEffectAllowed(e);
if (e.dataTransfer && e.dataTransfer.dropEffect !== 'none') {
if (attrs.onDropSuccess) {
var onDropSuccessFn = $parse(attrs.onDropSuccess);
scope.$evalAsync(function() {
onDropSuccessFn(scope, {$event: e});
});
}
}else if (e.dataTransfer && e.dataTransfer.dropEffect === 'none'){
if (attrs.onDropFailure) {
var onDropFailureFn = $parse(attrs.onDropFailure);
scope.$evalAsync(function() {
onDropFailureFn(scope, {$event: e});
});
}
}
element.removeClass(draggingClass);
}
function setDragElement(e, dragImageElementId) {
var dragImageElementFn;
if(e.originalEvent) {
e.dataTransfer = e.originalEvent.dataTransfer;
}
dragImageElementFn = $parse(dragImageElementId);
scope.$apply(function() {
var elementId = dragImageElementFn(scope, {$event: e}),
dragElement;
if (!(elementId && angular.isString(elementId))) {
return;
}
dragElement = document.getElementById(elementId);
if (!dragElement) {
return;
}
e.dataTransfer.setDragImage(dragElement, 0, 0);
});
}
function dragstartHandler(e) {
if(e.originalEvent) {
e.dataTransfer = e.originalEvent.dataTransfer;
}
var isDragAllowed = !isDragHandleUsed || dragTarget.classList.contains(dragHandleClass);
if (isDragAllowed) {
var sendChannel = attrs.dragChannel || 'defaultchannel';
var dragData = '';
if (attrs.drag) {
dragData = scope.$eval(attrs.drag);
}
var dragImage = attrs.dragImage || null;
element.addClass(draggingClass);
element.bind('$destroy', dragendHandler);
//Code to make sure that the setDragImage is available. IE 10, 11, and Opera do not support setDragImage.
var hasNativeDraggable = !(document.uniqueID || window.opera);
//If there is a draggable image passed in, then set the image to be dragged.
if (dragImage && hasNativeDraggable) {
var dragImageFn = $parse(attrs.dragImage);
scope.$apply(function() {
var dragImageParameters = dragImageFn(scope, {$event: e});
if (dragImageParameters) {
if (angular.isString(dragImageParameters)) {
dragImageParameters = $dragImage.generate(dragImageParameters);
}
if (dragImageParameters.image) {
var xOffset = dragImageParameters.xOffset || 0,
yOffset = dragImageParameters.yOffset || 0;
e.dataTransfer.setDragImage(dragImageParameters.image, xOffset, yOffset);
}
}
});
} else if (attrs.dragImageElementId) {
setDragElement(e, attrs.dragImageElementId);
}
var offset = {x: e.offsetX, y: e.offsetY};
var transferDataObject = {data: dragData, channel: sendChannel, offset: offset};
var transferDataText = angular.toJson(transferDataObject);
e.dataTransfer.setData('text', transferDataText);
e.dataTransfer.effectAllowed = 'copyMove';
$rootScope.$broadcast('ANGULAR_DRAG_START', e, sendChannel, transferDataObject);
}
else {
e.preventDefault();
}
}
};
}
]);
module.directive('uiOnDrop', ['$parse', '$rootScope', function($parse, $rootScope) {
return function(scope, element, attr) {
var dragging = 0; //Ref. http://stackoverflow.com/a/10906204
var dropChannel = attr.dropChannel || 'defaultchannel';
var dragChannel = '';
var dragEnterClass = attr.dragEnterClass || 'on-drag-enter';
var dragHoverClass = attr.dragHoverClass || 'on-drag-hover';
var customDragEnterEvent = $parse(attr.onDragEnter);
var customDragLeaveEvent = $parse(attr.onDragLeave);
function calculateDropOffset(e) {
var offset = {
x: e.offsetX,
y: e.offsetY
};
var target = e.target;
while (target !== element[0]) {
offset.x = offset.x + target.offsetLeft;
offset.y = offset.y + target.offsetTop;
target = target.offsetParent;
if (!target) {
return null;
}
}
return offset;
}
function onDragOver(e) {
if (e.preventDefault) {
e.preventDefault(); // Necessary. Allows us to drop.
}
if (e.stopPropagation) {
e.stopPropagation();
}
var uiOnDragOverFn = $parse(attr.uiOnDragOver);
scope.$evalAsync(function() {
uiOnDragOverFn(scope, {$event: e, $channel: dropChannel});
});
return false;
}
function onDragLeave(e) {
if (e.preventDefault) {
e.preventDefault();
}
if (e.stopPropagation) {
e.stopPropagation();
}
dragging--;
if (dragging === 0) {
scope.$evalAsync(function() {
customDragLeaveEvent(scope, {$event: e, $channel: dropChannel});
});
element.addClass(dragEnterClass);
element.removeClass(dragHoverClass);
}
var uiOnDragLeaveFn = $parse(attr.uiOnDragLeave);
scope.$evalAsync(function() {
uiOnDragLeaveFn(scope, {$event: e, $channel: dropChannel});
});
}
function onDragEnter(e) {
if (e.preventDefault) {
e.preventDefault();
}
if (e.stopPropagation) {
e.stopPropagation();
}
if (dragging === 0) {
scope.$evalAsync(function() {
customDragEnterEvent(scope, {$event: e, $channel: dropChannel});
});
element.removeClass(dragEnterClass);
element.addClass(dragHoverClass);
}
dragging++;
var uiOnDragEnterFn = $parse(attr.uiOnDragEnter);
scope.$evalAsync(function() {
uiOnDragEnterFn(scope, {$event: e, $channel: dropChannel});
});
$rootScope.$broadcast('ANGULAR_HOVER', dragChannel);
}
function onDrop(e) {
if(e.originalEvent) {
e.dataTransfer = e.originalEvent.dataTransfer;
}
if (e.preventDefault) {
e.preventDefault(); // Necessary. Allows us to drop.
}
if (e.stopPropagation) {
e.stopPropagation(); // Necessary. Allows us to drop.
}
var sendData = e.dataTransfer.getData('text');
sendData = angular.fromJson(sendData);
var dropOffset = calculateDropOffset(e);
var position = dropOffset ? {
x: dropOffset.x - sendData.offset.x,
y: dropOffset.y - sendData.offset.y
} : null;
determineEffectAllowed(e);
var uiOnDropFn = $parse(attr.uiOnDrop);
scope.$evalAsync(function() {
uiOnDropFn(scope, {$data: sendData.data, $event: e, $channel: sendData.channel, $position: position});
});
element.removeClass(dragEnterClass);
dragging = 0;
}
function isDragChannelAccepted(dragChannel, dropChannel) {
if (dropChannel === '*') {
return true;
}
var channelMatchPattern = new RegExp('(\\s|[,])+(' + dragChannel + ')(\\s|[,])+', 'i');
return channelMatchPattern.test(',' + dropChannel + ',');
}
function preventNativeDnD(e) {
if(e.originalEvent) {
e.dataTransfer = e.originalEvent.dataTransfer;
}
if (e.preventDefault) {
e.preventDefault();
}
if (e.stopPropagation) {
e.stopPropagation();
}
e.dataTransfer.dropEffect = 'none';
return false;
}
var deregisterDragStart = $rootScope.$on('ANGULAR_DRAG_START', function(_, e, channel, transferDataObject) {
dragChannel = channel;
var valid = true;
if (!isDragChannelAccepted(channel, dropChannel)) {
valid = false;
}
if (valid && attr.dropValidate) {
var validateFn = $parse(attr.dropValidate);
valid = validateFn(scope, {
$drop: {scope: scope, element: element},
$event: e,
$data: transferDataObject.data,
$channel: transferDataObject.channel
});
}
if (valid) {
element.bind('dragover', onDragOver);
element.bind('dragenter', onDragEnter);
element.bind('dragleave', onDragLeave);
element.bind('drop', onDrop);
element.addClass(dragEnterClass);
} else {
element.bind('dragover', preventNativeDnD);
element.bind('dragenter', preventNativeDnD);
element.bind('dragleave', preventNativeDnD);
element.bind('drop', preventNativeDnD);
element.removeClass(dragEnterClass);
}
});
var deregisterDragEnd = $rootScope.$on('ANGULAR_DRAG_END', function() {
element.unbind('dragover', onDragOver);
element.unbind('dragenter', onDragEnter);
element.unbind('dragleave', onDragLeave);
element.unbind('drop', onDrop);
element.removeClass(dragHoverClass);
element.removeClass(dragEnterClass);
element.unbind('dragover', preventNativeDnD);
element.unbind('dragenter', preventNativeDnD);
element.unbind('dragleave', preventNativeDnD);
element.unbind('drop', preventNativeDnD);
});
scope.$on('$destroy', function() {
deregisterDragStart();
deregisterDragEnd();
});
attr.$observe('dropChannel', function(value) {
if (value) {
dropChannel = value;
}
});
};
}
]);
module.constant('$dragImageConfig', {
height: 20,
width: 200,
padding: 10,
font: 'bold 11px Arial',
fontColor: '#eee8d5',
backgroundColor: '#93a1a1',
xOffset: 0,
yOffset: 0
});
module.service('$dragImage', ['$dragImageConfig', function(defaultConfig) {
var ELLIPSIS = '…';
function fitString(canvas, text, config) {
var width = canvas.measureText(text).width;
if (width < config.width) {
return text;
}
while (width + config.padding > config.width) {
text = text.substring(0, text.length - 1);
width = canvas.measureText(text + ELLIPSIS).width;
}
return text + ELLIPSIS;
}
this.generate = function(text, options) {
var config = angular.extend({}, defaultConfig, options || {});
var el = document.createElement('canvas');
el.height = config.height;
el.width = config.width;
var canvas = el.getContext('2d');
canvas.fillStyle = config.backgroundColor;
canvas.fillRect(0, 0, config.width, config.height);
canvas.font = config.font;
canvas.fillStyle = config.fontColor;
var title = fitString(canvas, text, config);
canvas.fillText(title, 4, config.padding + 4);
var image = new Image();
image.src = el.toDataURL();
return {
image: image,
xOffset: config.xOffset,
yOffset: config.yOffset
};
};
}
]);
}(angular));

File diff suppressed because one or more lines are too long

@ -1,2 +0,0 @@
require('./draganddrop');
module.exports = 'ang-drag-drop';

@ -1,14 +0,0 @@
site_name: Angular Drag and Drop
site_url: http://angular-dragdrop.github.io/angular-dragdrop/
site_description: Project documentation for angular Drag and Drop.
repo_url: https://github.com/angular-dragdrop/angular-dragdrop
theme : flatly
pages:
- 'index.md'
- 'getting-started.md'
- 'examples.md'

@ -1,26 +0,0 @@
{
"name": "angular-native-dragdrop",
"version": "1.2.2",
"description": "Angular HTML5 Drag and Drop directive written in pure with no dependency on JQuery.",
"main": "index.js",
"scripts": {
"test": "gulp"
},
"repository": {
"type": "git",
"url": "https://github.com/angular-dragdrop/angular-dragdrop.git"
},
"author": "ganarajpr",
"license": "MIT",
"bugs": {
"url": "https://github.com/angular-dragdrop/angular-dragdrop/issues"
},
"homepage": "http://angular-dragdrop.github.io/angular-dragdrop",
"devDependencies": {
"gulp": "^3.8.11",
"gulp-jshint": "^1.9.2",
"gulp-rename": "^1.2.2",
"gulp-uglify": "^1.4.2",
"jshint-stylish": "^1.0.1"
}
}

@ -1,33 +0,0 @@
{
"name": "clipboard",
"version": "1.5.16",
"description": "Modern copy to clipboard. No Flash. Just 2kb",
"license": "MIT",
"main": "dist/clipboard.js",
"ignore": [
"/.*/",
"/demo/",
"/test/",
"/.*",
"/bower.json",
"/karma.conf.js",
"/src",
"/lib"
],
"keywords": [
"clipboard",
"copy",
"cut"
],
"homepage": "https://github.com/zenorocha/clipboard.js",
"_release": "1.5.16",
"_resolution": {
"type": "version",
"tag": "v1.5.16",
"commit": "402c9ee17bed6f273bcbc7efa81874fd9a50b84c"
},
"_source": "https://github.com/zenorocha/clipboard.js.git",
"_target": "^1.5.16",
"_originalSource": "clipboard",
"_direct": true
}

@ -1,22 +0,0 @@
{
"name": "clipboard",
"version": "1.5.16",
"description": "Modern copy to clipboard. No Flash. Just 2kb",
"license": "MIT",
"main": "dist/clipboard.js",
"ignore": [
"/.*/",
"/demo/",
"/test/",
"/.*",
"/bower.json",
"/karma.conf.js",
"/src",
"/lib"
],
"keywords": [
"clipboard",
"copy",
"cut"
]
}

@ -1,28 +0,0 @@
# Contributing guide
Want to contribute to Clipboard.js? Awesome!
There are many ways you can contribute, see below.
## Opening issues
Open an issue to report bugs or to propose new features.
- Reporting bugs: describe the bug as clearly as you can, including steps to reproduce, what happened and what you were expecting to happen. Also include browser version, OS and other related software's (npm, Node.js, etc) versions when applicable.
- Proposing features: explain the proposed feature, what it should do, why it is useful, how users should use it. Give us as much info as possible so it will be easier to discuss, access and implement the proposed feature. When you're unsure about a certain aspect of the feature, feel free to leave it open for others to discuss and find an appropriate solution.
## Proposing pull requests
Pull requests are very welcome. Note that if you are going to propose drastic changes, be sure to open an issue for discussion first, to make sure that your PR will be accepted before you spend effort coding it.
Fork the Clipboard.js repository, clone it locally and create a branch for your proposed bug fix or new feature. Avoid working directly on the master branch.
Implement your bug fix or feature, write tests to cover it and make sure all tests are passing (run a final `npm test` to make sure everything is correct). Then commit your changes, push your bug fix/feature branch to the origin (your forked repo) and open a pull request to the upstream (the repository you originally forked)'s master branch.
## Documentation
Documentation is extremely important and takes a fair deal of time and effort to write and keep updated. Please submit any and all improvements you can make to the repository's docs.
## Known issues
If you're using npm@3 you'll probably face some issues related to peerDependencies.
https://github.com/npm/npm/issues/9204

@ -1,755 +0,0 @@
/*!
* clipboard.js v1.5.16
* https://zenorocha.github.io/clipboard.js
*
* Licensed MIT © Zeno Rocha
*/
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Clipboard = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var DOCUMENT_NODE_TYPE = 9;
/**
* A polyfill for Element.matches()
*/
if (Element && !Element.prototype.matches) {
var proto = Element.prototype;
proto.matches = proto.matchesSelector ||
proto.mozMatchesSelector ||
proto.msMatchesSelector ||
proto.oMatchesSelector ||
proto.webkitMatchesSelector;
}
/**
* Finds the closest parent that matches a selector.
*
* @param {Element} element
* @param {String} selector
* @return {Function}
*/
function closest (element, selector) {
while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {
if (element.matches(selector)) return element;
element = element.parentNode;
}
}
module.exports = closest;
},{}],2:[function(require,module,exports){
var closest = require('./closest');
/**
* Delegates event to a selector.
*
* @param {Element} element
* @param {String} selector
* @param {String} type
* @param {Function} callback
* @param {Boolean} useCapture
* @return {Object}
*/
function delegate(element, selector, type, callback, useCapture) {
var listenerFn = listener.apply(this, arguments);
element.addEventListener(type, listenerFn, useCapture);
return {
destroy: function() {
element.removeEventListener(type, listenerFn, useCapture);
}
}
}
/**
* Finds closest match and invokes callback.
*
* @param {Element} element
* @param {String} selector
* @param {String} type
* @param {Function} callback
* @return {Function}
*/
function listener(element, selector, type, callback) {
return function(e) {
e.delegateTarget = closest(e.target, selector);
if (e.delegateTarget) {
callback.call(element, e);
}
}
}
module.exports = delegate;
},{"./closest":1}],3:[function(require,module,exports){
/**
* Check if argument is a HTML element.
*
* @param {Object} value
* @return {Boolean}
*/
exports.node = function(value) {
return value !== undefined
&& value instanceof HTMLElement
&& value.nodeType === 1;
};
/**
* Check if argument is a list of HTML elements.
*
* @param {Object} value
* @return {Boolean}
*/
exports.nodeList = function(value) {
var type = Object.prototype.toString.call(value);
return value !== undefined
&& (type === '[object NodeList]' || type === '[object HTMLCollection]')
&& ('length' in value)
&& (value.length === 0 || exports.node(value[0]));
};
/**
* Check if argument is a string.
*
* @param {Object} value
* @return {Boolean}
*/
exports.string = function(value) {
return typeof value === 'string'
|| value instanceof String;
};
/**
* Check if argument is a function.
*
* @param {Object} value
* @return {Boolean}
*/
exports.fn = function(value) {
var type = Object.prototype.toString.call(value);
return type === '[object Function]';
};
},{}],4:[function(require,module,exports){
var is = require('./is');
var delegate = require('delegate');
/**
* Validates all params and calls the right
* listener function based on its target type.
*
* @param {String|HTMLElement|HTMLCollection|NodeList} target
* @param {String} type
* @param {Function} callback
* @return {Object}
*/
function listen(target, type, callback) {
if (!target && !type && !callback) {
throw new Error('Missing required arguments');
}
if (!is.string(type)) {
throw new TypeError('Second argument must be a String');
}
if (!is.fn(callback)) {
throw new TypeError('Third argument must be a Function');
}
if (is.node(target)) {
return listenNode(target, type, callback);
}
else if (is.nodeList(target)) {
return listenNodeList(target, type, callback);
}
else if (is.string(target)) {
return listenSelector(target, type, callback);
}
else {
throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');
}
}
/**
* Adds an event listener to a HTML element
* and returns a remove listener function.
*
* @param {HTMLElement} node
* @param {String} type
* @param {Function} callback
* @return {Object}
*/
function listenNode(node, type, callback) {
node.addEventListener(type, callback);
return {
destroy: function() {
node.removeEventListener(type, callback);
}
}
}
/**
* Add an event listener to a list of HTML elements
* and returns a remove listener function.
*
* @param {NodeList|HTMLCollection} nodeList
* @param {String} type
* @param {Function} callback
* @return {Object}
*/
function listenNodeList(nodeList, type, callback) {
Array.prototype.forEach.call(nodeList, function(node) {
node.addEventListener(type, callback);
});
return {
destroy: function() {
Array.prototype.forEach.call(nodeList, function(node) {
node.removeEventListener(type, callback);
});
}
}
}
/**
* Add an event listener to a selector
* and returns a remove listener function.
*
* @param {String} selector
* @param {String} type
* @param {Function} callback
* @return {Object}
*/
function listenSelector(selector, type, callback) {
return delegate(document.body, selector, type, callback);
}
module.exports = listen;
},{"./is":3,"delegate":2}],5:[function(require,module,exports){
function select(element) {
var selectedText;
if (element.nodeName === 'SELECT') {
element.focus();
selectedText = element.value;
}
else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {
element.focus();
element.setSelectionRange(0, element.value.length);
selectedText = element.value;
}
else {
if (element.hasAttribute('contenteditable')) {
element.focus();
}
var selection = window.getSelection();
var range = document.createRange();
range.selectNodeContents(element);
selection.removeAllRanges();
selection.addRange(range);
selectedText = selection.toString();
}
return selectedText;
}
module.exports = select;
},{}],6:[function(require,module,exports){
function E () {
// Keep this empty so it's easier to inherit from
// (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
}
E.prototype = {
on: function (name, callback, ctx) {
var e = this.e || (this.e = {});
(e[name] || (e[name] = [])).push({
fn: callback,
ctx: ctx
});
return this;
},
once: function (name, callback, ctx) {
var self = this;
function listener () {
self.off(name, listener);
callback.apply(ctx, arguments);
};
listener._ = callback
return this.on(name, listener, ctx);
},
emit: function (name) {
var data = [].slice.call(arguments, 1);
var evtArr = ((this.e || (this.e = {}))[name] || []).slice();
var i = 0;
var len = evtArr.length;
for (i; i < len; i++) {
evtArr[i].fn.apply(evtArr[i].ctx, data);
}
return this;
},
off: function (name, callback) {
var e = this.e || (this.e = {});
var evts = e[name];
var liveEvents = [];
if (evts && callback) {
for (var i = 0, len = evts.length; i < len; i++) {
if (evts[i].fn !== callback && evts[i].fn._ !== callback)
liveEvents.push(evts[i]);
}
}
// Remove event from queue to prevent memory leak
// Suggested by https://github.com/lazd
// Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
(liveEvents.length)
? e[name] = liveEvents
: delete e[name];
return this;
}
};
module.exports = E;
},{}],7:[function(require,module,exports){
(function (global, factory) {
if (typeof define === "function" && define.amd) {
define(['module', 'select'], factory);
} else if (typeof exports !== "undefined") {
factory(module, require('select'));
} else {
var mod = {
exports: {}
};
factory(mod, global.select);
global.clipboardAction = mod.exports;
}
})(this, function (module, _select) {
'use strict';
var _select2 = _interopRequireDefault(_select);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
return typeof obj;
} : function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
var _createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
var ClipboardAction = function () {
/**
* @param {Object} options
*/
function ClipboardAction(options) {
_classCallCheck(this, ClipboardAction);
this.resolveOptions(options);
this.initSelection();
}
/**
* Defines base properties passed from constructor.
* @param {Object} options
*/
_createClass(ClipboardAction, [{
key: 'resolveOptions',
value: function resolveOptions() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
this.action = options.action;
this.emitter = options.emitter;
this.target = options.target;
this.text = options.text;
this.trigger = options.trigger;
this.selectedText = '';
}
}, {
key: 'initSelection',
value: function initSelection() {
if (this.text) {
this.selectFake();
} else if (this.target) {
this.selectTarget();
}
}
}, {
key: 'selectFake',
value: function selectFake() {
var _this = this;
var isRTL = document.documentElement.getAttribute('dir') == 'rtl';
this.removeFake();
this.fakeHandlerCallback = function () {
return _this.removeFake();
};
this.fakeHandler = document.body.addEventListener('click', this.fakeHandlerCallback) || true;
this.fakeElem = document.createElement('textarea');
// Prevent zooming on iOS
this.fakeElem.style.fontSize = '12pt';
// Reset box model
this.fakeElem.style.border = '0';
this.fakeElem.style.padding = '0';
this.fakeElem.style.margin = '0';
// Move element out of screen horizontally
this.fakeElem.style.position = 'absolute';
this.fakeElem.style[isRTL ? 'right' : 'left'] = '-9999px';
// Move element to the same position vertically
var yPosition = window.pageYOffset || document.documentElement.scrollTop;
this.fakeElem.addEventListener('focus', window.scrollTo(0, yPosition));
this.fakeElem.style.top = yPosition + 'px';
this.fakeElem.setAttribute('readonly', '');
this.fakeElem.value = this.text;
document.body.appendChild(this.fakeElem);
this.selectedText = (0, _select2.default)(this.fakeElem);
this.copyText();
}
}, {
key: 'removeFake',
value: function removeFake() {
if (this.fakeHandler) {
document.body.removeEventListener('click', this.fakeHandlerCallback);
this.fakeHandler = null;
this.fakeHandlerCallback = null;
}
if (this.fakeElem) {
document.body.removeChild(this.fakeElem);
this.fakeElem = null;
}
}
}, {
key: 'selectTarget',
value: function selectTarget() {
this.selectedText = (0, _select2.default)(this.target);
this.copyText();
}
}, {
key: 'copyText',
value: function copyText() {
var succeeded = void 0;
try {
succeeded = document.execCommand(this.action);
} catch (err) {
succeeded = false;
}
this.handleResult(succeeded);
}
}, {
key: 'handleResult',
value: function handleResult(succeeded) {
this.emitter.emit(succeeded ? 'success' : 'error', {
action: this.action,
text: this.selectedText,
trigger: this.trigger,
clearSelection: this.clearSelection.bind(this)
});
}
}, {
key: 'clearSelection',
value: function clearSelection() {
if (this.target) {
this.target.blur();
}
window.getSelection().removeAllRanges();
}
}, {
key: 'destroy',
value: function destroy() {
this.removeFake();
}
}, {
key: 'action',
set: function set() {
var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'copy';
this._action = action;
if (this._action !== 'copy' && this._action !== 'cut') {
throw new Error('Invalid "action" value, use either "copy" or "cut"');
}
},
get: function get() {
return this._action;
}
}, {
key: 'target',
set: function set(target) {
if (target !== undefined) {
if (target && (typeof target === 'undefined' ? 'undefined' : _typeof(target)) === 'object' && target.nodeType === 1) {
if (this.action === 'copy' && target.hasAttribute('disabled')) {
throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');
}
if (this.action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) {
throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');
}
this._target = target;
} else {
throw new Error('Invalid "target" value, use a valid Element');
}
}
},
get: function get() {
return this._target;
}
}]);
return ClipboardAction;
}();
module.exports = ClipboardAction;
});
},{"select":5}],8:[function(require,module,exports){
(function (global, factory) {
if (typeof define === "function" && define.amd) {
define(['module', './clipboard-action', 'tiny-emitter', 'good-listener'], factory);
} else if (typeof exports !== "undefined") {
factory(module, require('./clipboard-action'), require('tiny-emitter'), require('good-listener'));
} else {
var mod = {
exports: {}
};
factory(mod, global.clipboardAction, global.tinyEmitter, global.goodListener);
global.clipboard = mod.exports;
}
})(this, function (module, _clipboardAction, _tinyEmitter, _goodListener) {
'use strict';
var _clipboardAction2 = _interopRequireDefault(_clipboardAction);
var _tinyEmitter2 = _interopRequireDefault(_tinyEmitter);
var _goodListener2 = _interopRequireDefault(_goodListener);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
var _createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}
var Clipboard = function (_Emitter) {
_inherits(Clipboard, _Emitter);
/**
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger
* @param {Object} options
*/
function Clipboard(trigger, options) {
_classCallCheck(this, Clipboard);
var _this = _possibleConstructorReturn(this, (Clipboard.__proto__ || Object.getPrototypeOf(Clipboard)).call(this));
_this.resolveOptions(options);
_this.listenClick(trigger);
return _this;
}
/**
* Defines if attributes would be resolved using internal setter functions
* or custom functions that were passed in the constructor.
* @param {Object} options
*/
_createClass(Clipboard, [{
key: 'resolveOptions',
value: function resolveOptions() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
this.action = typeof options.action === 'function' ? options.action : this.defaultAction;
this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;
this.text = typeof options.text === 'function' ? options.text : this.defaultText;
}
}, {
key: 'listenClick',
value: function listenClick(trigger) {
var _this2 = this;
this.listener = (0, _goodListener2.default)(trigger, 'click', function (e) {
return _this2.onClick(e);
});
}
}, {
key: 'onClick',
value: function onClick(e) {
var trigger = e.delegateTarget || e.currentTarget;
if (this.clipboardAction) {
this.clipboardAction = null;
}
this.clipboardAction = new _clipboardAction2.default({
action: this.action(trigger),
target: this.target(trigger),
text: this.text(trigger),
trigger: trigger,
emitter: this
});
}
}, {
key: 'defaultAction',
value: function defaultAction(trigger) {
return getAttributeValue('action', trigger);
}
}, {
key: 'defaultTarget',
value: function defaultTarget(trigger) {
var selector = getAttributeValue('target', trigger);
if (selector) {
return document.querySelector(selector);
}
}
}, {
key: 'defaultText',
value: function defaultText(trigger) {
return getAttributeValue('text', trigger);
}
}, {
key: 'destroy',
value: function destroy() {
this.listener.destroy();
if (this.clipboardAction) {
this.clipboardAction.destroy();
this.clipboardAction = null;
}
}
}]);
return Clipboard;
}(_tinyEmitter2.default);
/**
* Helper function to retrieve attribute value.
* @param {String} suffix
* @param {Element} element
*/
function getAttributeValue(suffix, element) {
var attribute = 'data-clipboard-' + suffix;
if (!element.hasAttribute(attribute)) {
return;
}
return element.getAttribute(attribute);
}
module.exports = Clipboard;
});
},{"./clipboard-action":7,"good-listener":4,"tiny-emitter":6}]},{},[8])(8)
});

File diff suppressed because one or more lines are too long

@ -1,12 +0,0 @@
// Package metadata for Meteor.js.
Package.describe({
name: "zenorocha:clipboard",
summary: "Modern copy to clipboard. No Flash. Just 2kb.",
version: "1.5.16",
git: "https://github.com/zenorocha/clipboard.js"
});
Package.onUse(function(api) {
api.addFiles("dist/clipboard.js", "client");
});

@ -1,48 +0,0 @@
{
"name": "clipboard",
"version": "1.5.16",
"description": "Modern copy to clipboard. No Flash. Just 2kb",
"repository": "zenorocha/clipboard.js",
"license": "MIT",
"main": "lib/clipboard.js",
"keywords": [
"clipboard",
"copy",
"cut"
],
"dependencies": {
"good-listener": "^1.2.0",
"select": "^1.0.6",
"tiny-emitter": "^1.0.0"
},
"devDependencies": {
"babel-cli": "^6.5.1",
"babel-core": "^6.5.2",
"babel-plugin-transform-es2015-modules-umd": "^6.5.0",
"babel-preset-es2015": "^6.5.0",
"babelify": "^7.2.0",
"bannerify": "Vekat/bannerify#feature-option",
"browserify": "^13.0.0",
"chai": "^3.4.1",
"install": "^0.8.1",
"karma": "^1.3.0",
"karma-browserify": "^5.0.1",
"karma-chai": "^0.1.0",
"karma-mocha": "^1.2.0",
"karma-phantomjs-launcher": "^1.0.0",
"karma-sinon": "^1.0.4",
"mocha": "^3.1.2",
"phantomjs-prebuilt": "^2.1.4",
"sinon": "^1.17.2",
"uglify-js": "^2.4.24",
"watchify": "^3.4.0"
},
"scripts": {
"build": "npm run build-debug && npm run build-min",
"build-debug": "browserify src/clipboard.js -s Clipboard -t [babelify] -p [bannerify --file .banner ] -o dist/clipboard.js",
"build-min": "uglifyjs dist/clipboard.js --comments '/!/' -m screw_ie8=true -c screw_ie8=true,unused=false -o dist/clipboard.min.js",
"build-watch": "watchify src/clipboard.js -s Clipboard -t [babelify] -o dist/clipboard.js -v",
"test": "karma start --single-run",
"prepublish": "babel src --out-dir lib"
}
}

@ -1,173 +0,0 @@
# clipboard.js
[![Build Status](http://img.shields.io/travis/zenorocha/clipboard.js/master.svg?style=flat)](https://travis-ci.org/zenorocha/clipboard.js)
![Killing Flash](https://img.shields.io/badge/killing-flash-brightgreen.svg?style=flat)
> Modern copy to clipboard. No Flash. Just 3kb gzipped.
<a href="https://clipboardjs.com/"><img width="728" src="https://cloud.githubusercontent.com/assets/398893/16165747/a0f6fc46-349a-11e6-8c9b-c5fd58d9099c.png" alt="Demo"></a>
## Why
Copying text to the clipboard shouldn't be hard. It shouldn't require dozens of steps to configure or hundreds of KBs to load. But most of all, it shouldn't depend on Flash or any bloated framework.
That's why clipboard.js exists.
## Install
You can get it on npm.
```
npm install clipboard --save
```
Or bower, too.
```
bower install clipboard --save
```
If you're not into package management, just [download a ZIP](https://github.com/zenorocha/clipboard.js/archive/master.zip) file.
## Setup
First, include the script located on the `dist` folder or load it from [a third-party CDN provider](https://github.com/zenorocha/clipboard.js/wiki/CDN-Providers).
```html
<script src="dist/clipboard.min.js"></script>
```
Now, you need to instantiate it by [passing a DOM selector](https://github.com/zenorocha/clipboard.js/blob/master/demo/constructor-selector.html#L18), [HTML element](https://github.com/zenorocha/clipboard.js/blob/master/demo/constructor-node.html#L16-L17), or [list of HTML elements](https://github.com/zenorocha/clipboard.js/blob/master/demo/constructor-nodelist.html#L18-L19).
```js
new Clipboard('.btn');
```
Internally, we need to fetch all elements that matches with your selector and attach event listeners for each one. But guess what? If you have hundreds of matches, this operation can consume a lot of memory.
For this reason we use [event delegation](http://stackoverflow.com/questions/1687296/what-is-dom-event-delegation) which replaces multiple event listeners with just a single listener. After all, [#perfmatters](https://twitter.com/hashtag/perfmatters).
# Usage
We're living a _declarative renaissance_, that's why we decided to take advantage of [HTML5 data attributes](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Using_data_attributes) for better usability.
### Copy text from another element
A pretty common use case is to copy content from another element. You can do that by adding a `data-clipboard-target` attribute in your trigger element.
The value you include on this attribute needs to match another's element selector.
<a href="https://clipboardjs.com/#example-target"><img width="473" alt="example-2" src="https://cloud.githubusercontent.com/assets/398893/9983467/a4946aaa-5fb1-11e5-9780-f09fcd7ca6c8.png"></a>
```html
<!-- Target -->
<input id="foo" value="https://github.com/zenorocha/clipboard.js.git">
<!-- Trigger -->
<button class="btn" data-clipboard-target="#foo">
<img src="assets/clippy.svg" alt="Copy to clipboard">
</button>
```
### Cut text from another element
Additionally, you can define a `data-clipboard-action` attribute to specify if you want to either `copy` or `cut` content.
If you omit this attribute, `copy` will be used by default.
<a href="https://clipboardjs.com/#example-action"><img width="473" alt="example-3" src="https://cloud.githubusercontent.com/assets/398893/10000358/7df57b9c-6050-11e5-9cd1-fbc51d2fd0a7.png"></a>
```html
<!-- Target -->
<textarea id="bar">Mussum ipsum cacilds...</textarea>
<!-- Trigger -->
<button class="btn" data-clipboard-action="cut" data-clipboard-target="#bar">
Cut to clipboard
</button>
```
As you may expect, the `cut` action only works on `<input>` or `<textarea>` elements.
### Copy text from attribute
Truth is, you don't even need another element to copy its content from. You can just include a `data-clipboard-text` attribute in your trigger element.
<a href="https://clipboardjs.com/#example-text"><img width="147" alt="example-1" src="https://cloud.githubusercontent.com/assets/398893/10000347/6e16cf8c-6050-11e5-9883-1c5681f9ec45.png"></a>
```html
<!-- Trigger -->
<button class="btn" data-clipboard-text="Just because you can doesn't mean you should — clipboard.js">
Copy to clipboard
</button>
```
## Events
There are cases where you'd like to show some user feedback or capture what has been selected after a copy/cut operation.
That's why we fire custom events such as `success` and `error` for you to listen and implement your custom logic.
```js
var clipboard = new Clipboard('.btn');
clipboard.on('success', function(e) {
console.info('Action:', e.action);
console.info('Text:', e.text);
console.info('Trigger:', e.trigger);
e.clearSelection();
});
clipboard.on('error', function(e) {
console.error('Action:', e.action);
console.error('Trigger:', e.trigger);
});
```
For a live demonstration, open this [site](https://clipboardjs.com/) and just your console :)
## Advanced Options
If you don't want to modify your HTML, there's a pretty handy imperative API for you to use. All you need to do is declare a function, do your thing, and return a value.
For instance, if you want to dynamically set a `target`, you'll need to return a Node.
```js
new Clipboard('.btn', {
target: function(trigger) {
return trigger.nextElementSibling;
}
});
```
If you want to dynamically set a `text`, you'll return a String.
```js
new Clipboard('.btn', {
text: function(trigger) {
return trigger.getAttribute('aria-label');
}
});
```
Also, if you are working with single page apps, you may want to manage the lifecycle of the DOM more precisely. Here's how you clean up the events and objects that we create.
```js
var clipboard = new Clipboard('.btn');
clipboard.destroy();
```
## Browser Support
This library relies on both [Selection](https://developer.mozilla.org/en-US/docs/Web/API/Selection) and [execCommand](https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand) APIs. The first one is [supported by all browsers](http://caniuse.com/#search=selection) while the second one is supported in the following browsers.
| <img src="https://clipboardjs.com/assets/images/chrome.png" width="48px" height="48px" alt="Chrome logo"> | <img src="https://clipboardjs.com/assets/images/edge.png" width="48px" height="48px" alt="Edge logo"> | <img src="https://clipboardjs.com/assets/images/firefox.png" width="48px" height="48px" alt="Firefox logo"> | <img src="https://clipboardjs.com/assets/images/ie.png" width="48px" height="48px" alt="Internet Explorer logo"> | <img src="https://clipboardjs.com/assets/images/opera.png" width="48px" height="48px" alt="Opera logo"> | <img src="https://clipboardjs.com/assets/images/safari.png" width="48px" height="48px" alt="Safari logo"> |
|:---:|:---:|:---:|:---:|:---:|:---:|
| 42+ ✔ | 12+ ✔ | 41+ ✔ | 9+ ✔ | 29+ ✔ | 10+ ✔ |
The good news is that clipboard.js gracefully degrades if you need to support older browsers. All you have to do is show a tooltip saying `Copied!` when `success` event is called and `Press Ctrl+C to copy` when `error` event is called because the text is already selected.
## License
[MIT License](http://zenorocha.mit-license.org/) © Zeno Rocha

@ -45,6 +45,9 @@ module.exports = function(config) {
'react/dist/*.js',
'react-dom/dist/*.js',
'ngreact/ngReact.js',
'angular-bindonce/bindonce.js',
'angular-native-dragdrop/draganddrop.js',
'clipboard/dist/clipboard.js',
],
dest: '<%= srcDir %>/vendor/npm'
}

@ -97,10 +97,18 @@ amdefine@>=0.0.4:
version "1.0.1"
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
angular-bindonce@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/angular-bindonce/-/angular-bindonce-0.3.1.tgz#af19574abd43f608b9236a302cc5ce49d71dc9c6"
angular-mocks@^1.6.6:
version "1.6.6"
resolved "https://registry.yarnpkg.com/angular-mocks/-/angular-mocks-1.6.6.tgz#c93018e7838c6dc5ceaf1a6bcf9be13c830ea515"
angular-native-dragdrop@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/angular-native-dragdrop/-/angular-native-dragdrop-1.2.2.tgz#d646c6b75b131c48073c3f6e36a225b2726d8bae"
angular-route@^1.6.6:
version "1.6.6"
resolved "https://registry.yarnpkg.com/angular-route/-/angular-route-1.6.6.tgz#8c11748aa195c717b1b615a7e746442bfc7c61f4"
@ -750,6 +758,14 @@ cli@~1.0.0:
exit "0.1.2"
glob "^7.1.1"
clipboard@^1.7.1:
version "1.7.1"
resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-1.7.1.tgz#360d6d6946e99a7a1fef395e42ba92b5e9b5a16b"
dependencies:
good-listener "^1.2.2"
select "^1.1.2"
tiny-emitter "^2.0.0"
cliui@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
@ -1046,6 +1062,10 @@ delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
delegate@^3.1.2:
version "3.1.3"
resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.1.3.tgz#9a8251a777d7025faa55737bc3b071742127a9fd"
delegates@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
@ -1818,6 +1838,12 @@ gonzales-pe@3.4.7:
dependencies:
minimist "1.1.x"
good-listener@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50"
dependencies:
delegate "^3.1.2"
graceful-fs@^4.1.0, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
version "4.1.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
@ -4114,6 +4140,10 @@ scss-tokenizer@^0.2.3:
js-base64 "^2.1.8"
source-map "^0.4.2"
select@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d"
"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.3.0:
version "5.4.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e"
@ -4553,6 +4583,10 @@ tiny-emitter@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-1.2.0.tgz#6dc845052cb08ebefc1874723b58f24a648c3b6f"
tiny-emitter@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.0.2.tgz#82d27468aca5ade8e5fd1e6d22b57dd43ebdfb7c"
tiny-lr@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-0.2.1.tgz#b3fdba802e5d56a33c2f6f10794b32e477ac729d"

Loading…
Cancel
Save